aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-06-01 21:29:07 +0100
committerDawer <[email protected]>2021-06-01 21:32:05 +0100
commit0a8c30a96fe09047da07a8e2980baa47a334a3d7 (patch)
treef2c866fb519a6df6b03181f43d072716573c9ef9 /crates
parent99516bbd67a0018c3c0bf94cb895896857d4263c (diff)
internal: implement pattern adjustments.
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs28
-rw-r--r--crates/hir_ty/src/infer.rs2
-rw-r--r--crates/hir_ty/src/infer/pat.rs7
3 files changed, 35 insertions, 2 deletions
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/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..a21f44d6a 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.