Check pattern error while lowering

This commit is contained in:
Nadrieril 2023-10-29 04:40:03 +01:00
parent 1f9a2f73e1
commit 380c56c6b3

View File

@ -81,6 +81,9 @@ struct MatchVisitor<'a, 'p, 'tcx> {
lint_level: HirId, lint_level: HirId,
let_source: LetSource, let_source: LetSource,
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>, pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
/// Tracks if we encountered an error while checking this body. That the first function to
/// report it stores it here. Some functions return `Result` to allow callers to short-circuit
/// on error, but callers don't need to store it here again.
error: Result<(), ErrorGuaranteed>, error: Result<(), ErrorGuaranteed>,
} }
@ -211,11 +214,16 @@ fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
} }
fn lower_pattern( fn lower_pattern(
&self, &mut self,
cx: &mut MatchCheckCtxt<'p, 'tcx>, cx: &MatchCheckCtxt<'p, 'tcx>,
pattern: &Pat<'tcx>, pattern: &Pat<'tcx>,
) -> &'p DeconstructedPat<'p, 'tcx> { ) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> {
cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) if let Err(err) = pattern.pat_error_reported() {
self.error = Err(err);
Err(err)
} else {
Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pattern)))
}
} }
fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> {
@ -233,13 +241,9 @@ fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, s
if let LetSource::None = source { if let LetSource::None = source {
return; return;
} }
if let Err(err) = pat.pat_error_reported() {
self.error = Err(err);
return;
}
self.check_patterns(pat, Refutable); self.check_patterns(pat, Refutable);
let mut cx = self.new_cx(self.lint_level, true); let mut cx = self.new_cx(self.lint_level, true);
let tpat = self.lower_pattern(&mut cx, pat); let Ok(tpat) = self.lower_pattern(&cx, pat) else { return };
self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span);
} }
@ -252,31 +256,22 @@ fn check_match(
) { ) {
let mut cx = self.new_cx(self.lint_level, true); let mut cx = self.new_cx(self.lint_level, true);
let mut tarms = Vec::with_capacity(arms.len());
for &arm in arms { for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness. // Check the arm for some things unrelated to exhaustiveness.
let arm = &self.thir.arms[arm]; let arm = &self.thir.arms[arm];
self.with_lint_level(arm.lint_level, |this| { self.with_lint_level(arm.lint_level, |this| {
this.check_patterns(&arm.pattern, Refutable); this.check_patterns(&arm.pattern, Refutable);
}); });
if let Err(err) = arm.pattern.pat_error_reported() { let hir_id = match arm.lint_level {
self.error = Err(err); LintLevel::Explicit(hir_id) => hir_id,
return; LintLevel::Inherited => self.lint_level,
} };
let Ok(pat) = self.lower_pattern(&mut cx, &arm.pattern) else { return };
let arm = MatchArm { pat, hir_id, has_guard: arm.guard.is_some() };
tarms.push(arm);
} }
let tarms: Vec<_> = arms
.iter()
.map(|&arm| {
let arm = &self.thir.arms[arm];
let hir_id = match arm.lint_level {
LintLevel::Explicit(hir_id) => hir_id,
LintLevel::Inherited => self.lint_level,
};
let pat = self.lower_pattern(&mut cx, &arm.pattern);
MatchArm { pat, hir_id, has_guard: arm.guard.is_some() }
})
.collect();
let scrut = &self.thir[scrut]; let scrut = &self.thir[scrut];
let scrut_ty = scrut.ty; let scrut_ty = scrut.ty;
let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span);
@ -340,7 +335,7 @@ fn check_let_chain(&mut self, let_source: LetSource, expr: &Expr<'tcx>) {
// and record chain members that aren't let exprs. // and record chain members that aren't let exprs.
let mut chain_refutabilities = Vec::new(); let mut chain_refutabilities = Vec::new();
let mut error = Ok(()); let mut got_lowering_error = false;
let mut next_expr = Some(expr); let mut next_expr = Some(expr);
while let Some(mut expr) = next_expr { while let Some(mut expr) = next_expr {
while let ExprKind::Scope { value, lint_level, .. } = expr.kind { while let ExprKind::Scope { value, lint_level, .. } = expr.kind {
@ -368,14 +363,13 @@ fn check_let_chain(&mut self, let_source: LetSource, expr: &Expr<'tcx>) {
} }
let value = match expr.kind { let value = match expr.kind {
ExprKind::Let { box ref pat, expr: _ } => { ExprKind::Let { box ref pat, expr: _ } => {
if let Err(err) = pat.pat_error_reported() { let mut ncx = self.new_cx(expr_lint_level, true);
error = Err(err); if let Ok(tpat) = self.lower_pattern(&mut ncx, pat) {
None
} else {
let mut ncx = self.new_cx(expr_lint_level, true);
let tpat = self.lower_pattern(&mut ncx, pat);
let refutable = !is_let_irrefutable(&mut ncx, expr_lint_level, tpat); let refutable = !is_let_irrefutable(&mut ncx, expr_lint_level, tpat);
Some((expr.span, refutable)) Some((expr.span, refutable))
} else {
got_lowering_error = true;
None
} }
} }
_ => None, _ => None,
@ -385,8 +379,7 @@ fn check_let_chain(&mut self, let_source: LetSource, expr: &Expr<'tcx>) {
debug!(?chain_refutabilities); debug!(?chain_refutabilities);
chain_refutabilities.reverse(); chain_refutabilities.reverse();
if error.is_err() { if got_lowering_error {
self.error = error;
return; return;
} }
@ -452,15 +445,9 @@ fn check_let_chain(&mut self, let_source: LetSource, expr: &Expr<'tcx>) {
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
// If we got errors while lowering, don't emit anything more.
if let Err(err) = pat.pat_error_reported() {
self.error = Err(err);
return;
}
let mut cx = self.new_cx(self.lint_level, false); let mut cx = self.new_cx(self.lint_level, false);
let pattern = self.lower_pattern(&mut cx, pat); let Ok(pattern) = self.lower_pattern(&mut cx, pat) else { return };
let pattern_ty = pattern.ty(); let pattern_ty = pattern.ty();
let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false };
let report = let report =