1use rustc_abi::{FieldIdx, VariantIdx};
2use rustc_middle::mir::interpret::Scalar;
3use rustc_middle::mir::tcx::PlaceTy;
4use rustc_middle::mir::*;
5use rustc_middle::thir::*;
6use rustc_middle::ty;
7use rustc_middle::ty::cast::mir_cast_kind;
8use rustc_span::Span;
9use rustc_span::source_map::Spanned;
10
11use super::{PResult, ParseCtxt, parse_by_kind};
12use crate::builder::custom::ParseError;
13use crate::builder::expr::as_constant::as_constant_inner;
14
15impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
16 pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
17 parse_by_kind!(self, expr_id, _, "statement",
18 @call(mir_storage_live, args) => {
19 Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
20 },
21 @call(mir_storage_dead, args) => {
22 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
23 },
24 @call(mir_assume, args) => {
25 let op = self.parse_operand(args[0])?;
26 Ok(StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(op))))
27 },
28 @call(mir_deinit, args) => {
29 Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
30 },
31 @call(mir_retag, args) => {
32 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
33 },
34 @call(mir_set_discriminant, args) => {
35 let place = self.parse_place(args[0])?;
36 let var = self.parse_integer_literal(args[1])? as u32;
37 Ok(StatementKind::SetDiscriminant {
38 place: Box::new(place),
39 variant_index: VariantIdx::from_u32(var),
40 })
41 },
42 ExprKind::Assign { lhs, rhs } => {
43 let lhs = self.parse_place(*lhs)?;
44 let rhs = self.parse_rvalue(*rhs)?;
45 Ok(StatementKind::Assign(Box::new((lhs, rhs))))
46 },
47 )
48 }
49
50 pub(crate) fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
51 parse_by_kind!(self, expr_id, expr, "terminator",
52 @call(mir_return, _args) => {
53 Ok(TerminatorKind::Return)
54 },
55 @call(mir_goto, args) => {
56 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
57 },
58 @call(mir_unreachable, _args) => {
59 Ok(TerminatorKind::Unreachable)
60 },
61 @call(mir_unwind_resume, _args) => {
62 Ok(TerminatorKind::UnwindResume)
63 },
64 @call(mir_unwind_terminate, args) => {
65 Ok(TerminatorKind::UnwindTerminate(self.parse_unwind_terminate_reason(args[0])?))
66 },
67 @call(mir_drop, args) => {
68 Ok(TerminatorKind::Drop {
69 place: self.parse_place(args[0])?,
70 target: self.parse_return_to(args[1])?,
71 unwind: self.parse_unwind_action(args[2])?,
72 replace: false,
73 })
74 },
75 @call(mir_call, args) => {
76 self.parse_call(args)
77 },
78 @call(mir_tail_call, args) => {
79 self.parse_tail_call(args)
80 },
81 ExprKind::Match { scrutinee, arms, .. } => {
82 let discr = self.parse_operand(*scrutinee)?;
83 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
84 },
85 )
86 }
87
88 fn parse_unwind_terminate_reason(&self, expr_id: ExprId) -> PResult<UnwindTerminateReason> {
89 parse_by_kind!(self, expr_id, _, "unwind terminate reason",
90 @variant(mir_unwind_terminate_reason, Abi) => {
91 Ok(UnwindTerminateReason::Abi)
92 },
93 @variant(mir_unwind_terminate_reason, InCleanup) => {
94 Ok(UnwindTerminateReason::InCleanup)
95 },
96 )
97 }
98
99 fn parse_unwind_action(&self, expr_id: ExprId) -> PResult<UnwindAction> {
100 parse_by_kind!(self, expr_id, _, "unwind action",
101 @call(mir_unwind_continue, _args) => {
102 Ok(UnwindAction::Continue)
103 },
104 @call(mir_unwind_unreachable, _args) => {
105 Ok(UnwindAction::Unreachable)
106 },
107 @call(mir_unwind_terminate, args) => {
108 Ok(UnwindAction::Terminate(self.parse_unwind_terminate_reason(args[0])?))
109 },
110 @call(mir_unwind_cleanup, args) => {
111 Ok(UnwindAction::Cleanup(self.parse_block(args[0])?))
112 },
113 )
114 }
115
116 fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> {
117 parse_by_kind!(self, expr_id, _, "return block",
118 @call(mir_return_to, args) => {
119 self.parse_block(args[0])
120 },
121 )
122 }
123
124 fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
125 let Some((otherwise, rest)) = arms.split_last() else {
126 return Err(ParseError {
127 span,
128 item_description: "no arms".to_string(),
129 expected: "at least one arm".to_string(),
130 });
131 };
132
133 let otherwise = &self.thir[*otherwise];
134 let PatKind::Wild = otherwise.pattern.kind else {
135 return Err(ParseError {
136 span: otherwise.span,
137 item_description: format!("{:?}", otherwise.pattern.kind),
138 expected: "wildcard pattern".to_string(),
139 });
140 };
141 let otherwise = self.parse_block(otherwise.body)?;
142
143 let mut values = Vec::new();
144 let mut targets = Vec::new();
145 for arm in rest {
146 let arm = &self.thir[*arm];
147 let value = match arm.pattern.kind {
148 PatKind::Constant { value } => value,
149 PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
150 if let PatKind::Constant { value } = subpattern.kind =>
151 {
152 value
153 }
154 _ => {
155 return Err(ParseError {
156 span: arm.pattern.span,
157 item_description: format!("{:?}", arm.pattern.kind),
158 expected: "constant pattern".to_string(),
159 });
160 }
161 };
162 values.push(value.eval_bits(self.tcx, self.typing_env));
163 targets.push(self.parse_block(arm.body)?);
164 }
165
166 Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
167 }
168
169 fn parse_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
170 let (destination, call) = parse_by_kind!(self, args[0], _, "function call",
171 ExprKind::Assign { lhs, rhs } => (*lhs, *rhs),
172 );
173 let destination = self.parse_place(destination)?;
174 let target = self.parse_return_to(args[1])?;
175 let unwind = self.parse_unwind_action(args[2])?;
176
177 parse_by_kind!(self, call, _, "function call",
178 ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
179 let fun = self.parse_operand(*fun)?;
180 let args = args
181 .iter()
182 .map(|arg|
183 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
184 )
185 .collect::<PResult<Box<[_]>>>()?;
186 Ok(TerminatorKind::Call {
187 func: fun,
188 args,
189 destination,
190 target: Some(target),
191 unwind,
192 call_source: if *from_hir_call { CallSource::Normal } else {
193 CallSource::OverloadedOperator
194 },
195 fn_span: *fn_span,
196 })
197 },
198 )
199 }
200
201 fn parse_tail_call(&self, args: &[ExprId]) -> PResult<TerminatorKind<'tcx>> {
202 parse_by_kind!(self, args[0], _, "tail call",
203 ExprKind::Call { fun, args, fn_span, .. } => {
204 let fun = self.parse_operand(*fun)?;
205 let args = args
206 .iter()
207 .map(|arg|
208 Ok(Spanned { node: self.parse_operand(*arg)?, span: self.thir.exprs[*arg].span } )
209 )
210 .collect::<PResult<Box<[_]>>>()?;
211 Ok(TerminatorKind::TailCall {
212 func: fun,
213 args,
214 fn_span: *fn_span,
215 })
216 },
217 )
218 }
219
220 fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
221 parse_by_kind!(self, expr_id, expr, "rvalue",
222 @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
223 @call(mir_cast_transmute, args) => {
224 let source = self.parse_operand(args[0])?;
225 Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
226 },
227 @call(mir_cast_ptr_to_ptr, args) => {
228 let source = self.parse_operand(args[0])?;
229 Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty))
230 },
231 @call(mir_checked, args) => {
232 parse_by_kind!(self, args[0], _, "binary op",
233 ExprKind::Binary { op, lhs, rhs } => {
234 if let Some(op_with_overflow) = op.wrapping_to_overflowing() {
235 Ok(Rvalue::BinaryOp(
236 op_with_overflow, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
237 ))
238 } else {
239 Err(self.expr_error(expr_id, "No WithOverflow form of this operator"))
240 }
241 },
242 )
243 },
244 @call(mir_offset, args) => {
245 let ptr = self.parse_operand(args[0])?;
246 let offset = self.parse_operand(args[1])?;
247 Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
248 },
249 @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
250 @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)),
251 @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
252 ExprKind::Borrow { borrow_kind, arg } => Ok(
253 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
254 ),
255 ExprKind::RawBorrow { mutability, arg } => Ok(
256 Rvalue::RawPtr((*mutability).into(), self.parse_place(*arg)?)
257 ),
258 ExprKind::Binary { op, lhs, rhs } => Ok(
259 Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
260 ),
261 ExprKind::Unary { op, arg } => Ok(
262 Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
263 ),
264 ExprKind::Repeat { value, count } => Ok(
265 Rvalue::Repeat(self.parse_operand(*value)?, *count)
266 ),
267 ExprKind::Cast { source } => {
268 let source = self.parse_operand(*source)?;
269 let source_ty = source.ty(self.body.local_decls(), self.tcx);
270 let cast_kind = mir_cast_kind(source_ty, expr.ty);
271 Ok(Rvalue::Cast(cast_kind, source, expr.ty))
272 },
273 ExprKind::Tuple { fields } => Ok(
274 Rvalue::Aggregate(
275 Box::new(AggregateKind::Tuple),
276 fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
277 )
278 ),
279 ExprKind::Array { fields } => {
280 let elem_ty = expr.ty.builtin_index().expect("ty must be an array");
281 Ok(Rvalue::Aggregate(
282 Box::new(AggregateKind::Array(elem_ty)),
283 fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()?
284 ))
285 },
286 ExprKind::Adt(box AdtExpr { adt_def, variant_index, args, fields, .. }) => {
287 let is_union = adt_def.is_union();
288 let active_field_index = is_union.then(|| fields[0].name);
289
290 Ok(Rvalue::Aggregate(
291 Box::new(AggregateKind::Adt(adt_def.did(), *variant_index, args, None, active_field_index)),
292 fields.iter().map(|f| self.parse_operand(f.expr)).collect::<Result<_, _>>()?
293 ))
294 },
295 _ => self.parse_operand(expr_id).map(Rvalue::Use),
296 )
297 }
298
299 pub(crate) fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
300 parse_by_kind!(self, expr_id, expr, "operand",
301 @call(mir_move, args) => self.parse_place(args[0]).map(Operand::Move),
302 @call(mir_static, args) => self.parse_static(args[0]),
303 @call(mir_static_mut, args) => self.parse_static(args[0]),
304 ExprKind::Literal { .. }
305 | ExprKind::NamedConst { .. }
306 | ExprKind::NonHirLiteral { .. }
307 | ExprKind::ZstLiteral { .. }
308 | ExprKind::ConstParam { .. }
309 | ExprKind::ConstBlock { .. } => {
310 Ok(Operand::Constant(Box::new(
311 as_constant_inner(expr, |_| None, self.tcx)
312 )))
313 },
314 _ => self.parse_place(expr_id).map(Operand::Copy),
315 )
316 }
317
318 fn parse_place(&self, expr_id: ExprId) -> PResult<Place<'tcx>> {
319 self.parse_place_inner(expr_id).map(|(x, _)| x)
320 }
321
322 fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
323 let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
324 @call(mir_field, args) => {
325 let (parent, ty) = self.parse_place_inner(args[0])?;
326 let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
327 let field_ty = ty.field_ty(self.tcx, field);
328 let proj = PlaceElem::Field(field, field_ty);
329 let place = parent.project_deeper(&[proj], self.tcx);
330 return Ok((place, PlaceTy::from_ty(field_ty)));
331 },
332 @call(mir_variant, args) => {
333 (args[0], PlaceElem::Downcast(
334 None,
335 VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
336 ))
337 },
338 ExprKind::Deref { arg } => {
339 parse_by_kind!(self, *arg, _, "does not matter",
340 @call(mir_make_place, args) => return self.parse_place_inner(args[0]),
341 _ => (*arg, PlaceElem::Deref),
342 )
343 },
344 ExprKind::Index { lhs, index } => (*lhs, PlaceElem::Index(self.parse_local(*index)?)),
345 ExprKind::Field { lhs, name: field, .. } => (*lhs, PlaceElem::Field(*field, expr.ty)),
346 _ => {
347 let place = self.parse_local(expr_id).map(Place::from)?;
348 return Ok((place, PlaceTy::from_ty(expr.ty)))
349 },
350 );
351 let (parent, ty) = self.parse_place_inner(parent)?;
352 let place = parent.project_deeper(&[proj], self.tcx);
353 let ty = ty.projection_ty(self.tcx, proj);
354 Ok((place, ty))
355 }
356
357 fn parse_local(&self, expr_id: ExprId) -> PResult<Local> {
358 parse_by_kind!(self, expr_id, _, "local",
359 ExprKind::VarRef { id } => Ok(self.local_map[id]),
360 )
361 }
362
363 fn parse_block(&self, expr_id: ExprId) -> PResult<BasicBlock> {
364 parse_by_kind!(self, expr_id, _, "basic block",
365 ExprKind::VarRef { id } => Ok(self.block_map[id]),
366 )
367 }
368
369 fn parse_static(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
370 let expr_id = parse_by_kind!(self, expr_id, _, "static",
371 ExprKind::Deref { arg } => *arg,
372 );
373
374 parse_by_kind!(self, expr_id, expr, "static",
375 ExprKind::StaticRef { alloc_id, ty, .. } => {
376 let const_val =
377 ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
378 let const_ = Const::Val(const_val, *ty);
379
380 Ok(Operand::Constant(Box::new(ConstOperand {
381 span: expr.span,
382 user_ty: None,
383 const_
384 })))
385 },
386 )
387 }
388
389 fn parse_integer_literal(&self, expr_id: ExprId) -> PResult<u128> {
390 parse_by_kind!(self, expr_id, expr, "constant",
391 ExprKind::Literal { .. }
392 | ExprKind::NamedConst { .. }
393 | ExprKind::NonHirLiteral { .. }
394 | ExprKind::ConstBlock { .. } => Ok({
395 let value = as_constant_inner(expr, |_| None, self.tcx);
396 value.const_.eval_bits(self.tcx, self.typing_env)
397 }),
398 )
399 }
400}