Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/diagnostics/expr.rs')
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs93
1 files changed, 52 insertions, 41 deletions
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 20b0da441d..a5a42c52af 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -11,6 +11,7 @@ use hir_def::{ItemContainerId, Lookup};
use hir_expand::name;
use itertools::Itertools;
use rustc_hash::FxHashSet;
+use rustc_pattern_analysis::constructor::Constructor;
use syntax::{ast, AstNode};
use tracing::debug;
use triomphe::Arc;
@@ -190,45 +191,45 @@ impl ExprValidator {
let pattern_arena = Arena::new();
let mut m_arms = Vec::with_capacity(arms.len());
let mut has_lowering_errors = false;
+ // Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
+ // preferred to avoid the chance of false positives.
for arm in arms {
- if let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) {
- // We only include patterns whose type matches the type
- // of the scrutinee expression. If we had an InvalidMatchArmPattern
- // diagnostic or similar we could raise that in an else
- // block here.
- //
- // When comparing the types, we also have to consider that rustc
- // will automatically de-reference the scrutinee expression type if
- // necessary.
- //
- // FIXME we should use the type checker for this.
- if (pat_ty == scrut_ty
- || scrut_ty
- .as_reference()
- .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
- .unwrap_or(false))
- && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
- {
- // If we had a NotUsefulMatchArm diagnostic, we could
- // check the usefulness of each pattern as we added it
- // to the matrix here.
- let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
- let m_arm = pat_analysis::MatchArm {
- pat: pattern_arena.alloc(pat),
- has_guard: arm.guard.is_some(),
- arm_data: (),
- };
- m_arms.push(m_arm);
- if !has_lowering_errors {
- continue;
- }
+ let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else {
+ return;
+ };
+
+ // We only include patterns whose type matches the type
+ // of the scrutinee expression. If we had an InvalidMatchArmPattern
+ // diagnostic or similar we could raise that in an else
+ // block here.
+ //
+ // When comparing the types, we also have to consider that rustc
+ // will automatically de-reference the scrutinee expression type if
+ // necessary.
+ //
+ // FIXME we should use the type checker for this.
+ if (pat_ty == scrut_ty
+ || scrut_ty
+ .as_reference()
+ .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
+ .unwrap_or(false))
+ && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
+ {
+ // If we had a NotUsefulMatchArm diagnostic, we could
+ // check the usefulness of each pattern as we added it
+ // to the matrix here.
+ let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
+ let m_arm = pat_analysis::MatchArm {
+ pat: pattern_arena.alloc(pat),
+ has_guard: arm.guard.is_some(),
+ arm_data: (),
+ };
+ m_arms.push(m_arm);
+ if !has_lowering_errors {
+ continue;
}
}
-
- // If we can't resolve the type of a pattern, or the pattern type doesn't
- // fit the match expression, we skip this diagnostic. Skipping the entire
- // diagnostic rather than just not including this match arm is preferred
- // to avoid the chance of false positives.
+ // If the pattern type doesn't fit the match expression, we skip this diagnostic.
cov_mark::hit!(validate_match_bailed_out);
return;
}
@@ -266,15 +267,17 @@ impl ExprValidator {
let mut have_errors = false;
let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
+
+ // optimization, wildcard trivially hold
+ if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
+ continue;
+ }
+
let match_arm = rustc_pattern_analysis::MatchArm {
pat: pattern_arena.alloc(deconstructed_pat),
has_guard: false,
arm_data: (),
};
- if have_errors {
- continue;
- }
-
let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) {
Ok(v) => v,
Err(e) => {
@@ -531,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
match infer.type_mismatch_for_pat(pat) {
Some(_) => *has_type_mismatches = true,
+ None if *has_type_mismatches => (),
None => {
- body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
+ let pat = &body[pat];
+ if let Pat::ConstBlock(expr) | Pat::Lit(expr) = *pat {
+ *has_type_mismatches |= infer.type_mismatch_for_expr(expr).is_some();
+ if *has_type_mismatches {
+ return;
+ }
+ }
+ pat.walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
}
}
}