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 fn locals(&self) -> &[LocalDecl] {
85 &self.locals
86 }
87
88 pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
90 self.locals.get(local)
91 }
92
93 pub fn local_decls(&self) -> impl Iterator<Item = (Local, &LocalDecl)> {
95 self.locals.iter().enumerate()
96 }
97
98 pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
100 function_body(w, self, fn_name)
101 }
102
103 pub fn spread_arg(&self) -> Option<Local> {
104 self.spread_arg
105 }
106}
107
108type LocalDecls = Vec<LocalDecl>;
109
110#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
111pub struct LocalDecl {
112 pub ty: Ty,
113 pub span: Span,
114 pub mutability: Mutability,
115}
116
117#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
118pub struct BasicBlock {
119 pub statements: Vec<Statement>,
120 pub terminator: Terminator,
121}
122
123#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
124pub struct Terminator {
125 pub kind: TerminatorKind,
126 pub span: Span,
127}
128
129impl Terminator {
130 pub fn successors(&self) -> Successors {
131 self.kind.successors()
132 }
133}
134
135pub type Successors = Vec<BasicBlockIdx>;
136
137#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
138pub enum TerminatorKind {
139 Goto {
140 target: BasicBlockIdx,
141 },
142 SwitchInt {
143 discr: Operand,
144 targets: SwitchTargets,
145 },
146 Resume,
147 Abort,
148 Return,
149 Unreachable,
150 Drop {
151 place: Place,
152 target: BasicBlockIdx,
153 unwind: UnwindAction,
154 },
155 Call {
156 func: Operand,
157 args: Vec<Operand>,
158 destination: Place,
159 target: Option<BasicBlockIdx>,
160 unwind: UnwindAction,
161 },
162 Assert {
163 cond: Operand,
164 expected: bool,
165 msg: AssertMessage,
166 target: BasicBlockIdx,
167 unwind: UnwindAction,
168 },
169 InlineAsm {
170 template: String,
171 operands: Vec<InlineAsmOperand>,
172 options: String,
173 line_spans: String,
174 destination: Option<BasicBlockIdx>,
175 unwind: UnwindAction,
176 },
177}
178
179impl TerminatorKind {
180 pub fn successors(&self) -> Successors {
181 use self::TerminatorKind::*;
182 match *self {
183 Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
184 | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
185 | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
186 | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
187 vec![t, u]
188 }
189 Goto { target: t }
190 | Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
191 | Call { target: Some(t), unwind: _, .. }
192 | Drop { target: t, unwind: _, .. }
193 | Assert { target: t, unwind: _, .. }
194 | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
195 | InlineAsm { destination: Some(t), unwind: _, .. } => {
196 vec![t]
197 }
198
199 Return
200 | Resume
201 | Abort
202 | Unreachable
203 | Call { target: None, unwind: _, .. }
204 | InlineAsm { destination: None, unwind: _, .. } => {
205 vec![]
206 }
207 SwitchInt { ref targets, .. } => targets.all_targets(),
208 }
209 }
210
211 pub fn unwind(&self) -> Option<&UnwindAction> {
212 match *self {
213 TerminatorKind::Goto { .. }
214 | TerminatorKind::Return
215 | TerminatorKind::Unreachable
216 | TerminatorKind::Resume
217 | TerminatorKind::Abort
218 | TerminatorKind::SwitchInt { .. } => None,
219 TerminatorKind::Call { ref unwind, .. }
220 | TerminatorKind::Assert { ref unwind, .. }
221 | TerminatorKind::Drop { ref unwind, .. }
222 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
223 }
224 }
225}
226
227#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
228pub struct InlineAsmOperand {
229 pub in_value: Option<Operand>,
230 pub out_place: Option<Place>,
231 pub raw_rpr: String,
234}
235
236#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
237pub enum UnwindAction {
238 Continue,
239 Unreachable,
240 Terminate,
241 Cleanup(BasicBlockIdx),
242}
243
244#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
245pub enum AssertMessage {
246 BoundsCheck { len: Operand, index: Operand },
247 Overflow(BinOp, Operand, Operand),
248 OverflowNeg(Operand),
249 DivisionByZero(Operand),
250 RemainderByZero(Operand),
251 ResumedAfterReturn(CoroutineKind),
252 ResumedAfterPanic(CoroutineKind),
253 MisalignedPointerDereference { required: Operand, found: Operand },
254 NullPointerDereference,
255}
256
257impl AssertMessage {
258 pub fn description(&self) -> Result<&'static str, Error> {
259 match self {
260 AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
261 AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
262 AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
263 AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
264 AssertMessage::Overflow(BinOp::Rem, _, _) => {
265 Ok("attempt to calculate the remainder with overflow")
266 }
267 AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
268 AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
269 AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
270 AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
271 AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
272 AssertMessage::RemainderByZero(_) => {
273 Ok("attempt to calculate the remainder with a divisor of zero")
274 }
275 AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
276 Ok("coroutine resumed after completion")
277 }
278 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
279 CoroutineDesugaring::Async,
280 _,
281 )) => Ok("`async fn` resumed after completion"),
282 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
283 CoroutineDesugaring::Gen,
284 _,
285 )) => Ok("`async gen fn` resumed after completion"),
286 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
287 CoroutineDesugaring::AsyncGen,
288 _,
289 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
290 AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
291 Ok("coroutine resumed after panicking")
292 }
293 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
294 CoroutineDesugaring::Async,
295 _,
296 )) => Ok("`async fn` resumed after panicking"),
297 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
298 CoroutineDesugaring::Gen,
299 _,
300 )) => Ok("`async gen fn` resumed after panicking"),
301 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
302 CoroutineDesugaring::AsyncGen,
303 _,
304 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
305
306 AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
307 AssertMessage::MisalignedPointerDereference { .. } => {
308 Ok("misaligned pointer dereference")
309 }
310 AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
311 }
312 }
313}
314
315#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
316pub enum BinOp {
317 Add,
318 AddUnchecked,
319 Sub,
320 SubUnchecked,
321 Mul,
322 MulUnchecked,
323 Div,
324 Rem,
325 BitXor,
326 BitAnd,
327 BitOr,
328 Shl,
329 ShlUnchecked,
330 Shr,
331 ShrUnchecked,
332 Eq,
333 Lt,
334 Le,
335 Ne,
336 Ge,
337 Gt,
338 Cmp,
339 Offset,
340}
341
342impl BinOp {
343 pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
346 with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
347 }
348}
349
350#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
351pub enum UnOp {
352 Not,
353 Neg,
354 PtrMetadata,
355}
356
357impl UnOp {
358 pub fn ty(&self, arg_ty: Ty) -> Ty {
361 with(|ctx| ctx.unop_ty(*self, arg_ty))
362 }
363}
364
365#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
366pub enum CoroutineKind {
367 Desugared(CoroutineDesugaring, CoroutineSource),
368 Coroutine(Movability),
369}
370
371#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
372pub enum CoroutineSource {
373 Block,
374 Closure,
375 Fn,
376}
377
378#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
379pub enum CoroutineDesugaring {
380 Async,
381
382 Gen,
383
384 AsyncGen,
385}
386
387pub(crate) type LocalDefId = Opaque;
388pub(crate) type Coverage = Opaque;
392
393#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
395pub enum FakeReadCause {
396 ForMatchGuard,
397 ForMatchedPlace(LocalDefId),
398 ForGuardBinding,
399 ForLet(LocalDefId),
400 ForIndex,
401}
402
403#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
405pub enum RetagKind {
406 FnEntry,
407 TwoPhase,
408 Raw,
409 Default,
410}
411
412#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
413pub enum Variance {
414 Covariant,
415 Invariant,
416 Contravariant,
417 Bivariant,
418}
419
420#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
421pub struct CopyNonOverlapping {
422 pub src: Operand,
423 pub dst: Operand,
424 pub count: Operand,
425}
426
427#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
428pub enum NonDivergingIntrinsic {
429 Assume(Operand),
430 CopyNonOverlapping(CopyNonOverlapping),
431}
432
433#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
434pub struct Statement {
435 pub kind: StatementKind,
436 pub span: Span,
437}
438
439#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
440pub enum StatementKind {
441 Assign(Place, Rvalue),
442 FakeRead(FakeReadCause, Place),
443 SetDiscriminant { place: Place, variant_index: VariantIdx },
444 Deinit(Place),
445 StorageLive(Local),
446 StorageDead(Local),
447 Retag(RetagKind, Place),
448 PlaceMention(Place),
449 AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
450 Coverage(Coverage),
451 Intrinsic(NonDivergingIntrinsic),
452 ConstEvalCounter,
453 Nop,
454}
455
456#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
457pub enum Rvalue {
458 AddressOf(RawPtrKind, Place),
463
464 Aggregate(AggregateKind, Vec<Operand>),
473
474 BinaryOp(BinOp, Operand, Operand),
487
488 Cast(CastKind, Operand, Ty),
492
493 CheckedBinaryOp(BinOp, Operand, Operand),
498
499 CopyForDeref(Place),
503
504 Discriminant(Place),
513
514 Len(Place),
520
521 Ref(Region, BorrowKind, Place),
523
524 Repeat(Operand, TyConst),
533
534 ShallowInitBox(Operand, Ty),
540
541 ThreadLocalRef(crate::CrateItem),
553
554 NullaryOp(NullOp, Ty),
556
557 UnaryOp(UnOp, Operand),
563
564 Use(Operand),
566}
567
568impl Rvalue {
569 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
570 match self {
571 Rvalue::Use(operand) => operand.ty(locals),
572 Rvalue::Repeat(operand, count) => {
573 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
574 }
575 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
576 Rvalue::Ref(reg, bk, place) => {
577 let place_ty = place.ty(locals)?;
578 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
579 }
580 Rvalue::AddressOf(mutability, place) => {
581 let place_ty = place.ty(locals)?;
582 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
583 }
584 Rvalue::Len(..) => Ok(Ty::usize_ty()),
585 Rvalue::Cast(.., ty) => Ok(*ty),
586 Rvalue::BinaryOp(op, lhs, rhs) => {
587 let lhs_ty = lhs.ty(locals)?;
588 let rhs_ty = rhs.ty(locals)?;
589 Ok(op.ty(lhs_ty, rhs_ty))
590 }
591 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
592 let lhs_ty = lhs.ty(locals)?;
593 let rhs_ty = rhs.ty(locals)?;
594 let ty = op.ty(lhs_ty, rhs_ty);
595 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
596 }
597 Rvalue::UnaryOp(op, operand) => {
598 let arg_ty = operand.ty(locals)?;
599 Ok(op.ty(arg_ty))
600 }
601 Rvalue::Discriminant(place) => {
602 let place_ty = place.ty(locals)?;
603 place_ty
604 .kind()
605 .discriminant_ty()
606 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
607 }
608 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
609 Ok(Ty::usize_ty())
610 }
611 Rvalue::NullaryOp(NullOp::ContractChecks, _)
612 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
613 Rvalue::Aggregate(ak, ops) => match *ak {
614 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
615 AggregateKind::Tuple => Ok(Ty::new_tuple(
616 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
617 )),
618 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
619 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
620 AggregateKind::Coroutine(def, ref args, mov) => {
621 Ok(Ty::new_coroutine(def, args.clone(), mov))
622 }
623 AggregateKind::CoroutineClosure(def, ref args) => {
624 Ok(Ty::new_coroutine_closure(def, args.clone()))
625 }
626 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
627 },
628 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
629 Rvalue::CopyForDeref(place) => place.ty(locals),
630 }
631 }
632}
633
634#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
635pub enum AggregateKind {
636 Array(Ty),
637 Tuple,
638 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
639 Closure(ClosureDef, GenericArgs),
640 Coroutine(CoroutineDef, GenericArgs, Movability),
642 CoroutineClosure(CoroutineClosureDef, GenericArgs),
643 RawPtr(Ty, Mutability),
644}
645
646#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
647pub enum Operand {
648 Copy(Place),
649 Move(Place),
650 Constant(ConstOperand),
651}
652
653#[derive(Clone, Eq, PartialEq, Serialize)]
654pub struct Place {
655 pub local: Local,
656 pub projection: Vec<ProjectionElem>,
658}
659
660impl From<Local> for Place {
661 fn from(local: Local) -> Self {
662 Place { local, projection: vec![] }
663 }
664}
665
666#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
667pub struct ConstOperand {
668 pub span: Span,
669 pub user_ty: Option<UserTypeAnnotationIndex>,
670 pub const_: MirConst,
671}
672
673#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
675pub struct VarDebugInfo {
676 pub name: Symbol,
678
679 pub source_info: SourceInfo,
682
683 pub composite: Option<VarDebugInfoFragment>,
686
687 pub value: VarDebugInfoContents,
689
690 pub argument_index: Option<u16>,
694}
695
696impl VarDebugInfo {
697 pub fn local(&self) -> Option<Local> {
699 match &self.value {
700 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
701 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
702 }
703 }
704
705 pub fn constant(&self) -> Option<&ConstOperand> {
707 match &self.value {
708 VarDebugInfoContents::Place(_) => None,
709 VarDebugInfoContents::Const(const_op) => Some(const_op),
710 }
711 }
712}
713
714pub type SourceScope = u32;
715
716#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
717pub struct SourceInfo {
718 pub span: Span,
719 pub scope: SourceScope,
720}
721
722#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
723pub struct VarDebugInfoFragment {
724 pub ty: Ty,
725 pub projection: Vec<ProjectionElem>,
726}
727
728#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
729pub enum VarDebugInfoContents {
730 Place(Place),
731 Const(ConstOperand),
732}
733
734#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
740pub enum ProjectionElem {
741 Deref,
743
744 Field(FieldIdx, Ty),
748
749 Index(Local),
764
765 ConstantIndex {
776 offset: u64,
778 min_length: u64,
783 from_end: bool,
786 },
787
788 Subslice {
793 from: u64,
794 to: u64,
795 from_end: bool,
797 },
798
799 Downcast(VariantIdx),
801
802 OpaqueCast(Ty),
805
806 Subtype(Ty),
813}
814
815#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
816pub struct UserTypeProjection {
817 pub base: UserTypeAnnotationIndex,
818
819 pub projection: Opaque,
820}
821
822pub type Local = usize;
823
824pub const RETURN_LOCAL: Local = 0;
825
826pub type FieldIdx = usize;
841
842type UserTypeAnnotationIndex = usize;
843
844#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
846pub struct SwitchTargets {
847 branches: Vec<(u128, BasicBlockIdx)>,
850 otherwise: BasicBlockIdx,
853}
854
855impl SwitchTargets {
856 pub fn all_targets(&self) -> Successors {
858 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
859 }
860
861 pub fn otherwise(&self) -> BasicBlockIdx {
863 self.otherwise
864 }
865
866 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> + '_ {
868 self.branches.iter().copied()
869 }
870
871 pub fn len(&self) -> usize {
873 self.branches.len() + 1
874 }
875
876 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
878 SwitchTargets { branches, otherwise }
879 }
880}
881
882#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
883pub enum BorrowKind {
884 Shared,
886
887 Fake(FakeBorrowKind),
890
891 Mut {
893 kind: MutBorrowKind,
895 },
896}
897
898impl BorrowKind {
899 pub fn to_mutable_lossy(self) -> Mutability {
900 match self {
901 BorrowKind::Mut { .. } => Mutability::Mut,
902 BorrowKind::Shared => Mutability::Not,
903 BorrowKind::Fake(_) => Mutability::Not,
905 }
906 }
907}
908
909#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
910pub enum RawPtrKind {
911 Mut,
912 Const,
913 FakeForPtrMetadata,
914}
915
916impl RawPtrKind {
917 pub fn to_mutable_lossy(self) -> Mutability {
918 match self {
919 RawPtrKind::Mut { .. } => Mutability::Mut,
920 RawPtrKind::Const => Mutability::Not,
921 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
923 }
924 }
925}
926
927#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
928pub enum MutBorrowKind {
929 Default,
930 TwoPhaseBorrow,
931 ClosureCapture,
932}
933
934#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
935pub enum FakeBorrowKind {
936 Deep,
938 Shallow,
943}
944
945#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
946pub enum Mutability {
947 Not,
948 Mut,
949}
950
951#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
952pub enum Safety {
953 Safe,
954 Unsafe,
955}
956
957#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
958pub enum PointerCoercion {
959 ReifyFnPointer,
961
962 UnsafeFnPointer,
964
965 ClosureFnPointer(Safety),
968
969 MutToConstPointer,
971
972 ArrayToPointer,
974
975 Unsize,
982}
983
984#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
985pub enum CastKind {
986 PointerExposeAddress,
988 PointerWithExposedProvenance,
989 PointerCoercion(PointerCoercion),
990 DynStar,
992 IntToInt,
993 FloatToInt,
994 FloatToFloat,
995 IntToFloat,
996 PtrToPtr,
997 FnPtrToPtr,
998 Transmute,
999}
1000
1001#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1002pub enum NullOp {
1003 SizeOf,
1005 AlignOf,
1007 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1009 UbChecks,
1011 ContractChecks,
1013}
1014
1015impl Operand {
1016 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1023 match self {
1024 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1025 Operand::Constant(c) => Ok(c.ty()),
1026 }
1027 }
1028}
1029
1030impl ConstOperand {
1031 pub fn ty(&self) -> Ty {
1032 self.const_.ty()
1033 }
1034}
1035
1036impl Place {
1037 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1044 let start_ty = locals[self.local].ty;
1045 self.projection.iter().fold(Ok(start_ty), |place_ty, elem| elem.ty(place_ty?))
1046 }
1047}
1048
1049impl ProjectionElem {
1050 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1052 let ty = place_ty;
1053 match &self {
1054 ProjectionElem::Deref => Self::deref_ty(ty),
1055 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1056 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1057 ProjectionElem::Subslice { from, to, from_end } => {
1058 Self::subslice_ty(ty, *from, *to, *from_end)
1059 }
1060 ProjectionElem::Downcast(_) => Ok(ty),
1061 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1062 }
1063 }
1064
1065 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1066 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1067 }
1068
1069 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1070 let ty_kind = ty.kind();
1071 match ty_kind {
1072 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1073 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1074 inner,
1075 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1076 ),
1077 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1078 let size = size.eval_target_usize()?;
1079 let len = size - from - to;
1080 Ty::try_new_array(inner, len)
1081 }
1082 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1083 }
1084 }
1085
1086 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1087 let deref_ty = ty
1088 .kind()
1089 .builtin_deref(true)
1090 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1091 Ok(deref_ty.ty)
1092 }
1093}