rustc_ast_lowering/
block.rs

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