loop match: run exhaustiveness check
This commit is contained in:
@@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> {
|
|||||||
},
|
},
|
||||||
/// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression.
|
/// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression.
|
||||||
LoopMatch {
|
LoopMatch {
|
||||||
/// The state variable that is updated, and also the scrutinee of the match.
|
/// The state variable that is updated.
|
||||||
|
/// The `match_data.scrutinee` is the same variable, but with a different span.
|
||||||
state: ExprId,
|
state: ExprId,
|
||||||
region_scope: region::Scope,
|
region_scope: region::Scope,
|
||||||
arms: Box<[ArmId]>,
|
match_data: Box<LoopMatchMatchData>,
|
||||||
match_span: Span,
|
|
||||||
},
|
},
|
||||||
/// Special expression representing the `let` part of an `if let` or similar construct
|
/// Special expression representing the `let` part of an `if let` or similar construct
|
||||||
/// (including `if let` guards in match arms, and let-chains formed by `&&`).
|
/// (including `if let` guards in match arms, and let-chains formed by `&&`).
|
||||||
@@ -599,6 +599,14 @@ pub struct Arm<'tcx> {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `match` part of a `#[loop_match]`
|
||||||
|
#[derive(Clone, Debug, HashStable)]
|
||||||
|
pub struct LoopMatchMatchData {
|
||||||
|
pub scrutinee: ExprId,
|
||||||
|
pub arms: Box<[ArmId]>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, HashStable)]
|
#[derive(Copy, Clone, Debug, HashStable)]
|
||||||
pub enum LogicalOp {
|
pub enum LogicalOp {
|
||||||
/// The `&&` operator.
|
/// The `&&` operator.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use super::{
|
|||||||
AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand,
|
AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand,
|
||||||
Pat, PatKind, Stmt, StmtKind, Thir,
|
Pat, PatKind, Stmt, StmtKind, Thir,
|
||||||
};
|
};
|
||||||
|
use crate::thir::LoopMatchMatchData;
|
||||||
|
|
||||||
/// Every `walk_*` method uses deconstruction to access fields of structs and
|
/// Every `walk_*` method uses deconstruction to access fields of structs and
|
||||||
/// enums. This will result in a compile error if a field is added, which makes
|
/// enums. This will result in a compile error if a field is added, which makes
|
||||||
@@ -83,7 +84,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||||||
visitor.visit_pat(pat);
|
visitor.visit_pat(pat);
|
||||||
}
|
}
|
||||||
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
|
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
|
||||||
LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => {
|
LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. }
|
||||||
|
| Match { scrutinee, ref arms, .. } => {
|
||||||
visitor.visit_expr(&visitor.thir()[scrutinee]);
|
visitor.visit_expr(&visitor.thir()[scrutinee]);
|
||||||
for &arm in &**arms {
|
for &arm in &**arms {
|
||||||
visitor.visit_arm(&visitor.thir()[arm]);
|
visitor.visit_arm(&visitor.thir()[arm]);
|
||||||
|
|||||||
@@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
None
|
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
|
// Intuitively, this is a combination of a loop containing a labeled block
|
||||||
// containing a match.
|
// containing a match.
|
||||||
//
|
//
|
||||||
@@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
// Logic for `match`.
|
// Logic for `match`.
|
||||||
let scrutinee_place_builder =
|
let scrutinee_place_builder =
|
||||||
unpack!(body_block = this.as_place_builder(body_block, state));
|
unpack!(body_block = this.as_place_builder(body_block, scrutinee));
|
||||||
let scrutinee_span = this.thir.exprs[state].span;
|
let scrutinee_span = this.thir.exprs[scrutinee].span;
|
||||||
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
|
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
|
||||||
|
|
||||||
let mut patterns = Vec::with_capacity(arms.len());
|
let mut patterns = Vec::with_capacity(arms.len());
|
||||||
@@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
move |this| {
|
move |this| {
|
||||||
this.in_breakable_scope(None, state_place, expr_span, |this| {
|
this.in_breakable_scope(None, state_place, expr_span, |this| {
|
||||||
Some(this.in_const_continuable_scope(
|
Some(this.in_const_continuable_scope(
|
||||||
arms.clone(),
|
Box::from(arms),
|
||||||
built_tree.clone(),
|
built_tree.clone(),
|
||||||
state_place,
|
state_place,
|
||||||
expr_span,
|
expr_span,
|
||||||
|
|||||||
@@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||||||
data: region::ScopeData::Node,
|
data: region::ScopeData::Node,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
match_data: Box::new(LoopMatchMatchData {
|
||||||
|
scrutinee: self.mirror_expr(scrutinee),
|
||||||
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
|
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
|
||||||
match_span: block_body_expr.span,
|
span: block_body_expr.span,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let block_ty = self.typeck_results.node_type(body.hir_id);
|
let block_ty = self.typeck_results.node_type(body.hir_id);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
|
|||||||
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
|
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
|
||||||
use rustc_hir::def::*;
|
use rustc_hir::def::*;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
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_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_lint::Level;
|
use rustc_lint::Level;
|
||||||
use rustc_middle::bug;
|
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 } => {
|
ExprKind::Match { scrutinee, box ref arms, match_source } => {
|
||||||
self.check_match(scrutinee, arms, match_source, ex.span);
|
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 } => {
|
ExprKind::Let { box ref pat, expr } => {
|
||||||
self.check_let(pat, Some(expr), ex.span);
|
self.check_let(pat, Some(expr), ex.span);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||||||
self.print_expr(*body, depth_lvl + 2);
|
self.print_expr(*body, depth_lvl + 2);
|
||||||
print_indented!(self, ")", depth_lvl);
|
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, "LoopMatch {", depth_lvl);
|
||||||
print_indented!(self, "state:", depth_lvl + 1);
|
print_indented!(self, "state:", depth_lvl + 1);
|
||||||
self.print_expr(*state, depth_lvl + 2);
|
self.print_expr(*state, depth_lvl + 2);
|
||||||
print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
|
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);
|
print_indented!(self, "arms: [", depth_lvl + 3);
|
||||||
for arm_id in arms.iter() {
|
for arm_id in match_data.arms.iter() {
|
||||||
self.print_arm(*arm_id, depth_lvl + 2);
|
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);
|
print_indented!(self, "}", depth_lvl);
|
||||||
}
|
}
|
||||||
Let { expr, pat } => {
|
Let { expr, pat } => {
|
||||||
|
|||||||
@@ -159,3 +159,16 @@ fn arm_has_guard(cond: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn non_exhaustive() {
|
||||||
|
let mut state = State::A;
|
||||||
|
#[loop_match]
|
||||||
|
loop {
|
||||||
|
state = 'blk: {
|
||||||
|
match state {
|
||||||
|
//~^ ERROR non-exhaustive patterns: `State::B` and `State::C` not covered
|
||||||
|
State::A => State::B,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -86,6 +86,30 @@ error: match arms that are part of a `#[loop_match]` cannot have guards
|
|||||||
LL | State::B if cond => break 'a,
|
LL | State::B if cond => break 'a,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error[E0004]: non-exhaustive patterns: `State::B` and `State::C` not covered
|
||||||
|
--> $DIR/invalid.rs:168:19
|
||||||
|
|
|
||||||
|
LL | match state {
|
||||||
|
| ^^^^^ patterns `State::B` and `State::C` not covered
|
||||||
|
|
|
||||||
|
note: `State` defined here
|
||||||
|
--> $DIR/invalid.rs:7:6
|
||||||
|
|
|
||||||
|
LL | enum State {
|
||||||
|
| ^^^^^
|
||||||
|
LL | A,
|
||||||
|
LL | B,
|
||||||
|
| - not covered
|
||||||
|
LL | C,
|
||||||
|
| - not covered
|
||||||
|
= note: the matched value is of type `State`
|
||||||
|
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
||||||
|
|
|
||||||
|
LL ~ State::A => State::B,
|
||||||
|
LL ~ State::B | State::C => todo!(),
|
||||||
|
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0004, E0308.
|
||||||
|
For more information about an error, try `rustc --explain E0004`.
|
||||||
|
|||||||
@@ -89,7 +89,30 @@ body:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
region_scope: Node(10)
|
region_scope: Node(10)
|
||||||
match_span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0)
|
match_data:
|
||||||
|
LoopMatchMatchData {
|
||||||
|
span: $DIR/thir-tree-loop-match.rs:11:13: 17:14 (#0)
|
||||||
|
scrutinee:
|
||||||
|
Expr {
|
||||||
|
ty: bool
|
||||||
|
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None }
|
||||||
|
span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0)
|
||||||
|
kind:
|
||||||
|
Scope {
|
||||||
|
region_scope: Node(12)
|
||||||
|
lint_level: Explicit(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).12))
|
||||||
|
value:
|
||||||
|
Expr {
|
||||||
|
ty: bool
|
||||||
|
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(5)), backwards_incompatible: None }
|
||||||
|
span: $DIR/thir-tree-loop-match.rs:11:19: 11:24 (#0)
|
||||||
|
kind:
|
||||||
|
VarRef {
|
||||||
|
id: LocalVarId(HirId(DefId(0:3 ~ thir_tree_loop_match[3c53]::boolean).2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
arms: [
|
arms: [
|
||||||
Arm {
|
Arm {
|
||||||
pattern:
|
pattern:
|
||||||
@@ -266,6 +289,7 @@ body:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DefId(0:4 ~ thir_tree_loop_match[3c53]::main):
|
DefId(0:4 ~ thir_tree_loop_match[3c53]::main):
|
||||||
|
|||||||
Reference in New Issue
Block a user