loop match: run exhaustiveness check

This commit is contained in:
Folkert de Vries
2025-07-01 15:29:09 +02:00
parent f46ce66fcc
commit aa7cc5d2f4
9 changed files with 241 additions and 152 deletions

View File

@@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None
})
}
ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => {
ExprKind::LoopMatch {
state,
region_scope,
match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee },
} => {
// Intuitively, this is a combination of a loop containing a labeled block
// containing a match.
//
@@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Logic for `match`.
let scrutinee_place_builder =
unpack!(body_block = this.as_place_builder(body_block, state));
let scrutinee_span = this.thir.exprs[state].span;
unpack!(body_block = this.as_place_builder(body_block, scrutinee));
let scrutinee_span = this.thir.exprs[scrutinee].span;
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
let mut patterns = Vec::with_capacity(arms.len());
@@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
move |this| {
this.in_breakable_scope(None, state_place, expr_span, |this| {
Some(this.in_const_continuable_scope(
arms.clone(),
Box::from(arms),
built_tree.clone(),
state_place,
expr_span,

View File

@@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> {
data: region::ScopeData::Node,
},
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
match_span: block_body_expr.span,
match_data: Box::new(LoopMatchMatchData {
scrutinee: self.mirror_expr(scrutinee),
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
span: block_body_expr.span,
}),
}
} else {
let block_ty = self.typeck_results.node_type(body.hir_id);

View File

@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
use rustc_hir::def::*;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::Level;
use rustc_middle::bug;
@@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
ExprKind::Match { scrutinee, box ref arms, match_source } => {
self.check_match(scrutinee, arms, match_source, ex.span);
}
ExprKind::LoopMatch {
match_data: box LoopMatchMatchData { scrutinee, box ref arms, span },
..
} => {
self.check_match(scrutinee, arms, MatchSource::Normal, span);
}
ExprKind::Let { box ref pat, expr } => {
self.check_let(pat, Some(expr), ex.span);
}

View File

@@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_expr(*body, depth_lvl + 2);
print_indented!(self, ")", depth_lvl);
}
LoopMatch { state, region_scope, match_span, arms } => {
LoopMatch { state, region_scope, match_data } => {
print_indented!(self, "LoopMatch {", depth_lvl);
print_indented!(self, "state:", depth_lvl + 1);
self.print_expr(*state, depth_lvl + 2);
print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1);
print_indented!(self, "match_data:", depth_lvl + 1);
print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2);
print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3);
print_indented!(self, "scrutinee:", depth_lvl + 3);
self.print_expr(match_data.scrutinee, depth_lvl + 4);
print_indented!(self, "arms: [", depth_lvl + 1);
for arm_id in arms.iter() {
self.print_arm(*arm_id, depth_lvl + 2);
print_indented!(self, "arms: [", depth_lvl + 3);
for arm_id in match_data.arms.iter() {
self.print_arm(*arm_id, depth_lvl + 4);
}
print_indented!(self, "]", depth_lvl + 1);
print_indented!(self, "]", depth_lvl + 3);
print_indented!(self, "}", depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
Let { expr, pat } => {