From b42c5ced68c019108e079dc01d0bd29606efc10c Mon Sep 17 00:00:00 2001 From: Michael Killough Date: Sat, 16 Mar 2019 18:13:13 +0000 Subject: Implement BindingMode for pattern matching. Implement `BindingMode` for pattern matching, so that types can be correctly inferred using match ergonomics. The binding mode defaults to `Move` (referred to as 'BindingMode::BindByValue` in rustc), and is updated by automatic dereferencing of the value being matched. --- crates/ra_hir/src/ty/infer.rs | 95 +++++++++++++++++++++++++++------ crates/ra_hir/src/ty/tests.rs | 121 ++++++++++++++++++++++++++---------------- 2 files changed, 154 insertions(+), 62 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 268d2c110..7200446ba 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -63,6 +63,24 @@ enum ExprOrPatId { impl_froms!(ExprOrPatId: ExprId, PatId); +/// Binding modes inferred for patterns. +/// https://doc.rust-lang.org/reference/patterns.html#binding-modes +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum BindingMode { + Move, + Ref(Mutability), +} + +impl BindingMode { + pub fn convert(annotation: &BindingAnnotation) -> BindingMode { + match annotation { + BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, + BindingAnnotation::Ref => BindingMode::Ref(Mutability::Shared), + BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), + } + } +} + /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { @@ -530,6 +548,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { path: Option<&Path>, subpats: &[PatId], expected: &Ty, + default_bm: BindingMode, ) -> Ty { let (ty, def) = self.resolve_variant(path); @@ -542,13 +561,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) .map_or(Ty::Unknown, |field| field.ty(self.db)) .subst(&substs); - self.infer_pat(subpat, &expected_ty); + self.infer_pat(subpat, &expected_ty, default_bm); } ty } - fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { + fn infer_struct_pat( + &mut self, + path: Option<&Path>, + subpats: &[FieldPat], + expected: &Ty, + default_bm: BindingMode, + ) -> Ty { let (ty, def) = self.resolve_variant(path); self.unify(&ty, expected); @@ -559,15 +584,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); let expected_ty = matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); - self.infer_pat(subpat.pat, &expected_ty); + self.infer_pat(subpat.pat, &expected_ty, default_bm); } ty } - fn infer_pat(&mut self, pat: PatId, expected: &Ty) -> Ty { + fn infer_pat(&mut self, pat: PatId, mut expected: &Ty, mut default_bm: BindingMode) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem + let is_non_ref_pat = match &body[pat] { + Pat::Tuple(..) + | Pat::TupleStruct { .. } + | Pat::Struct { .. } + | Pat::Range { .. } + | Pat::Slice { .. } => true, + // TODO: Path/Lit might actually evaluate to ref, but inference is unimplemented. + Pat::Path(..) | Pat::Lit(..) => true, + Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, + }; + if is_non_ref_pat { + while let Ty::Ref(inner, mutability) = expected { + expected = inner; + default_bm = match default_bm { + BindingMode::Move => BindingMode::Ref(*mutability), + BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared), + BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(*mutability), + } + } + } else if let Pat::Ref { .. } = &body[pat] { + default_bm = BindingMode::Move; + } + + // Lose mutability. + let default_bm = default_bm; + let expected = expected; + let ty = match &body[pat] { Pat::Tuple(ref args) => { let expectations = match *expected { @@ -579,7 +631,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let inner_tys = args .iter() .zip(expectations_iter) - .map(|(&pat, ty)| self.infer_pat(pat, ty)) + .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) .collect::>() .into(); @@ -595,14 +647,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } _ => &Ty::Unknown, }; - let subty = self.infer_pat(*pat, expectation); + let subty = self.infer_pat(*pat, expectation, default_bm); Ty::Ref(subty.into(), *mutability) } Pat::TupleStruct { path: ref p, args: ref subpats } => { - self.infer_tuple_struct_pat(p.as_ref(), subpats, expected) + self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) } Pat::Struct { path: ref p, args: ref fields } => { - self.infer_struct_pat(p.as_ref(), fields, expected) + self.infer_struct_pat(p.as_ref(), fields, expected, default_bm) } Pat::Path(path) => { // TODO use correct resolver for the surrounding expression @@ -610,17 +662,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) } Pat::Bind { mode, name: _name, subpat } => { + let mode = if mode == &BindingAnnotation::Unannotated { + default_bm + } else { + BindingMode::convert(mode) + }; let inner_ty = if let Some(subpat) = subpat { - self.infer_pat(*subpat, expected) + self.infer_pat(*subpat, expected, default_bm) } else { expected.clone() }; let inner_ty = self.insert_type_vars_shallow(inner_ty); let bound_ty = match mode { - BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), - BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), - BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(), + BindingMode::Ref(Mutability::Shared) => { + Ty::Ref(inner_ty.clone().into(), Mutability::Shared) + } + BindingMode::Ref(Mutability::Mut) => { + Ty::Ref(inner_ty.clone().into(), Mutability::Mut) + } + BindingMode::Move => inner_ty.clone(), }; let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); self.write_pat_ty(pat, bound_ty); @@ -700,7 +761,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::For { iterable, body, pat } => { let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - self.infer_pat(*pat, &Ty::Unknown); + self.infer_pat(*pat, &Ty::Unknown, BindingMode::Move); self.infer_expr(*body, &Expectation::has_type(Ty::unit())); Ty::unit() } @@ -714,7 +775,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } else { Ty::Unknown }; - self.infer_pat(*arg_pat, &expected); + self.infer_pat(*arg_pat, &expected, BindingMode::Move); } // TODO: infer lambda type etc. @@ -804,7 +865,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for arm in arms { for &pat in &arm.pats { - let _pat_ty = self.infer_pat(pat, &input_ty); + let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::Move); } if let Some(guard_expr) = arm.guard { self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); @@ -1004,7 +1065,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { decl_ty }; - self.infer_pat(*pat, &ty); + self.infer_pat(*pat, &ty, BindingMode::Move); } Statement::Expr(expr) => { self.infer_expr(*expr, &Expectation::none()); @@ -1020,7 +1081,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for (type_ref, pat) in signature.params().iter().zip(body.params()) { let ty = self.make_ty(type_ref); - self.infer_pat(*pat, &ty); + self.infer_pat(*pat, &ty, BindingMode::Move); } self.return_ty = self.make_ty(signature.ret_type()); } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c7d409e6d..b12ea4334 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -756,6 +756,8 @@ fn test(x: &str, y: isize) { fn infer_pattern() { assert_snapshot_matches!( infer(r#" +struct A(T); + fn test(x: &i32) { let y = x; let &z = x; @@ -772,6 +774,12 @@ fn test(x: &i32) { let lambda = |a: u64, b, c: i32| { a + b; c }; + let A(n) = &A(1); + let A(n) = &mut A(1); + + let v = &(1, &2); + let (_, &w) = v; + let ref ref_to_x = x; let mut mut_x = x; let ref mut mut_ref_to_x = x; @@ -779,53 +787,76 @@ fn test(x: &i32) { } "#), @r###" -[9; 10) 'x': &i32 -[18; 369) '{ ...o_x; }': () -[28; 29) 'y': &i32 -[32; 33) 'x': &i32 -[43; 45) '&z': &i32 -[44; 45) 'z': i32 -[48; 49) 'x': &i32 -[59; 60) 'a': i32 -[63; 64) 'z': i32 -[74; 80) '(c, d)': (i32, &str) -[75; 76) 'c': i32 -[78; 79) 'd': &str -[83; 95) '(1, "hello")': (i32, &str) -[84; 85) '1': i32 -[87; 94) '"hello"': &str -[102; 152) 'for (e... }': () -[106; 112) '(e, f)': ({unknown}, {unknown}) -[107; 108) 'e': {unknown} -[110; 111) 'f': {unknown} -[116; 125) 'some_iter': {unknown} -[126; 152) '{ ... }': () -[140; 141) 'g': {unknown} -[144; 145) 'e': {unknown} -[158; 205) 'if let... }': () -[165; 170) '[val]': {unknown} -[173; 176) 'opt': {unknown} -[177; 205) '{ ... }': () -[191; 192) 'h': {unknown} -[195; 198) 'val': {unknown} -[215; 221) 'lambda': {unknown} -[224; 256) '|a: u6...b; c }': {unknown} -[225; 226) 'a': u64 -[233; 234) 'b': u64 -[236; 237) 'c': i32 -[244; 256) '{ a + b; c }': i32 -[246; 247) 'a': u64 -[246; 251) 'a + b': u64 +[26; 27) 'x': &i32 +[35; 479) '{ ...o_x; }': () +[45; 46) 'y': &i32 +[49; 50) 'x': &i32 +[60; 62) '&z': &i32 +[61; 62) 'z': i32 +[65; 66) 'x': &i32 +[76; 77) 'a': i32 +[80; 81) 'z': i32 +[91; 97) '(c, d)': (i32, &str) +[92; 93) 'c': i32 +[95; 96) 'd': &str +[100; 112) '(1, "hello")': (i32, &str) +[101; 102) '1': i32 +[104; 111) '"hello"': &str +[119; 169) 'for (e... }': () +[123; 129) '(e, f)': ({unknown}, {unknown}) +[124; 125) 'e': {unknown} +[127; 128) 'f': {unknown} +[133; 142) 'some_iter': {unknown} +[143; 169) '{ ... }': () +[157; 158) 'g': {unknown} +[161; 162) 'e': {unknown} +[175; 222) 'if let... }': () +[182; 187) '[val]': {unknown} +[190; 193) 'opt': {unknown} +[194; 222) '{ ... }': () +[208; 209) 'h': {unknown} +[212; 215) 'val': {unknown} +[232; 238) 'lambda': {unknown} +[241; 273) '|a: u6...b; c }': {unknown} +[242; 243) 'a': u64 [250; 251) 'b': u64 [253; 254) 'c': i32 -[267; 279) 'ref ref_to_x': &&i32 -[282; 283) 'x': &i32 -[293; 302) 'mut mut_x': &i32 -[305; 306) 'x': &i32 -[316; 336) 'ref mu...f_to_x': &mut &i32 -[339; 340) 'x': &i32 -[350; 351) 'k': &mut &i32 -[354; 366) 'mut_ref_to_x': &mut &i32"### +[261; 273) '{ a + b; c }': i32 +[263; 264) 'a': u64 +[263; 268) 'a + b': u64 +[267; 268) 'b': u64 +[270; 271) 'c': i32 +[284; 288) 'A(n)': A +[286; 287) 'n': &i32 +[291; 296) '&A(1)': &A +[292; 293) 'A': A(T) -> A +[292; 296) 'A(1)': A +[294; 295) '1': i32 +[306; 310) 'A(n)': A +[308; 309) 'n': &mut i32 +[313; 322) '&mut A(1)': &mut A +[318; 319) 'A': A(T) -> A +[318; 322) 'A(1)': A +[320; 321) '1': i32 +[333; 334) 'v': &(i32, &i32) +[337; 345) '&(1, &2)': &(i32, &i32) +[338; 345) '(1, &2)': (i32, &i32) +[339; 340) '1': i32 +[342; 344) '&2': &i32 +[343; 344) '2': i32 +[355; 362) '(_, &w)': (i32, &i32) +[356; 357) '_': i32 +[359; 361) '&w': &i32 +[360; 361) 'w': i32 +[365; 366) 'v': &(i32, &i32) +[377; 389) 'ref ref_to_x': &&i32 +[392; 393) 'x': &i32 +[403; 412) 'mut mut_x': &i32 +[415; 416) 'x': &i32 +[426; 446) 'ref mu...f_to_x': &mut &i32 +[449; 450) 'x': &i32 +[460; 461) 'k': &mut &i32 +[464; 476) 'mut_ref_to_x': &mut &i32"### ); } -- cgit v1.2.3 From 354134ffb4e6a0962e9faf19ebe2bb1cda4da9ab Mon Sep 17 00:00:00 2001 From: Michael Killough Date: Sun, 17 Mar 2019 18:46:01 +0000 Subject: impl Default for BindingMode. This decouples callers from knowing what the default binding mode of pattern matching is. --- crates/ra_hir/src/ty/infer.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7200446ba..92c79df15 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -81,6 +81,12 @@ impl BindingMode { } } +impl Default for BindingMode { + fn default() -> Self { + BindingMode::Move + } +} + /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { @@ -761,7 +767,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::For { iterable, body, pat } => { let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - self.infer_pat(*pat, &Ty::Unknown, BindingMode::Move); + self.infer_pat(*pat, &Ty::Unknown, BindingMode::default()); self.infer_expr(*body, &Expectation::has_type(Ty::unit())); Ty::unit() } @@ -775,7 +781,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } else { Ty::Unknown }; - self.infer_pat(*arg_pat, &expected, BindingMode::Move); + self.infer_pat(*arg_pat, &expected, BindingMode::default()); } // TODO: infer lambda type etc. @@ -865,7 +871,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for arm in arms { for &pat in &arm.pats { - let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::Move); + let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default()); } if let Some(guard_expr) = arm.guard { self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); @@ -1065,7 +1071,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { decl_ty }; - self.infer_pat(*pat, &ty, BindingMode::Move); + self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr(expr) => { self.infer_expr(*expr, &Expectation::none()); @@ -1081,7 +1087,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for (type_ref, pat) in signature.params().iter().zip(body.params()) { let ty = self.make_ty(type_ref); - self.infer_pat(*pat, &ty, BindingMode::Move); + self.infer_pat(*pat, &ty, BindingMode::default()); } self.return_ty = self.make_ty(signature.ret_type()); } -- cgit v1.2.3 From 33add0ee30ed9deb715d15e07b16568d4deb56b3 Mon Sep 17 00:00:00 2001 From: Michael Killough Date: Sun, 17 Mar 2019 18:50:22 +0000 Subject: Simplify match statement. --- crates/ra_hir/src/ty/infer.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 92c79df15..3d0b7a827 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -681,12 +681,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let inner_ty = self.insert_type_vars_shallow(inner_ty); let bound_ty = match mode { - BindingMode::Ref(Mutability::Shared) => { - Ty::Ref(inner_ty.clone().into(), Mutability::Shared) - } - BindingMode::Ref(Mutability::Mut) => { - Ty::Ref(inner_ty.clone().into(), Mutability::Mut) - } + BindingMode::Ref(mutability) => Ty::Ref(inner_ty.clone().into(), mutability), BindingMode::Move => inner_ty.clone(), }; let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); -- cgit v1.2.3 From 6299ccd350c190003c51aa68f48b1edfb1a497b1 Mon Sep 17 00:00:00 2001 From: Michael Killough Date: Sun, 17 Mar 2019 19:05:10 +0000 Subject: Split test case and use tested_by!. --- crates/ra_hir/src/marks.rs | 1 + crates/ra_hir/src/ty/infer.rs | 3 + crates/ra_hir/src/ty/tests.rs | 175 ++++++++++++++++++++++++------------------ 3 files changed, 103 insertions(+), 76 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 16852a6a1..6f3e5f09d 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -7,4 +7,5 @@ test_utils::marks!( glob_enum glob_across_crates std_prelude + match_ergonomics_ref ); diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 3d0b7a827..0a698988c 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -619,6 +619,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } } else if let Pat::Ref { .. } = &body[pat] { + tested_by!(match_ergonomics_ref); + // When you encounter a `&pat` pattern, reset to Move. + // This is so that `w` is by value: `let (_, &w) = &(1, &2);` default_bm = BindingMode::Move; } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index b12ea4334..0f8551a9d 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -756,8 +756,6 @@ fn test(x: &str, y: isize) { fn infer_pattern() { assert_snapshot_matches!( infer(r#" -struct A(T); - fn test(x: &i32) { let y = x; let &z = x; @@ -774,12 +772,6 @@ fn test(x: &i32) { let lambda = |a: u64, b, c: i32| { a + b; c }; - let A(n) = &A(1); - let A(n) = &mut A(1); - - let v = &(1, &2); - let (_, &w) = v; - let ref ref_to_x = x; let mut mut_x = x; let ref mut mut_ref_to_x = x; @@ -787,76 +779,107 @@ fn test(x: &i32) { } "#), @r###" -[26; 27) 'x': &i32 -[35; 479) '{ ...o_x; }': () -[45; 46) 'y': &i32 -[49; 50) 'x': &i32 -[60; 62) '&z': &i32 -[61; 62) 'z': i32 -[65; 66) 'x': &i32 -[76; 77) 'a': i32 -[80; 81) 'z': i32 -[91; 97) '(c, d)': (i32, &str) -[92; 93) 'c': i32 -[95; 96) 'd': &str -[100; 112) '(1, "hello")': (i32, &str) -[101; 102) '1': i32 -[104; 111) '"hello"': &str -[119; 169) 'for (e... }': () -[123; 129) '(e, f)': ({unknown}, {unknown}) -[124; 125) 'e': {unknown} -[127; 128) 'f': {unknown} -[133; 142) 'some_iter': {unknown} -[143; 169) '{ ... }': () -[157; 158) 'g': {unknown} -[161; 162) 'e': {unknown} -[175; 222) 'if let... }': () -[182; 187) '[val]': {unknown} -[190; 193) 'opt': {unknown} -[194; 222) '{ ... }': () -[208; 209) 'h': {unknown} -[212; 215) 'val': {unknown} -[232; 238) 'lambda': {unknown} -[241; 273) '|a: u6...b; c }': {unknown} -[242; 243) 'a': u64 +[9; 10) 'x': &i32 +[18; 369) '{ ...o_x; }': () +[28; 29) 'y': &i32 +[32; 33) 'x': &i32 +[43; 45) '&z': &i32 +[44; 45) 'z': i32 +[48; 49) 'x': &i32 +[59; 60) 'a': i32 +[63; 64) 'z': i32 +[74; 80) '(c, d)': (i32, &str) +[75; 76) 'c': i32 +[78; 79) 'd': &str +[83; 95) '(1, "hello")': (i32, &str) +[84; 85) '1': i32 +[87; 94) '"hello"': &str +[102; 152) 'for (e... }': () +[106; 112) '(e, f)': ({unknown}, {unknown}) +[107; 108) 'e': {unknown} +[110; 111) 'f': {unknown} +[116; 125) 'some_iter': {unknown} +[126; 152) '{ ... }': () +[140; 141) 'g': {unknown} +[144; 145) 'e': {unknown} +[158; 205) 'if let... }': () +[165; 170) '[val]': {unknown} +[173; 176) 'opt': {unknown} +[177; 205) '{ ... }': () +[191; 192) 'h': {unknown} +[195; 198) 'val': {unknown} +[215; 221) 'lambda': {unknown} +[224; 256) '|a: u6...b; c }': {unknown} +[225; 226) 'a': u64 +[233; 234) 'b': u64 +[236; 237) 'c': i32 +[244; 256) '{ a + b; c }': i32 +[246; 247) 'a': u64 +[246; 251) 'a + b': u64 [250; 251) 'b': u64 [253; 254) 'c': i32 -[261; 273) '{ a + b; c }': i32 -[263; 264) 'a': u64 -[263; 268) 'a + b': u64 -[267; 268) 'b': u64 -[270; 271) 'c': i32 -[284; 288) 'A(n)': A -[286; 287) 'n': &i32 -[291; 296) '&A(1)': &A -[292; 293) 'A': A(T) -> A -[292; 296) 'A(1)': A -[294; 295) '1': i32 -[306; 310) 'A(n)': A -[308; 309) 'n': &mut i32 -[313; 322) '&mut A(1)': &mut A -[318; 319) 'A': A(T) -> A -[318; 322) 'A(1)': A -[320; 321) '1': i32 -[333; 334) 'v': &(i32, &i32) -[337; 345) '&(1, &2)': &(i32, &i32) -[338; 345) '(1, &2)': (i32, &i32) -[339; 340) '1': i32 -[342; 344) '&2': &i32 -[343; 344) '2': i32 -[355; 362) '(_, &w)': (i32, &i32) -[356; 357) '_': i32 -[359; 361) '&w': &i32 -[360; 361) 'w': i32 -[365; 366) 'v': &(i32, &i32) -[377; 389) 'ref ref_to_x': &&i32 -[392; 393) 'x': &i32 -[403; 412) 'mut mut_x': &i32 -[415; 416) 'x': &i32 -[426; 446) 'ref mu...f_to_x': &mut &i32 -[449; 450) 'x': &i32 -[460; 461) 'k': &mut &i32 -[464; 476) 'mut_ref_to_x': &mut &i32"### +[267; 279) 'ref ref_to_x': &&i32 +[282; 283) 'x': &i32 +[293; 302) 'mut mut_x': &i32 +[305; 306) 'x': &i32 +[316; 336) 'ref mu...f_to_x': &mut &i32 +[339; 340) 'x': &i32 +[350; 351) 'k': &mut &i32 +[354; 366) 'mut_ref_to_x': &mut &i32"### + ); +} + +#[test] +fn infer_pattern_match_ergonomics() { + assert_snapshot_matches!( + infer(r#" +struct A(T); + +fn test() { + let A(n) = &A(1); + let A(n) = &mut A(1); +} +"#), + @r###" +[28; 79) '{ ...(1); }': () +[38; 42) 'A(n)': A +[40; 41) 'n': &i32 +[45; 50) '&A(1)': &A +[46; 47) 'A': A(T) -> A +[46; 50) 'A(1)': A +[48; 49) '1': i32 +[60; 64) 'A(n)': A +[62; 63) 'n': &mut i32 +[67; 76) '&mut A(1)': &mut A +[72; 73) 'A': A(T) -> A +[72; 76) 'A(1)': A +[74; 75) '1': i32"### + ); +} + +#[test] +fn infer_pattern_match_ergonomics_ref() { + covers!(match_ergonomics_ref); + assert_snapshot_matches!( + infer(r#" +fn test() { + let v = &(1, &2); + let (_, &w) = v; +} +"#), + @r###" +[11; 57) '{ ...= v; }': () +[21; 22) 'v': &(i32, &i32) +[25; 33) '&(1, &2)': &(i32, &i32) +[26; 33) '(1, &2)': (i32, &i32) +[27; 28) '1': i32 +[30; 32) '&2': &i32 +[31; 32) '2': i32 +[43; 50) '(_, &w)': (i32, &i32) +[44; 45) '_': i32 +[47; 49) '&w': &i32 +[48; 49) 'w': i32 +[53; 54) 'v': &(i32, &i32)"### ); } -- cgit v1.2.3