about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSimonas Kazlauskas <git@kazlauskas.me>2016-02-24 17:14:03 +0200
committerSimonas Kazlauskas <git@kazlauskas.me>2016-02-24 22:04:22 +0200
commit77be4ecc1795787eab4b51b9def35096546122ec (patch)
tree298378970f1eefc214a700d333212d25a9409c26 /src
parentfbd817115525b8f11ffe0a301e17341684771369 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc_mir/build/block.rs68
-rw-r--r--src/librustc_mir/build/mod.rs1
-rw-r--r--src/librustc_mir/build/scope.rs1
-rw-r--r--src/librustc_mir/build/stmt.rs83
-rw-r--r--src/librustc_mir/hair/cx/block.rs23
-rw-r--r--src/librustc_mir/hair/mod.rs5
7 files changed, 73 insertions, 110 deletions
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index faf97f5808e..a4d222d24ca 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -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)
         }
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 12b9130b48c..7d8a35165d2 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -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()
         })
     }
 }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index b83d0f6a980..5d9f827984e 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -185,4 +185,3 @@ mod into;
 mod matches;
 mod misc;
 mod scope;
-mod stmt;
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 7be70867796..a738663bf8c 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -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))
diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs
deleted file mode 100644
index 6c0f1c7081b..00000000000
--- a/src/librustc_mir/build/stmt.rs
+++ /dev/null
@@ -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()
-    }
-}
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 49617ed5171..66cb1f56b91 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -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;
                     }
                 }
             }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index e8edd4067e2..707dd972003 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -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>>
     },
 }