mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +00:00
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 <7803845+iDawer@users.noreply.github.com>
This commit is contained in:
commit
50936397cc
5 changed files with 50 additions and 15 deletions
|
@ -357,17 +357,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
|||
infer: &infer,
|
||||
db,
|
||||
pattern_arena: &pattern_arena,
|
||||
eprint_panic_context: &|| {
|
||||
panic_context: &|| {
|
||||
use syntax::AstNode;
|
||||
if let Ok(scrutinee_sptr) = source_map.expr_syntax(match_expr) {
|
||||
let root = scrutinee_sptr.file_syntax(db.upcast());
|
||||
if let Some(match_ast) = scrutinee_sptr.value.to_node(&root).syntax().parent() {
|
||||
eprintln!(
|
||||
"Match checking is about to panic on this expression:\n{}",
|
||||
match_ast.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
let match_expr_text = source_map
|
||||
.expr_syntax(match_expr)
|
||||
.ok()
|
||||
.and_then(|scrutinee_sptr| {
|
||||
let root = scrutinee_sptr.file_syntax(db.upcast());
|
||||
scrutinee_sptr.value.to_node(&root).syntax().parent()
|
||||
})
|
||||
.map(|node| node.to_string());
|
||||
format!(
|
||||
"expression:\n{}",
|
||||
match_expr_text.as_deref().unwrap_or("<synthesized expr>")
|
||||
)
|
||||
},
|
||||
};
|
||||
let report = compute_match_usefulness(&cx, &m_arms);
|
||||
|
|
|
@ -100,10 +100,19 @@ impl<'a> PatCtxt<'a> {
|
|||
}
|
||||
|
||||
pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
|
||||
// FIXME: implement pattern adjustments (implicit pattern dereference; "RFC 2005-match-ergonomics")
|
||||
// XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
|
||||
// When lowering of & and box patterns are implemented this should be tested
|
||||
// in a manner of `match_ergonomics_issue_9095` test.
|
||||
// Pattern adjustment is part of RFC 2005-match-ergonomics.
|
||||
// More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089
|
||||
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
|
||||
unadjusted_pat
|
||||
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
|
||||
unadjusted_pat,
|
||||
|subpattern, ref_ty| Pat {
|
||||
ty: ref_ty.clone(),
|
||||
kind: Box::new(PatKind::Deref { subpattern }),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
|
||||
|
@ -1236,6 +1245,21 @@ fn main(f: Foo) {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_ergonomics_issue_9095() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
enum Foo<T> { A(T) }
|
||||
fn main() {
|
||||
match &Foo::A(true) {
|
||||
_ => {}
|
||||
Foo::A(_) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
mod false_negatives {
|
||||
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
||||
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
||||
|
|
|
@ -295,7 +295,7 @@ pub(crate) struct MatchCheckCtx<'a> {
|
|||
pub(crate) db: &'a dyn HirDatabase,
|
||||
/// Lowered patterns from arms plus generated by the check.
|
||||
pub(crate) pattern_arena: &'a RefCell<PatternArena>,
|
||||
pub(crate) eprint_panic_context: &'a dyn Fn(),
|
||||
pub(crate) panic_context: &'a dyn Fn() -> String,
|
||||
}
|
||||
|
||||
impl<'a> MatchCheckCtx<'a> {
|
||||
|
@ -331,8 +331,7 @@ impl<'a> MatchCheckCtx<'a> {
|
|||
|
||||
#[track_caller]
|
||||
pub(super) fn bug(&self, info: &str) -> ! {
|
||||
(self.eprint_panic_context)();
|
||||
panic!("bug: {}", info);
|
||||
panic!("bug: {}\n{}", info, (self.panic_context)());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,6 +150,8 @@ pub struct InferenceResult {
|
|||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||
/// Interned Unknown to return references to.
|
||||
standard_types: InternedStandardTypes,
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
||||
}
|
||||
|
||||
impl InferenceResult {
|
||||
|
|
|
@ -101,7 +101,9 @@ impl<'a> InferenceContext<'a> {
|
|||
let mut expected = self.resolve_ty_shallow(expected);
|
||||
|
||||
if is_non_ref_pat(&body, pat) {
|
||||
let mut pat_adjustments = Vec::new();
|
||||
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
|
||||
pat_adjustments.push(expected.clone());
|
||||
expected = self.resolve_ty_shallow(inner);
|
||||
default_bm = match default_bm {
|
||||
BindingMode::Move => BindingMode::Ref(mutability),
|
||||
|
@ -109,6 +111,11 @@ impl<'a> InferenceContext<'a> {
|
|||
BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
|
||||
}
|
||||
}
|
||||
|
||||
if !pat_adjustments.is_empty() {
|
||||
pat_adjustments.shrink_to_fit();
|
||||
self.result.pat_adjustments.insert(pat, pat_adjustments);
|
||||
}
|
||||
} else if let Pat::Ref { .. } = &body[pat] {
|
||||
cov_mark::hit!(match_ergonomics_ref);
|
||||
// When you encounter a `&pat` pattern, reset to Move.
|
||||
|
|
Loading…
Reference in a new issue