1
Fork 0

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 (🤞)
This commit is contained in:
Dylan DPC 2022-11-22 16:36:38 +05:30 committed by GitHub
commit d29491aba0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 17 deletions

View file

@ -1,4 +1,3 @@
use crate::build::matches::ArmHasGuard;
use crate::build::ForGuard::OutsideGuard; use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use rustc_middle::middle::region::Scope; use rustc_middle::middle::region::Scope;
@ -231,7 +230,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
visibility_scope, visibility_scope,
remainder_span, remainder_span,
pattern, pattern,
ArmHasGuard(false), None,
Some((None, initializer_span)), Some((None, initializer_span)),
); );
this.visit_primary_bindings( this.visit_primary_bindings(
@ -308,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
visibility_scope, visibility_scope,
remainder_span, remainder_span,
pattern, pattern,
ArmHasGuard(false), None,
Some((None, initializer_span)), Some((None, initializer_span)),
); );
this.expr_into_pattern(block, &pattern, init) this.expr_into_pattern(block, &pattern, init)
@ -324,7 +323,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
visibility_scope, visibility_scope,
remainder_span, remainder_span,
pattern, pattern,
ArmHasGuard(false), None,
None, None,
); );
block.unit() block.unit()

View file

@ -108,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::Let { expr, ref pat } => { ExprKind::Let { expr, ref pat } => {
let scope = this.local_scope(); let scope = this.local_scope();
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| { let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span) this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span, true)
}); });
this.cfg.push_assign_constant( this.cfg.push_assign_constant(

View file

@ -84,6 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
break_scope, break_scope,
Some(variable_source_info.scope), Some(variable_source_info.scope),
variable_source_info.span, variable_source_info.span,
true,
), ),
_ => { _ => {
let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope()); let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
@ -357,7 +358,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None, None,
arm.span, arm.span,
&arm.pattern, &arm.pattern,
ArmHasGuard(arm.guard.is_some()), arm.guard.as_ref(),
opt_scrutinee_place, opt_scrutinee_place,
); );
@ -645,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mut visibility_scope: Option<SourceScope>, mut visibility_scope: Option<SourceScope>,
scope_span: Span, scope_span: Span,
pattern: &Pat<'tcx>, pattern: &Pat<'tcx>,
has_guard: ArmHasGuard, guard: Option<&Guard<'tcx>>,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> { ) -> Option<SourceScope> {
self.visit_primary_bindings( self.visit_primary_bindings(
@ -667,12 +668,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
var, var,
ty, ty,
user_ty, user_ty,
has_guard, ArmHasGuard(guard.is_some()),
opt_match_place.map(|(x, y)| (x.cloned(), y)), opt_match_place.map(|(x, y)| (x.cloned(), y)),
pattern.span, pattern.span,
); );
}, },
); );
if let Some(Guard::IfLet(guard_pat, _)) = guard {
// FIXME: pass a proper `opt_match_place`
self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None);
}
visibility_scope visibility_scope
} }
@ -1766,6 +1771,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Pat binding - used for `let` and function parameters as well. // Pat binding - used for `let` and function parameters as well.
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// If the bindings have already been declared, set `declare_bindings` to
/// `false` to avoid duplicated bindings declaration. Used for if-let guards.
pub(crate) fn lower_let_expr( pub(crate) fn lower_let_expr(
&mut self, &mut self,
mut block: BasicBlock, mut block: BasicBlock,
@ -1774,6 +1781,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
else_target: region::Scope, else_target: region::Scope,
source_scope: Option<SourceScope>, source_scope: Option<SourceScope>,
span: Span, span: Span,
declare_bindings: bool,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let expr_span = expr.span; let expr_span = expr.span;
let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span)); let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
@ -1797,13 +1805,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span)); self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span));
self.declare_bindings( if declare_bindings {
source_scope, self.declare_bindings(source_scope, pat.span.to(span), pat, None, opt_expr_place);
pat.span.to(span), }
pat,
ArmHasGuard(false),
opt_expr_place,
);
let post_guard_block = self.bind_pattern( let post_guard_block = self.bind_pattern(
self.source_info(pat.span), self.source_info(pat.span),
@ -1984,7 +1988,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Guard::IfLet(ref pat, scrutinee) => { Guard::IfLet(ref pat, scrutinee) => {
let s = &this.thir[scrutinee]; let s = &this.thir[scrutinee];
guard_span = s.span; guard_span = s.span;
this.lower_let_expr(block, s, pat, match_scope, None, arm.span) this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false)
} }
}); });

View file

@ -924,7 +924,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
scope, scope,
expr.span, expr.span,
&pat, &pat,
matches::ArmHasGuard(false), None,
Some((Some(&place), span)), Some((Some(&place), span)),
); );
let place_builder = PlaceBuilder::from(local); let place_builder = PlaceBuilder::from(local);

View file

@ -30,4 +30,11 @@ fn main() {
Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84), Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84),
_ => panic!(), _ => panic!(),
} }
// issue #88015
#[allow(irrefutable_let_patterns)]
match () {
() | () if let x = 42 => assert_eq!(x, 42),
_ => panic!()
}
} }