Make list of statements flat
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.
This commit is contained in:
parent
fbd8171155
commit
77be4ecc17
7 changed files with 73 additions and 110 deletions
|
|
@ -198,8 +198,8 @@ pub fn visit_all_items_in_krate<'tcx,V,F>(tcx: &ty::ctxt<'tcx>,
|
|||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,70 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
-> 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,4 +185,3 @@ mod into;
|
|||
mod matches;
|
||||
mod misc;
|
||||
mod scope;
|
||||
mod stmt;
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
// 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()
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
|
|||
extent: cx.tcx.region_maps.node_extent(self.id),
|
||||
span: self.span,
|
||||
stmts: stmts,
|
||||
expr: self.expr.to_ref(),
|
||||
expr: self.expr.to_ref()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,13 +41,13 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
|||
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 */ }
|
||||
|
|
@ -59,10 +59,6 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
|||
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,
|
||||
|
|
@ -71,11 +67,8 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
|||
init_scope: cx.tcx.region_maps.node_extent(id),
|
||||
pattern: pattern,
|
||||
initializer: local.init.to_ref(),
|
||||
stmts: following_stmts,
|
||||
},
|
||||
})));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,10 +78,7 @@ pub enum StmtKind<'tcx> {
|
|||
pattern: Pattern<'tcx>,
|
||||
|
||||
/// let pat = <INIT> ...
|
||||
initializer: Option<ExprRef<'tcx>>,
|
||||
|
||||
/// let pat = init; <STMTS>
|
||||
stmts: Vec<StmtRef<'tcx>>,
|
||||
initializer: Option<ExprRef<'tcx>>
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue