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 Deinit(Place),
482 StorageLive(Local),
483 StorageDead(Local),
484 Retag(RetagKind, Place),
485 PlaceMention(Place),
486 AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
487 Coverage(Coverage),
488 Intrinsic(NonDivergingIntrinsic),
489 ConstEvalCounter,
490 Nop,
491}
492
493#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
494pub enum Rvalue {
495 AddressOf(RawPtrKind, Place),
500
501 Aggregate(AggregateKind, Vec<Operand>),
510
511 BinaryOp(BinOp, Operand, Operand),
524
525 Cast(CastKind, Operand, Ty),
529
530 CheckedBinaryOp(BinOp, Operand, Operand),
535
536 CopyForDeref(Place),
540
541 Discriminant(Place),
550
551 Len(Place),
557
558 Ref(Region, BorrowKind, Place),
560
561 Repeat(Operand, TyConst),
570
571 ShallowInitBox(Operand, Ty),
577
578 ThreadLocalRef(crate::CrateItem),
590
591 NullaryOp(NullOp, Ty),
593
594 UnaryOp(UnOp, Operand),
600
601 Use(Operand),
603}
604
605impl Rvalue {
606 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
607 match self {
608 Rvalue::Use(operand) => operand.ty(locals),
609 Rvalue::Repeat(operand, count) => {
610 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
611 }
612 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
613 Rvalue::Ref(reg, bk, place) => {
614 let place_ty = place.ty(locals)?;
615 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
616 }
617 Rvalue::AddressOf(mutability, place) => {
618 let place_ty = place.ty(locals)?;
619 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
620 }
621 Rvalue::Len(..) => Ok(Ty::usize_ty()),
622 Rvalue::Cast(.., ty) => Ok(*ty),
623 Rvalue::BinaryOp(op, lhs, rhs) => {
624 let lhs_ty = lhs.ty(locals)?;
625 let rhs_ty = rhs.ty(locals)?;
626 Ok(op.ty(lhs_ty, rhs_ty))
627 }
628 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
629 let lhs_ty = lhs.ty(locals)?;
630 let rhs_ty = rhs.ty(locals)?;
631 let ty = op.ty(lhs_ty, rhs_ty);
632 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
633 }
634 Rvalue::UnaryOp(op, operand) => {
635 let arg_ty = operand.ty(locals)?;
636 Ok(op.ty(arg_ty))
637 }
638 Rvalue::Discriminant(place) => {
639 let place_ty = place.ty(locals)?;
640 place_ty
641 .kind()
642 .discriminant_ty()
643 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
644 }
645 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
646 Ok(Ty::usize_ty())
647 }
648 Rvalue::NullaryOp(NullOp::ContractChecks, _)
649 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
650 Rvalue::Aggregate(ak, ops) => match *ak {
651 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
652 AggregateKind::Tuple => Ok(Ty::new_tuple(
653 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
654 )),
655 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
656 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
657 AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
658 AggregateKind::CoroutineClosure(def, ref args) => {
659 Ok(Ty::new_coroutine_closure(def, args.clone()))
660 }
661 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
662 },
663 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
664 Rvalue::CopyForDeref(place) => place.ty(locals),
665 }
666 }
667}
668
669#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
670pub enum AggregateKind {
671 Array(Ty),
672 Tuple,
673 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
674 Closure(ClosureDef, GenericArgs),
675 Coroutine(CoroutineDef, GenericArgs),
676 CoroutineClosure(CoroutineClosureDef, GenericArgs),
677 RawPtr(Ty, Mutability),
678}
679
680#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
681pub enum Operand {
682 Copy(Place),
683 Move(Place),
684 Constant(ConstOperand),
685}
686
687#[derive(Clone, Eq, PartialEq, Hash, 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, Hash, 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, Hash, 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
841#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
842pub struct UserTypeProjection {
843 pub base: UserTypeAnnotationIndex,
844
845 pub projection: Opaque,
846}
847
848pub type Local = usize;
849
850pub const RETURN_LOCAL: Local = 0;
851
852pub type FieldIdx = usize;
867
868type UserTypeAnnotationIndex = usize;
869
870#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
872pub struct SwitchTargets {
873 branches: Vec<(u128, BasicBlockIdx)>,
876 otherwise: BasicBlockIdx,
879}
880
881impl SwitchTargets {
882 pub fn all_targets(&self) -> Successors {
884 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
885 }
886
887 pub fn otherwise(&self) -> BasicBlockIdx {
889 self.otherwise
890 }
891
892 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
894 self.branches.iter().copied()
895 }
896
897 pub fn len(&self) -> usize {
899 self.branches.len() + 1
900 }
901
902 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
904 SwitchTargets { branches, otherwise }
905 }
906}
907
908#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
909pub enum BorrowKind {
910 Shared,
912
913 Fake(FakeBorrowKind),
916
917 Mut {
919 kind: MutBorrowKind,
921 },
922}
923
924impl BorrowKind {
925 pub fn to_mutable_lossy(self) -> Mutability {
926 match self {
927 BorrowKind::Mut { .. } => Mutability::Mut,
928 BorrowKind::Shared => Mutability::Not,
929 BorrowKind::Fake(_) => Mutability::Not,
931 }
932 }
933}
934
935#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
936pub enum RawPtrKind {
937 Mut,
938 Const,
939 FakeForPtrMetadata,
940}
941
942impl RawPtrKind {
943 pub fn to_mutable_lossy(self) -> Mutability {
944 match self {
945 RawPtrKind::Mut { .. } => Mutability::Mut,
946 RawPtrKind::Const => Mutability::Not,
947 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
949 }
950 }
951}
952
953#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
954pub enum MutBorrowKind {
955 Default,
956 TwoPhaseBorrow,
957 ClosureCapture,
958}
959
960#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
961pub enum FakeBorrowKind {
962 Deep,
964 Shallow,
969}
970
971#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
972pub enum Mutability {
973 Not,
974 Mut,
975}
976
977#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
978pub enum Safety {
979 Safe,
980 Unsafe,
981}
982
983#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
984pub enum PointerCoercion {
985 ReifyFnPointer,
987
988 UnsafeFnPointer,
990
991 ClosureFnPointer(Safety),
994
995 MutToConstPointer,
997
998 ArrayToPointer,
1000
1001 Unsize,
1008}
1009
1010#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1011pub enum CastKind {
1012 PointerExposeAddress,
1014 PointerWithExposedProvenance,
1015 PointerCoercion(PointerCoercion),
1016 IntToInt,
1017 FloatToInt,
1018 FloatToFloat,
1019 IntToFloat,
1020 PtrToPtr,
1021 FnPtrToPtr,
1022 Transmute,
1023 Subtype,
1024}
1025
1026#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1027pub enum NullOp {
1028 SizeOf,
1030 AlignOf,
1032 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1034 UbChecks,
1036 ContractChecks,
1038}
1039
1040impl Operand {
1041 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1048 match self {
1049 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1050 Operand::Constant(c) => Ok(c.ty()),
1051 }
1052 }
1053}
1054
1055impl ConstOperand {
1056 pub fn ty(&self) -> Ty {
1057 self.const_.ty()
1058 }
1059}
1060
1061impl Place {
1062 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1069 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1070 }
1071}
1072
1073impl ProjectionElem {
1074 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1076 let ty = place_ty;
1077 match &self {
1078 ProjectionElem::Deref => Self::deref_ty(ty),
1079 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1080 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1081 ProjectionElem::Subslice { from, to, from_end } => {
1082 Self::subslice_ty(ty, *from, *to, *from_end)
1083 }
1084 ProjectionElem::Downcast(_) => Ok(ty),
1085 ProjectionElem::OpaqueCast(ty) => Ok(*ty),
1086 }
1087 }
1088
1089 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1090 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1091 }
1092
1093 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1094 let ty_kind = ty.kind();
1095 match ty_kind {
1096 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1097 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1098 inner,
1099 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1100 ),
1101 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1102 let size = size.eval_target_usize()?;
1103 let len = size - from - to;
1104 Ty::try_new_array(inner, len)
1105 }
1106 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1107 }
1108 }
1109
1110 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1111 let deref_ty = ty
1112 .kind()
1113 .builtin_deref(true)
1114 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1115 Ok(deref_ty.ty)
1116 }
1117}