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 Subtype(Ty),
847}
848
849#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
850pub struct UserTypeProjection {
851 pub base: UserTypeAnnotationIndex,
852
853 pub projection: Opaque,
854}
855
856pub type Local = usize;
857
858pub const RETURN_LOCAL: Local = 0;
859
860pub type FieldIdx = usize;
875
876type UserTypeAnnotationIndex = usize;
877
878#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
880pub struct SwitchTargets {
881 branches: Vec<(u128, BasicBlockIdx)>,
884 otherwise: BasicBlockIdx,
887}
888
889impl SwitchTargets {
890 pub fn all_targets(&self) -> Successors {
892 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
893 }
894
895 pub fn otherwise(&self) -> BasicBlockIdx {
897 self.otherwise
898 }
899
900 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
902 self.branches.iter().copied()
903 }
904
905 pub fn len(&self) -> usize {
907 self.branches.len() + 1
908 }
909
910 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
912 SwitchTargets { branches, otherwise }
913 }
914}
915
916#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
917pub enum BorrowKind {
918 Shared,
920
921 Fake(FakeBorrowKind),
924
925 Mut {
927 kind: MutBorrowKind,
929 },
930}
931
932impl BorrowKind {
933 pub fn to_mutable_lossy(self) -> Mutability {
934 match self {
935 BorrowKind::Mut { .. } => Mutability::Mut,
936 BorrowKind::Shared => Mutability::Not,
937 BorrowKind::Fake(_) => Mutability::Not,
939 }
940 }
941}
942
943#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
944pub enum RawPtrKind {
945 Mut,
946 Const,
947 FakeForPtrMetadata,
948}
949
950impl RawPtrKind {
951 pub fn to_mutable_lossy(self) -> Mutability {
952 match self {
953 RawPtrKind::Mut { .. } => Mutability::Mut,
954 RawPtrKind::Const => Mutability::Not,
955 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
957 }
958 }
959}
960
961#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
962pub enum MutBorrowKind {
963 Default,
964 TwoPhaseBorrow,
965 ClosureCapture,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
969pub enum FakeBorrowKind {
970 Deep,
972 Shallow,
977}
978
979#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
980pub enum Mutability {
981 Not,
982 Mut,
983}
984
985#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
986pub enum Safety {
987 Safe,
988 Unsafe,
989}
990
991#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
992pub enum PointerCoercion {
993 ReifyFnPointer,
995
996 UnsafeFnPointer,
998
999 ClosureFnPointer(Safety),
1002
1003 MutToConstPointer,
1005
1006 ArrayToPointer,
1008
1009 Unsize,
1016}
1017
1018#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1019pub enum CastKind {
1020 PointerExposeAddress,
1022 PointerWithExposedProvenance,
1023 PointerCoercion(PointerCoercion),
1024 IntToInt,
1025 FloatToInt,
1026 FloatToFloat,
1027 IntToFloat,
1028 PtrToPtr,
1029 FnPtrToPtr,
1030 Transmute,
1031}
1032
1033#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1034pub enum NullOp {
1035 SizeOf,
1037 AlignOf,
1039 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1041 UbChecks,
1043 ContractChecks,
1045}
1046
1047impl Operand {
1048 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1055 match self {
1056 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1057 Operand::Constant(c) => Ok(c.ty()),
1058 }
1059 }
1060}
1061
1062impl ConstOperand {
1063 pub fn ty(&self) -> Ty {
1064 self.const_.ty()
1065 }
1066}
1067
1068impl Place {
1069 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1076 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1077 }
1078}
1079
1080impl ProjectionElem {
1081 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1083 let ty = place_ty;
1084 match &self {
1085 ProjectionElem::Deref => Self::deref_ty(ty),
1086 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1087 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1088 ProjectionElem::Subslice { from, to, from_end } => {
1089 Self::subslice_ty(ty, *from, *to, *from_end)
1090 }
1091 ProjectionElem::Downcast(_) => Ok(ty),
1092 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1093 }
1094 }
1095
1096 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1097 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1098 }
1099
1100 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1101 let ty_kind = ty.kind();
1102 match ty_kind {
1103 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1104 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1105 inner,
1106 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1107 ),
1108 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1109 let size = size.eval_target_usize()?;
1110 let len = size - from - to;
1111 Ty::try_new_array(inner, len)
1112 }
1113 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1114 }
1115 }
1116
1117 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1118 let deref_ty = ty
1119 .kind()
1120 .builtin_deref(true)
1121 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1122 Ok(deref_ty.ty)
1123 }
1124}