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::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
645 Ok(Ty::usize_ty())
646 }
647 Rvalue::NullaryOp(NullOp::ContractChecks, _)
648 | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
649 Rvalue::Aggregate(ak, ops) => match *ak {
650 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
651 AggregateKind::Tuple => Ok(Ty::new_tuple(
652 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
653 )),
654 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
655 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
656 AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
657 AggregateKind::CoroutineClosure(def, ref args) => {
658 Ok(Ty::new_coroutine_closure(def, args.clone()))
659 }
660 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
661 },
662 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
663 Rvalue::CopyForDeref(place) => place.ty(locals),
664 }
665 }
666}
667
668#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
669pub enum AggregateKind {
670 Array(Ty),
671 Tuple,
672 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
673 Closure(ClosureDef, GenericArgs),
674 Coroutine(CoroutineDef, GenericArgs),
675 CoroutineClosure(CoroutineClosureDef, GenericArgs),
676 RawPtr(Ty, Mutability),
677}
678
679#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
680pub enum Operand {
681 Copy(Place),
682 Move(Place),
683 Constant(ConstOperand),
684}
685
686#[derive(Clone, Eq, PartialEq, Hash, Serialize)]
687pub struct Place {
688 pub local: Local,
689 pub projection: Vec<ProjectionElem>,
691}
692
693impl From<Local> for Place {
694 fn from(local: Local) -> Self {
695 Place { local, projection: vec![] }
696 }
697}
698
699#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
700pub struct ConstOperand {
701 pub span: Span,
702 pub user_ty: Option<UserTypeAnnotationIndex>,
703 pub const_: MirConst,
704}
705
706#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
708pub struct VarDebugInfo {
709 pub name: Symbol,
711
712 pub source_info: SourceInfo,
715
716 pub composite: Option<VarDebugInfoFragment>,
719
720 pub value: VarDebugInfoContents,
722
723 pub argument_index: Option<u16>,
727}
728
729impl VarDebugInfo {
730 pub fn local(&self) -> Option<Local> {
732 match &self.value {
733 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
734 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
735 }
736 }
737
738 pub fn constant(&self) -> Option<&ConstOperand> {
740 match &self.value {
741 VarDebugInfoContents::Place(_) => None,
742 VarDebugInfoContents::Const(const_op) => Some(const_op),
743 }
744 }
745}
746
747pub type SourceScope = u32;
748
749#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
750pub struct SourceInfo {
751 pub span: Span,
752 pub scope: SourceScope,
753}
754
755#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
756pub struct VarDebugInfoFragment {
757 pub ty: Ty,
758 pub projection: Vec<ProjectionElem>,
759}
760
761#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
762pub enum VarDebugInfoContents {
763 Place(Place),
764 Const(ConstOperand),
765}
766
767#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
773pub enum ProjectionElem {
774 Deref,
776
777 Field(FieldIdx, Ty),
781
782 Index(Local),
797
798 ConstantIndex {
809 offset: u64,
811 min_length: u64,
816 from_end: bool,
819 },
820
821 Subslice {
826 from: u64,
827 to: u64,
828 from_end: bool,
830 },
831
832 Downcast(VariantIdx),
834
835 OpaqueCast(Ty),
838}
839
840#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
841pub struct UserTypeProjection {
842 pub base: UserTypeAnnotationIndex,
843
844 pub projection: Opaque,
845}
846
847pub type Local = usize;
848
849pub const RETURN_LOCAL: Local = 0;
850
851pub type FieldIdx = usize;
866
867type UserTypeAnnotationIndex = usize;
868
869#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
871pub struct SwitchTargets {
872 branches: Vec<(u128, BasicBlockIdx)>,
875 otherwise: BasicBlockIdx,
878}
879
880impl SwitchTargets {
881 pub fn all_targets(&self) -> Successors {
883 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
884 }
885
886 pub fn otherwise(&self) -> BasicBlockIdx {
888 self.otherwise
889 }
890
891 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
893 self.branches.iter().copied()
894 }
895
896 pub fn len(&self) -> usize {
898 self.branches.len() + 1
899 }
900
901 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
903 SwitchTargets { branches, otherwise }
904 }
905}
906
907#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
908pub enum BorrowKind {
909 Shared,
911
912 Fake(FakeBorrowKind),
915
916 Mut {
918 kind: MutBorrowKind,
920 },
921}
922
923impl BorrowKind {
924 pub fn to_mutable_lossy(self) -> Mutability {
925 match self {
926 BorrowKind::Mut { .. } => Mutability::Mut,
927 BorrowKind::Shared => Mutability::Not,
928 BorrowKind::Fake(_) => Mutability::Not,
930 }
931 }
932}
933
934#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
935pub enum RawPtrKind {
936 Mut,
937 Const,
938 FakeForPtrMetadata,
939}
940
941impl RawPtrKind {
942 pub fn to_mutable_lossy(self) -> Mutability {
943 match self {
944 RawPtrKind::Mut { .. } => Mutability::Mut,
945 RawPtrKind::Const => Mutability::Not,
946 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
948 }
949 }
950}
951
952#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
953pub enum MutBorrowKind {
954 Default,
955 TwoPhaseBorrow,
956 ClosureCapture,
957}
958
959#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
960pub enum FakeBorrowKind {
961 Deep,
963 Shallow,
968}
969
970#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
971pub enum Mutability {
972 Not,
973 Mut,
974}
975
976#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
977pub enum Safety {
978 Safe,
979 Unsafe,
980}
981
982#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
983pub enum PointerCoercion {
984 ReifyFnPointer,
986
987 UnsafeFnPointer,
989
990 ClosureFnPointer(Safety),
993
994 MutToConstPointer,
996
997 ArrayToPointer,
999
1000 Unsize,
1007}
1008
1009#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1010pub enum CastKind {
1011 PointerExposeAddress,
1013 PointerWithExposedProvenance,
1014 PointerCoercion(PointerCoercion),
1015 IntToInt,
1016 FloatToInt,
1017 FloatToFloat,
1018 IntToFloat,
1019 PtrToPtr,
1020 FnPtrToPtr,
1021 Transmute,
1022 Subtype,
1023}
1024
1025#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1026pub enum NullOp {
1027 SizeOf,
1029 AlignOf,
1031 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1033 UbChecks,
1035 ContractChecks,
1037}
1038
1039impl Operand {
1040 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1047 match self {
1048 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1049 Operand::Constant(c) => Ok(c.ty()),
1050 }
1051 }
1052}
1053
1054impl ConstOperand {
1055 pub fn ty(&self) -> Ty {
1056 self.const_.ty()
1057 }
1058}
1059
1060impl Place {
1061 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1068 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1069 }
1070}
1071
1072impl ProjectionElem {
1073 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1075 let ty = place_ty;
1076 match &self {
1077 ProjectionElem::Deref => Self::deref_ty(ty),
1078 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1079 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1080 ProjectionElem::Subslice { from, to, from_end } => {
1081 Self::subslice_ty(ty, *from, *to, *from_end)
1082 }
1083 ProjectionElem::Downcast(_) => Ok(ty),
1084 ProjectionElem::OpaqueCast(ty) => Ok(*ty),
1085 }
1086 }
1087
1088 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1089 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1090 }
1091
1092 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1093 let ty_kind = ty.kind();
1094 match ty_kind {
1095 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1096 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1097 inner,
1098 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1099 ),
1100 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1101 let size = size.eval_target_usize()?;
1102 let len = size - from - to;
1103 Ty::try_new_array(inner, len)
1104 }
1105 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1106 }
1107 }
1108
1109 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1110 let deref_ty = ty
1111 .kind()
1112 .builtin_deref(true)
1113 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1114 Ok(deref_ty.ty)
1115 }
1116}