Check pattern types.

This commit is contained in:
Dawer 2021-05-10 13:22:13 +05:00
parent 9b841a9a04
commit 49e016169f
3 changed files with 84 additions and 29 deletions

View File

@ -379,32 +379,58 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) = let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
db.body_with_source_map(self.owner); db.body_with_source_map(self.owner);
let _match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() { let match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() {
return; return;
} else { } else {
&infer.type_of_expr[match_expr] &infer.type_of_expr[match_expr]
}; };
// eprintln!("ExprValidator::validate_match2({:?})", _match_expr_ty.kind(&Interner));
let pattern_arena = RefCell::new(PatternArena::new()); let pattern_arena = RefCell::new(PatternArena::new());
let mut have_errors = false; let mut m_arms = Vec::new();
let m_arms: Vec<_> = arms let mut has_lowering_errors = false;
.iter() for arm in arms {
.map(|arm| usefulness::MatchArm { if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
pat: self.lower_pattern( // We only include patterns whose type matches the type
arm.pat, // of the match expression. If we had a InvalidMatchArmPattern
&mut pattern_arena.borrow_mut(), // diagnostic or similar we could raise that in an else
db, // block here.
&body, //
&mut have_errors, // When comparing the types, we also have to consider that rustc
), // will automatically de-reference the match expression type if
has_guard: arm.guard.is_some(), // necessary.
}) //
.collect(); // FIXME we should use the type checker for this.
if pat_ty == match_expr_ty
|| match_expr_ty
.as_reference()
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
.unwrap_or(false)
{
// If we had a NotUsefulMatchArm diagnostic, we could
// check the usefulness of each pattern as we added it
// to the matrix here.
let m_arm = usefulness::MatchArm {
pat: self.lower_pattern(
arm.pat,
&mut pattern_arena.borrow_mut(),
db,
&body,
&mut has_lowering_errors,
),
has_guard: arm.guard.is_some(),
};
m_arms.push(m_arm);
if !has_lowering_errors {
continue;
}
}
}
// Bail out early if lowering failed. // If we can't resolve the type of a pattern, or the pattern type doesn't
if have_errors { // 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.
return; return;
} }
@ -418,18 +444,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
}; };
let report = usefulness::compute_match_usefulness(&cx, &m_arms); let report = usefulness::compute_match_usefulness(&cx, &m_arms);
// TODO Report unreacheble arms // FIXME Report unreacheble arms
// let mut catchall = None; // https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201
// for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
// match is_useful{
// Unreachable => {
// }
// Reachable(_) => {}
// }
// }
let witnesses = report.non_exhaustiveness_witnesses; let witnesses = report.non_exhaustiveness_witnesses;
eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
if !witnesses.is_empty() { if !witnesses.is_empty() {
if let Ok(source_ptr) = source_map.expr_syntax(id) { if let Ok(source_ptr) = source_map.expr_syntax(id) {
let root = source_ptr.file_syntax(db.upcast()); let root = source_ptr.file_syntax(db.upcast());

View File

@ -511,4 +511,40 @@ fn main() {
"#, "#,
); );
} }
/// These failing tests are narrowed down from "hir_ty::diagnostics::match_check::tests"
// TODO fix
mod failing {
use super::*;
#[test]
fn never() {
check_diagnostics(
r#"
enum Never {}
fn enum_ref(never: &Never) {
match never {}
}
"#,
);
}
#[test]
fn unknown_type() {
check_diagnostics(
r#"
enum Option<T> { Some(T), None }
fn main() {
// `Never` is deliberately not defined so that it's an uninferred type.
match Option::<Never>::None {
None => {}
Some(never) => {}
}
}
"#,
);
}
}
} }

View File

@ -28,7 +28,7 @@ pub(crate) struct MatchCheckCtx<'a> {
pub(crate) body: Arc<Body>, pub(crate) body: Arc<Body>,
pub(crate) infer: &'a InferenceResult, pub(crate) infer: &'a InferenceResult,
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
/// Patterns from self.body.pats plus generated by the check. /// Lowered patterns from self.body.pats plus generated by the check.
pub(crate) pattern_arena: &'a RefCell<PatternArena>, pub(crate) pattern_arena: &'a RefCell<PatternArena>,
} }