1
Fork 0

Rollup merge of #99518 - dingxiangfei2009:let-else-additional-tests, r=oli-obk

Let-else: break out scopes when a let-else pattern fails to match

This PR will commit to a new behavior so that values from initializer expressions are dropped earlier when a let-else pattern fails to match.

Fix #98672.
Close #93951.
cc `@camsteffen` `@est31`
This commit is contained in:
Yuki Okushi 2022-07-30 07:39:49 +09:00 committed by GitHub
commit 955091be8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 138 additions and 42 deletions

View file

@ -132,6 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer_span,
else_block,
visibility_scope,
*remainder_scope,
remainder_span,
pattern,
)

View file

@ -2282,49 +2282,55 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
initializer_span: Span,
else_block: &Block,
visibility_scope: Option<SourceScope>,
remainder_scope: region::Scope,
remainder_span: Span,
pattern: &Pat<'tcx>,
) -> BlockAnd<()> {
let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
self.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
let fake_borrow_temps = self.lower_match_tree(
block,
initializer_span,
pattern.span,
false,
&mut [&mut candidate, &mut wildcard],
);
// This block is for the matching case
let matching = self.bind_pattern(
self.source_info(pattern.span),
candidate,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
// This block is for the failure case
let failure = self.bind_pattern(
self.source_info(else_block.span),
wildcard,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
let fake_borrow_temps = this.lower_match_tree(
block,
initializer_span,
pattern.span,
false,
&mut [&mut candidate, &mut wildcard],
);
// This block is for the matching case
let matching = this.bind_pattern(
this.source_info(pattern.span),
candidate,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
// This block is for the failure case
let failure = this.bind_pattern(
this.source_info(else_block.span),
wildcard,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
this.break_for_else(failure, remainder_scope, this.source_info(initializer_span));
matching.unit()
});
// This place is not really used because this destination place
// should never be used to take values at the end of the failure
// block.

View file

@ -690,7 +690,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
drops.add_entry(block, drop_idx);
// `build_drop_tree` doesn't have access to our source_info, so we
// `build_drop_trees` doesn't have access to our source_info, so we
// create a dummy terminator now. `TerminatorKind::Resume` is used
// because MIR type checking will panic if it hasn't been overwritten.
self.cfg.terminate(block, source_info, TerminatorKind::Resume);
@ -722,7 +722,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
drops.add_entry(block, drop_idx);
// `build_drop_tree` doesn't have access to our source_info, so we
// `build_drop_trees` doesn't have access to our source_info, so we
// create a dummy terminator now. `TerminatorKind::Resume` is used
// because MIR type checking will panic if it hasn't been overwritten.
self.cfg.terminate(block, source_info, TerminatorKind::Resume);