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>) =
|
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());
|
||||||
|
@ -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) 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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user