debug!("in_scope(extent={:?}, block={:?})", extent, block);
self.push_scope(extent, block);
let rv = unpack!(block = f(self));
- assert_eq!(self.extent_of_innermost_scope(), extent);
- self.pop_scope(block);
+ self.pop_scope(extent, block);
debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
block.and(rv)
}
});
}
- /// Pops the innermost scope, adding any drops onto the end of
- /// `block` that are needed. This must match 1-to-1 with
- /// `push_scope`.
- pub fn pop_scope(&mut self, block: BasicBlock) {
- debug!("pop_scope({:?})", block);
+ /// Pops a scope, which should have extent `extent`, adding any
+ /// drops onto the end of `block` that are needed. This must
+ /// match 1-to-1 with `push_scope`.
+ pub fn pop_scope(&mut self, extent: CodeExtent, block: BasicBlock) {
+ debug!("pop_scope({:?}, {:?})", extent, block);
let scope = self.scopes.pop().unwrap();
+ assert_eq!(scope.extent, extent);
+
// add in any drops needed on the fallthrough path (any other
// exiting paths, such as those that arise from `break`, will
// have drops already)
impl<'a,'tcx> Builder<'a,'tcx> {
pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<'tcx>>) -> BlockAnd<()> {
- for stmt in stmts {
- unpack!(block = self.stmt(block, stmt));
- }
- block.unit()
- }
-
- pub fn stmt(&mut self, mut block: BasicBlock, stmt: 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 Stmt { span, kind } = this.hir.mirror(stmt);
- match kind {
- StmtKind::Let { remainder_scope,
- init_scope,
- pattern,
- initializer: Some(initializer),
- stmts } => {
- this.in_scope(remainder_scope, block, |this| {
- unpack!(block = this.in_scope(init_scope, block, |this| {
- this.expr_into_pattern(block, remainder_scope, pattern, initializer)
+ 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 {
+ 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, block);
+ 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()
+ }
+ }
}));
- this.stmts(block, stmts)
- })
- }
+ }
- StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => {
- this.in_scope(remainder_scope, block, |this| {
- unpack!(block = this.in_scope(init_scope, block, |this| {
- this.declare_bindings(remainder_scope, &pattern);
+ 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));
+ this.cfg.push_drop(block, span, DropKind::Deep, &temp);
block.unit()
}));
- this.stmts(block, stmts)
- })
- }
-
- StmtKind::Expr { scope, expr } => {
- 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));
- this.cfg.push_drop(block, span, DropKind::Deep, &temp);
- block.unit()
- })
+ }
}
}
+ block.unit()
}
}