]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_lowering/src/block.rs
move else block into the `Local` struct
[rust.git] / compiler / rustc_ast_lowering / src / block.rs
1 use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
2 use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
3 use rustc_hir as hir;
4 use rustc_session::parse::feature_err;
5 use rustc_span::sym;
6
7 use smallvec::SmallVec;
8
9 impl<'a, 'hir> LoweringContext<'a, 'hir> {
10     pub(super) fn lower_block(
11         &mut self,
12         b: &Block,
13         targeted_by_break: bool,
14     ) -> &'hir hir::Block<'hir> {
15         self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
16     }
17
18     pub(super) fn lower_block_noalloc(
19         &mut self,
20         b: &Block,
21         targeted_by_break: bool,
22     ) -> hir::Block<'hir> {
23         let (stmts, expr) = self.lower_stmts(&b.stmts);
24         let rules = self.lower_block_check_mode(&b.rules);
25         let hir_id = self.lower_node_id(b.id);
26         hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
27     }
28
29     fn lower_stmts(
30         &mut self,
31         mut ast_stmts: &[Stmt],
32     ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
33         let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
34         let mut expr = None;
35         while let [s, tail @ ..] = ast_stmts {
36             match s.kind {
37                 StmtKind::Local(ref local) => {
38                     let hir_id = self.lower_node_id(s.id);
39                     let els = if let LocalKind::InitElse(_, els) = &local.kind {
40                         if !self.tcx.features().let_else {
41                             feature_err(
42                                 &self.tcx.sess.parse_sess,
43                                 sym::let_else,
44                                 s.span,
45                                 "`let...else` statements are unstable",
46                             )
47                             .emit();
48                         }
49                         Some(self.lower_block(els, false))
50                     } else {
51                         None
52                     };
53                     let local = self.lower_local(local);
54                     self.alias_attrs(hir_id, local.hir_id);
55                     let kind = hir::StmtKind::Local(local);
56                     let span = self.lower_span(s.span);
57                     stmts.push(hir::Stmt { hir_id, kind, span });
58                 }
59                 StmtKind::Item(ref it) => {
60                     stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
61                         |(i, item_id)| {
62                             let hir_id = match i {
63                                 0 => self.lower_node_id(s.id),
64                                 _ => self.next_id(),
65                             };
66                             let kind = hir::StmtKind::Item(item_id);
67                             let span = self.lower_span(s.span);
68                             hir::Stmt { hir_id, kind, span }
69                         },
70                     ));
71                 }
72                 StmtKind::Expr(ref e) => {
73                     let e = self.lower_expr(e);
74                     if tail.is_empty() {
75                         expr = Some(e);
76                     } else {
77                         let hir_id = self.lower_node_id(s.id);
78                         self.alias_attrs(hir_id, e.hir_id);
79                         let kind = hir::StmtKind::Expr(e);
80                         let span = self.lower_span(s.span);
81                         stmts.push(hir::Stmt { hir_id, kind, span });
82                     }
83                 }
84                 StmtKind::Semi(ref e) => {
85                     let e = self.lower_expr(e);
86                     let hir_id = self.lower_node_id(s.id);
87                     self.alias_attrs(hir_id, e.hir_id);
88                     let kind = hir::StmtKind::Semi(e);
89                     let span = self.lower_span(s.span);
90                     stmts.push(hir::Stmt { hir_id, kind, span });
91                 }
92                 StmtKind::Empty => {}
93                 StmtKind::MacCall(..) => panic!("shouldn't exist here"),
94             }
95             ast_stmts = &ast_stmts[1..];
96         }
97         (self.arena.alloc_from_iter(stmts), expr)
98     }
99
100     fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
101         let ty = l
102             .ty
103             .as_ref()
104             .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
105         let init = l.kind.init().map(|init| self.lower_expr(init));
106         let hir_id = self.lower_node_id(l.id);
107         let pat = self.lower_pat(&l.pat);
108         let els = if let LocalKind::InitElse(_, els) = &l.kind {
109             if !self.sess.features_untracked().let_else {
110                 feature_err(
111                     &self.sess.parse_sess,
112                     sym::let_else,
113                     l.span,
114                     "`let...else` statements are unstable",
115                 )
116                 .emit();
117             }
118             Some(self.lower_block(els, false))
119         } else {
120             None
121         };
122         let span = self.lower_span(l.span);
123         let source = hir::LocalSource::Normal;
124         self.lower_attrs(hir_id, &l.attrs);
125         self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
126     }
127
128     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
129         match *b {
130             BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
131             BlockCheckMode::Unsafe(u) => {
132                 hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
133             }
134         }
135     }
136 }