Skip to content

Commit 0617a9e

Browse files
authored
Rollup merge of #143276 - folkertdev:loop-match-opaque-pattern, r=Nadrieril
loop match: handle opaque patterns tracking issue #132306 fixes #143203 I believe the `Opaque` comes up because the range pattern is invalid? Because we do handle float patterns already so those should be fine. r? `@Nadrieril`
2 parents 2becacf + 8fdf0ef commit 0617a9e

File tree

11 files changed

+270
-156
lines changed

11 files changed

+270
-156
lines changed

compiler/rustc_middle/src/thir.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,11 @@ pub enum ExprKind<'tcx> {
380380
},
381381
/// A `#[loop_match] loop { state = 'blk: { match state { ... } } }` expression.
382382
LoopMatch {
383-
/// The state variable that is updated, and also the scrutinee of the match.
383+
/// The state variable that is updated.
384+
/// The `match_data.scrutinee` is the same variable, but with a different span.
384385
state: ExprId,
385386
region_scope: region::Scope,
386-
arms: Box<[ArmId]>,
387-
match_span: Span,
387+
match_data: Box<LoopMatchMatchData>,
388388
},
389389
/// Special expression representing the `let` part of an `if let` or similar construct
390390
/// (including `if let` guards in match arms, and let-chains formed by `&&`).
@@ -599,6 +599,14 @@ pub struct Arm<'tcx> {
599599
pub span: Span,
600600
}
601601

602+
/// The `match` part of a `#[loop_match]`
603+
#[derive(Clone, Debug, HashStable)]
604+
pub struct LoopMatchMatchData {
605+
pub scrutinee: ExprId,
606+
pub arms: Box<[ArmId]>,
607+
pub span: Span,
608+
}
609+
602610
#[derive(Copy, Clone, Debug, HashStable)]
603611
pub enum LogicalOp {
604612
/// The `&&` operator.

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::{
22
AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand,
33
Pat, PatKind, Stmt, StmtKind, Thir,
44
};
5+
use crate::thir::LoopMatchMatchData;
56

67
/// Every `walk_*` method uses deconstruction to access fields of structs and
78
/// 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>>(
8384
visitor.visit_pat(pat);
8485
}
8586
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
86-
LoopMatch { state: scrutinee, ref arms, .. } | Match { scrutinee, ref arms, .. } => {
87+
LoopMatch { match_data: box LoopMatchMatchData { scrutinee, ref arms, .. }, .. }
88+
| Match { scrutinee, ref arms, .. } => {
8789
visitor.visit_expr(&visitor.thir()[scrutinee]);
8890
for &arm in &**arms {
8991
visitor.visit_arm(&visitor.thir()[arm]);

compiler/rustc_mir_build/src/builder/expr/into.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
245245
None
246246
})
247247
}
248-
ExprKind::LoopMatch { state, region_scope, match_span, ref arms } => {
248+
ExprKind::LoopMatch {
249+
state,
250+
region_scope,
251+
match_data: box LoopMatchMatchData { box ref arms, span: match_span, scrutinee },
252+
} => {
249253
// Intuitively, this is a combination of a loop containing a labeled block
250254
// containing a match.
251255
//
@@ -292,8 +296,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
292296

293297
// Logic for `match`.
294298
let scrutinee_place_builder =
295-
unpack!(body_block = this.as_place_builder(body_block, state));
296-
let scrutinee_span = this.thir.exprs[state].span;
299+
unpack!(body_block = this.as_place_builder(body_block, scrutinee));
300+
let scrutinee_span = this.thir.exprs[scrutinee].span;
297301
let match_start_span = match_span.shrink_to_lo().to(scrutinee_span);
298302

299303
let mut patterns = Vec::with_capacity(arms.len());
@@ -335,7 +339,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
335339
move |this| {
336340
this.in_breakable_scope(None, state_place, expr_span, |this| {
337341
Some(this.in_const_continuable_scope(
338-
arms.clone(),
342+
Box::from(arms),
339343
built_tree.clone(),
340344
state_place,
341345
expr_span,

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
29702970
}
29712971
Constructor::Wildcard => true,
29722972

2973+
// Opaque patterns must not be matched on structurally.
2974+
Constructor::Opaque(_) => false,
2975+
29732976
// These we may eventually support:
29742977
Constructor::Struct
29752978
| Constructor::Ref
@@ -2980,8 +2983,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
29802983
| Constructor::Str(_) => bug!("unsupported pattern constructor {:?}", pat.ctor()),
29812984

29822985
// These should never occur here:
2983-
Constructor::Opaque(_)
2984-
| Constructor::Never
2986+
Constructor::Never
29852987
| Constructor::NonExhaustive
29862988
| Constructor::Hidden
29872989
| Constructor::Missing

compiler/rustc_mir_build/src/errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,6 @@ pub(crate) struct ConstContinueMissingValue {
12301230

12311231
#[derive(Diagnostic)]
12321232
#[diag(mir_build_const_continue_unknown_jump_target)]
1233-
#[note]
12341233
pub(crate) struct ConstContinueUnknownJumpTarget {
12351234
#[primary_span]
12361235
pub span: Span,

compiler/rustc_mir_build/src/thir/cx/expr.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,11 @@ impl<'tcx> ThirBuildCx<'tcx> {
983983
data: region::ScopeData::Node,
984984
},
985985

986-
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
987-
match_span: block_body_expr.span,
986+
match_data: Box::new(LoopMatchMatchData {
987+
scrutinee: self.mirror_expr(scrutinee),
988+
arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
989+
span: block_body_expr.span,
990+
}),
988991
}
989992
} else {
990993
let block_ty = self.typeck_results.node_type(body.hir_id);

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_errors::codes::*;
66
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
77
use rustc_hir::def::*;
88
use rustc_hir::def_id::LocalDefId;
9-
use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
9+
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
1010
use rustc_infer::infer::TyCtxtInferExt;
1111
use rustc_lint::Level;
1212
use rustc_middle::bug;
@@ -154,6 +154,12 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
154154
ExprKind::Match { scrutinee, box ref arms, match_source } => {
155155
self.check_match(scrutinee, arms, match_source, ex.span);
156156
}
157+
ExprKind::LoopMatch {
158+
match_data: box LoopMatchMatchData { scrutinee, box ref arms, span },
159+
..
160+
} => {
161+
self.check_match(scrutinee, arms, MatchSource::Normal, span);
162+
}
157163
ExprKind::Let { box ref pat, expr } => {
158164
self.check_let(pat, Some(expr), ex.span);
159165
}

compiler/rustc_mir_build/src/thir/print.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,23 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
318318
self.print_expr(*body, depth_lvl + 2);
319319
print_indented!(self, ")", depth_lvl);
320320
}
321-
LoopMatch { state, region_scope, match_span, arms } => {
321+
LoopMatch { state, region_scope, match_data } => {
322322
print_indented!(self, "LoopMatch {", depth_lvl);
323323
print_indented!(self, "state:", depth_lvl + 1);
324324
self.print_expr(*state, depth_lvl + 2);
325325
print_indented!(self, format!("region_scope: {:?}", region_scope), depth_lvl + 1);
326-
print_indented!(self, format!("match_span: {:?}", match_span), depth_lvl + 1);
327-
328-
print_indented!(self, "arms: [", depth_lvl + 1);
329-
for arm_id in arms.iter() {
330-
self.print_arm(*arm_id, depth_lvl + 2);
326+
print_indented!(self, "match_data:", depth_lvl + 1);
327+
print_indented!(self, "LoopMatchMatchData {", depth_lvl + 2);
328+
print_indented!(self, format!("span: {:?}", match_data.span), depth_lvl + 3);
329+
print_indented!(self, "scrutinee:", depth_lvl + 3);
330+
self.print_expr(match_data.scrutinee, depth_lvl + 4);
331+
332+
print_indented!(self, "arms: [", depth_lvl + 3);
333+
for arm_id in match_data.arms.iter() {
334+
self.print_arm(*arm_id, depth_lvl + 4);
331335
}
332-
print_indented!(self, "]", depth_lvl + 1);
336+
print_indented!(self, "]", depth_lvl + 3);
337+
print_indented!(self, "}", depth_lvl + 2);
333338
print_indented!(self, "}", depth_lvl);
334339
}
335340
Let { expr, pat } => {

tests/ui/loop-match/invalid.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,34 @@ fn arm_has_guard(cond: bool) {
159159
}
160160
}
161161
}
162+
163+
fn non_exhaustive() {
164+
let mut state = State::A;
165+
#[loop_match]
166+
loop {
167+
state = 'blk: {
168+
match state {
169+
//~^ ERROR non-exhaustive patterns: `State::B` and `State::C` not covered
170+
State::A => State::B,
171+
}
172+
}
173+
}
174+
}
175+
176+
fn invalid_range_pattern(state: f32) {
177+
#[loop_match]
178+
loop {
179+
state = 'blk: {
180+
match state {
181+
1.0 => {
182+
#[const_continue]
183+
break 'blk 2.5;
184+
}
185+
4.0..3.0 => {
186+
//~^ ERROR lower range bound must be less than upper
187+
todo!()
188+
}
189+
}
190+
}
191+
}
192+
}

tests/ui/loop-match/invalid.stderr

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,36 @@ error: match arms that are part of a `#[loop_match]` cannot have guards
8686
LL | State::B if cond => break 'a,
8787
| ^^^^
8888

89-
error: aborting due to 12 previous errors
89+
error[E0004]: non-exhaustive patterns: `State::B` and `State::C` not covered
90+
--> $DIR/invalid.rs:168:19
91+
|
92+
LL | match state {
93+
| ^^^^^ patterns `State::B` and `State::C` not covered
94+
|
95+
note: `State` defined here
96+
--> $DIR/invalid.rs:7:6
97+
|
98+
LL | enum State {
99+
| ^^^^^
100+
LL | A,
101+
LL | B,
102+
| - not covered
103+
LL | C,
104+
| - not covered
105+
= note: the matched value is of type `State`
106+
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
107+
|
108+
LL ~ State::A => State::B,
109+
LL ~ State::B | State::C => todo!(),
110+
|
111+
112+
error[E0579]: lower range bound must be less than upper
113+
--> $DIR/invalid.rs:185:17
114+
|
115+
LL | 4.0..3.0 => {
116+
| ^^^^^^^^
117+
118+
error: aborting due to 14 previous errors
90119

91-
For more information about this error, try `rustc --explain E0308`.
120+
Some errors have detailed explanations: E0004, E0308, E0579.
121+
For more information about an error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)