]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/block.rs
Auto merge of #38920 - petrochenkov:selfimpl, r=eddyb
[rust.git] / src / librustc_mir / build / block.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use build::{BlockAnd, BlockAndExtension, Builder};
12 use hair::*;
13 use rustc::mir::*;
14 use rustc::hir;
15
16 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
17     pub fn ast_block(&mut self,
18                      destination: &Lvalue<'tcx>,
19                      // FIXME(#32959): temporary measure for the issue
20                      dest_is_unit: bool,
21                      mut block: BasicBlock,
22                      ast_block: &'tcx hir::Block)
23                      -> BlockAnd<()> {
24         let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
25         self.in_scope(extent, block, move |this| {
26             // This convoluted structure is to avoid using recursion as we walk down a list
27             // of statements. Basically, the structure we get back is something like:
28             //
29             //    let x = <init> in {
30             //       expr1;
31             //       let y = <init> in {
32             //           expr2;
33             //           expr3;
34             //           ...
35             //       }
36             //    }
37             //
38             // The let bindings are valid till the end of block so all we have to do is to pop all
39             // the let-scopes at the end.
40             //
41             // First we build all the statements in the block.
42             let mut let_extent_stack = Vec::with_capacity(8);
43             let outer_visibility_scope = this.visibility_scope;
44             for stmt in stmts {
45                 let Stmt { span: _, kind } = this.hir.mirror(stmt);
46                 match kind {
47                     StmtKind::Expr { scope, expr } => {
48                         unpack!(block = this.in_scope(scope, block, |this| {
49                             let expr = this.hir.mirror(expr);
50                             this.stmt_expr(block, expr)
51                         }));
52                     }
53                     StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
54                         let tcx = this.hir.tcx();
55
56                         // Enter the remainder scope, i.e. the bindings' destruction scope.
57                         this.push_scope(remainder_scope);
58                         let_extent_stack.push(remainder_scope);
59
60                         // Declare the bindings, which may create a visibility scope.
61                         let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.map);
62                         let remainder_span = remainder_span.unwrap_or(span);
63                         let scope = this.declare_bindings(None, remainder_span, &pattern);
64
65                         // Evaluate the initializer, if present.
66                         if let Some(init) = initializer {
67                             unpack!(block = this.in_scope(init_scope, block, move |this| {
68                                 // FIXME #30046                              ^~~~
69                                 this.expr_into_pattern(block, pattern, init)
70                             }));
71                         } else {
72                             this.storage_live_for_bindings(block, &pattern);
73                         }
74
75                         // Enter the visibility scope, after evaluating the initializer.
76                         if let Some(visibility_scope) = scope {
77                             this.visibility_scope = visibility_scope;
78                         }
79                     }
80                 }
81             }
82             // Then, the block may have an optional trailing expression which is a “return” value
83             // of the block.
84             if let Some(expr) = expr {
85                 unpack!(block = this.into(destination, block, expr));
86             } else if dest_is_unit {
87                 // FIXME(#31472)
88                 let source_info = this.source_info(span);
89                 this.cfg.push_assign_unit(block, source_info, destination);
90             }
91             // Finally, we pop all the let scopes before exiting out from the scope of block
92             // itself.
93             for extent in let_extent_stack.into_iter().rev() {
94                 unpack!(block = this.pop_scope(extent, block));
95             }
96             // Restore the original visibility scope.
97             this.visibility_scope = outer_visibility_scope;
98             block.unit()
99         })
100     }
101 }