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