Skip to content

Commit d29491a

Browse files
authored
Rollup merge of #104669 - LeSeulArtichaut:88015-if-let-guard-bindings, r=cjgillot
Only declare bindings for if-let guards once per arm Currently, each candidate for a match arm uses separate locals for the bindings in the if-let guard, causing problems (#88015) when those branches converge in the arm body. Fixes #88015 (🤞)
2 parents 88542a3 + baa59d1 commit d29491a

File tree

5 files changed

+27
-17
lines changed

5 files changed

+27
-17
lines changed

compiler/rustc_mir_build/src/build/block.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::build::matches::ArmHasGuard;
21
use crate::build::ForGuard::OutsideGuard;
32
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
43
use rustc_middle::middle::region::Scope;
@@ -231,7 +230,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
231230
visibility_scope,
232231
remainder_span,
233232
pattern,
234-
ArmHasGuard(false),
233+
None,
235234
Some((None, initializer_span)),
236235
);
237236
this.visit_primary_bindings(
@@ -308,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
308307
visibility_scope,
309308
remainder_span,
310309
pattern,
311-
ArmHasGuard(false),
310+
None,
312311
Some((None, initializer_span)),
313312
);
314313
this.expr_into_pattern(block, &pattern, init)
@@ -324,7 +323,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
324323
visibility_scope,
325324
remainder_span,
326325
pattern,
327-
ArmHasGuard(false),
326+
None,
328327
None,
329328
);
330329
block.unit()

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
108108
ExprKind::Let { expr, ref pat } => {
109109
let scope = this.local_scope();
110110
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
111-
this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span)
111+
this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span, true)
112112
});
113113

114114
this.cfg.push_assign_constant(

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

+15-11
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
8484
break_scope,
8585
Some(variable_source_info.scope),
8686
variable_source_info.span,
87+
true,
8788
),
8889
_ => {
8990
let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
@@ -357,7 +358,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
357358
None,
358359
arm.span,
359360
&arm.pattern,
360-
ArmHasGuard(arm.guard.is_some()),
361+
arm.guard.as_ref(),
361362
opt_scrutinee_place,
362363
);
363364

@@ -645,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
645646
mut visibility_scope: Option<SourceScope>,
646647
scope_span: Span,
647648
pattern: &Pat<'tcx>,
648-
has_guard: ArmHasGuard,
649+
guard: Option<&Guard<'tcx>>,
649650
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
650651
) -> Option<SourceScope> {
651652
self.visit_primary_bindings(
@@ -667,12 +668,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
667668
var,
668669
ty,
669670
user_ty,
670-
has_guard,
671+
ArmHasGuard(guard.is_some()),
671672
opt_match_place.map(|(x, y)| (x.cloned(), y)),
672673
pattern.span,
673674
);
674675
},
675676
);
677+
if let Some(Guard::IfLet(guard_pat, _)) = guard {
678+
// FIXME: pass a proper `opt_match_place`
679+
self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None);
680+
}
676681
visibility_scope
677682
}
678683

@@ -1766,6 +1771,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17661771
// Pat binding - used for `let` and function parameters as well.
17671772

17681773
impl<'a, 'tcx> Builder<'a, 'tcx> {
1774+
/// If the bindings have already been declared, set `declare_bindings` to
1775+
/// `false` to avoid duplicated bindings declaration. Used for if-let guards.
17691776
pub(crate) fn lower_let_expr(
17701777
&mut self,
17711778
mut block: BasicBlock,
@@ -1774,6 +1781,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17741781
else_target: region::Scope,
17751782
source_scope: Option<SourceScope>,
17761783
span: Span,
1784+
declare_bindings: bool,
17771785
) -> BlockAnd<()> {
17781786
let expr_span = expr.span;
17791787
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
@@ -1797,13 +1805,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17971805
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
17981806
self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span));
17991807

1800-
self.declare_bindings(
1801-
source_scope,
1802-
pat.span.to(span),
1803-
pat,
1804-
ArmHasGuard(false),
1805-
opt_expr_place,
1806-
);
1808+
if declare_bindings {
1809+
self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place);
1810+
}
18071811

18081812
let post_guard_block = self.bind_pattern(
18091813
self.source_info(pat.span),
@@ -1984,7 +1988,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19841988
Guard::IfLet(ref pat, scrutinee) => {
19851989
let s = &this.thir[scrutinee];
19861990
guard_span = s.span;
1987-
this.lower_let_expr(block, s, pat, match_scope, None, arm.span)
1991+
this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false)
19881992
}
19891993
});
19901994

compiler/rustc_mir_build/src/build/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
924924
scope,
925925
expr.span,
926926
&pat,
927-
matches::ArmHasGuard(false),
927+
None,
928928
Some((Some(&place), span)),
929929
);
930930
let place_builder = PlaceBuilder::from(local);

src/test/ui/rfc-2294-if-let-guard/run-pass.rs

+7
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,11 @@ fn main() {
3030
Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84),
3131
_ => panic!(),
3232
}
33+
34+
// issue #88015
35+
#[allow(irrefutable_let_patterns)]
36+
match () {
37+
() | () if let x = 42 => assert_eq!(x, 42),
38+
_ => panic!()
39+
}
3340
}

0 commit comments

Comments
 (0)