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 UnaryOp(UnOp, Operand),
596
597 Use(Operand),
599}
600
601impl Rvalue {
602 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
603 match self {
604 Rvalue::Use(operand) => operand.ty(locals),
605 Rvalue::Repeat(operand, count) => {
606 Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
607 }
608 Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
609 Rvalue::Ref(reg, bk, place) => {
610 let place_ty = place.ty(locals)?;
611 Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
612 }
613 Rvalue::AddressOf(mutability, place) => {
614 let place_ty = place.ty(locals)?;
615 Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
616 }
617 Rvalue::Len(..) => Ok(Ty::usize_ty()),
618 Rvalue::Cast(.., ty) => Ok(*ty),
619 Rvalue::BinaryOp(op, lhs, rhs) => {
620 let lhs_ty = lhs.ty(locals)?;
621 let rhs_ty = rhs.ty(locals)?;
622 Ok(op.ty(lhs_ty, rhs_ty))
623 }
624 Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
625 let lhs_ty = lhs.ty(locals)?;
626 let rhs_ty = rhs.ty(locals)?;
627 let ty = op.ty(lhs_ty, rhs_ty);
628 Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
629 }
630 Rvalue::UnaryOp(op, operand) => {
631 let arg_ty = operand.ty(locals)?;
632 Ok(op.ty(arg_ty))
633 }
634 Rvalue::Discriminant(place) => {
635 let place_ty = place.ty(locals)?;
636 place_ty
637 .kind()
638 .discriminant_ty()
639 .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
640 }
641 Rvalue::Aggregate(ak, ops) => match *ak {
642 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
643 AggregateKind::Tuple => Ok(Ty::new_tuple(
644 &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
645 )),
646 AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
647 AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
648 AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
649 AggregateKind::CoroutineClosure(def, ref args) => {
650 Ok(Ty::new_coroutine_closure(def, args.clone()))
651 }
652 AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
653 },
654 Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
655 Rvalue::CopyForDeref(place) => place.ty(locals),
656 }
657 }
658}
659
660#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
661pub enum AggregateKind {
662 Array(Ty),
663 Tuple,
664 Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
665 Closure(ClosureDef, GenericArgs),
666 Coroutine(CoroutineDef, GenericArgs),
667 CoroutineClosure(CoroutineClosureDef, GenericArgs),
668 RawPtr(Ty, Mutability),
669}
670
671#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
672pub enum Operand {
673 Copy(Place),
674 Move(Place),
675 Constant(ConstOperand),
676 RuntimeChecks(RuntimeChecks),
677}
678
679#[derive(Clone, Eq, PartialEq, Hash, Serialize)]
680pub struct Place {
681 pub local: Local,
682 pub projection: Vec<ProjectionElem>,
684}
685
686impl From<Local> for Place {
687 fn from(local: Local) -> Self {
688 Place { local, projection: vec![] }
689 }
690}
691
692#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
693pub struct ConstOperand {
694 pub span: Span,
695 pub user_ty: Option<UserTypeAnnotationIndex>,
696 pub const_: MirConst,
697}
698
699#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
700pub enum RuntimeChecks {
701 UbChecks,
703 ContractChecks,
705 OverflowChecks,
707}
708
709#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
711pub struct VarDebugInfo {
712 pub name: Symbol,
714
715 pub source_info: SourceInfo,
718
719 pub composite: Option<VarDebugInfoFragment>,
722
723 pub value: VarDebugInfoContents,
725
726 pub argument_index: Option<u16>,
730}
731
732impl VarDebugInfo {
733 pub fn local(&self) -> Option<Local> {
735 match &self.value {
736 VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
737 VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
738 }
739 }
740
741 pub fn constant(&self) -> Option<&ConstOperand> {
743 match &self.value {
744 VarDebugInfoContents::Place(_) => None,
745 VarDebugInfoContents::Const(const_op) => Some(const_op),
746 }
747 }
748}
749
750pub type SourceScope = u32;
751
752#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
753pub struct SourceInfo {
754 pub span: Span,
755 pub scope: SourceScope,
756}
757
758#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
759pub struct VarDebugInfoFragment {
760 pub ty: Ty,
761 pub projection: Vec<ProjectionElem>,
762}
763
764#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
765pub enum VarDebugInfoContents {
766 Place(Place),
767 Const(ConstOperand),
768}
769
770#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
776pub enum ProjectionElem {
777 Deref,
779
780 Field(FieldIdx, Ty),
784
785 Index(Local),
800
801 ConstantIndex {
812 offset: u64,
814 min_length: u64,
819 from_end: bool,
822 },
823
824 Subslice {
829 from: u64,
830 to: u64,
831 from_end: bool,
833 },
834
835 Downcast(VariantIdx),
837
838 OpaqueCast(Ty),
841}
842
843#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
844pub struct UserTypeProjection {
845 pub base: UserTypeAnnotationIndex,
846
847 pub projection: Opaque,
848}
849
850pub type Local = usize;
851
852pub const RETURN_LOCAL: Local = 0;
853
854pub type FieldIdx = usize;
869
870type UserTypeAnnotationIndex = usize;
871
872#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
874pub struct SwitchTargets {
875 branches: Vec<(u128, BasicBlockIdx)>,
878 otherwise: BasicBlockIdx,
881}
882
883impl SwitchTargets {
884 pub fn all_targets(&self) -> Successors {
886 self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
887 }
888
889 pub fn otherwise(&self) -> BasicBlockIdx {
891 self.otherwise
892 }
893
894 pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
896 self.branches.iter().copied()
897 }
898
899 pub fn len(&self) -> usize {
901 self.branches.len() + 1
902 }
903
904 pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
906 SwitchTargets { branches, otherwise }
907 }
908}
909
910#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
911pub enum BorrowKind {
912 Shared,
914
915 Fake(FakeBorrowKind),
918
919 Mut {
921 kind: MutBorrowKind,
923 },
924}
925
926impl BorrowKind {
927 pub fn to_mutable_lossy(self) -> Mutability {
928 match self {
929 BorrowKind::Mut { .. } => Mutability::Mut,
930 BorrowKind::Shared => Mutability::Not,
931 BorrowKind::Fake(_) => Mutability::Not,
933 }
934 }
935}
936
937#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
938pub enum RawPtrKind {
939 Mut,
940 Const,
941 FakeForPtrMetadata,
942}
943
944impl RawPtrKind {
945 pub fn to_mutable_lossy(self) -> Mutability {
946 match self {
947 RawPtrKind::Mut { .. } => Mutability::Mut,
948 RawPtrKind::Const => Mutability::Not,
949 RawPtrKind::FakeForPtrMetadata => Mutability::Not,
951 }
952 }
953}
954
955#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
956pub enum MutBorrowKind {
957 Default,
958 TwoPhaseBorrow,
959 ClosureCapture,
960}
961
962#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
963pub enum FakeBorrowKind {
964 Deep,
966 Shallow,
971}
972
973#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
974pub enum Mutability {
975 Not,
976 Mut,
977}
978
979#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
980pub enum Safety {
981 Safe,
982 Unsafe,
983}
984
985#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
986pub enum PointerCoercion {
987 ReifyFnPointer(Safety),
989
990 UnsafeFnPointer,
992
993 ClosureFnPointer(Safety),
996
997 MutToConstPointer,
999
1000 ArrayToPointer,
1002
1003 Unsize,
1010}
1011
1012#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1013pub enum CastKind {
1014 PointerExposeAddress,
1016 PointerWithExposedProvenance,
1017 PointerCoercion(PointerCoercion),
1018 IntToInt,
1019 FloatToInt,
1020 FloatToFloat,
1021 IntToFloat,
1022 PtrToPtr,
1023 FnPtrToPtr,
1024 Transmute,
1025 Subtype,
1026}
1027
1028impl Operand {
1029 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1036 match self {
1037 Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1038 Operand::Constant(c) => Ok(c.ty()),
1039 Operand::RuntimeChecks(_) => Ok(Ty::bool_ty()),
1040 }
1041 }
1042}
1043
1044impl ConstOperand {
1045 pub fn ty(&self) -> Ty {
1046 self.const_.ty()
1047 }
1048}
1049
1050impl Place {
1051 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1058 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1059 }
1060}
1061
1062impl ProjectionElem {
1063 pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1065 let ty = place_ty;
1066 match &self {
1067 ProjectionElem::Deref => Self::deref_ty(ty),
1068 ProjectionElem::Field(_idx, fty) => Ok(*fty),
1069 ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1070 ProjectionElem::Subslice { from, to, from_end } => {
1071 Self::subslice_ty(ty, *from, *to, *from_end)
1072 }
1073 ProjectionElem::Downcast(_) => Ok(ty),
1074 ProjectionElem::OpaqueCast(ty) => Ok(*ty),
1075 }
1076 }
1077
1078 fn index_ty(ty: Ty) -> Result<Ty, Error> {
1079 ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1080 }
1081
1082 fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1083 let ty_kind = ty.kind();
1084 match ty_kind {
1085 TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1086 TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1087 inner,
1088 to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1089 ),
1090 TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1091 let size = size.eval_target_usize()?;
1092 let len = size - from - to;
1093 Ty::try_new_array(inner, len)
1094 }
1095 _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1096 }
1097 }
1098
1099 fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1100 let deref_ty = ty
1101 .kind()
1102 .builtin_deref(true)
1103 .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1104 Ok(deref_ty.ty)
1105 }
1106}