Skip to content

Commit 0a8c30a

Browse files
committed
internal: implement pattern adjustments.
1 parent 99516bb commit 0a8c30a

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

crates/hir_ty/src/diagnostics/match_check.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,19 @@ impl<'a> PatCtxt<'a> {
100100
}
101101

102102
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.
104107
// More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
105108
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+
)
107116
}
108117

109118
fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
@@ -1236,6 +1245,21 @@ fn main(f: Foo) {
12361245
);
12371246
}
12381247

1248+
#[test]
1249+
fn match_ergonomics_issue_9095() {
1250+
check_diagnostics(
1251+
r#"
1252+
enum Foo<T> { A(T) }
1253+
fn main() {
1254+
match &Foo::A(true) {
1255+
_ => {}
1256+
Foo::A(_) => {}
1257+
}
1258+
}
1259+
"#,
1260+
);
1261+
}
1262+
12391263
mod false_negatives {
12401264
//! The implementation of match checking here is a work in progress. As we roll this out, we
12411265
//! prefer false negatives to false positives (ideally there would be no false positives). This

crates/hir_ty/src/infer.rs

+2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ pub struct InferenceResult {
150150
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
151151
/// Interned Unknown to return references to.
152152
standard_types: InternedStandardTypes,
153+
/// Stores the types which were implicitly dereferenced in pattern binding modes.
154+
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
153155
}
154156

155157
impl InferenceResult {

crates/hir_ty/src/infer/pat.rs

+7
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,21 @@ impl<'a> InferenceContext<'a> {
101101
let mut expected = self.resolve_ty_shallow(expected);
102102

103103
if is_non_ref_pat(&body, pat) {
104+
let mut pat_adjustments = Vec::new();
104105
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
106+
pat_adjustments.push(expected.clone());
105107
expected = self.resolve_ty_shallow(inner);
106108
default_bm = match default_bm {
107109
BindingMode::Move => BindingMode::Ref(mutability),
108110
BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not),
109111
BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
110112
}
111113
}
114+
115+
if !pat_adjustments.is_empty() {
116+
pat_adjustments.shrink_to_fit();
117+
self.result.pat_adjustments.insert(pat, pat_adjustments);
118+
}
112119
} else if let Pat::Ref { .. } = &body[pat] {
113120
cov_mark::hit!(match_ergonomics_ref);
114121
// When you encounter a `&pat` pattern, reset to Move.

0 commit comments

Comments
 (0)