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 ResumedAfterDrop(CoroutineKind),
271 MisalignedPointerDereference { required: Operand, found: Operand },
272 NullPointerDereference,
273}
274
275impl AssertMessage {
276 pub fn description(&self) -> Result<&'static str, Error> {
277 match self {
278 AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
279 AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
280 AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
281 AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
282 AssertMessage::Overflow(BinOp::Rem, _, _) => {
283 Ok("attempt to calculate the remainder with overflow")
284 }
285 AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
286 AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
287 AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
288 AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
289 AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
290 AssertMessage::RemainderByZero(_) => {
291 Ok("attempt to calculate the remainder with a divisor of zero")
292 }
293 AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
294 Ok("coroutine resumed after completion")
295 }
296 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
297 CoroutineDesugaring::Async,
298 _,
299 )) => Ok("`async fn` resumed after completion"),
300 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
301 CoroutineDesugaring::Gen,
302 _,
303 )) => Ok("`async gen fn` resumed after completion"),
304 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
305 CoroutineDesugaring::AsyncGen,
306 _,
307 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
308 AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
309 Ok("coroutine resumed after panicking")
310 }
311 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
312 CoroutineDesugaring::Async,
313 _,
314 )) => Ok("`async fn` resumed after panicking"),
315 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
316 CoroutineDesugaring::Gen,
317 _,
318 )) => Ok("`async gen fn` resumed after panicking"),
319 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
320 CoroutineDesugaring::AsyncGen,
321 _,
322 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
323
324 AssertMessage::ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
325 Ok("coroutine resumed after async drop")
326 }
327 AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
328 CoroutineDesugaring::Async,
329 _,
330 )) => Ok("`async fn` resumed after async drop"),
331 AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
332 CoroutineDesugaring::Gen,
333 _,
334 )) => Ok("`async gen fn` resumed after async drop"),
335 AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
336 CoroutineDesugaring::AsyncGen,
337 _,
338 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after async drop"),
339
340 AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
341 AssertMessage::MisalignedPointerDereference { .. } => {
342 Ok("misaligned pointer dereference")
343 }
344 AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
345 }
346 }
347}
348
349#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
350pub enum BinOp {
351 Add,
352 AddUnchecked,
353 Sub,
354 SubUnchecked,
355 Mul,
356 MulUnchecked,
357 Div,
358 Rem,
359 BitXor,
360 BitAnd,
361 BitOr,
362 Shl,
363 ShlUnchecked,
364 Shr,
365 ShrUnchecked,
366 Eq,
367 Lt,
368 Le,
369 Ne,
370 Ge,
371 Gt,
372 Cmp,
373 Offset,
374}
375
376impl BinOp {
377 pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
380 with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
381 }
382}
383
384#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
385pub enum UnOp {
386 Not,
387 Neg,
388 PtrMetadata,
389}
390
391impl UnOp {
392 pub fn ty(&self, arg_ty: Ty) -> Ty {
395 with(|ctx| ctx.unop_ty(*self, arg_ty))
396 }
397}
398
399#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
400pub enum CoroutineKind {
401 Desugared(CoroutineDesugaring, CoroutineSource),
402 Coroutine(Movability),
403}
404
405#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
406pub enum CoroutineSource {
407 Block,
408 Closure,
409 Fn,
410}
411
412#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
413pub enum CoroutineDesugaring {
414 Async,
415
416 Gen,
417
418 AsyncGen,
419}
420
421pub(crate) type LocalDefId = Opaque;
422pub(crate) type Coverage = Opaque;
426
427#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
429pub enum FakeReadCause {
430 ForMatchGuard,
431 ForMatchedPlace(LocalDefId),
432 ForGuardBinding,
433 ForLet(LocalDefId),
434 ForIndex,
435}
436
437#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
439pub enum RetagKind {
440 FnEntry,
441 TwoPhase,
442 Raw,
443 Default,
444}
445
446#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
447pub enum Variance {
448 Covariant,
449 Invariant,
450 Contravariant,
451 Bivariant,
452}
453
454#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
455pub struct CopyNonOverlapping {
456 pub src: Operand,
457 pub dst: Operand,
458 pub count: Operand,
459}
460
461#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
462pub enum NonDivergingIntrinsic {
463 Assume(Operand),
464 CopyNonOverlapping(CopyNonOverlapping),
465}
466
467#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
468pub struct Statement {
469 pub kind: StatementKind,
470 pub span: Span,
471}
472
473#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
474pub enum StatementKind {
475 Assign(Place, Rvalue),
476 FakeRead(FakeReadCause, Place),
477 SetDiscriminant { place: Place, variant_index: VariantIdx },
478 Deinit(Place),
479 StorageLive(Local),
480 StorageDead(Local),
481 Retag(RetagKind, Place),
482 PlaceMention(Place),
483 AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
484 Coverage(Coverage),
485 Intrinsic(NonDivergingIntrinsic),
486 ConstEvalCounter,
487 Nop,
488}
489
490#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
491pub enum Rvalue {
492 AddressOf(RawPtrKind, Place),
497
498 Aggregate(AggregateKind, Vec<Operand>),
507
508 BinaryOp(BinOp, Operand, Operand),
521
522 Cast(CastKind, Operand, Ty),
526
527 CheckedBinaryOp(BinOp, Operand, Operand),
532
533 CopyForDeref(Place),
537
538 Discriminant(Place),
547
548 Len(Place),
554
555 Ref(Region, BorrowKind, Place),
557
558 Repeat(Operand, TyConst),
567
568 ShallowInitBox(Operand, Ty),
574
575 ThreadLocalRef(stable_mir::CrateItem),
587
588 NullaryOp(NullOp, Ty),
590
591 UnaryOp(UnOp, Operand),
597
598 Use(Operand),
600}
601
602impl Rvalue {
603 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
604 match self {
605 Rvalue::Use(operand) => operand.ty(locals),
606 Rvalue::Repeat(operand, count) => {
607 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
608 }
609 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
610 Rvalue::Ref(reg, bk, place) => {
611 let place_ty = place.ty(locals)?;
612 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
613 }
614 Rvalue::AddressOf(mutability, place) => {
615 let place_ty = place.ty(locals)?;
616 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
617 }
618 Rvalue::Len(..) => Ok(Ty::usize_ty()),
619 Rvalue::Cast(.., ty) => Ok(*ty),
620 Rvalue::BinaryOp(op, lhs, rhs) => {
621 let lhs_ty = lhs.ty(locals)?;
622 let rhs_ty = rhs.ty(locals)?;
623 Ok(op.ty(lhs_ty, rhs_ty))
624 }
625 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
626 let lhs_ty = lhs.ty(locals)?;
627 let rhs_ty = rhs.ty(locals)?;
628 let ty = op.ty(lhs_ty, rhs_ty);
629 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
630 }
631 Rvalue::UnaryOp(op, operand) => {
632 let arg_ty = operand.ty(locals)?;
633 Ok(op.ty(arg_ty))
634 }
635 Rvalue::Discriminant(place) => {
636 let place_ty = place.ty(locals)?;
637 place_ty
638 .kind()
639 .discriminant_ty()
640 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
641 }
642 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
643 Ok(Ty::usize_ty())
644 }
645 Rvalue::NullaryOp(NullOp::ContractChecks, _)
646 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
647 Rvalue::Aggregate(ak, ops) => match *ak {
648 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
649 AggregateKind::Tuple => Ok(Ty::new_tuple(
650 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
651 )),
652 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
653 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
654 AggregateKind::Coroutine(def, ref args, mov) => {
655 Ok(Ty::new_coroutine(def, args.clone(), mov))
656 }
657 AggregateKind::CoroutineClosure(def, ref args) => {
658 Ok(Ty::new_coroutine_closure(def, args.clone()))
659 }
660 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
661 },
662 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
663 Rvalue::CopyForDeref(place) => place.ty(locals),
664 }
665 }
666}
667
668#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
669pub enum AggregateKind {
670 Array(Ty),
671 Tuple,
672 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
673 Closure(ClosureDef, GenericArgs),
674 Coroutine(CoroutineDef, GenericArgs, Movability),
676 CoroutineClosure(CoroutineClosureDef, GenericArgs),
677 RawPtr(Ty, Mutability),
678}
679
680#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
681pub enum Operand {
682 Copy(Place),
683 Move(Place),
684 Constant(ConstOperand),
685}
686
687#[derive(Clone, Eq, PartialEq, Serialize)]
688pub struct Place {
689 pub local: Local,
690 pub projection: Vec<ProjectionElem>,
692}
693
694impl From<Local> for Place {
695 fn from(local: Local) -> Self {
696 Place { local, projection: vec![] }
697 }
698}
699
700#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
701pub struct ConstOperand {
702 pub span: Span,
703 pub user_ty: Option<UserTypeAnnotationIndex>,
704 pub const_: MirConst,
705}
706
707#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
709pub struct VarDebugInfo {
710 pub name: Symbol,
712
713 pub source_info: SourceInfo,
716
717 pub composite: Option<VarDebugInfoFragment>,
720
721 pub value: VarDebugInfoContents,
723
724 pub argument_index: Option<u16>,
728}
729
730impl VarDebugInfo {
731 pub fn local(&self) -> Option<Local> {
733 match &self.value {
734 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
735 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
736 }
737 }
738
739 pub fn constant(&self) -> Option<&ConstOperand> {
741 match &self.value {
742 VarDebugInfoContents::Place(_) => None,
743 VarDebugInfoContents::Const(const_op) => Some(const_op),
744 }
745 }
746}
747
748pub type SourceScope = u32;
749
750#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
751pub struct SourceInfo {
752 pub span: Span,
753 pub scope: SourceScope,
754}
755
756#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
757pub struct VarDebugInfoFragment {
758 pub ty: Ty,
759 pub projection: Vec<ProjectionElem>,
760}
761
762#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
763pub enum VarDebugInfoContents {
764 Place(Place),
765 Const(ConstOperand),
766}
767
768#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
774pub enum ProjectionElem {
775 Deref,
777
778 Field(FieldIdx, Ty),
782
783 Index(Local),
798
799 ConstantIndex {
810 offset: u64,
812 min_length: u64,
817 from_end: bool,
820 },
821
822 Subslice {
827 from: u64,
828 to: u64,
829 from_end: bool,
831 },
832
833 Downcast(VariantIdx),
835
836 OpaqueCast(Ty),
839
840 Subtype(Ty),
847}
848
849#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
850pub struct UserTypeProjection {
851 pub base: UserTypeAnnotationIndex,
852
853 pub projection: Opaque,
854}
855
856pub type Local = usize;
857
858pub const RETURN_LOCAL: Local = 0;
859
860pub type FieldIdx = usize;
875
876type UserTypeAnnotationIndex = usize;
877
878#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
880pub struct SwitchTargets {
881 branches: Vec<(u128, BasicBlockIdx)>,
884 otherwise: BasicBlockIdx,
887}
888
889impl SwitchTargets {
890 pub fn all_targets(&self) -> Successors {
892 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
893 }
894
895 pub fn otherwise(&self) -> BasicBlockIdx {
897 self.otherwise
898 }
899
900 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
902 self.branches.iter().copied()
903 }
904
905 pub fn len(&self) -> usize {
907 self.branches.len() + 1
908 }
909
910 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
912 SwitchTargets { branches, otherwise }
913 }
914}
915
916#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
917pub enum BorrowKind {
918 Shared,
920
921 Fake(FakeBorrowKind),
924
925 Mut {
927 kind: MutBorrowKind,
929 },
930}
931
932impl BorrowKind {
933 pub fn to_mutable_lossy(self) -> Mutability {
934 match self {
935 BorrowKind::Mut { .. } => Mutability::Mut,
936 BorrowKind::Shared => Mutability::Not,
937 BorrowKind::Fake(_) => Mutability::Not,
939 }
940 }
941}
942
943#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
944pub enum RawPtrKind {
945 Mut,
946 Const,
947 FakeForPtrMetadata,
948}
949
950impl RawPtrKind {
951 pub fn to_mutable_lossy(self) -> Mutability {
952 match self {
953 RawPtrKind::Mut { .. } => Mutability::Mut,
954 RawPtrKind::Const => Mutability::Not,
955 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
957 }
958 }
959}
960
961#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
962pub enum MutBorrowKind {
963 Default,
964 TwoPhaseBorrow,
965 ClosureCapture,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
969pub enum FakeBorrowKind {
970 Deep,
972 Shallow,
977}
978
979#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
980pub enum Mutability {
981 Not,
982 Mut,
983}
984
985#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
986pub enum Safety {
987 Safe,
988 Unsafe,
989}
990
991#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
992pub enum PointerCoercion {
993 ReifyFnPointer,
995
996 UnsafeFnPointer,
998
999 ClosureFnPointer(Safety),
1002
1003 MutToConstPointer,
1005
1006 ArrayToPointer,
1008
1009 Unsize,
1016}
1017
1018#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1019pub enum CastKind {
1020 PointerExposeAddress,
1022 PointerWithExposedProvenance,
1023 PointerCoercion(PointerCoercion),
1024 DynStar,
1026 IntToInt,
1027 FloatToInt,
1028 FloatToFloat,
1029 IntToFloat,
1030 PtrToPtr,
1031 FnPtrToPtr,
1032 Transmute,
1033}
1034
1035#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1036pub enum NullOp {
1037 SizeOf,
1039 AlignOf,
1041 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1043 UbChecks,
1045 ContractChecks,
1047}
1048
1049impl Operand {
1050 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1057 match self {
1058 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1059 Operand::Constant(c) => Ok(c.ty()),
1060 }
1061 }
1062}
1063
1064impl ConstOperand {
1065 pub fn ty(&self) -> Ty {
1066 self.const_.ty()
1067 }
1068}
1069
1070impl Place {
1071 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1078 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1079 }
1080}
1081
1082impl ProjectionElem {
1083 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1085 let ty = place_ty;
1086 match &self {
1087 ProjectionElem::Deref => Self::deref_ty(ty),
1088 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1089 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1090 ProjectionElem::Subslice { from, to, from_end } => {
1091 Self::subslice_ty(ty, *from, *to, *from_end)
1092 }
1093 ProjectionElem::Downcast(_) => Ok(ty),
1094 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1095 }
1096 }
1097
1098 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1099 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1100 }
1101
1102 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1103 let ty_kind = ty.kind();
1104 match ty_kind {
1105 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1106 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1107 inner,
1108 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1109 ),
1110 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1111 let size = size.eval_target_usize()?;
1112 let len = size - from - to;
1113 Ty::try_new_array(inner, len)
1114 }
1115 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1116 }
1117 }
1118
1119 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1120 let deref_ty = ty
1121 .kind()
1122 .builtin_deref(true)
1123 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1124 Ok(deref_ty.ty)
1125 }
1126}