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
{
29 @
call($name
:literal
, $args
:ident
) => $call_expr
:expr
,
32 $pat
:pat
=> $expr
:expr
,
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
;
41 ExprKind
::Call { ty, fun: _, args: $args, .. }
if {
43 ty
::FnDef(did
, _
) => {
44 $
self.tcx
.is_diagnostic_item(rustc_span
::Symbol
::intern($name
), *did
)
53 #[allow(unreachable_patterns)]
54 _
=> return Err($
self.expr_error(expr_id
, $expected
))
58 pub(crate) use parse_by_kind
;
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
];
66 ExprKind
::Scope { value, .. }
=> self.preparse(value
),
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
{
77 item_description
: format
!("{:?}", kind
),
78 expected
: "expression".to_string(),
84 pub fn parse_args(&mut self, params
: &IndexVec
<ParamId
, Param
<'tcx
>>) -> PResult
<()> {
85 for param
in params
.iter() {
87 let pat
= param
.pat
.as_ref().unwrap();
89 PatKind
::Binding { var, .. }
=> (*var
, pat
.span
),
91 return Err(ParseError
{
93 item_description
: format
!("{:?}", pat
.kind
),
94 expected
: "local".to_string(),
99 let decl
= LocalDecl
::new(param
.ty
, span
);
100 let local
= self.body
.local_decls
.push(decl
);
101 self.local_map
.insert(var
, local
);
107 /// Bodies are of the form:
111 /// let bb1: BasicBlock;
112 /// let bb2: BasicBlock;
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(),
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())
152 self.parse_block_decls(block_decls
.iter().copied())?
;
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())
160 self.parse_local_decls(local_decls
.iter().copied())?
;
162 let block_defs
= parse_by_kind
!(self, rest
, _
, "body with block defs",
163 ExprKind
::Block { block }
=> &self.thir
[*block
].stmts
,
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
;
173 fn parse_block_decls(&mut self, stmts
: impl Iterator
<Item
= StmtId
>) -> PResult
<()> {
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
);
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));
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
);
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"));
206 self.parse_var(pattern
)
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
213 PatKind
::Binding { var, ty, .. }
=> break Ok((*var
, *ty
, pat
.span
)),
214 PatKind
::AscribeUserType { subpattern, .. }
=> {
218 break Err(ParseError
{
220 item_description
: format
!("{:?}", pat
.kind
),
221 expected
: "local".to_string(),
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
],
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 }
,
244 let Some(trailing
) = block
.expr
else {
245 return Err(self.expr_error(expr_id
, "terminator"))
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 }
,