mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Check pattern types.
This commit is contained in:
parent
9b841a9a04
commit
49e016169f
@ -379,32 +379,58 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||
let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
|
||||
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;
|
||||
} else {
|
||||
&infer.type_of_expr[match_expr]
|
||||
};
|
||||
// eprintln!("ExprValidator::validate_match2({:?})", _match_expr_ty.kind(&Interner));
|
||||
|
||||
let pattern_arena = RefCell::new(PatternArena::new());
|
||||
|
||||
let mut have_errors = false;
|
||||
let m_arms: Vec<_> = arms
|
||||
.iter()
|
||||
.map(|arm| usefulness::MatchArm {
|
||||
pat: self.lower_pattern(
|
||||
arm.pat,
|
||||
&mut pattern_arena.borrow_mut(),
|
||||
db,
|
||||
&body,
|
||||
&mut have_errors,
|
||||
),
|
||||
has_guard: arm.guard.is_some(),
|
||||
})
|
||||
.collect();
|
||||
let mut m_arms = Vec::new();
|
||||
let mut has_lowering_errors = false;
|
||||
for arm in arms {
|
||||
if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
|
||||
// We only include patterns whose type matches the type
|
||||
// of the match expression. If we had a 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 match expression type if
|
||||
// necessary.
|
||||
//
|
||||
// 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 have_errors {
|
||||
// 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.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -418,18 +444,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||
};
|
||||
let report = usefulness::compute_match_usefulness(&cx, &m_arms);
|
||||
|
||||
// TODO Report unreacheble arms
|
||||
// let mut catchall = None;
|
||||
// for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
|
||||
// match is_useful{
|
||||
// Unreachable => {
|
||||
// }
|
||||
// Reachable(_) => {}
|
||||
// }
|
||||
// }
|
||||
// FIXME Report unreacheble arms
|
||||
// https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201
|
||||
|
||||
let witnesses = report.non_exhaustiveness_witnesses;
|
||||
eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
|
||||
// eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses);
|
||||
if !witnesses.is_empty() {
|
||||
if let Ok(source_ptr) = source_map.expr_syntax(id) {
|
||||
let root = source_ptr.file_syntax(db.upcast());
|
||||
|
@ -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) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub(crate) struct MatchCheckCtx<'a> {
|
||||
pub(crate) body: Arc<Body>,
|
||||
pub(crate) infer: &'a InferenceResult,
|
||||
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>,
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user