1use std::io;
2
3use serde::Serialize;
4
5use crate::compiler_interface::with;
6use crate::mir::pretty::function_body;
7use crate::ty::{
8    AdtDef, ClosureDef, CoroutineClosureDef, CoroutineDef, GenericArgs, MirConst, Movability,
9    Region, RigidTy, Ty, TyConst, TyKind, VariantIdx,
10};
11use crate::{Error, Opaque, Span, Symbol};
12
13#[derive(Clone, Debug, Serialize)]
15pub struct Body {
16    pub blocks: Vec<BasicBlock>,
17
18    pub(super) locals: LocalDecls,
24
25    pub(super) arg_count: usize,
27
28    pub var_debug_info: Vec<VarDebugInfo>,
30
31    pub(super) spread_arg: Option<Local>,
35
36    pub span: Span,
38}
39
40pub type BasicBlockIdx = usize;
41
42impl Body {
43    pub fn new(
48        blocks: Vec<BasicBlock>,
49        locals: LocalDecls,
50        arg_count: usize,
51        var_debug_info: Vec<VarDebugInfo>,
52        spread_arg: Option<Local>,
53        span: Span,
54    ) -> Self {
55        assert!(
58            locals.len() > arg_count,
59            "A Body must contain at least a local for the return value and each of the function's arguments"
60        );
61        Self { blocks, locals, arg_count, var_debug_info, spread_arg, span }
62    }
63
64    pub fn ret_local(&self) -> &LocalDecl {
66        &self.locals[RETURN_LOCAL]
67    }
68
69    pub fn arg_locals(&self) -> &[LocalDecl] {
71        &self.locals[1..][..self.arg_count]
72    }
73
74    pub fn inner_locals(&self) -> &[LocalDecl] {
77        &self.locals[self.arg_count + 1..]
78    }
79
80    pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl {
82        &mut self.locals[RETURN_LOCAL]
83    }
84
85    pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] {
87        &mut self.locals[1..][..self.arg_count]
88    }
89
90    pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] {
93        &mut self.locals[self.arg_count + 1..]
94    }
95
96    pub fn locals(&self) -> &[LocalDecl] {
101        &self.locals
102    }
103
104    pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
106        self.locals.get(local)
107    }
108
109    pub fn local_decls(&self) -> impl Iterator<Item = (Local, &LocalDecl)> {
111        self.locals.iter().enumerate()
112    }
113
114    pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
116        function_body(w, self, fn_name)
117    }
118
119    pub fn spread_arg(&self) -> Option<Local> {
120        self.spread_arg
121    }
122}
123
124type LocalDecls = Vec<LocalDecl>;
125
126#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
127pub struct LocalDecl {
128    pub ty: Ty,
129    pub span: Span,
130    pub mutability: Mutability,
131}
132
133#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
134pub struct BasicBlock {
135    pub statements: Vec<Statement>,
136    pub terminator: Terminator,
137}
138
139#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
140pub struct Terminator {
141    pub kind: TerminatorKind,
142    pub span: Span,
143}
144
145impl Terminator {
146    pub fn successors(&self) -> Successors {
147        self.kind.successors()
148    }
149}
150
151pub type Successors = Vec<BasicBlockIdx>;
152
153#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
154pub enum TerminatorKind {
155    Goto {
156        target: BasicBlockIdx,
157    },
158    SwitchInt {
159        discr: Operand,
160        targets: SwitchTargets,
161    },
162    Resume,
163    Abort,
164    Return,
165    Unreachable,
166    Drop {
167        place: Place,
168        target: BasicBlockIdx,
169        unwind: UnwindAction,
170    },
171    Call {
172        func: Operand,
173        args: Vec<Operand>,
174        destination: Place,
175        target: Option<BasicBlockIdx>,
176        unwind: UnwindAction,
177    },
178    Assert {
179        cond: Operand,
180        expected: bool,
181        msg: AssertMessage,
182        target: BasicBlockIdx,
183        unwind: UnwindAction,
184    },
185    InlineAsm {
186        template: String,
187        operands: Vec<InlineAsmOperand>,
188        options: String,
189        line_spans: String,
190        destination: Option<BasicBlockIdx>,
191        unwind: UnwindAction,
192    },
193}
194
195impl TerminatorKind {
196    pub fn successors(&self) -> Successors {
197        use self::TerminatorKind::*;
198        match *self {
199            Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
200            | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
201            | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
202            | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
203                vec![t, u]
204            }
205            Goto { target: t }
206            | Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
207            | Call { target: Some(t), unwind: _, .. }
208            | Drop { target: t, unwind: _, .. }
209            | Assert { target: t, unwind: _, .. }
210            | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
211            | InlineAsm { destination: Some(t), unwind: _, .. } => {
212                vec![t]
213            }
214
215            Return
216            | Resume
217            | Abort
218            | Unreachable
219            | Call { target: None, unwind: _, .. }
220            | InlineAsm { destination: None, unwind: _, .. } => {
221                vec![]
222            }
223            SwitchInt { ref targets, .. } => targets.all_targets(),
224        }
225    }
226
227    pub fn unwind(&self) -> Option<&UnwindAction> {
228        match *self {
229            TerminatorKind::Goto { .. }
230            | TerminatorKind::Return
231            | TerminatorKind::Unreachable
232            | TerminatorKind::Resume
233            | TerminatorKind::Abort
234            | TerminatorKind::SwitchInt { .. } => None,
235            TerminatorKind::Call { ref unwind, .. }
236            | TerminatorKind::Assert { ref unwind, .. }
237            | TerminatorKind::Drop { ref unwind, .. }
238            | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
239        }
240    }
241}
242
243#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
244pub struct InlineAsmOperand {
245    pub in_value: Option<Operand>,
246    pub out_place: Option<Place>,
247    pub raw_rpr: String,
250}
251
252#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
253pub enum UnwindAction {
254    Continue,
255    Unreachable,
256    Terminate,
257    Cleanup(BasicBlockIdx),
258}
259
260#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
261pub enum AssertMessage {
262    BoundsCheck { len: Operand, index: Operand },
263    Overflow(BinOp, Operand, Operand),
264    OverflowNeg(Operand),
265    DivisionByZero(Operand),
266    RemainderByZero(Operand),
267    ResumedAfterReturn(CoroutineKind),
268    ResumedAfterPanic(CoroutineKind),
269    ResumedAfterDrop(CoroutineKind),
270    MisalignedPointerDereference { required: Operand, found: Operand },
271    NullPointerDereference,
272    InvalidEnumConstruction(Operand),
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            AssertMessage::InvalidEnumConstruction(_) => {
346                Ok("trying to construct an enum from an invalid value")
347            }
348        }
349    }
350}
351
352#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
353pub enum BinOp {
354    Add,
355    AddUnchecked,
356    Sub,
357    SubUnchecked,
358    Mul,
359    MulUnchecked,
360    Div,
361    Rem,
362    BitXor,
363    BitAnd,
364    BitOr,
365    Shl,
366    ShlUnchecked,
367    Shr,
368    ShrUnchecked,
369    Eq,
370    Lt,
371    Le,
372    Ne,
373    Ge,
374    Gt,
375    Cmp,
376    Offset,
377}
378
379impl BinOp {
380    pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
383        with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
384    }
385}
386
387#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
388pub enum UnOp {
389    Not,
390    Neg,
391    PtrMetadata,
392}
393
394impl UnOp {
395    pub fn ty(&self, arg_ty: Ty) -> Ty {
398        with(|ctx| ctx.unop_ty(*self, arg_ty))
399    }
400}
401
402#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
403pub enum CoroutineKind {
404    Desugared(CoroutineDesugaring, CoroutineSource),
405    Coroutine(Movability),
406}
407
408#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
409pub enum CoroutineSource {
410    Block,
411    Closure,
412    Fn,
413}
414
415#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
416pub enum CoroutineDesugaring {
417    Async,
418
419    Gen,
420
421    AsyncGen,
422}
423
424pub(crate) type LocalDefId = Opaque;
425pub(crate) type Coverage = Opaque;
429
430#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
432pub enum FakeReadCause {
433    ForMatchGuard,
434    ForMatchedPlace(LocalDefId),
435    ForGuardBinding,
436    ForLet(LocalDefId),
437    ForIndex,
438}
439
440#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
442pub enum RetagKind {
443    FnEntry,
444    TwoPhase,
445    Raw,
446    Default,
447}
448
449#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
450pub enum Variance {
451    Covariant,
452    Invariant,
453    Contravariant,
454    Bivariant,
455}
456
457#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
458pub struct CopyNonOverlapping {
459    pub src: Operand,
460    pub dst: Operand,
461    pub count: Operand,
462}
463
464#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
465pub enum NonDivergingIntrinsic {
466    Assume(Operand),
467    CopyNonOverlapping(CopyNonOverlapping),
468}
469
470#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
471pub struct Statement {
472    pub kind: StatementKind,
473    pub span: Span,
474}
475
476#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
477pub enum StatementKind {
478    Assign(Place, Rvalue),
479    FakeRead(FakeReadCause, Place),
480    SetDiscriminant { place: Place, variant_index: VariantIdx },
481    StorageLive(Local),
482    StorageDead(Local),
483    Retag(RetagKind, Place),
484    PlaceMention(Place),
485    AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
486    Coverage(Coverage),
487    Intrinsic(NonDivergingIntrinsic),
488    ConstEvalCounter,
489    Nop,
490}
491
492#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
493pub enum Rvalue {
494    AddressOf(RawPtrKind, Place),
499
500    Aggregate(AggregateKind, Vec<Operand>),
509
510    BinaryOp(BinOp, Operand, Operand),
523
524    Cast(CastKind, Operand, Ty),
528
529    CheckedBinaryOp(BinOp, Operand, Operand),
534
535    CopyForDeref(Place),
539
540    Discriminant(Place),
549
550    Len(Place),
556
557    Ref(Region, BorrowKind, Place),
559
560    Repeat(Operand, TyConst),
569
570    ShallowInitBox(Operand, Ty),
576
577    ThreadLocalRef(crate::CrateItem),
589
590    NullaryOp(NullOp, Ty),
592
593    UnaryOp(UnOp, Operand),
599
600    Use(Operand),
602}
603
604impl Rvalue {
605    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
606        match self {
607            Rvalue::Use(operand) => operand.ty(locals),
608            Rvalue::Repeat(operand, count) => {
609                Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
610            }
611            Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
612            Rvalue::Ref(reg, bk, place) => {
613                let place_ty = place.ty(locals)?;
614                Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
615            }
616            Rvalue::AddressOf(mutability, place) => {
617                let place_ty = place.ty(locals)?;
618                Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
619            }
620            Rvalue::Len(..) => Ok(Ty::usize_ty()),
621            Rvalue::Cast(.., ty) => Ok(*ty),
622            Rvalue::BinaryOp(op, lhs, rhs) => {
623                let lhs_ty = lhs.ty(locals)?;
624                let rhs_ty = rhs.ty(locals)?;
625                Ok(op.ty(lhs_ty, rhs_ty))
626            }
627            Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
628                let lhs_ty = lhs.ty(locals)?;
629                let rhs_ty = rhs.ty(locals)?;
630                let ty = op.ty(lhs_ty, rhs_ty);
631                Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
632            }
633            Rvalue::UnaryOp(op, operand) => {
634                let arg_ty = operand.ty(locals)?;
635                Ok(op.ty(arg_ty))
636            }
637            Rvalue::Discriminant(place) => {
638                let place_ty = place.ty(locals)?;
639                place_ty
640                    .kind()
641                    .discriminant_ty()
642                    .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
643            }
644            Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()),
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) => Ok(Ty::new_coroutine(def, args.clone())),
655                AggregateKind::CoroutineClosure(def, ref args) => {
656                    Ok(Ty::new_coroutine_closure(def, args.clone()))
657                }
658                AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
659            },
660            Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
661            Rvalue::CopyForDeref(place) => place.ty(locals),
662        }
663    }
664}
665
666#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
667pub enum AggregateKind {
668    Array(Ty),
669    Tuple,
670    Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
671    Closure(ClosureDef, GenericArgs),
672    Coroutine(CoroutineDef, GenericArgs),
673    CoroutineClosure(CoroutineClosureDef, GenericArgs),
674    RawPtr(Ty, Mutability),
675}
676
677#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
678pub enum Operand {
679    Copy(Place),
680    Move(Place),
681    Constant(ConstOperand),
682}
683
684#[derive(Clone, Eq, PartialEq, Hash, Serialize)]
685pub struct Place {
686    pub local: Local,
687    pub projection: Vec<ProjectionElem>,
689}
690
691impl From<Local> for Place {
692    fn from(local: Local) -> Self {
693        Place { local, projection: vec![] }
694    }
695}
696
697#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
698pub struct ConstOperand {
699    pub span: Span,
700    pub user_ty: Option<UserTypeAnnotationIndex>,
701    pub const_: MirConst,
702}
703
704#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
706pub struct VarDebugInfo {
707    pub name: Symbol,
709
710    pub source_info: SourceInfo,
713
714    pub composite: Option<VarDebugInfoFragment>,
717
718    pub value: VarDebugInfoContents,
720
721    pub argument_index: Option<u16>,
725}
726
727impl VarDebugInfo {
728    pub fn local(&self) -> Option<Local> {
730        match &self.value {
731            VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
732            VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
733        }
734    }
735
736    pub fn constant(&self) -> Option<&ConstOperand> {
738        match &self.value {
739            VarDebugInfoContents::Place(_) => None,
740            VarDebugInfoContents::Const(const_op) => Some(const_op),
741        }
742    }
743}
744
745pub type SourceScope = u32;
746
747#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
748pub struct SourceInfo {
749    pub span: Span,
750    pub scope: SourceScope,
751}
752
753#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
754pub struct VarDebugInfoFragment {
755    pub ty: Ty,
756    pub projection: Vec<ProjectionElem>,
757}
758
759#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
760pub enum VarDebugInfoContents {
761    Place(Place),
762    Const(ConstOperand),
763}
764
765#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
771pub enum ProjectionElem {
772    Deref,
774
775    Field(FieldIdx, Ty),
779
780    Index(Local),
795
796    ConstantIndex {
807        offset: u64,
809        min_length: u64,
814        from_end: bool,
817    },
818
819    Subslice {
824        from: u64,
825        to: u64,
826        from_end: bool,
828    },
829
830    Downcast(VariantIdx),
832
833    OpaqueCast(Ty),
836}
837
838#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
839pub struct UserTypeProjection {
840    pub base: UserTypeAnnotationIndex,
841
842    pub projection: Opaque,
843}
844
845pub type Local = usize;
846
847pub const RETURN_LOCAL: Local = 0;
848
849pub type FieldIdx = usize;
864
865type UserTypeAnnotationIndex = usize;
866
867#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
869pub struct SwitchTargets {
870    branches: Vec<(u128, BasicBlockIdx)>,
873    otherwise: BasicBlockIdx,
876}
877
878impl SwitchTargets {
879    pub fn all_targets(&self) -> Successors {
881        self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
882    }
883
884    pub fn otherwise(&self) -> BasicBlockIdx {
886        self.otherwise
887    }
888
889    pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
891        self.branches.iter().copied()
892    }
893
894    pub fn len(&self) -> usize {
896        self.branches.len() + 1
897    }
898
899    pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
901        SwitchTargets { branches, otherwise }
902    }
903}
904
905#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
906pub enum BorrowKind {
907    Shared,
909
910    Fake(FakeBorrowKind),
913
914    Mut {
916        kind: MutBorrowKind,
918    },
919}
920
921impl BorrowKind {
922    pub fn to_mutable_lossy(self) -> Mutability {
923        match self {
924            BorrowKind::Mut { .. } => Mutability::Mut,
925            BorrowKind::Shared => Mutability::Not,
926            BorrowKind::Fake(_) => Mutability::Not,
928        }
929    }
930}
931
932#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
933pub enum RawPtrKind {
934    Mut,
935    Const,
936    FakeForPtrMetadata,
937}
938
939impl RawPtrKind {
940    pub fn to_mutable_lossy(self) -> Mutability {
941        match self {
942            RawPtrKind::Mut { .. } => Mutability::Mut,
943            RawPtrKind::Const => Mutability::Not,
944            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
946        }
947    }
948}
949
950#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
951pub enum MutBorrowKind {
952    Default,
953    TwoPhaseBorrow,
954    ClosureCapture,
955}
956
957#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
958pub enum FakeBorrowKind {
959    Deep,
961    Shallow,
966}
967
968#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
969pub enum Mutability {
970    Not,
971    Mut,
972}
973
974#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
975pub enum Safety {
976    Safe,
977    Unsafe,
978}
979
980#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
981pub enum PointerCoercion {
982    ReifyFnPointer,
984
985    UnsafeFnPointer,
987
988    ClosureFnPointer(Safety),
991
992    MutToConstPointer,
994
995    ArrayToPointer,
997
998    Unsize,
1005}
1006
1007#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1008pub enum CastKind {
1009    PointerExposeAddress,
1011    PointerWithExposedProvenance,
1012    PointerCoercion(PointerCoercion),
1013    IntToInt,
1014    FloatToInt,
1015    FloatToFloat,
1016    IntToFloat,
1017    PtrToPtr,
1018    FnPtrToPtr,
1019    Transmute,
1020    Subtype,
1021}
1022
1023#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1024pub enum NullOp {
1025    OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1027    UbChecks,
1029    ContractChecks,
1031}
1032
1033impl Operand {
1034    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1041        match self {
1042            Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1043            Operand::Constant(c) => Ok(c.ty()),
1044        }
1045    }
1046}
1047
1048impl ConstOperand {
1049    pub fn ty(&self) -> Ty {
1050        self.const_.ty()
1051    }
1052}
1053
1054impl Place {
1055    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1062        self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1063    }
1064}
1065
1066impl ProjectionElem {
1067    pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1069        let ty = place_ty;
1070        match &self {
1071            ProjectionElem::Deref => Self::deref_ty(ty),
1072            ProjectionElem::Field(_idx, fty) => Ok(*fty),
1073            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1074            ProjectionElem::Subslice { from, to, from_end } => {
1075                Self::subslice_ty(ty, *from, *to, *from_end)
1076            }
1077            ProjectionElem::Downcast(_) => Ok(ty),
1078            ProjectionElem::OpaqueCast(ty) => Ok(*ty),
1079        }
1080    }
1081
1082    fn index_ty(ty: Ty) -> Result<Ty, Error> {
1083        ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1084    }
1085
1086    fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1087        let ty_kind = ty.kind();
1088        match ty_kind {
1089            TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1090            TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1091                inner,
1092                to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1093            ),
1094            TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1095                let size = size.eval_target_usize()?;
1096                let len = size - from - to;
1097                Ty::try_new_array(inner, len)
1098            }
1099            _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1100        }
1101    }
1102
1103    fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1104        let deref_ty = ty
1105            .kind()
1106            .builtin_deref(true)
1107            .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1108        Ok(deref_ty.ty)
1109    }
1110}