1 use rustc_index::vec::IndexVec;
2 use rustc_middle::{mir::*, thir::*, ty::Ty};
5 use super::{PResult, ParseCtxt, ParseError};
9 /// Helper macro for parsing custom MIR.
11 /// Example usage looks something like:
12 /// ```rust,ignore (incomplete example)
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
22 macro_rules! parse_by_kind {
28 @call($name:literal, $args:ident) => $call_expr:expr,
31 $pat:pat => $expr:expr,
34 let expr_id = $self.preparse($expr_id);
35 let expr = &$self.thir[expr_id];
38 ExprKind::Call { ty, fun: _, args: $args, .. } if {
40 ty::FnDef(did, _) => {
41 $self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
50 #[allow(unreachable_patterns)]
51 _ => return Err($self.expr_error(expr_id, $expected))
55 pub(crate) use parse_by_kind;
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];
63 ExprKind::Scope { value, .. } => self.preparse(value),
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 {
74 item_description: format!("{:?}", kind),
75 expected: "expression".to_string(),
81 pub fn parse_args(&mut self, params: &IndexVec<ParamId, Param<'tcx>>) -> PResult<()> {
82 for param in params.iter() {
84 let pat = param.pat.as_ref().unwrap();
86 PatKind::Binding { var, .. } => (*var, pat.span),
88 return Err(ParseError {
90 item_description: format!("{:?}", pat.kind),
91 expected: "local".to_string(),
96 let decl = LocalDecl::new(param.ty, span);
97 let local = self.body.local_decls.push(decl);
98 self.local_map.insert(var, local);
104 /// Bodies are of the form:
108 /// let bb1: BasicBlock;
109 /// let bb2: BasicBlock;
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(),
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())
149 self.parse_block_decls(block_decls.iter().copied())?;
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())
157 self.parse_local_decls(local_decls.iter().copied())?;
159 let block_defs = parse_by_kind!(self, rest, "body with block defs",
160 ExprKind::Block { block } => &self.thir[*block].stmts,
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;
170 fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
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);
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));
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);
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"));
203 self.parse_var(pattern)
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
210 PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)),
211 PatKind::AscribeUserType { subpattern, .. } => {
215 break Err(ParseError {
217 item_description: format!("{:?}", pat.kind),
218 expected: "local".to_string(),
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],
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 });
237 let Some(trailing) = block.expr else {
238 return Err(self.expr_error(expr_id, "terminator"))
240 let terminator = self.parse_terminator(trailing)?;
241 data.terminator = Some(Terminator { source_info: self.source_info, kind: terminator });