aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs23
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs28
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs5
-rw-r--r--crates/hir_ty/src/infer.rs2
-rw-r--r--crates/hir_ty/src/infer/pat.rs11
-rw-r--r--crates/hir_ty/src/tests/patterns.rs47
6 files changed, 82 insertions, 34 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 3efbce773..a2a4d61db 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -357,17 +357,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
357 infer: &infer, 357 infer: &infer,
358 db, 358 db,
359 pattern_arena: &pattern_arena, 359 pattern_arena: &pattern_arena,
360 eprint_panic_context: &|| { 360 panic_context: &|| {
361 use syntax::AstNode; 361 use syntax::AstNode;
362 if let Ok(scrutinee_sptr) = source_map.expr_syntax(match_expr) { 362 let match_expr_text = source_map
363 let root = scrutinee_sptr.file_syntax(db.upcast()); 363 .expr_syntax(match_expr)
364 if let Some(match_ast) = scrutinee_sptr.value.to_node(&root).syntax().parent() { 364 .ok()
365 eprintln!( 365 .and_then(|scrutinee_sptr| {
366 "Match checking is about to panic on this expression:\n{}", 366 let root = scrutinee_sptr.file_syntax(db.upcast());
367 match_ast.to_string(), 367 scrutinee_sptr.value.to_node(&root).syntax().parent()
368 ); 368 })
369 } 369 .map(|node| node.to_string());
370 } 370 format!(
371 "expression:\n{}",
372 match_expr_text.as_deref().unwrap_or("<synthesized expr>")
373 )
371 }, 374 },
372 }; 375 };
373 let report = compute_match_usefulness(&cx, &m_arms); 376 let report = compute_match_usefulness(&cx, &m_arms);
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index a9a99f57a..c8e1b23de 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -100,10 +100,19 @@ impl<'a> PatCtxt<'a> {
100 } 100 }
101 101
102 pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat { 102 pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
103 // FIXME: implement pattern adjustments (implicit pattern dereference; "RFC 2005-match-ergonomics") 103 // XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
104 // When lowering of & and box patterns are implemented this should be tested
105 // in a manner of `match_ergonomics_issue_9095` test.
106 // Pattern adjustment is part of RFC 2005-match-ergonomics.
104 // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089 107 // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
105 let unadjusted_pat = self.lower_pattern_unadjusted(pat); 108 let unadjusted_pat = self.lower_pattern_unadjusted(pat);
106 unadjusted_pat 109 self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
110 unadjusted_pat,
111 |subpattern, ref_ty| Pat {
112 ty: ref_ty.clone(),
113 kind: Box::new(PatKind::Deref { subpattern }),
114 },
115 )
107 } 116 }
108 117
109 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat { 118 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
@@ -1236,6 +1245,21 @@ fn main(f: Foo) {
1236 ); 1245 );
1237 } 1246 }
1238 1247
1248 #[test]
1249 fn match_ergonomics_issue_9095() {
1250 check_diagnostics(
1251 r#"
1252enum Foo<T> { A(T) }
1253fn main() {
1254 match &Foo::A(true) {
1255 _ => {}
1256 Foo::A(_) => {}
1257 }
1258}
1259"#,
1260 );
1261 }
1262
1239 mod false_negatives { 1263 mod false_negatives {
1240 //! The implementation of match checking here is a work in progress. As we roll this out, we 1264 //! The implementation of match checking here is a work in progress. As we roll this out, we
1241 //! prefer false negatives to false positives (ideally there would be no false positives). This 1265 //! prefer false negatives to false positives (ideally there would be no false positives). This
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
index 83b094a89..bd76a606c 100644
--- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
@@ -295,7 +295,7 @@ pub(crate) struct MatchCheckCtx<'a> {
295 pub(crate) db: &'a dyn HirDatabase, 295 pub(crate) db: &'a dyn HirDatabase,
296 /// Lowered patterns from arms plus generated by the check. 296 /// Lowered patterns from arms plus generated by the check.
297 pub(crate) pattern_arena: &'a RefCell<PatternArena>, 297 pub(crate) pattern_arena: &'a RefCell<PatternArena>,
298 pub(crate) eprint_panic_context: &'a dyn Fn(), 298 pub(crate) panic_context: &'a dyn Fn() -> String,
299} 299}
300 300
301impl<'a> MatchCheckCtx<'a> { 301impl<'a> MatchCheckCtx<'a> {
@@ -331,8 +331,7 @@ impl<'a> MatchCheckCtx<'a> {
331 331
332 #[track_caller] 332 #[track_caller]
333 pub(super) fn bug(&self, info: &str) -> ! { 333 pub(super) fn bug(&self, info: &str) -> ! {
334 (self.eprint_panic_context)(); 334 panic!("bug: {}\n{}", info, (self.panic_context)());
335 panic!("bug: {}", info);
336 } 335 }
337} 336}
338 337
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 7a4268819..0e9f777da 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -150,6 +150,8 @@ pub struct InferenceResult {
150 type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>, 150 type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
151 /// Interned Unknown to return references to. 151 /// Interned Unknown to return references to.
152 standard_types: InternedStandardTypes, 152 standard_types: InternedStandardTypes,
153 /// Stores the types which were implicitly dereferenced in pattern binding modes.
154 pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
153} 155}
154 156
155impl InferenceResult { 157impl InferenceResult {
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 83e0a7a9e..25dff7e49 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -101,7 +101,9 @@ impl<'a> InferenceContext<'a> {
101 let mut expected = self.resolve_ty_shallow(expected); 101 let mut expected = self.resolve_ty_shallow(expected);
102 102
103 if is_non_ref_pat(&body, pat) { 103 if is_non_ref_pat(&body, pat) {
104 let mut pat_adjustments = Vec::new();
104 while let Some((inner, _lifetime, mutability)) = expected.as_reference() { 105 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
106 pat_adjustments.push(expected.clone());
105 expected = self.resolve_ty_shallow(inner); 107 expected = self.resolve_ty_shallow(inner);
106 default_bm = match default_bm { 108 default_bm = match default_bm {
107 BindingMode::Move => BindingMode::Ref(mutability), 109 BindingMode::Move => BindingMode::Ref(mutability),
@@ -109,6 +111,11 @@ impl<'a> InferenceContext<'a> {
109 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability), 111 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
110 } 112 }
111 } 113 }
114
115 if !pat_adjustments.is_empty() {
116 pat_adjustments.shrink_to_fit();
117 self.result.pat_adjustments.insert(pat, pat_adjustments);
118 }
112 } else if let Pat::Ref { .. } = &body[pat] { 119 } else if let Pat::Ref { .. } = &body[pat] {
113 cov_mark::hit!(match_ergonomics_ref); 120 cov_mark::hit!(match_ergonomics_ref);
114 // When you encounter a `&pat` pattern, reset to Move. 121 // When you encounter a `&pat` pattern, reset to Move.
@@ -290,6 +297,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
290 Expr::Literal(Literal::String(..)) => false, 297 Expr::Literal(Literal::String(..)) => false,
291 _ => true, 298 _ => true,
292 }, 299 },
300 Pat::Bind { mode: BindingAnnotation::Mutable, subpat: Some(subpat), .. }
301 | Pat::Bind { mode: BindingAnnotation::Unannotated, subpat: Some(subpat), .. } => {
302 is_non_ref_pat(body, *subpat)
303 }
293 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, 304 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
294 } 305 }
295} 306}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index cd08b5c7a..7d00cee9b 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -20,6 +20,8 @@ fn infer_pattern() {
20 let h = val; 20 let h = val;
21 } 21 }
22 22
23 if let x @ true = &true {}
24
23 let lambda = |a: u64, b, c: i32| { a + b; c }; 25 let lambda = |a: u64, b, c: i32| { a + b; c };
24 26
25 let ref ref_to_x = x; 27 let ref ref_to_x = x;
@@ -30,7 +32,7 @@ fn infer_pattern() {
30 "#, 32 "#,
31 expect![[r#" 33 expect![[r#"
32 8..9 'x': &i32 34 8..9 'x': &i32
33 17..368 '{ ...o_x; }': () 35 17..400 '{ ...o_x; }': ()
34 27..28 'y': &i32 36 27..28 'y': &i32
35 31..32 'x': &i32 37 31..32 'x': &i32
36 42..44 '&z': &i32 38 42..44 '&z': &i32
@@ -59,24 +61,31 @@ fn infer_pattern() {
59 176..204 '{ ... }': () 61 176..204 '{ ... }': ()
60 190..191 'h': {unknown} 62 190..191 'h': {unknown}
61 194..197 'val': {unknown} 63 194..197 'val': {unknown}
62 214..220 'lambda': |u64, u64, i32| -> i32 64 210..236 'if let...rue {}': ()
63 223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32 65 217..225 'x @ true': &bool
64 224..225 'a': u64 66 221..225 'true': bool
65 232..233 'b': u64 67 221..225 'true': bool
66 235..236 'c': i32 68 228..233 '&true': &bool
67 243..255 '{ a + b; c }': i32 69 229..233 'true': bool
68 245..246 'a': u64 70 234..236 '{}': ()
69 245..250 'a + b': u64 71 246..252 'lambda': |u64, u64, i32| -> i32
70 249..250 'b': u64 72 255..287 '|a: u6...b; c }': |u64, u64, i32| -> i32
71 252..253 'c': i32 73 256..257 'a': u64
72 266..278 'ref ref_to_x': &&i32 74 264..265 'b': u64
73 281..282 'x': &i32 75 267..268 'c': i32
74 292..301 'mut mut_x': &i32 76 275..287 '{ a + b; c }': i32
75 304..305 'x': &i32 77 277..278 'a': u64
76 315..335 'ref mu...f_to_x': &mut &i32 78 277..282 'a + b': u64
77 338..339 'x': &i32 79 281..282 'b': u64
78 349..350 'k': &mut &i32 80 284..285 'c': i32
79 353..365 'mut_ref_to_x': &mut &i32 81 298..310 'ref ref_to_x': &&i32
82 313..314 'x': &i32
83 324..333 'mut mut_x': &i32
84 336..337 'x': &i32
85 347..367 'ref mu...f_to_x': &mut &i32
86 370..371 'x': &i32
87 381..382 'k': &mut &i32
88 385..397 'mut_ref_to_x': &mut &i32
80 "#]], 89 "#]],
81 ); 90 );
82} 91}