]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast_lowering/src/block.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / compiler / rustc_ast_lowering / src / block.rs
CommitLineData
94222f64
XL
1use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
2use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
3use rustc_hir as hir;
4use rustc_session::parse::feature_err;
5use rustc_span::symbol::Ident;
6use rustc_span::{sym, DesugaringKind};
7
8use smallvec::SmallVec;
9
10impl<'a, 'hir> LoweringContext<'a, 'hir> {
11 pub(super) fn lower_block(
12 &mut self,
13 b: &Block,
14 targeted_by_break: bool,
15 ) -> &'hir hir::Block<'hir> {
16 self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
17 }
18
19 pub(super) fn lower_block_noalloc(
20 &mut self,
21 b: &Block,
22 targeted_by_break: bool,
23 ) -> hir::Block<'hir> {
24 let (stmts, expr) = self.lower_stmts(&b.stmts);
25 let rules = self.lower_block_check_mode(&b.rules);
26 let hir_id = self.lower_node_id(b.id);
27 hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
28 }
29
30 fn lower_stmts(
31 &mut self,
32 mut ast_stmts: &[Stmt],
33 ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
34 let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
35 let mut expr = None;
36 while let [s, tail @ ..] = ast_stmts {
37 match s.kind {
38 StmtKind::Local(ref local) => {
39 let hir_id = self.lower_node_id(s.id);
40 match &local.kind {
41 LocalKind::InitElse(init, els) => {
42 let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
43 stmts.push(s);
44 expr = Some(e);
45 // remaining statements are in let-else expression
46 break;
47 }
48 _ => {
49 let local = self.lower_local(local);
50 self.alias_attrs(hir_id, local.hir_id);
51 let kind = hir::StmtKind::Local(local);
52 let span = self.lower_span(s.span);
53 stmts.push(hir::Stmt { hir_id, kind, span });
54 }
55 }
56 }
57 StmtKind::Item(ref it) => {
c295e0f8 58 stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
94222f64
XL
59 |(i, item_id)| {
60 let hir_id = match i {
61 0 => self.lower_node_id(s.id),
62 _ => self.next_id(),
63 };
64 let kind = hir::StmtKind::Item(item_id);
65 let span = self.lower_span(s.span);
66 hir::Stmt { hir_id, kind, span }
67 },
68 ));
69 }
70 StmtKind::Expr(ref e) => {
71 let e = self.lower_expr(e);
72 if tail.is_empty() {
73 expr = Some(e);
74 } else {
75 let hir_id = self.lower_node_id(s.id);
76 self.alias_attrs(hir_id, e.hir_id);
77 let kind = hir::StmtKind::Expr(e);
78 let span = self.lower_span(s.span);
79 stmts.push(hir::Stmt { hir_id, kind, span });
80 }
81 }
82 StmtKind::Semi(ref e) => {
83 let e = self.lower_expr(e);
84 let hir_id = self.lower_node_id(s.id);
85 self.alias_attrs(hir_id, e.hir_id);
86 let kind = hir::StmtKind::Semi(e);
87 let span = self.lower_span(s.span);
88 stmts.push(hir::Stmt { hir_id, kind, span });
89 }
90 StmtKind::Empty => {}
91 StmtKind::MacCall(..) => panic!("shouldn't exist here"),
92 }
93 ast_stmts = &ast_stmts[1..];
94 }
95 (self.arena.alloc_from_iter(stmts), expr)
96 }
97
98 fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
99 let ty = l
100 .ty
101 .as_ref()
102 .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
103 let init = l.kind.init().map(|init| self.lower_expr(init));
104 let hir_id = self.lower_node_id(l.id);
105 let pat = self.lower_pat(&l.pat);
106 let span = self.lower_span(l.span);
107 let source = hir::LocalSource::Normal;
108 self.lower_attrs(hir_id, &l.attrs);
109 self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
110 }
111
112 fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
113 match *b {
114 BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
115 BlockCheckMode::Unsafe(u) => {
116 hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
117 }
118 }
119 }
120
121 fn lower_let_else(
122 &mut self,
123 stmt_hir_id: hir::HirId,
124 local: &Local,
125 init: &Expr,
126 els: &Block,
127 tail: &[Stmt],
128 ) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
129 let ty = local
130 .ty
131 .as_ref()
132 .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
133 let span = self.lower_span(local.span);
134 let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
135 let init = Some(self.lower_expr(init));
136 let val = Ident::with_dummy_span(sym::val);
137 let (pat, val_id) =
138 self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
139 let local_hir_id = self.lower_node_id(local.id);
140 self.lower_attrs(local_hir_id, &local.attrs);
141 // first statement which basically exists for the type annotation
142 let stmt = {
143 let local = self.arena.alloc(hir::Local {
144 hir_id: local_hir_id,
145 ty,
146 pat,
147 init,
148 span,
149 source: hir::LocalSource::Normal,
150 });
151 let kind = hir::StmtKind::Local(local);
152 hir::Stmt { hir_id: stmt_hir_id, kind, span }
153 };
154 let let_expr = {
155 let scrutinee = self.expr_ident(span, val, val_id);
156 let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
157 self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
158 };
159 let then_expr = {
160 let (stmts, expr) = self.lower_stmts(tail);
161 let block = self.block_all(span, stmts, expr);
162 self.arena.alloc(self.expr_block(block, AttrVec::new()))
163 };
164 let else_expr = {
165 let block = self.lower_block(els, false);
166 self.arena.alloc(self.expr_block(block, AttrVec::new()))
167 };
168 self.alias_attrs(else_expr.hir_id, local_hir_id);
169 let if_expr = self.arena.alloc(hir::Expr {
170 hir_id: self.next_id(),
171 span,
172 kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
173 });
174 if !self.sess.features_untracked().let_else {
175 feature_err(
176 &self.sess.parse_sess,
177 sym::let_else,
178 local.span,
179 "`let...else` statements are unstable",
180 )
181 .emit();
182 }
183 (stmt, if_expr)
184 }
185}