1use rustc_index::IndexSlice;
2use rustc_middle::mir::*;
3use rustc_middle::thir::*;
4use rustc_middle::ty::{self, Ty};
5use rustc_span::Span;
6
7use super::{PResult, ParseCtxt, ParseError};
8
9mod instruction;
10
11macro_rules! parse_by_kind {
25 (
26 $self:ident,
27 $expr_id:expr,
28 $expr_name:pat,
29 $expected:literal,
30 $(
31 @call($name:ident, $args:ident) => $call_expr:expr,
32 )*
33 $(
34 @variant($adt:ident, $variant:ident) => $variant_expr:expr,
35 )*
36 $(
37 $pat:pat $(if $guard:expr)? => $expr:expr,
38 )*
39 ) => {{
40 let expr_id = $self.preparse($expr_id);
41 let expr = &$self.thir[expr_id];
42 tracing::debug!("Trying to parse {:?} as {}", expr.kind, $expected);
43 let $expr_name = expr;
44 match &expr.kind {
45 $(
46 ExprKind::Call { ty, fun: _, args: $args, .. } if {
47 match ty.kind() {
48 ty::FnDef(did, _) => {
49 $self.tcx.is_diagnostic_item(rustc_span::sym::$name, *did)
50 }
51 _ => false,
52 }
53 } => $call_expr,
54 )*
55 $(
56 ExprKind::Adt(box AdtExpr { adt_def, variant_index, .. }) if {
57 $self.tcx.is_diagnostic_item(rustc_span::sym::$adt, adt_def.did()) &&
58 adt_def.variants()[*variant_index].name == rustc_span::sym::$variant
59 } => $variant_expr,
60 )*
61 $(
62 $pat $(if $guard)? => $expr,
63 )*
64 #[allow(unreachable_patterns)]
65 _ => return Err($self.expr_error(expr_id, $expected))
66 }
67 }};
68}
69pub(crate) use parse_by_kind;
70
71impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
72 fn preparse(&self, expr_id: ExprId) -> ExprId {
75 let expr = &self.thir[expr_id];
76 match expr.kind {
77 ExprKind::Scope { value, .. } => self.preparse(value),
78 _ => expr_id,
79 }
80 }
81
82 fn statement_as_expr(&self, stmt_id: StmtId) -> PResult<ExprId> {
83 match &self.thir[stmt_id].kind {
84 StmtKind::Expr { expr, .. } => Ok(*expr),
85 kind @ StmtKind::Let { pattern, .. } => Err(ParseError {
86 span: pattern.span,
87 item_description: format!("{kind:?}"),
88 expected: "expression".to_string(),
89 }),
90 }
91 }
92
93 pub(crate) fn parse_args(&mut self, params: &IndexSlice<ParamId, Param<'tcx>>) -> PResult<()> {
94 for param in params.iter() {
95 let (var, span) = {
96 let pat = param.pat.as_ref().unwrap();
97 match &pat.kind {
98 PatKind::Binding { var, .. } => (*var, pat.span),
99 _ => {
100 return Err(ParseError {
101 span: pat.span,
102 item_description: format!("{:?}", pat.kind),
103 expected: "local".to_string(),
104 });
105 }
106 }
107 };
108 let decl = LocalDecl::new(param.ty, span);
109 let local = self.body.local_decls.push(decl);
110 self.local_map.insert(var, local);
111 }
112
113 Ok(())
114 }
115
116 pub(crate) fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> {
152 let body = parse_by_kind!(self, expr_id, _, "whole body",
153 ExprKind::Block { block } => self.thir[*block].expr.unwrap(),
154 );
155 let (block_decls, rest) = parse_by_kind!(self, body, _, "body with block decls",
156 ExprKind::Block { block } => {
157 let block = &self.thir[*block];
158 (&block.stmts, block.expr.unwrap())
159 },
160 );
161 self.parse_block_decls(block_decls.iter().copied())?;
162
163 let (local_decls, rest) = parse_by_kind!(self, rest, _, "body with local decls",
164 ExprKind::Block { block } => {
165 let block = &self.thir[*block];
166 (&block.stmts, block.expr.unwrap())
167 },
168 );
169 self.parse_local_decls(local_decls.iter().copied())?;
170
171 let (debuginfo, rest) = parse_by_kind!(self, rest, _, "body with debuginfo",
172 ExprKind::Block { block } => {
173 let block = &self.thir[*block];
174 (&block.stmts, block.expr.unwrap())
175 },
176 );
177 self.parse_debuginfo(debuginfo.iter().copied())?;
178
179 let block_defs = parse_by_kind!(self, rest, _, "body with block defs",
180 ExprKind::Block { block } => &self.thir[*block].stmts,
181 );
182 for (i, block_def) in block_defs.iter().enumerate() {
183 let is_cleanup = self.body.basic_blocks_mut()[BasicBlock::from_usize(i)].is_cleanup;
184 let block = self.parse_block_def(self.statement_as_expr(*block_def)?, is_cleanup)?;
185 self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
186 }
187
188 Ok(())
189 }
190
191 fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
192 for stmt in stmts {
193 self.parse_basic_block_decl(stmt)?;
194 }
195 Ok(())
196 }
197
198 fn parse_basic_block_decl(&mut self, stmt: StmtId) -> PResult<()> {
199 match &self.thir[stmt].kind {
200 StmtKind::Let { pattern, initializer: Some(initializer), .. } => {
201 let (var, ..) = self.parse_var(pattern)?;
202 let data = BasicBlockData::new(
203 None,
204 parse_by_kind!(self, *initializer, _, "basic block declaration",
205 @variant(mir_basic_block, Normal) => false,
206 @variant(mir_basic_block, Cleanup) => true,
207 ),
208 );
209 let block = self.body.basic_blocks_mut().push(data);
210 self.block_map.insert(var, block);
211 Ok(())
212 }
213 _ => Err(self.stmt_error(stmt, "let statement with an initializer")),
214 }
215 }
216
217 fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
218 let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
219 self.local_map.insert(ret_var, Local::ZERO);
220
221 for stmt in stmts {
222 let (var, ty, span) = self.parse_let_statement(stmt)?;
223 let decl = LocalDecl::new(ty, span);
224 let local = self.body.local_decls.push(decl);
225 self.local_map.insert(var, local);
226 }
227
228 Ok(())
229 }
230
231 fn parse_debuginfo(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
232 for stmt in stmts {
233 let stmt = &self.thir[stmt];
234 let expr = match stmt.kind {
235 StmtKind::Let { span, .. } => {
236 return Err(ParseError {
237 span,
238 item_description: format!("{:?}", stmt),
239 expected: "debuginfo".to_string(),
240 });
241 }
242 StmtKind::Expr { expr, .. } => expr,
243 };
244 let span = self.thir[expr].span;
245 let (name, operand) = parse_by_kind!(self, expr, _, "debuginfo",
246 @call(mir_debuginfo, args) => {
247 (args[0], args[1])
248 },
249 );
250 let name = parse_by_kind!(self, name, _, "debuginfo",
251 ExprKind::Literal { lit, neg: false } => lit,
252 );
253 let Some(name) = name.node.str() else {
254 return Err(ParseError {
255 span,
256 item_description: format!("{:?}", name),
257 expected: "string".to_string(),
258 });
259 };
260 let operand = self.parse_operand(operand)?;
261 let value = match operand {
262 Operand::Constant(c) => VarDebugInfoContents::Const(*c),
263 Operand::Copy(p) | Operand::Move(p) => VarDebugInfoContents::Place(p),
264 };
265 let dbginfo = VarDebugInfo {
266 name,
267 source_info: SourceInfo { span, scope: self.source_scope },
268 composite: None,
269 argument_index: None,
270 value,
271 };
272 self.body.var_debug_info.push(dbginfo);
273 }
274
275 Ok(())
276 }
277
278 fn parse_let_statement(&mut self, stmt_id: StmtId) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
279 let pattern = match &self.thir[stmt_id].kind {
280 StmtKind::Let { pattern, .. } => pattern,
281 StmtKind::Expr { expr, .. } => {
282 return Err(self.expr_error(*expr, "let statement"));
283 }
284 };
285
286 self.parse_var(pattern)
287 }
288
289 fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> {
290 loop {
292 match &pat.kind {
293 PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
294 PatKind::AscribeUserType { subpattern, .. } => {
295 pat = subpattern;
296 }
297 _ => {
298 break Err(ParseError {
299 span: pat.span,
300 item_description: format!("{:?}", pat.kind),
301 expected: "local".to_string(),
302 });
303 }
304 }
305 }
306 }
307
308 fn parse_block_def(&self, expr_id: ExprId, is_cleanup: bool) -> PResult<BasicBlockData<'tcx>> {
309 let block = parse_by_kind!(self, expr_id, _, "basic block",
310 ExprKind::Block { block } => &self.thir[*block],
311 );
312
313 let mut data = BasicBlockData::new(None, is_cleanup);
314 for stmt_id in &*block.stmts {
315 let stmt = self.statement_as_expr(*stmt_id)?;
316 let span = self.thir[stmt].span;
317 let statement = self.parse_statement(stmt)?;
318 data.statements.push(Statement {
319 source_info: SourceInfo { span, scope: self.source_scope },
320 kind: statement,
321 });
322 }
323
324 let Some(trailing) = block.expr else { return Err(self.expr_error(expr_id, "terminator")) };
325 let span = self.thir[trailing].span;
326 let terminator = self.parse_terminator(trailing)?;
327 data.terminator = Some(Terminator {
328 source_info: SourceInfo { span, scope: self.source_scope },
329 kind: terminator,
330 });
331
332 Ok(data)
333 }
334}