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