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:
commit
955091be8f
5 changed files with 138 additions and 42 deletions
|
@ -132,6 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
initializer_span,
|
||||
else_block,
|
||||
visibility_scope,
|
||||
*remainder_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue