rustc_ast_lowering/
block.rs
1use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
2use rustc_hir as hir;
3use rustc_span::sym;
4use smallvec::SmallVec;
5
6use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
7
8impl<'a, 'hir> LoweringContext<'a, 'hir> {
9 pub(super) fn lower_block(
10 &mut self,
11 b: &Block,
12 targeted_by_break: bool,
13 ) -> &'hir hir::Block<'hir> {
14 let hir_id = self.lower_node_id(b.id);
15 self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break))
16 }
17
18 pub(super) fn lower_block_noalloc(
19 &mut self,
20 hir_id: hir::HirId,
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 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::Let(local) => {
38 let hir_id = self.lower_node_id(s.id);
39 let local = self.lower_local(local);
40 self.alias_attrs(hir_id, local.hir_id);
41 let kind = hir::StmtKind::Let(local);
42 let span = self.lower_span(s.span);
43 stmts.push(hir::Stmt { hir_id, kind, span });
44 }
45 StmtKind::Item(it) => {
46 stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
47 |(i, item_id)| {
48 let hir_id = match i {
49 0 => self.lower_node_id(s.id),
50 _ => self.next_id(),
51 };
52 let kind = hir::StmtKind::Item(item_id);
53 let span = self.lower_span(s.span);
54 hir::Stmt { hir_id, kind, span }
55 },
56 ));
57 }
58 StmtKind::Expr(e) => {
59 let e = self.lower_expr(e);
60 if tail.is_empty() {
61 expr = Some(e);
62 } else {
63 let hir_id = self.lower_node_id(s.id);
64 self.alias_attrs(hir_id, e.hir_id);
65 let kind = hir::StmtKind::Expr(e);
66 let span = self.lower_span(s.span);
67 stmts.push(hir::Stmt { hir_id, kind, span });
68 }
69 }
70 StmtKind::Semi(e) => {
71 let e = self.lower_expr(e);
72 let hir_id = self.lower_node_id(s.id);
73 self.alias_attrs(hir_id, e.hir_id);
74 let kind = hir::StmtKind::Semi(e);
75 let span = self.lower_span(s.span);
76 stmts.push(hir::Stmt { hir_id, kind, span });
77 }
78 StmtKind::Empty => {}
79 StmtKind::MacCall(..) => panic!("shouldn't exist here"),
80 }
81 ast_stmts = tail;
82 }
83 (self.arena.alloc_from_iter(stmts), expr)
84 }
85
86 fn impl_trait_in_bindings_ctxt(&self, position: ImplTraitPosition) -> ImplTraitContext {
89 if self.tcx.features().impl_trait_in_bindings() {
90 ImplTraitContext::InBinding
91 } else {
92 ImplTraitContext::FeatureGated(position, sym::impl_trait_in_bindings)
93 }
94 }
95
96 fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
97 let ty = l.ty.as_ref().map(|t| {
99 self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
100 });
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 els = if let LocalKind::InitElse(_, els) = &l.kind {
105 Some(self.lower_block(els, false))
106 } else {
107 None
108 };
109 let span = self.lower_span(l.span);
110 let source = hir::LocalSource::Normal;
111 self.lower_attrs(hir_id, &l.attrs, l.span);
112 self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
113 }
114
115 fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
116 match *b {
117 BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
118 BlockCheckMode::Unsafe(u) => {
119 hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
120 }
121 }
122 }
123}