1use std::io;
2
3use serde::Serialize;
4use stable_mir::compiler_interface::with;
5use stable_mir::mir::pretty::function_body;
6use stable_mir::ty::{
7 AdtDef, ClosureDef, CoroutineClosureDef, CoroutineDef, GenericArgs, MirConst, Movability,
8 Region, RigidTy, Ty, TyConst, TyKind, VariantIdx,
9};
10use stable_mir::{Error, Opaque, Span, Symbol};
11
12use crate::stable_mir;
13
14#[derive(Clone, Debug, Serialize)]
16pub struct Body {
17 pub blocks: Vec<BasicBlock>,
18
19 pub(super) locals: LocalDecls,
25
26 pub(super) arg_count: usize,
28
29 pub var_debug_info: Vec<VarDebugInfo>,
31
32 pub(super) spread_arg: Option<Local>,
36
37 pub span: Span,
39}
40
41pub type BasicBlockIdx = usize;
42
43impl Body {
44 pub fn new(
49 blocks: Vec<BasicBlock>,
50 locals: LocalDecls,
51 arg_count: usize,
52 var_debug_info: Vec<VarDebugInfo>,
53 spread_arg: Option<Local>,
54 span: Span,
55 ) -> Self {
56 assert!(
59 locals.len() > arg_count,
60 "A Body must contain at least a local for the return value and each of the function's arguments"
61 );
62 Self { blocks, locals, arg_count, var_debug_info, spread_arg, span }
63 }
64
65 pub fn ret_local(&self) -> &LocalDecl {
67 &self.locals[RETURN_LOCAL]
68 }
69
70 pub fn arg_locals(&self) -> &[LocalDecl] {
72 &self.locals[1..][..self.arg_count]
73 }
74
75 pub fn inner_locals(&self) -> &[LocalDecl] {
78 &self.locals[self.arg_count + 1..]
79 }
80
81 pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl {
83 &mut self.locals[RETURN_LOCAL]
84 }
85
86 pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] {
88 &mut self.locals[1..][..self.arg_count]
89 }
90
91 pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] {
94 &mut self.locals[self.arg_count + 1..]
95 }
96
97 pub fn locals(&self) -> &[LocalDecl] {
102 &self.locals
103 }
104
105 pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
107 self.locals.get(local)
108 }
109
110 pub fn local_decls(&self) -> impl Iterator<Item = (Local, &LocalDecl)> {
112 self.locals.iter().enumerate()
113 }
114
115 pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
117 function_body(w, self, fn_name)
118 }
119
120 pub fn spread_arg(&self) -> Option<Local> {
121 self.spread_arg
122 }
123}
124
125type LocalDecls = Vec<LocalDecl>;
126
127#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
128pub struct LocalDecl {
129 pub ty: Ty,
130 pub span: Span,
131 pub mutability: Mutability,
132}
133
134#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
135pub struct BasicBlock {
136 pub statements: Vec<Statement>,
137 pub terminator: Terminator,
138}
139
140#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
141pub struct Terminator {
142 pub kind: TerminatorKind,
143 pub span: Span,
144}
145
146impl Terminator {
147 pub fn successors(&self) -> Successors {
148 self.kind.successors()
149 }
150}
151
152pub type Successors = Vec<BasicBlockIdx>;
153
154#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
155pub enum TerminatorKind {
156 Goto {
157 target: BasicBlockIdx,
158 },
159 SwitchInt {
160 discr: Operand,
161 targets: SwitchTargets,
162 },
163 Resume,
164 Abort,
165 Return,
166 Unreachable,
167 Drop {
168 place: Place,
169 target: BasicBlockIdx,
170 unwind: UnwindAction,
171 },
172 Call {
173 func: Operand,
174 args: Vec<Operand>,
175 destination: Place,
176 target: Option<BasicBlockIdx>,
177 unwind: UnwindAction,
178 },
179 Assert {
180 cond: Operand,
181 expected: bool,
182 msg: AssertMessage,
183 target: BasicBlockIdx,
184 unwind: UnwindAction,
185 },
186 InlineAsm {
187 template: String,
188 operands: Vec<InlineAsmOperand>,
189 options: String,
190 line_spans: String,
191 destination: Option<BasicBlockIdx>,
192 unwind: UnwindAction,
193 },
194}
195
196impl TerminatorKind {
197 pub fn successors(&self) -> Successors {
198 use self::TerminatorKind::*;
199 match *self {
200 Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
201 | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
202 | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
203 | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
204 vec![t, u]
205 }
206 Goto { target: t }
207 | Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
208 | Call { target: Some(t), unwind: _, .. }
209 | Drop { target: t, unwind: _, .. }
210 | Assert { target: t, unwind: _, .. }
211 | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
212 | InlineAsm { destination: Some(t), unwind: _, .. } => {
213 vec![t]
214 }
215
216 Return
217 | Resume
218 | Abort
219 | Unreachable
220 | Call { target: None, unwind: _, .. }
221 | InlineAsm { destination: None, unwind: _, .. } => {
222 vec![]
223 }
224 SwitchInt { ref targets, .. } => targets.all_targets(),
225 }
226 }
227
228 pub fn unwind(&self) -> Option<&UnwindAction> {
229 match *self {
230 TerminatorKind::Goto { .. }
231 | TerminatorKind::Return
232 | TerminatorKind::Unreachable
233 | TerminatorKind::Resume
234 | TerminatorKind::Abort
235 | TerminatorKind::SwitchInt { .. } => None,
236 TerminatorKind::Call { ref unwind, .. }
237 | TerminatorKind::Assert { ref unwind, .. }
238 | TerminatorKind::Drop { ref unwind, .. }
239 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
240 }
241 }
242}
243
244#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
245pub struct InlineAsmOperand {
246 pub in_value: Option<Operand>,
247 pub out_place: Option<Place>,
248 pub raw_rpr: String,
251}
252
253#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
254pub enum UnwindAction {
255 Continue,
256 Unreachable,
257 Terminate,
258 Cleanup(BasicBlockIdx),
259}
260
261#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
262pub enum AssertMessage {
263 BoundsCheck { len: Operand, index: Operand },
264 Overflow(BinOp, Operand, Operand),
265 OverflowNeg(Operand),
266 DivisionByZero(Operand),
267 RemainderByZero(Operand),
268 ResumedAfterReturn(CoroutineKind),
269 ResumedAfterPanic(CoroutineKind),
270 MisalignedPointerDereference { required: Operand, found: Operand },
271 NullPointerDereference,
272}
273
274impl AssertMessage {
275 pub fn description(&self) -> Result<&'static str, Error> {
276 match self {
277 AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
278 AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
279 AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
280 AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
281 AssertMessage::Overflow(BinOp::Rem, _, _) => {
282 Ok("attempt to calculate the remainder with overflow")
283 }
284 AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
285 AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
286 AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
287 AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
288 AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
289 AssertMessage::RemainderByZero(_) => {
290 Ok("attempt to calculate the remainder with a divisor of zero")
291 }
292 AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
293 Ok("coroutine resumed after completion")
294 }
295 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
296 CoroutineDesugaring::Async,
297 _,
298 )) => Ok("`async fn` resumed after completion"),
299 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
300 CoroutineDesugaring::Gen,
301 _,
302 )) => Ok("`async gen fn` resumed after completion"),
303 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
304 CoroutineDesugaring::AsyncGen,
305 _,
306 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
307 AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
308 Ok("coroutine resumed after panicking")
309 }
310 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
311 CoroutineDesugaring::Async,
312 _,
313 )) => Ok("`async fn` resumed after panicking"),
314 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
315 CoroutineDesugaring::Gen,
316 _,
317 )) => Ok("`async gen fn` resumed after panicking"),
318 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
319 CoroutineDesugaring::AsyncGen,
320 _,
321 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
322
323 AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
324 AssertMessage::MisalignedPointerDereference { .. } => {
325 Ok("misaligned pointer dereference")
326 }
327 AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
328 }
329 }
330}
331
332#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
333pub enum BinOp {
334 Add,
335 AddUnchecked,
336 Sub,
337 SubUnchecked,
338 Mul,
339 MulUnchecked,
340 Div,
341 Rem,
342 BitXor,
343 BitAnd,
344 BitOr,
345 Shl,
346 ShlUnchecked,
347 Shr,
348 ShrUnchecked,
349 Eq,
350 Lt,
351 Le,
352 Ne,
353 Ge,
354 Gt,
355 Cmp,
356 Offset,
357}
358
359impl BinOp {
360 pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
363 with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
364 }
365}
366
367#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
368pub enum UnOp {
369 Not,
370 Neg,
371 PtrMetadata,
372}
373
374impl UnOp {
375 pub fn ty(&self, arg_ty: Ty) -> Ty {
378 with(|ctx| ctx.unop_ty(*self, arg_ty))
379 }
380}
381
382#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
383pub enum CoroutineKind {
384 Desugared(CoroutineDesugaring, CoroutineSource),
385 Coroutine(Movability),
386}
387
388#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
389pub enum CoroutineSource {
390 Block,
391 Closure,
392 Fn,
393}
394
395#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
396pub enum CoroutineDesugaring {
397 Async,
398
399 Gen,
400
401 AsyncGen,
402}
403
404pub(crate) type LocalDefId = Opaque;
405pub(crate) type Coverage = Opaque;
409
410#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
412pub enum FakeReadCause {
413 ForMatchGuard,
414 ForMatchedPlace(LocalDefId),
415 ForGuardBinding,
416 ForLet(LocalDefId),
417 ForIndex,
418}
419
420#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
422pub enum RetagKind {
423 FnEntry,
424 TwoPhase,
425 Raw,
426 Default,
427}
428
429#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
430pub enum Variance {
431 Covariant,
432 Invariant,
433 Contravariant,
434 Bivariant,
435}
436
437#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
438pub struct CopyNonOverlapping {
439 pub src: Operand,
440 pub dst: Operand,
441 pub count: Operand,
442}
443
444#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
445pub enum NonDivergingIntrinsic {
446 Assume(Operand),
447 CopyNonOverlapping(CopyNonOverlapping),
448}
449
450#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
451pub struct Statement {
452 pub kind: StatementKind,
453 pub span: Span,
454}
455
456#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
457pub enum StatementKind {
458 Assign(Place, Rvalue),
459 FakeRead(FakeReadCause, Place),
460 SetDiscriminant { place: Place, variant_index: VariantIdx },
461 Deinit(Place),
462 StorageLive(Local),
463 StorageDead(Local),
464 Retag(RetagKind, Place),
465 PlaceMention(Place),
466 AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
467 Coverage(Coverage),
468 Intrinsic(NonDivergingIntrinsic),
469 ConstEvalCounter,
470 Nop,
471}
472
473#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
474pub enum Rvalue {
475 AddressOf(RawPtrKind, Place),
480
481 Aggregate(AggregateKind, Vec<Operand>),
490
491 BinaryOp(BinOp, Operand, Operand),
504
505 Cast(CastKind, Operand, Ty),
509
510 CheckedBinaryOp(BinOp, Operand, Operand),
515
516 CopyForDeref(Place),
520
521 Discriminant(Place),
530
531 Len(Place),
537
538 Ref(Region, BorrowKind, Place),
540
541 Repeat(Operand, TyConst),
550
551 ShallowInitBox(Operand, Ty),
557
558 ThreadLocalRef(stable_mir::CrateItem),
570
571 NullaryOp(NullOp, Ty),
573
574 UnaryOp(UnOp, Operand),
580
581 Use(Operand),
583}
584
585impl Rvalue {
586 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
587 match self {
588 Rvalue::Use(operand) => operand.ty(locals),
589 Rvalue::Repeat(operand, count) => {
590 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
591 }
592 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
593 Rvalue::Ref(reg, bk, place) => {
594 let place_ty = place.ty(locals)?;
595 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
596 }
597 Rvalue::AddressOf(mutability, place) => {
598 let place_ty = place.ty(locals)?;
599 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
600 }
601 Rvalue::Len(..) => Ok(Ty::usize_ty()),
602 Rvalue::Cast(.., ty) => Ok(*ty),
603 Rvalue::BinaryOp(op, lhs, rhs) => {
604 let lhs_ty = lhs.ty(locals)?;
605 let rhs_ty = rhs.ty(locals)?;
606 Ok(op.ty(lhs_ty, rhs_ty))
607 }
608 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
609 let lhs_ty = lhs.ty(locals)?;
610 let rhs_ty = rhs.ty(locals)?;
611 let ty = op.ty(lhs_ty, rhs_ty);
612 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
613 }
614 Rvalue::UnaryOp(op, operand) => {
615 let arg_ty = operand.ty(locals)?;
616 Ok(op.ty(arg_ty))
617 }
618 Rvalue::Discriminant(place) => {
619 let place_ty = place.ty(locals)?;
620 place_ty
621 .kind()
622 .discriminant_ty()
623 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
624 }
625 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
626 Ok(Ty::usize_ty())
627 }
628 Rvalue::NullaryOp(NullOp::ContractChecks, _)
629 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
630 Rvalue::Aggregate(ak, ops) => match *ak {
631 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
632 AggregateKind::Tuple => Ok(Ty::new_tuple(
633 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
634 )),
635 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
636 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
637 AggregateKind::Coroutine(def, ref args, mov) => {
638 Ok(Ty::new_coroutine(def, args.clone(), mov))
639 }
640 AggregateKind::CoroutineClosure(def, ref args) => {
641 Ok(Ty::new_coroutine_closure(def, args.clone()))
642 }
643 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
644 },
645 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
646 Rvalue::CopyForDeref(place) => place.ty(locals),
647 }
648 }
649}
650
651#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
652pub enum AggregateKind {
653 Array(Ty),
654 Tuple,
655 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
656 Closure(ClosureDef, GenericArgs),
657 Coroutine(CoroutineDef, GenericArgs, Movability),
659 CoroutineClosure(CoroutineClosureDef, GenericArgs),
660 RawPtr(Ty, Mutability),
661}
662
663#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
664pub enum Operand {
665 Copy(Place),
666 Move(Place),
667 Constant(ConstOperand),
668}
669
670#[derive(Clone, Eq, PartialEq, Serialize)]
671pub struct Place {
672 pub local: Local,
673 pub projection: Vec<ProjectionElem>,
675}
676
677impl From<Local> for Place {
678 fn from(local: Local) -> Self {
679 Place { local, projection: vec![] }
680 }
681}
682
683#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
684pub struct ConstOperand {
685 pub span: Span,
686 pub user_ty: Option<UserTypeAnnotationIndex>,
687 pub const_: MirConst,
688}
689
690#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
692pub struct VarDebugInfo {
693 pub name: Symbol,
695
696 pub source_info: SourceInfo,
699
700 pub composite: Option<VarDebugInfoFragment>,
703
704 pub value: VarDebugInfoContents,
706
707 pub argument_index: Option<u16>,
711}
712
713impl VarDebugInfo {
714 pub fn local(&self) -> Option<Local> {
716 match &self.value {
717 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
718 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
719 }
720 }
721
722 pub fn constant(&self) -> Option<&ConstOperand> {
724 match &self.value {
725 VarDebugInfoContents::Place(_) => None,
726 VarDebugInfoContents::Const(const_op) => Some(const_op),
727 }
728 }
729}
730
731pub type SourceScope = u32;
732
733#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
734pub struct SourceInfo {
735 pub span: Span,
736 pub scope: SourceScope,
737}
738
739#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
740pub struct VarDebugInfoFragment {
741 pub ty: Ty,
742 pub projection: Vec<ProjectionElem>,
743}
744
745#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
746pub enum VarDebugInfoContents {
747 Place(Place),
748 Const(ConstOperand),
749}
750
751#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
757pub enum ProjectionElem {
758 Deref,
760
761 Field(FieldIdx, Ty),
765
766 Index(Local),
781
782 ConstantIndex {
793 offset: u64,
795 min_length: u64,
800 from_end: bool,
803 },
804
805 Subslice {
810 from: u64,
811 to: u64,
812 from_end: bool,
814 },
815
816 Downcast(VariantIdx),
818
819 OpaqueCast(Ty),
822
823 Subtype(Ty),
830}
831
832#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
833pub struct UserTypeProjection {
834 pub base: UserTypeAnnotationIndex,
835
836 pub projection: Opaque,
837}
838
839pub type Local = usize;
840
841pub const RETURN_LOCAL: Local = 0;
842
843pub type FieldIdx = usize;
858
859type UserTypeAnnotationIndex = usize;
860
861#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
863pub struct SwitchTargets {
864 branches: Vec<(u128, BasicBlockIdx)>,
867 otherwise: BasicBlockIdx,
870}
871
872impl SwitchTargets {
873 pub fn all_targets(&self) -> Successors {
875 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
876 }
877
878 pub fn otherwise(&self) -> BasicBlockIdx {
880 self.otherwise
881 }
882
883 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
885 self.branches.iter().copied()
886 }
887
888 pub fn len(&self) -> usize {
890 self.branches.len() + 1
891 }
892
893 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
895 SwitchTargets { branches, otherwise }
896 }
897}
898
899#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
900pub enum BorrowKind {
901 Shared,
903
904 Fake(FakeBorrowKind),
907
908 Mut {
910 kind: MutBorrowKind,
912 },
913}
914
915impl BorrowKind {
916 pub fn to_mutable_lossy(self) -> Mutability {
917 match self {
918 BorrowKind::Mut { .. } => Mutability::Mut,
919 BorrowKind::Shared => Mutability::Not,
920 BorrowKind::Fake(_) => Mutability::Not,
922 }
923 }
924}
925
926#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
927pub enum RawPtrKind {
928 Mut,
929 Const,
930 FakeForPtrMetadata,
931}
932
933impl RawPtrKind {
934 pub fn to_mutable_lossy(self) -> Mutability {
935 match self {
936 RawPtrKind::Mut { .. } => Mutability::Mut,
937 RawPtrKind::Const => Mutability::Not,
938 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
940 }
941 }
942}
943
944#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
945pub enum MutBorrowKind {
946 Default,
947 TwoPhaseBorrow,
948 ClosureCapture,
949}
950
951#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
952pub enum FakeBorrowKind {
953 Deep,
955 Shallow,
960}
961
962#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
963pub enum Mutability {
964 Not,
965 Mut,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
969pub enum Safety {
970 Safe,
971 Unsafe,
972}
973
974#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
975pub enum PointerCoercion {
976 ReifyFnPointer,
978
979 UnsafeFnPointer,
981
982 ClosureFnPointer(Safety),
985
986 MutToConstPointer,
988
989 ArrayToPointer,
991
992 Unsize,
999}
1000
1001#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1002pub enum CastKind {
1003 PointerExposeAddress,
1005 PointerWithExposedProvenance,
1006 PointerCoercion(PointerCoercion),
1007 DynStar,
1009 IntToInt,
1010 FloatToInt,
1011 FloatToFloat,
1012 IntToFloat,
1013 PtrToPtr,
1014 FnPtrToPtr,
1015 Transmute,
1016}
1017
1018#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1019pub enum NullOp {
1020 SizeOf,
1022 AlignOf,
1024 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1026 UbChecks,
1028 ContractChecks,
1030}
1031
1032impl Operand {
1033 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1040 match self {
1041 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1042 Operand::Constant(c) => Ok(c.ty()),
1043 }
1044 }
1045}
1046
1047impl ConstOperand {
1048 pub fn ty(&self) -> Ty {
1049 self.const_.ty()
1050 }
1051}
1052
1053impl Place {
1054 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1061 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1062 }
1063}
1064
1065impl ProjectionElem {
1066 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1068 let ty = place_ty;
1069 match &self {
1070 ProjectionElem::Deref => Self::deref_ty(ty),
1071 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1072 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1073 ProjectionElem::Subslice { from, to, from_end } => {
1074 Self::subslice_ty(ty, *from, *to, *from_end)
1075 }
1076 ProjectionElem::Downcast(_) => Ok(ty),
1077 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1078 }
1079 }
1080
1081 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1082 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1083 }
1084
1085 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1086 let ty_kind = ty.kind();
1087 match ty_kind {
1088 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1089 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1090 inner,
1091 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1092 ),
1093 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1094 let size = size.eval_target_usize()?;
1095 let len = size - from - to;
1096 Ty::try_new_array(inner, len)
1097 }
1098 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1099 }
1100 }
1101
1102 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1103 let deref_ty = ty
1104 .kind()
1105 .builtin_deref(true)
1106 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1107 Ok(deref_ty.ty)
1108 }
1109}