mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
reorder nesting scopes and declare bindings without drop schedule
This commit is contained in:
parent
750bd1a7ff
commit
1b87ce0d40
@ -109,13 +109,99 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
)
|
||||
);
|
||||
}
|
||||
StmtKind::Let {
|
||||
remainder_scope,
|
||||
init_scope,
|
||||
pattern,
|
||||
initializer: Some(initializer),
|
||||
lint_level,
|
||||
else_block: Some(else_block),
|
||||
} => {
|
||||
let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
|
||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
||||
// This place is not really used because this destination place
|
||||
// should never be used to take values at the end of the failure
|
||||
// block.
|
||||
let else_block_span = this.thir[*else_block].span;
|
||||
let dummy_place = this.temp(this.tcx.types.never, else_block_span);
|
||||
let failure_entry = this.cfg.start_new_block();
|
||||
let failure_block;
|
||||
unpack!(
|
||||
failure_block = this.ast_block(
|
||||
dummy_place,
|
||||
failure_entry,
|
||||
*else_block,
|
||||
this.source_info(else_block_span),
|
||||
)
|
||||
);
|
||||
this.cfg.terminate(
|
||||
failure_block,
|
||||
this.source_info(else_block_span),
|
||||
TerminatorKind::Unreachable,
|
||||
);
|
||||
|
||||
// Declare the bindings, which may create a source scope.
|
||||
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
|
||||
this.push_scope((*remainder_scope, source_info));
|
||||
let_scope_stack.push(remainder_scope);
|
||||
|
||||
let visibility_scope =
|
||||
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));
|
||||
|
||||
let init = &this.thir[*initializer];
|
||||
let initializer_span = init.span;
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(block, node, span, OutsideGuard, false);
|
||||
},
|
||||
);
|
||||
let failure = unpack!(
|
||||
block = this.in_opt_scope(
|
||||
opt_destruction_scope.map(|de| (de, source_info)),
|
||||
|this| {
|
||||
let scope = (*init_scope, source_info);
|
||||
this.in_scope(scope, *lint_level, |this| {
|
||||
this.ast_let_else(
|
||||
block,
|
||||
init,
|
||||
initializer_span,
|
||||
*else_block,
|
||||
&last_remainder_scope,
|
||||
pattern,
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
this.cfg.goto(failure, source_info, failure_entry);
|
||||
|
||||
if let Some(source_scope) = visibility_scope {
|
||||
this.source_scope = source_scope;
|
||||
}
|
||||
last_remainder_scope = *remainder_scope;
|
||||
}
|
||||
StmtKind::Let { init_scope, initializer: None, else_block: Some(_), .. } => {
|
||||
span_bug!(
|
||||
init_scope.span(this.tcx, this.region_scope_tree),
|
||||
"initializer is missing, but else block is present in this let binding",
|
||||
)
|
||||
}
|
||||
StmtKind::Let {
|
||||
remainder_scope,
|
||||
init_scope,
|
||||
ref pattern,
|
||||
initializer,
|
||||
lint_level,
|
||||
else_block,
|
||||
else_block: None,
|
||||
} => {
|
||||
let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
|
||||
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
|
||||
@ -141,27 +227,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|this| {
|
||||
let scope = (*init_scope, source_info);
|
||||
this.in_scope(scope, *lint_level, |this| {
|
||||
if let Some(else_block) = else_block {
|
||||
this.ast_let_else(
|
||||
block,
|
||||
init,
|
||||
initializer_span,
|
||||
*else_block,
|
||||
visibility_scope,
|
||||
last_remainder_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
)
|
||||
} else {
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, pattern, init) // irrefutable pattern
|
||||
}
|
||||
this.declare_bindings(
|
||||
visibility_scope,
|
||||
remainder_span,
|
||||
pattern,
|
||||
ArmHasGuard(false),
|
||||
Some((None, initializer_span)),
|
||||
);
|
||||
this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
|
||||
})
|
||||
},
|
||||
)
|
||||
|
@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
|
||||
// Although there is almost always scope for given variable in corner cases
|
||||
// like #92893 we might get variable with no scope.
|
||||
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
|
||||
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop {
|
||||
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
|
||||
}
|
||||
Place::from(local_id)
|
||||
@ -2274,23 +2274,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
init: &Expr<'tcx>,
|
||||
initializer_span: Span,
|
||||
else_block: BlockId,
|
||||
visibility_scope: Option<SourceScope>,
|
||||
remainder_scope: region::Scope,
|
||||
remainder_span: Span,
|
||||
let_else_scope: ®ion::Scope,
|
||||
pattern: &Pat<'tcx>,
|
||||
) -> BlockAnd<()> {
|
||||
) -> BlockAnd<BasicBlock> {
|
||||
let else_block_span = self.thir[else_block].span;
|
||||
let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
|
||||
let (matching, failure) = self.in_if_then_scope(*let_else_scope, |this| {
|
||||
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
|
||||
let pat = Pat { ty: init.ty, span: else_block_span, kind: 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,
|
||||
@ -2321,28 +2312,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
None,
|
||||
None,
|
||||
);
|
||||
this.break_for_else(failure, remainder_scope, this.source_info(initializer_span));
|
||||
this.break_for_else(failure, *let_else_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.
|
||||
let dummy_place = self.temp(self.tcx.types.never, else_block_span);
|
||||
let failure_block;
|
||||
unpack!(
|
||||
failure_block = self.ast_block(
|
||||
dummy_place,
|
||||
failure,
|
||||
else_block,
|
||||
self.source_info(else_block_span),
|
||||
)
|
||||
);
|
||||
self.cfg.terminate(
|
||||
failure_block,
|
||||
self.source_info(else_block_span),
|
||||
TerminatorKind::Unreachable,
|
||||
);
|
||||
matching.unit()
|
||||
matching.and(failure)
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +126,20 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
||||
|
||||
for (i, statement) in blk.stmts.iter().enumerate() {
|
||||
match statement.kind {
|
||||
hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => {
|
||||
// Let-else has a special lexical structure for variables.
|
||||
let mut prev_cx = visitor.cx;
|
||||
visitor.enter_scope(Scope {
|
||||
id: blk.hir_id.local_id,
|
||||
data: ScopeData::Remainder(FirstStatementIndex::new(i)),
|
||||
});
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
visitor.visit_stmt(statement);
|
||||
mem::swap(&mut prev_cx, &mut visitor.cx);
|
||||
// We need to back out temporarily and
|
||||
visitor.visit_block(els);
|
||||
visitor.cx = prev_cx;
|
||||
}
|
||||
hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => {
|
||||
// Each declaration introduces a subscope for bindings
|
||||
// introduced by the declaration; this subscope covers a
|
||||
@ -138,10 +152,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
||||
data: ScopeData::Remainder(FirstStatementIndex::new(i)),
|
||||
});
|
||||
visitor.cx.var_parent = visitor.cx.parent;
|
||||
visitor.visit_stmt(statement)
|
||||
}
|
||||
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
|
||||
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
|
||||
}
|
||||
visitor.visit_stmt(statement)
|
||||
}
|
||||
walk_list!(visitor, visit_expr, &blk.expr);
|
||||
}
|
||||
@ -460,7 +474,6 @@ fn resolve_local<'tcx>(
|
||||
visitor: &mut RegionResolutionVisitor<'tcx>,
|
||||
pat: Option<&'tcx hir::Pat<'tcx>>,
|
||||
init: Option<&'tcx hir::Expr<'tcx>>,
|
||||
els: Option<&'tcx hir::Block<'tcx>>,
|
||||
) {
|
||||
debug!("resolve_local(pat={:?}, init={:?})", pat, init);
|
||||
|
||||
@ -547,9 +560,6 @@ fn resolve_local<'tcx>(
|
||||
if let Some(pat) = pat {
|
||||
visitor.visit_pat(pat);
|
||||
}
|
||||
if let Some(els) = els {
|
||||
visitor.visit_block(els);
|
||||
}
|
||||
|
||||
/// Returns `true` if `pat` match the `P&` non-terminal.
|
||||
///
|
||||
@ -766,7 +776,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
// (i.e., `'static`), which means that after `g` returns, it drops,
|
||||
// and all the associated destruction scope rules apply.
|
||||
self.cx.var_parent = None;
|
||||
resolve_local(self, None, Some(&body.value), None);
|
||||
resolve_local(self, None, Some(&body.value));
|
||||
}
|
||||
|
||||
if body.generator_kind.is_some() {
|
||||
@ -793,7 +803,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
resolve_expr(self, ex);
|
||||
}
|
||||
fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
|
||||
resolve_local(self, Some(&l.pat), l.init, l.els)
|
||||
resolve_local(self, Some(&l.pat), l.init)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,8 @@ LL | bar2(Rc::new(())).await
|
||||
| |
|
||||
| has type `Rc<()>` which is not `Send`
|
||||
LL | };
|
||||
| - `Rc::new(())` is later dropped here
|
||||
LL | }
|
||||
| - `Rc::new(())` is later dropped here
|
||||
note: required by a bound in `is_send`
|
||||
--> $DIR/async-await-let-else.rs:19:15
|
||||
|
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-pass
|
||||
// compile-flags: -Zvalidate-mir
|
||||
#![feature(let_else)]
|
||||
|
||||
use std::fmt::Display;
|
||||
|
Loading…
Reference in New Issue
Block a user