Skip to content

Commit 5093639

Browse files
bors[bot]iDawer
andauthored
Merge #9105
9105: internal: calculate pattern adjustments r=flodiebold a=iDawer This extends `InferenceResult` with `pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>`. Fixes #9095 Co-authored-by: Dawer <[email protected]>
2 parents e8e14e1 + 0a8c30a commit 5093639

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

crates/hir_ty/src/diagnostics/expr.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -357,17 +357,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
357357
infer: &infer,
358358
db,
359359
pattern_arena: &pattern_arena,
360-
eprint_panic_context: &|| {
360+
panic_context: &|| {
361361
use syntax::AstNode;
362-
if let Ok(scrutinee_sptr) = source_map.expr_syntax(match_expr) {
363-
let root = scrutinee_sptr.file_syntax(db.upcast());
364-
if let Some(match_ast) = scrutinee_sptr.value.to_node(&root).syntax().parent() {
365-
eprintln!(
366-
"Match checking is about to panic on this expression:\n{}",
367-
match_ast.to_string(),
368-
);
369-
}
370-
}
362+
let match_expr_text = source_map
363+
.expr_syntax(match_expr)
364+
.ok()
365+
.and_then(|scrutinee_sptr| {
366+
let root = scrutinee_sptr.file_syntax(db.upcast());
367+
scrutinee_sptr.value.to_node(&root).syntax().parent()
368+
})
369+
.map(|node| node.to_string());
370+
format!(
371+
"expression:\n{}",
372+
match_expr_text.as_deref().unwrap_or("<synthesized expr>")
373+
)
371374
},
372375
};
373376
let report = compute_match_usefulness(&cx, &m_arms);

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/diagnostics/match_check/usefulness.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ pub(crate) struct MatchCheckCtx<'a> {
295295
pub(crate) db: &'a dyn HirDatabase,
296296
/// Lowered patterns from arms plus generated by the check.
297297
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,
299299
}
300300

301301
impl<'a> MatchCheckCtx<'a> {
@@ -331,8 +331,7 @@ impl<'a> MatchCheckCtx<'a> {
331331

332332
#[track_caller]
333333
pub(super) fn bug(&self, info: &str) -> ! {
334-
(self.eprint_panic_context)();
335-
panic!("bug: {}", info);
334+
panic!("bug: {}\n{}", info, (self.panic_context)());
336335
}
337336
}
338337

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)