In MIR we previously tried to match `let x in { exprs; let y in { exprs; }}` with our data
structures which is rather unwieldy, espeicially because it requires some sort of recursion or
stack to process, while, a flat list of statements is enough – lets only relinquish their lifetime
at the end of the block (i.e. end of the list).
Also fixes #31853.
fn visit_item(&mut self, i: &'tcx hir::Item) {
let item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(item_def_id);
- debug!("About to start task {:?}", task_id);
let _task = self.tcx.dep_graph.in_task(task_id);
+ debug!("Started task {:?}", task_id);
self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
self.visitor.visit_item(i)
}
-> BlockAnd<()> {
let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
self.in_scope(extent, block, move |this| {
- unpack!(block = this.stmts(block, stmts));
- match expr {
- Some(expr) => this.into(destination, block, expr),
- None => {
- this.cfg.push_assign_unit(block, span, destination);
- block.unit()
+ // This convoluted structure is to avoid using recursion as we walk down a list
+ // of statements. Basically, the structure we get back is something like:
+ //
+ // let x = <init> in {
+ // expr1;
+ // let y = <init> in {
+ // expr2;
+ // expr3;
+ // ...
+ // }
+ // }
+ //
+ // The let bindings are valid till the end of block so all we have to do is to pop all
+ // the let-scopes at the end.
+ //
+ // First we build all the statements in the block.
+ let mut let_extent_stack = Vec::with_capacity(8);
+ for stmt in stmts {
+ let Stmt { span: _, kind } = this.hir.mirror(stmt);
+ match kind {
+ StmtKind::Expr { scope, expr } => {
+ unpack!(block = this.in_scope(scope, block, |this| {
+ let expr = this.hir.mirror(expr);
+ let temp = this.temp(expr.ty.clone());
+ unpack!(block = this.into(&temp, block, expr));
+ unpack!(block = this.build_drop(block, temp));
+ block.unit()
+ }));
+ }
+ StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
+ this.push_scope(remainder_scope);
+ let_extent_stack.push(remainder_scope);
+ unpack!(block = this.in_scope(init_scope, block, move |this| {
+ // FIXME #30046 ^~~~
+ match initializer {
+ Some(initializer) => {
+ this.expr_into_pattern(block,
+ remainder_scope,
+ pattern,
+ initializer)
+ }
+ None => {
+ this.declare_bindings(remainder_scope, &pattern);
+ block.unit()
+ }
+ }
+ }));
+ }
}
}
+ // Then, the block may have an optional trailing expression which is a “return” value
+ // of the block.
+ if let Some(expr) = expr {
+ unpack!(block = this.into(destination, block, expr));
+ } else {
+ // FIXME(#31472)
+ this.cfg.push_assign_unit(block, span, destination);
+ }
+ // Finally, we pop all the let scopes before exiting out from the scope of block
+ // itself.
+ for extent in let_extent_stack.into_iter().rev() {
+ unpack!(block = this.pop_scope(extent, block));
+ }
+ block.unit()
})
}
}
mod matches;
mod misc;
mod scope;
-mod stmt;
extent: CodeExtent,
mut block: BasicBlock,
target: BasicBlock) {
+ debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
let scope_count = 1 + self.scopes.iter().rev().position(|scope| scope.extent == extent)
.unwrap_or_else(||{
self.hir.span_bug(span, &format!("extent {:?} does not enclose", extent))
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use build::{BlockAnd, BlockAndExtension, Builder};
-use hair::*;
-use rustc::mir::repr::*;
-
-impl<'a,'tcx> Builder<'a,'tcx> {
- pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<'tcx>>) -> BlockAnd<()> {
- // This convoluted structure is to avoid using recursion as we walk down a list
- // of statements. Basically, the structure we get back is something like:
- //
- // let x = <init> in {
- // let y = <init> in {
- // expr1;
- // expr2;
- // }
- // }
- //
- // To process this, we keep a stack of (Option<CodeExtent>,
- // vec::IntoIter<Stmt>) pairs. At each point we pull off the
- // top most pair and extract one statement from the
- // iterator. Once it's complete, we pop the scope from the
- // first half the pair.
- let this = self;
- let mut stmt_lists = vec![(None, stmts.into_iter())];
- while !stmt_lists.is_empty() {
- let stmt = {
- let &mut (_, ref mut stmts) = stmt_lists.last_mut().unwrap();
- stmts.next()
- };
-
- let stmt = match stmt {
- Some(stmt) => stmt,
- None => {
- let (extent, _) = stmt_lists.pop().unwrap();
- if let Some(extent) = extent {
- unpack!(block = this.pop_scope(extent, block));
- }
- continue
- }
- };
-
- let Stmt { span: _, kind } = this.hir.mirror(stmt);
- match kind {
- StmtKind::Let { remainder_scope, init_scope, pattern, initializer, stmts } => {
- this.push_scope(remainder_scope);
- stmt_lists.push((Some(remainder_scope), stmts.into_iter()));
- unpack!(block = this.in_scope(init_scope, block, move |this| {
- // FIXME #30046 ^~~~
- match initializer {
- Some(initializer) => {
- this.expr_into_pattern(block, remainder_scope, pattern, initializer)
- }
- None => {
- this.declare_bindings(remainder_scope, &pattern);
- block.unit()
- }
- }
- }));
- }
-
- StmtKind::Expr { scope, expr } => {
- unpack!(block = this.in_scope(scope, block, |this| {
- let expr = this.hir.mirror(expr);
- let temp = this.temp(expr.ty.clone());
- unpack!(block = this.into(&temp, block, expr));
- unpack!(block = this.build_drop(block, temp));
- block.unit()
- }));
- }
- }
- }
- block.unit()
- }
-}
extent: cx.tcx.region_maps.node_extent(self.id),
span: self.span,
stmts: stmts,
- expr: self.expr.to_ref(),
+ expr: self.expr.to_ref()
}
}
}
while let Some((index, stmt)) = stmts.next() {
match stmt.node {
hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) =>
- result.push(
- StmtRef::Mirror(
- Box::new(Stmt { span: stmt.span,
- kind: StmtKind::Expr {
- scope: cx.tcx.region_maps.node_extent(id),
- expr: expr.to_ref() } }))),
-
+ result.push(StmtRef::Mirror(Box::new(Stmt {
+ span: stmt.span,
+ kind: StmtKind::Expr {
+ scope: cx.tcx.region_maps.node_extent(id),
+ expr: expr.to_ref()
+ }
+ }))),
hir::StmtDecl(ref decl, id) => {
match decl.node {
hir::DeclItem(..) => { /* ignore for purposes of the MIR */ }
let remainder_extent =
cx.tcx.region_maps.lookup_code_extent(remainder_extent);
- // pull in all following statements, since
- // they are within the scope of this let:
- let following_stmts = mirror_stmts(cx, block_id, stmts);
-
let pattern = cx.irrefutable_pat(&local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span,
init_scope: cx.tcx.region_maps.node_extent(id),
pattern: pattern,
initializer: local.init.to_ref(),
- stmts: following_stmts,
},
})));
-
- return result;
}
}
}
pattern: Pattern<'tcx>,
/// let pat = <INIT> ...
- initializer: Option<ExprRef<'tcx>>,
-
- /// let pat = init; <STMTS>
- stmts: Vec<StmtRef<'tcx>>,
+ initializer: Option<ExprRef<'tcx>>
},
}