]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_lowering/src/block.rs
Rollup merge of #88313 - jyn514:pre-push, r=Mark-Simulacrum
[rust.git] / compiler / rustc_ast_lowering / src / block.rs
1 use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
2 use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
3 use rustc_hir as hir;
4 use rustc_session::parse::feature_err;
5 use rustc_span::{sym, DesugaringKind};
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                     match &local.kind {
40                         LocalKind::InitElse(init, els) => {
41                             let e = self.lower_let_else(hir_id, local, init, els, tail);
42                             expr = Some(e);
43                             // remaining statements are in let-else expression
44                             break;
45                         }
46                         _ => {
47                             let local = self.lower_local(local);
48                             self.alias_attrs(hir_id, local.hir_id);
49                             let kind = hir::StmtKind::Local(local);
50                             let span = self.lower_span(s.span);
51                             stmts.push(hir::Stmt { hir_id, kind, span });
52                         }
53                     }
54                 }
55                 StmtKind::Item(ref it) => {
56                     stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
57                         |(i, item_id)| {
58                             let hir_id = match i {
59                                 0 => self.lower_node_id(s.id),
60                                 _ => self.next_id(),
61                             };
62                             let kind = hir::StmtKind::Item(item_id);
63                             let span = self.lower_span(s.span);
64                             hir::Stmt { hir_id, kind, span }
65                         },
66                     ));
67                 }
68                 StmtKind::Expr(ref e) => {
69                     let e = self.lower_expr(e);
70                     if tail.is_empty() {
71                         expr = Some(e);
72                     } else {
73                         let hir_id = self.lower_node_id(s.id);
74                         self.alias_attrs(hir_id, e.hir_id);
75                         let kind = hir::StmtKind::Expr(e);
76                         let span = self.lower_span(s.span);
77                         stmts.push(hir::Stmt { hir_id, kind, span });
78                     }
79                 }
80                 StmtKind::Semi(ref e) => {
81                     let e = self.lower_expr(e);
82                     let hir_id = self.lower_node_id(s.id);
83                     self.alias_attrs(hir_id, e.hir_id);
84                     let kind = hir::StmtKind::Semi(e);
85                     let span = self.lower_span(s.span);
86                     stmts.push(hir::Stmt { hir_id, kind, span });
87                 }
88                 StmtKind::Empty => {}
89                 StmtKind::MacCall(..) => panic!("shouldn't exist here"),
90             }
91             ast_stmts = &ast_stmts[1..];
92         }
93         (self.arena.alloc_from_iter(stmts), expr)
94     }
95
96     fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
97         let ty = l
98             .ty
99             .as_ref()
100             .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
101         let init = l.kind.init().map(|init| self.lower_expr(init));
102         let hir_id = self.lower_node_id(l.id);
103         let pat = self.lower_pat(&l.pat);
104         let span = self.lower_span(l.span);
105         let source = hir::LocalSource::Normal;
106         self.lower_attrs(hir_id, &l.attrs);
107         self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
108     }
109
110     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
111         match *b {
112             BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
113             BlockCheckMode::Unsafe(u) => {
114                 hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
115             }
116         }
117     }
118
119     fn lower_let_else(
120         &mut self,
121         stmt_hir_id: hir::HirId,
122         local: &Local,
123         init: &Expr,
124         els: &Block,
125         tail: &[Stmt],
126     ) -> &'hir hir::Expr<'hir> {
127         let ty = local
128             .ty
129             .as_ref()
130             .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
131         let span = self.lower_span(local.span);
132         let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
133         let init = self.lower_expr(init);
134         let local_hir_id = self.lower_node_id(local.id);
135         self.lower_attrs(local_hir_id, &local.attrs);
136         let let_expr = {
137             let lex = self.arena.alloc(hir::Let {
138                 hir_id: local_hir_id,
139                 pat: self.lower_pat(&local.pat),
140                 ty,
141                 init,
142                 span,
143             });
144             self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
145         };
146         let then_expr = {
147             let (stmts, expr) = self.lower_stmts(tail);
148             let block = self.block_all(span, stmts, expr);
149             self.arena.alloc(self.expr_block(block, AttrVec::new()))
150         };
151         let else_expr = {
152             let block = self.lower_block(els, false);
153             self.arena.alloc(self.expr_block(block, AttrVec::new()))
154         };
155         self.alias_attrs(let_expr.hir_id, local_hir_id);
156         self.alias_attrs(else_expr.hir_id, local_hir_id);
157         let if_expr = self.arena.alloc(hir::Expr {
158             hir_id: stmt_hir_id,
159             span,
160             kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
161         });
162         if !self.sess.features_untracked().let_else {
163             feature_err(
164                 &self.sess.parse_sess,
165                 sym::let_else,
166                 local.span,
167                 "`let...else` statements are unstable",
168             )
169             .emit();
170         }
171         if_expr
172     }
173 }