1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use rustc_hir as hir;
use rustc_index::Idx;
use rustc_middle::middle::region;
use rustc_middle::thir::*;
use rustc_middle::ty;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
use tracing::debug;

use crate::thir::cx::Cx;

impl<'tcx> Cx<'tcx> {
    pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId {
        // We have to eagerly lower the "spine" of the statements
        // in order to get the lexical scoping correctly.
        let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
        let block = Block {
            targeted_by_break: block.targeted_by_break,
            region_scope: region::Scope {
                id: block.hir_id.local_id,
                data: region::ScopeData::Node,
            },
            span: block.span,
            stmts,
            expr: block.expr.map(|expr| self.mirror_expr(expr)),
            safety_mode: match block.rules {
                hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
                hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated) => {
                    BlockSafety::BuiltinUnsafe
                }
                hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) => {
                    BlockSafety::ExplicitUnsafe(block.hir_id)
                }
            },
        };

        self.thir.blocks.push(block)
    }

    fn mirror_stmts(
        &mut self,
        block_id: hir::ItemLocalId,
        stmts: &'tcx [hir::Stmt<'tcx>],
    ) -> Box<[StmtId]> {
        stmts
            .iter()
            .enumerate()
            .filter_map(|(index, stmt)| {
                let hir_id = stmt.hir_id;
                match stmt.kind {
                    hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => {
                        let stmt = Stmt {
                            kind: StmtKind::Expr {
                                scope: region::Scope {
                                    id: hir_id.local_id,
                                    data: region::ScopeData::Node,
                                },
                                expr: self.mirror_expr(expr),
                            },
                        };
                        Some(self.thir.stmts.push(stmt))
                    }
                    hir::StmtKind::Item(..) => {
                        // ignore for purposes of the MIR
                        None
                    }
                    hir::StmtKind::Let(local) => {
                        let remainder_scope = region::Scope {
                            id: block_id,
                            data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
                                index,
                            )),
                        };

                        let else_block = local.els.map(|els| self.mirror_block(els));

                        let mut pattern = self.pattern_from_hir(local.pat);
                        debug!(?pattern);

                        if let Some(ty) = &local.ty {
                            if let Some(&user_ty) =
                                self.typeck_results.user_provided_types().get(ty.hir_id)
                            {
                                debug!("mirror_stmts: user_ty={:?}", user_ty);
                                let annotation = CanonicalUserTypeAnnotation {
                                    user_ty: Box::new(user_ty),
                                    span: ty.span,
                                    inferred_ty: self.typeck_results.node_type(ty.hir_id),
                                };
                                pattern = Box::new(Pat {
                                    ty: pattern.ty,
                                    span: pattern.span,
                                    kind: PatKind::AscribeUserType {
                                        ascription: Ascription {
                                            annotation,
                                            variance: ty::Covariant,
                                        },
                                        subpattern: pattern,
                                    },
                                });
                            }
                        }

                        let span = match local.init {
                            Some(init) => local.span.with_hi(init.span.hi()),
                            None => local.span,
                        };
                        let stmt = Stmt {
                            kind: StmtKind::Let {
                                remainder_scope,
                                init_scope: region::Scope {
                                    id: hir_id.local_id,
                                    data: region::ScopeData::Node,
                                },
                                pattern,
                                initializer: local.init.map(|init| self.mirror_expr(init)),
                                else_block,
                                lint_level: LintLevel::Explicit(local.hir_id),
                                span,
                            },
                        };
                        Some(self.thir.stmts.push(stmt))
                    }
                }
            })
            .collect()
    }
}