Check pattern error while lowering
This commit is contained in:
parent
1f9a2f73e1
commit
380c56c6b3
@ -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 =
|
||||||
|
Loading…
Reference in New Issue
Block a user