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, 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, 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, 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, mov) => {
658 Ok(Ty::new_coroutine(def, args.clone(), mov))
659 }
660 AggregateKind::CoroutineClosure(def, ref args) => {
661 Ok(Ty::new_coroutine_closure(def, args.clone()))
662 }
663 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
664 },
665 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
666 Rvalue::CopyForDeref(place) => place.ty(locals),
667 }
668 }
669}
670
671#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
672pub enum AggregateKind {
673 Array(Ty),
674 Tuple,
675 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
676 Closure(ClosureDef, GenericArgs),
677 Coroutine(CoroutineDef, GenericArgs, Movability),
679 CoroutineClosure(CoroutineClosureDef, GenericArgs),
680 RawPtr(Ty, Mutability),
681}
682
683#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
684pub enum Operand {
685 Copy(Place),
686 Move(Place),
687 Constant(ConstOperand),
688}
689
690#[derive(Clone, Eq, PartialEq, Serialize)]
691pub struct Place {
692 pub local: Local,
693 pub projection: Vec<ProjectionElem>,
695}
696
697impl From<Local> for Place {
698 fn from(local: Local) -> Self {
699 Place { local, projection: vec![] }
700 }
701}
702
703#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
704pub struct ConstOperand {
705 pub span: Span,
706 pub user_ty: Option<UserTypeAnnotationIndex>,
707 pub const_: MirConst,
708}
709
710#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
712pub struct VarDebugInfo {
713 pub name: Symbol,
715
716 pub source_info: SourceInfo,
719
720 pub composite: Option<VarDebugInfoFragment>,
723
724 pub value: VarDebugInfoContents,
726
727 pub argument_index: Option<u16>,
731}
732
733impl VarDebugInfo {
734 pub fn local(&self) -> Option<Local> {
736 match &self.value {
737 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
738 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
739 }
740 }
741
742 pub fn constant(&self) -> Option<&ConstOperand> {
744 match &self.value {
745 VarDebugInfoContents::Place(_) => None,
746 VarDebugInfoContents::Const(const_op) => Some(const_op),
747 }
748 }
749}
750
751pub type SourceScope = u32;
752
753#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
754pub struct SourceInfo {
755 pub span: Span,
756 pub scope: SourceScope,
757}
758
759#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
760pub struct VarDebugInfoFragment {
761 pub ty: Ty,
762 pub projection: Vec<ProjectionElem>,
763}
764
765#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
766pub enum VarDebugInfoContents {
767 Place(Place),
768 Const(ConstOperand),
769}
770
771#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
777pub enum ProjectionElem {
778 Deref,
780
781 Field(FieldIdx, Ty),
785
786 Index(Local),
801
802 ConstantIndex {
813 offset: u64,
815 min_length: u64,
820 from_end: bool,
823 },
824
825 Subslice {
830 from: u64,
831 to: u64,
832 from_end: bool,
834 },
835
836 Downcast(VariantIdx),
838
839 OpaqueCast(Ty),
842
843 Subtype(Ty),
850}
851
852#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
853pub struct UserTypeProjection {
854 pub base: UserTypeAnnotationIndex,
855
856 pub projection: Opaque,
857}
858
859pub type Local = usize;
860
861pub const RETURN_LOCAL: Local = 0;
862
863pub type FieldIdx = usize;
878
879type UserTypeAnnotationIndex = usize;
880
881#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
883pub struct SwitchTargets {
884 branches: Vec<(u128, BasicBlockIdx)>,
887 otherwise: BasicBlockIdx,
890}
891
892impl SwitchTargets {
893 pub fn all_targets(&self) -> Successors {
895 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
896 }
897
898 pub fn otherwise(&self) -> BasicBlockIdx {
900 self.otherwise
901 }
902
903 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
905 self.branches.iter().copied()
906 }
907
908 pub fn len(&self) -> usize {
910 self.branches.len() + 1
911 }
912
913 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
915 SwitchTargets { branches, otherwise }
916 }
917}
918
919#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
920pub enum BorrowKind {
921 Shared,
923
924 Fake(FakeBorrowKind),
927
928 Mut {
930 kind: MutBorrowKind,
932 },
933}
934
935impl BorrowKind {
936 pub fn to_mutable_lossy(self) -> Mutability {
937 match self {
938 BorrowKind::Mut { .. } => Mutability::Mut,
939 BorrowKind::Shared => Mutability::Not,
940 BorrowKind::Fake(_) => Mutability::Not,
942 }
943 }
944}
945
946#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
947pub enum RawPtrKind {
948 Mut,
949 Const,
950 FakeForPtrMetadata,
951}
952
953impl RawPtrKind {
954 pub fn to_mutable_lossy(self) -> Mutability {
955 match self {
956 RawPtrKind::Mut { .. } => Mutability::Mut,
957 RawPtrKind::Const => Mutability::Not,
958 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
960 }
961 }
962}
963
964#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
965pub enum MutBorrowKind {
966 Default,
967 TwoPhaseBorrow,
968 ClosureCapture,
969}
970
971#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
972pub enum FakeBorrowKind {
973 Deep,
975 Shallow,
980}
981
982#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
983pub enum Mutability {
984 Not,
985 Mut,
986}
987
988#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
989pub enum Safety {
990 Safe,
991 Unsafe,
992}
993
994#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
995pub enum PointerCoercion {
996 ReifyFnPointer,
998
999 UnsafeFnPointer,
1001
1002 ClosureFnPointer(Safety),
1005
1006 MutToConstPointer,
1008
1009 ArrayToPointer,
1011
1012 Unsize,
1019}
1020
1021#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1022pub enum CastKind {
1023 PointerExposeAddress,
1025 PointerWithExposedProvenance,
1026 PointerCoercion(PointerCoercion),
1027 IntToInt,
1028 FloatToInt,
1029 FloatToFloat,
1030 IntToFloat,
1031 PtrToPtr,
1032 FnPtrToPtr,
1033 Transmute,
1034}
1035
1036#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1037pub enum NullOp {
1038 SizeOf,
1040 AlignOf,
1042 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1044 UbChecks,
1046 ContractChecks,
1048}
1049
1050impl Operand {
1051 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1058 match self {
1059 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1060 Operand::Constant(c) => Ok(c.ty()),
1061 }
1062 }
1063}
1064
1065impl ConstOperand {
1066 pub fn ty(&self) -> Ty {
1067 self.const_.ty()
1068 }
1069}
1070
1071impl Place {
1072 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1079 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1080 }
1081}
1082
1083impl ProjectionElem {
1084 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1086 let ty = place_ty;
1087 match &self {
1088 ProjectionElem::Deref => Self::deref_ty(ty),
1089 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1090 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1091 ProjectionElem::Subslice { from, to, from_end } => {
1092 Self::subslice_ty(ty, *from, *to, *from_end)
1093 }
1094 ProjectionElem::Downcast(_) => Ok(ty),
1095 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1096 }
1097 }
1098
1099 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1100 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1101 }
1102
1103 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1104 let ty_kind = ty.kind();
1105 match ty_kind {
1106 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1107 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1108 inner,
1109 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1110 ),
1111 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1112 let size = size.eval_target_usize()?;
1113 let len = size - from - to;
1114 Ty::try_new_array(inner, len)
1115 }
1116 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1117 }
1118 }
1119
1120 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1121 let deref_ty = ty
1122 .kind()
1123 .builtin_deref(true)
1124 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1125 Ok(deref_ty.ty)
1126 }
1127}