]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/custom/parse.rs
Rollup merge of #104121 - Lokathor:mir-opt-when-instruction-set-missing-on-callee...
[rust.git] / compiler / rustc_mir_build / src / build / custom / parse.rs
1 use rustc_index::vec::IndexVec;
2 use rustc_middle::{mir::*, thir::*, ty::Ty};
3 use rustc_span::Span;
4
5 use super::{PResult, ParseCtxt, ParseError};
6
7 mod instruction;
8
9 /// Helper macro for parsing custom MIR.
10 ///
11 /// Example usage looks something like:
12 /// ```rust,ignore (incomplete example)
13 /// parse_by_kind!(
14 ///     self, // : &ParseCtxt
15 ///     expr_id, // what you're matching against
16 ///     "assignment", // the thing you're trying to parse
17 ///     @call("mir_assign", args) => { args[0] }, // match invocations of the `mir_assign` special function
18 ///     ExprKind::Assign { lhs, .. } => { lhs }, // match thir assignment expressions
19 ///     // no need for fallthrough case - reasonable error is automatically generated
20 /// )
21 /// ```
22 macro_rules! parse_by_kind {
23     (
24         $self:ident,
25         $expr_id:expr,
26         $expected:literal,
27         $(
28             @call($name:literal, $args:ident) => $call_expr:expr,
29         )*
30         $(
31             $pat:pat => $expr:expr,
32         )*
33     ) => {{
34         let expr_id = $self.preparse($expr_id);
35         let expr = &$self.thir[expr_id];
36         match &expr.kind {
37             $(
38                 ExprKind::Call { ty, fun: _, args: $args, .. } if {
39                     match ty.kind() {
40                         ty::FnDef(did, _) => {
41                             $self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
42                         }
43                         _ => false,
44                     }
45                 } => $call_expr,
46             )*
47             $(
48                 $pat => $expr,
49             )*
50             #[allow(unreachable_patterns)]
51             _ => return Err($self.expr_error(expr_id, $expected))
52         }
53     }};
54 }
55 pub(crate) use parse_by_kind;
56
57 impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
58     /// Expressions should only ever be matched on after preparsing them. This removes extra scopes
59     /// we don't care about.
60     fn preparse(&self, expr_id: ExprId) -> ExprId {
61         let expr = &self.thir[expr_id];
62         match expr.kind {
63             ExprKind::Scope { value, .. } => self.preparse(value),
64             _ => expr_id,
65         }
66     }
67
68     fn statement_as_expr(&self, stmt_id: StmtId) -> PResult<ExprId> {
69         match &self.thir[stmt_id].kind {
70             StmtKind::Expr { expr, .. } => Ok(*expr),
71             kind @ StmtKind::Let { pattern, .. } => {
72                 return Err(ParseError {
73                     span: pattern.span,
74                     item_description: format!("{:?}", kind),
75                     expected: "expression".to_string(),
76                 });
77             }
78         }
79     }
80
81     pub fn parse_args(&mut self, params: &IndexVec<ParamId, Param<'tcx>>) -> PResult<()> {
82         for param in params.iter() {
83             let (var, span) = {
84                 let pat = param.pat.as_ref().unwrap();
85                 match &pat.kind {
86                     PatKind::Binding { var, .. } => (*var, pat.span),
87                     _ => {
88                         return Err(ParseError {
89                             span: pat.span,
90                             item_description: format!("{:?}", pat.kind),
91                             expected: "local".to_string(),
92                         });
93                     }
94                 }
95             };
96             let decl = LocalDecl::new(param.ty, span);
97             let local = self.body.local_decls.push(decl);
98             self.local_map.insert(var, local);
99         }
100
101         Ok(())
102     }
103
104     /// Bodies are of the form:
105     ///
106     /// ```text
107     /// {
108     ///     let bb1: BasicBlock;
109     ///     let bb2: BasicBlock;
110     ///     {
111     ///         let RET: _;
112     ///         let local1;
113     ///         let local2;
114     ///
115     ///         {
116     ///             { // entry block
117     ///                 statement1;
118     ///                 terminator1
119     ///             };
120     ///
121     ///             bb1 = {
122     ///                 statement2;
123     ///                 terminator2
124     ///             };
125     ///
126     ///             bb2 = {
127     ///                 statement3;
128     ///                 terminator3
129     ///             }
130     ///
131     ///             RET
132     ///         }
133     ///     }
134     /// }
135     /// ```
136     ///
137     /// This allows us to easily parse the basic blocks declarations, local declarations, and
138     /// basic block definitions in order.
139     pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
140         let body = parse_by_kind!(self, expr_id, "whole body",
141             ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
142         );
143         let (block_decls, rest) = parse_by_kind!(self, body, "body with block decls",
144             ExprKind::Block { block } => {
145                 let block = &self.thir[*block];
146                 (&block.stmts, block.expr.unwrap())
147             },
148         );
149         self.parse_block_decls(block_decls.iter().copied())?;
150
151         let (local_decls, rest) = parse_by_kind!(self, rest, "body with local decls",
152             ExprKind::Block { block } => {
153                 let block = &self.thir[*block];
154                 (&block.stmts, block.expr.unwrap())
155             },
156         );
157         self.parse_local_decls(local_decls.iter().copied())?;
158
159         let block_defs = parse_by_kind!(self, rest, "body with block defs",
160             ExprKind::Block { block } => &self.thir[*block].stmts,
161         );
162         for (i, block_def) in block_defs.iter().enumerate() {
163             let block = self.parse_block_def(self.statement_as_expr(*block_def)?)?;
164             self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
165         }
166
167         Ok(())
168     }
169
170     fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
171         for stmt in stmts {
172             let (var, _, _) = self.parse_let_statement(stmt)?;
173             let data = BasicBlockData::new(None);
174             let block = self.body.basic_blocks_mut().push(data);
175             self.block_map.insert(var, block);
176         }
177
178         Ok(())
179     }
180
181     fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
182         let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
183         self.local_map.insert(ret_var, Local::from_u32(0));
184
185         for stmt in stmts {
186             let (var, ty, span) = self.parse_let_statement(stmt)?;
187             let decl = LocalDecl::new(ty, span);
188             let local = self.body.local_decls.push(decl);
189             self.local_map.insert(var, local);
190         }
191
192         Ok(())
193     }
194
195     fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
196         let pattern = match &self.thir[stmt_id].kind {
197             StmtKind::Let { pattern, .. } => pattern,
198             StmtKind::Expr { expr, .. } => {
199                 return Err(self.expr_error(*expr, "let statement"));
200             }
201         };
202
203         self.parse_var(pattern)
204     }
205
206     fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
207         // Make sure we throw out any `AscribeUserType` we find
208         loop {
209             match &pat.kind {
210                 PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
211                 PatKind::AscribeUserType { subpattern, .. } => {
212                     pat = subpattern;
213                 }
214                 _ => {
215                     break Err(ParseError {
216                         span: pat.span,
217                         item_description: format!("{:?}", pat.kind),
218                         expected: "local".to_string(),
219                     });
220                 }
221             }
222         }
223     }
224
225     fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
226         let block = parse_by_kind!(self, expr_id, "basic block",
227             ExprKind::Block { block } => &self.thir[*block],
228         );
229
230         let mut data = BasicBlockData::new(None);
231         for stmt_id in &*block.stmts {
232             let stmt = self.statement_as_expr(*stmt_id)?;
233             let statement = self.parse_statement(stmt)?;
234             data.statements.push(Statement { source_info: self.source_info, kind: statement });
235         }
236
237         let Some(trailing) = block.expr else {
238             return Err(self.expr_error(expr_id, "terminator"))
239         };
240         let terminator = self.parse_terminator(trailing)?;
241         data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });
242
243         Ok(data)
244     }
245 }