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 MisalignedPointerDereference { required: Operand, found: Operand },
270 NullPointerDereference,
271}
272
273impl AssertMessage {
274 pub fn description(&self) -> Result<&'static str, Error> {
275 match self {
276 AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
277 AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
278 AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
279 AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
280 AssertMessage::Overflow(BinOp::Rem, _, _) => {
281 Ok("attempt to calculate the remainder with overflow")
282 }
283 AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
284 AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
285 AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
286 AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
287 AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
288 AssertMessage::RemainderByZero(_) => {
289 Ok("attempt to calculate the remainder with a divisor of zero")
290 }
291 AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
292 Ok("coroutine resumed after completion")
293 }
294 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
295 CoroutineDesugaring::Async,
296 _,
297 )) => Ok("`async fn` resumed after completion"),
298 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
299 CoroutineDesugaring::Gen,
300 _,
301 )) => Ok("`async gen fn` resumed after completion"),
302 AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
303 CoroutineDesugaring::AsyncGen,
304 _,
305 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
306 AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
307 Ok("coroutine resumed after panicking")
308 }
309 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
310 CoroutineDesugaring::Async,
311 _,
312 )) => Ok("`async fn` resumed after panicking"),
313 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
314 CoroutineDesugaring::Gen,
315 _,
316 )) => Ok("`async gen fn` resumed after panicking"),
317 AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
318 CoroutineDesugaring::AsyncGen,
319 _,
320 )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
321
322 AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
323 AssertMessage::MisalignedPointerDereference { .. } => {
324 Ok("misaligned pointer dereference")
325 }
326 AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
327 }
328 }
329}
330
331#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
332pub enum BinOp {
333 Add,
334 AddUnchecked,
335 Sub,
336 SubUnchecked,
337 Mul,
338 MulUnchecked,
339 Div,
340 Rem,
341 BitXor,
342 BitAnd,
343 BitOr,
344 Shl,
345 ShlUnchecked,
346 Shr,
347 ShrUnchecked,
348 Eq,
349 Lt,
350 Le,
351 Ne,
352 Ge,
353 Gt,
354 Cmp,
355 Offset,
356}
357
358impl BinOp {
359 pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
362 with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
363 }
364}
365
366#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
367pub enum UnOp {
368 Not,
369 Neg,
370 PtrMetadata,
371}
372
373impl UnOp {
374 pub fn ty(&self, arg_ty: Ty) -> Ty {
377 with(|ctx| ctx.unop_ty(*self, arg_ty))
378 }
379}
380
381#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
382pub enum CoroutineKind {
383 Desugared(CoroutineDesugaring, CoroutineSource),
384 Coroutine(Movability),
385}
386
387#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
388pub enum CoroutineSource {
389 Block,
390 Closure,
391 Fn,
392}
393
394#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
395pub enum CoroutineDesugaring {
396 Async,
397
398 Gen,
399
400 AsyncGen,
401}
402
403pub(crate) type LocalDefId = Opaque;
404pub(crate) type Coverage = Opaque;
408
409#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
411pub enum FakeReadCause {
412 ForMatchGuard,
413 ForMatchedPlace(LocalDefId),
414 ForGuardBinding,
415 ForLet(LocalDefId),
416 ForIndex,
417}
418
419#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
421pub enum RetagKind {
422 FnEntry,
423 TwoPhase,
424 Raw,
425 Default,
426}
427
428#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
429pub enum Variance {
430 Covariant,
431 Invariant,
432 Contravariant,
433 Bivariant,
434}
435
436#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
437pub struct CopyNonOverlapping {
438 pub src: Operand,
439 pub dst: Operand,
440 pub count: Operand,
441}
442
443#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
444pub enum NonDivergingIntrinsic {
445 Assume(Operand),
446 CopyNonOverlapping(CopyNonOverlapping),
447}
448
449#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
450pub struct Statement {
451 pub kind: StatementKind,
452 pub span: Span,
453}
454
455#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
456pub enum StatementKind {
457 Assign(Place, Rvalue),
458 FakeRead(FakeReadCause, Place),
459 SetDiscriminant { place: Place, variant_index: VariantIdx },
460 Deinit(Place),
461 StorageLive(Local),
462 StorageDead(Local),
463 Retag(RetagKind, Place),
464 PlaceMention(Place),
465 AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
466 Coverage(Coverage),
467 Intrinsic(NonDivergingIntrinsic),
468 ConstEvalCounter,
469 Nop,
470}
471
472#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
473pub enum Rvalue {
474 AddressOf(RawPtrKind, Place),
479
480 Aggregate(AggregateKind, Vec<Operand>),
489
490 BinaryOp(BinOp, Operand, Operand),
503
504 Cast(CastKind, Operand, Ty),
508
509 CheckedBinaryOp(BinOp, Operand, Operand),
514
515 CopyForDeref(Place),
519
520 Discriminant(Place),
529
530 Len(Place),
536
537 Ref(Region, BorrowKind, Place),
539
540 Repeat(Operand, TyConst),
549
550 ShallowInitBox(Operand, Ty),
556
557 ThreadLocalRef(crate::CrateItem),
569
570 NullaryOp(NullOp, Ty),
572
573 UnaryOp(UnOp, Operand),
579
580 Use(Operand),
582}
583
584impl Rvalue {
585 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
586 match self {
587 Rvalue::Use(operand) => operand.ty(locals),
588 Rvalue::Repeat(operand, count) => {
589 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
590 }
591 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
592 Rvalue::Ref(reg, bk, place) => {
593 let place_ty = place.ty(locals)?;
594 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
595 }
596 Rvalue::AddressOf(mutability, place) => {
597 let place_ty = place.ty(locals)?;
598 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
599 }
600 Rvalue::Len(..) => Ok(Ty::usize_ty()),
601 Rvalue::Cast(.., ty) => Ok(*ty),
602 Rvalue::BinaryOp(op, lhs, rhs) => {
603 let lhs_ty = lhs.ty(locals)?;
604 let rhs_ty = rhs.ty(locals)?;
605 Ok(op.ty(lhs_ty, rhs_ty))
606 }
607 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
608 let lhs_ty = lhs.ty(locals)?;
609 let rhs_ty = rhs.ty(locals)?;
610 let ty = op.ty(lhs_ty, rhs_ty);
611 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
612 }
613 Rvalue::UnaryOp(op, operand) => {
614 let arg_ty = operand.ty(locals)?;
615 Ok(op.ty(arg_ty))
616 }
617 Rvalue::Discriminant(place) => {
618 let place_ty = place.ty(locals)?;
619 place_ty
620 .kind()
621 .discriminant_ty()
622 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
623 }
624 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
625 Ok(Ty::usize_ty())
626 }
627 Rvalue::NullaryOp(NullOp::ContractChecks, _)
628 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
629 Rvalue::Aggregate(ak, ops) => match *ak {
630 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
631 AggregateKind::Tuple => Ok(Ty::new_tuple(
632 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
633 )),
634 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
635 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
636 AggregateKind::Coroutine(def, ref args, mov) => {
637 Ok(Ty::new_coroutine(def, args.clone(), mov))
638 }
639 AggregateKind::CoroutineClosure(def, ref args) => {
640 Ok(Ty::new_coroutine_closure(def, args.clone()))
641 }
642 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
643 },
644 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
645 Rvalue::CopyForDeref(place) => place.ty(locals),
646 }
647 }
648}
649
650#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
651pub enum AggregateKind {
652 Array(Ty),
653 Tuple,
654 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
655 Closure(ClosureDef, GenericArgs),
656 Coroutine(CoroutineDef, GenericArgs, Movability),
658 CoroutineClosure(CoroutineClosureDef, GenericArgs),
659 RawPtr(Ty, Mutability),
660}
661
662#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
663pub enum Operand {
664 Copy(Place),
665 Move(Place),
666 Constant(ConstOperand),
667}
668
669#[derive(Clone, Eq, PartialEq, Serialize)]
670pub struct Place {
671 pub local: Local,
672 pub projection: Vec<ProjectionElem>,
674}
675
676impl From<Local> for Place {
677 fn from(local: Local) -> Self {
678 Place { local, projection: vec![] }
679 }
680}
681
682#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
683pub struct ConstOperand {
684 pub span: Span,
685 pub user_ty: Option<UserTypeAnnotationIndex>,
686 pub const_: MirConst,
687}
688
689#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
691pub struct VarDebugInfo {
692 pub name: Symbol,
694
695 pub source_info: SourceInfo,
698
699 pub composite: Option<VarDebugInfoFragment>,
702
703 pub value: VarDebugInfoContents,
705
706 pub argument_index: Option<u16>,
710}
711
712impl VarDebugInfo {
713 pub fn local(&self) -> Option<Local> {
715 match &self.value {
716 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
717 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
718 }
719 }
720
721 pub fn constant(&self) -> Option<&ConstOperand> {
723 match &self.value {
724 VarDebugInfoContents::Place(_) => None,
725 VarDebugInfoContents::Const(const_op) => Some(const_op),
726 }
727 }
728}
729
730pub type SourceScope = u32;
731
732#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
733pub struct SourceInfo {
734 pub span: Span,
735 pub scope: SourceScope,
736}
737
738#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
739pub struct VarDebugInfoFragment {
740 pub ty: Ty,
741 pub projection: Vec<ProjectionElem>,
742}
743
744#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
745pub enum VarDebugInfoContents {
746 Place(Place),
747 Const(ConstOperand),
748}
749
750#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
756pub enum ProjectionElem {
757 Deref,
759
760 Field(FieldIdx, Ty),
764
765 Index(Local),
780
781 ConstantIndex {
792 offset: u64,
794 min_length: u64,
799 from_end: bool,
802 },
803
804 Subslice {
809 from: u64,
810 to: u64,
811 from_end: bool,
813 },
814
815 Downcast(VariantIdx),
817
818 OpaqueCast(Ty),
821
822 Subtype(Ty),
829}
830
831#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
832pub struct UserTypeProjection {
833 pub base: UserTypeAnnotationIndex,
834
835 pub projection: Opaque,
836}
837
838pub type Local = usize;
839
840pub const RETURN_LOCAL: Local = 0;
841
842pub type FieldIdx = usize;
857
858type UserTypeAnnotationIndex = usize;
859
860#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
862pub struct SwitchTargets {
863 branches: Vec<(u128, BasicBlockIdx)>,
866 otherwise: BasicBlockIdx,
869}
870
871impl SwitchTargets {
872 pub fn all_targets(&self) -> Successors {
874 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
875 }
876
877 pub fn otherwise(&self) -> BasicBlockIdx {
879 self.otherwise
880 }
881
882 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
884 self.branches.iter().copied()
885 }
886
887 pub fn len(&self) -> usize {
889 self.branches.len() + 1
890 }
891
892 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
894 SwitchTargets { branches, otherwise }
895 }
896}
897
898#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
899pub enum BorrowKind {
900 Shared,
902
903 Fake(FakeBorrowKind),
906
907 Mut {
909 kind: MutBorrowKind,
911 },
912}
913
914impl BorrowKind {
915 pub fn to_mutable_lossy(self) -> Mutability {
916 match self {
917 BorrowKind::Mut { .. } => Mutability::Mut,
918 BorrowKind::Shared => Mutability::Not,
919 BorrowKind::Fake(_) => Mutability::Not,
921 }
922 }
923}
924
925#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
926pub enum RawPtrKind {
927 Mut,
928 Const,
929 FakeForPtrMetadata,
930}
931
932impl RawPtrKind {
933 pub fn to_mutable_lossy(self) -> Mutability {
934 match self {
935 RawPtrKind::Mut { .. } => Mutability::Mut,
936 RawPtrKind::Const => Mutability::Not,
937 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
939 }
940 }
941}
942
943#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
944pub enum MutBorrowKind {
945 Default,
946 TwoPhaseBorrow,
947 ClosureCapture,
948}
949
950#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
951pub enum FakeBorrowKind {
952 Deep,
954 Shallow,
959}
960
961#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
962pub enum Mutability {
963 Not,
964 Mut,
965}
966
967#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
968pub enum Safety {
969 Safe,
970 Unsafe,
971}
972
973#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
974pub enum PointerCoercion {
975 ReifyFnPointer,
977
978 UnsafeFnPointer,
980
981 ClosureFnPointer(Safety),
984
985 MutToConstPointer,
987
988 ArrayToPointer,
990
991 Unsize,
998}
999
1000#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1001pub enum CastKind {
1002 PointerExposeAddress,
1004 PointerWithExposedProvenance,
1005 PointerCoercion(PointerCoercion),
1006 DynStar,
1008 IntToInt,
1009 FloatToInt,
1010 FloatToFloat,
1011 IntToFloat,
1012 PtrToPtr,
1013 FnPtrToPtr,
1014 Transmute,
1015}
1016
1017#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1018pub enum NullOp {
1019 SizeOf,
1021 AlignOf,
1023 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1025 UbChecks,
1027 ContractChecks,
1029}
1030
1031impl Operand {
1032 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1039 match self {
1040 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1041 Operand::Constant(c) => Ok(c.ty()),
1042 }
1043 }
1044}
1045
1046impl ConstOperand {
1047 pub fn ty(&self) -> Ty {
1048 self.const_.ty()
1049 }
1050}
1051
1052impl Place {
1053 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1060 let start_ty = locals[self.local].ty;
1061 self.projection.iter().fold(Ok(start_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}