rustc_smir/stable_mir/mir/
body.rs

1use std::io;
2
3use serde::Serialize;
4use stable_mir::compiler_interface::with;
5use stable_mir::mir::pretty::function_body;
6use stable_mir::ty::{
7    AdtDef, ClosureDef, CoroutineClosureDef, CoroutineDef, GenericArgs, MirConst, Movability,
8    Region, RigidTy, Ty, TyConst, TyKind, VariantIdx,
9};
10use stable_mir::{Error, Opaque, Span, Symbol};
11
12use crate::stable_mir;
13
14/// The SMIR representation of a single function.
15#[derive(Clone, Debug, Serialize)]
16pub struct Body {
17    pub blocks: Vec<BasicBlock>,
18
19    /// Declarations of locals within the function.
20    ///
21    /// The first local is the return value pointer, followed by `arg_count`
22    /// locals for the function arguments, followed by any user-declared
23    /// variables and temporaries.
24    pub(super) locals: LocalDecls,
25
26    /// The number of arguments this function takes.
27    pub(super) arg_count: usize,
28
29    /// Debug information pertaining to user variables, including captures.
30    pub var_debug_info: Vec<VarDebugInfo>,
31
32    /// Mark an argument (which must be a tuple) as getting passed as its individual components.
33    ///
34    /// This is used for the "rust-call" ABI such as closures.
35    pub(super) spread_arg: Option<Local>,
36
37    /// The span that covers the entire function body.
38    pub span: Span,
39}
40
41pub type BasicBlockIdx = usize;
42
43impl Body {
44    /// Constructs a `Body`.
45    ///
46    /// A constructor is required to build a `Body` from outside the crate
47    /// because the `arg_count` and `locals` fields are private.
48    pub fn new(
49        blocks: Vec<BasicBlock>,
50        locals: LocalDecls,
51        arg_count: usize,
52        var_debug_info: Vec<VarDebugInfo>,
53        spread_arg: Option<Local>,
54        span: Span,
55    ) -> Self {
56        // If locals doesn't contain enough entries, it can lead to panics in
57        // `ret_local`, `arg_locals`, and `inner_locals`.
58        assert!(
59            locals.len() > arg_count,
60            "A Body must contain at least a local for the return value and each of the function's arguments"
61        );
62        Self { blocks, locals, arg_count, var_debug_info, spread_arg, span }
63    }
64
65    /// Return local that holds this function's return value.
66    pub fn ret_local(&self) -> &LocalDecl {
67        &self.locals[RETURN_LOCAL]
68    }
69
70    /// Locals in `self` that correspond to this function's arguments.
71    pub fn arg_locals(&self) -> &[LocalDecl] {
72        &self.locals[1..][..self.arg_count]
73    }
74
75    /// Inner locals for this function. These are the locals that are
76    /// neither the return local nor the argument locals.
77    pub fn inner_locals(&self) -> &[LocalDecl] {
78        &self.locals[self.arg_count + 1..]
79    }
80
81    /// Returns a mutable reference to the local that holds this function's return value.
82    pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl {
83        &mut self.locals[RETURN_LOCAL]
84    }
85
86    /// Returns a mutable slice of locals corresponding to this function's arguments.
87    pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] {
88        &mut self.locals[1..][..self.arg_count]
89    }
90
91    /// Returns a mutable slice of inner locals for this function.
92    /// Inner locals are those that are neither the return local nor the argument locals.
93    pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] {
94        &mut self.locals[self.arg_count + 1..]
95    }
96
97    /// Convenience function to get all the locals in this function.
98    ///
99    /// Locals are typically accessed via the more specific methods `ret_local`,
100    /// `arg_locals`, and `inner_locals`.
101    pub fn locals(&self) -> &[LocalDecl] {
102        &self.locals
103    }
104
105    /// Get the local declaration for this local.
106    pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
107        self.locals.get(local)
108    }
109
110    /// Get an iterator for all local declarations.
111    pub fn local_decls(&self) -> impl Iterator<Item = (Local, &LocalDecl)> {
112        self.locals.iter().enumerate()
113    }
114
115    /// Emit the body using the provided name for the signature.
116    pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
117        function_body(w, self, fn_name)
118    }
119
120    pub fn spread_arg(&self) -> Option<Local> {
121        self.spread_arg
122    }
123}
124
125type LocalDecls = Vec<LocalDecl>;
126
127#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
128pub struct LocalDecl {
129    pub ty: Ty,
130    pub span: Span,
131    pub mutability: Mutability,
132}
133
134#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
135pub struct BasicBlock {
136    pub statements: Vec<Statement>,
137    pub terminator: Terminator,
138}
139
140#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
141pub struct Terminator {
142    pub kind: TerminatorKind,
143    pub span: Span,
144}
145
146impl Terminator {
147    pub fn successors(&self) -> Successors {
148        self.kind.successors()
149    }
150}
151
152pub type Successors = Vec<BasicBlockIdx>;
153
154#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
155pub enum TerminatorKind {
156    Goto {
157        target: BasicBlockIdx,
158    },
159    SwitchInt {
160        discr: Operand,
161        targets: SwitchTargets,
162    },
163    Resume,
164    Abort,
165    Return,
166    Unreachable,
167    Drop {
168        place: Place,
169        target: BasicBlockIdx,
170        unwind: UnwindAction,
171    },
172    Call {
173        func: Operand,
174        args: Vec<Operand>,
175        destination: Place,
176        target: Option<BasicBlockIdx>,
177        unwind: UnwindAction,
178    },
179    Assert {
180        cond: Operand,
181        expected: bool,
182        msg: AssertMessage,
183        target: BasicBlockIdx,
184        unwind: UnwindAction,
185    },
186    InlineAsm {
187        template: String,
188        operands: Vec<InlineAsmOperand>,
189        options: String,
190        line_spans: String,
191        destination: Option<BasicBlockIdx>,
192        unwind: UnwindAction,
193    },
194}
195
196impl TerminatorKind {
197    pub fn successors(&self) -> Successors {
198        use self::TerminatorKind::*;
199        match *self {
200            Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
201            | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
202            | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
203            | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
204                vec![t, u]
205            }
206            Goto { target: t }
207            | Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
208            | Call { target: Some(t), unwind: _, .. }
209            | Drop { target: t, unwind: _, .. }
210            | Assert { target: t, unwind: _, .. }
211            | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
212            | InlineAsm { destination: Some(t), unwind: _, .. } => {
213                vec![t]
214            }
215
216            Return
217            | Resume
218            | Abort
219            | Unreachable
220            | Call { target: None, unwind: _, .. }
221            | InlineAsm { destination: None, unwind: _, .. } => {
222                vec![]
223            }
224            SwitchInt { ref targets, .. } => targets.all_targets(),
225        }
226    }
227
228    pub fn unwind(&self) -> Option<&UnwindAction> {
229        match *self {
230            TerminatorKind::Goto { .. }
231            | TerminatorKind::Return
232            | TerminatorKind::Unreachable
233            | TerminatorKind::Resume
234            | TerminatorKind::Abort
235            | TerminatorKind::SwitchInt { .. } => None,
236            TerminatorKind::Call { ref unwind, .. }
237            | TerminatorKind::Assert { ref unwind, .. }
238            | TerminatorKind::Drop { ref unwind, .. }
239            | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
240        }
241    }
242}
243
244#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
245pub struct InlineAsmOperand {
246    pub in_value: Option<Operand>,
247    pub out_place: Option<Place>,
248    // This field has a raw debug representation of MIR's InlineAsmOperand.
249    // For now we care about place/operand + the rest in a debug format.
250    pub raw_rpr: String,
251}
252
253#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
254pub enum UnwindAction {
255    Continue,
256    Unreachable,
257    Terminate,
258    Cleanup(BasicBlockIdx),
259}
260
261#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
262pub enum AssertMessage {
263    BoundsCheck { len: Operand, index: Operand },
264    Overflow(BinOp, Operand, Operand),
265    OverflowNeg(Operand),
266    DivisionByZero(Operand),
267    RemainderByZero(Operand),
268    ResumedAfterReturn(CoroutineKind),
269    ResumedAfterPanic(CoroutineKind),
270    ResumedAfterDrop(CoroutineKind),
271    MisalignedPointerDereference { required: Operand, found: Operand },
272    NullPointerDereference,
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        }
346    }
347}
348
349#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
350pub enum BinOp {
351    Add,
352    AddUnchecked,
353    Sub,
354    SubUnchecked,
355    Mul,
356    MulUnchecked,
357    Div,
358    Rem,
359    BitXor,
360    BitAnd,
361    BitOr,
362    Shl,
363    ShlUnchecked,
364    Shr,
365    ShrUnchecked,
366    Eq,
367    Lt,
368    Le,
369    Ne,
370    Ge,
371    Gt,
372    Cmp,
373    Offset,
374}
375
376impl BinOp {
377    /// Return the type of this operation for the given input Ty.
378    /// This function does not perform type checking, and it currently doesn't handle SIMD.
379    pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
380        with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
381    }
382}
383
384#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
385pub enum UnOp {
386    Not,
387    Neg,
388    PtrMetadata,
389}
390
391impl UnOp {
392    /// Return the type of this operation for the given input Ty.
393    /// This function does not perform type checking, and it currently doesn't handle SIMD.
394    pub fn ty(&self, arg_ty: Ty) -> Ty {
395        with(|ctx| ctx.unop_ty(*self, arg_ty))
396    }
397}
398
399#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
400pub enum CoroutineKind {
401    Desugared(CoroutineDesugaring, CoroutineSource),
402    Coroutine(Movability),
403}
404
405#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
406pub enum CoroutineSource {
407    Block,
408    Closure,
409    Fn,
410}
411
412#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
413pub enum CoroutineDesugaring {
414    Async,
415
416    Gen,
417
418    AsyncGen,
419}
420
421pub(crate) type LocalDefId = Opaque;
422/// The rustc coverage data structures are heavily tied to internal details of the
423/// coverage implementation that are likely to change, and are unlikely to be
424/// useful to third-party tools for the foreseeable future.
425pub(crate) type Coverage = Opaque;
426
427/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
428#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
429pub enum FakeReadCause {
430    ForMatchGuard,
431    ForMatchedPlace(LocalDefId),
432    ForGuardBinding,
433    ForLet(LocalDefId),
434    ForIndex,
435}
436
437/// Describes what kind of retag is to be performed
438#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
439pub enum RetagKind {
440    FnEntry,
441    TwoPhase,
442    Raw,
443    Default,
444}
445
446#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
447pub enum Variance {
448    Covariant,
449    Invariant,
450    Contravariant,
451    Bivariant,
452}
453
454#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
455pub struct CopyNonOverlapping {
456    pub src: Operand,
457    pub dst: Operand,
458    pub count: Operand,
459}
460
461#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
462pub enum NonDivergingIntrinsic {
463    Assume(Operand),
464    CopyNonOverlapping(CopyNonOverlapping),
465}
466
467#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
468pub struct Statement {
469    pub kind: StatementKind,
470    pub span: Span,
471}
472
473#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
474pub enum StatementKind {
475    Assign(Place, Rvalue),
476    FakeRead(FakeReadCause, Place),
477    SetDiscriminant { place: Place, variant_index: VariantIdx },
478    Deinit(Place),
479    StorageLive(Local),
480    StorageDead(Local),
481    Retag(RetagKind, Place),
482    PlaceMention(Place),
483    AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
484    Coverage(Coverage),
485    Intrinsic(NonDivergingIntrinsic),
486    ConstEvalCounter,
487    Nop,
488}
489
490#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
491pub enum Rvalue {
492    /// Creates a pointer with the indicated mutability to the place.
493    ///
494    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
495    /// `&raw v` or `addr_of!(v)`.
496    AddressOf(RawPtrKind, Place),
497
498    /// Creates an aggregate value, like a tuple or struct.
499    ///
500    /// This is needed because dataflow analysis needs to distinguish
501    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
502    /// has a destructor.
503    ///
504    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
505    /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
506    Aggregate(AggregateKind, Vec<Operand>),
507
508    /// * `Offset` has the same semantics as `<*const T>::offset`, except that the second
509    ///   parameter may be a `usize` as well.
510    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
511    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
512    ///   matching, up to the usual caveat of the lifetimes in function pointers.
513    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
514    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
515    ///   truncated as needed.
516    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
517    ///   types and return a value of that type.
518    /// * The remaining operations accept signed integers, unsigned integers, or floats with
519    ///   matching types and return a value of that type.
520    BinaryOp(BinOp, Operand, Operand),
521
522    /// Performs essentially all of the casts that can be performed via `as`.
523    ///
524    /// This allows for casts from/to a variety of types.
525    Cast(CastKind, Operand, Ty),
526
527    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
528    ///
529    /// For addition, subtraction, and multiplication on integers the error condition is set when
530    /// the infinite precision result would not be equal to the actual result.
531    CheckedBinaryOp(BinOp, Operand, Operand),
532
533    /// A CopyForDeref is equivalent to a read from a place.
534    /// When such a read happens, it is guaranteed that the only use of the returned value is a
535    /// deref operation, immediately followed by one or more projections.
536    CopyForDeref(Place),
537
538    /// Computes the discriminant of the place, returning it as an integer.
539    /// Returns zero for types without discriminant.
540    ///
541    /// The validity requirements for the underlying value are undecided for this rvalue, see
542    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
543    /// variant index;
544    ///
545    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
546    Discriminant(Place),
547
548    /// Yields the length of the place, as a `usize`.
549    ///
550    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
551    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
552    /// ill-formed for places of other types.
553    Len(Place),
554
555    /// Creates a reference to the place.
556    Ref(Region, BorrowKind, Place),
557
558    /// Creates an array where each element is the value of the operand.
559    ///
560    /// This is the cause of a bug in the case where the repetition count is zero because the value
561    /// is not dropped, see [#74836].
562    ///
563    /// Corresponds to source code like `[x; 32]`.
564    ///
565    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
566    Repeat(Operand, TyConst),
567
568    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
569    ///
570    /// This is different from a normal transmute because dataflow analysis will treat the box as
571    /// initialized but its content as uninitialized. Like other pointer casts, this in general
572    /// affects alias analysis.
573    ShallowInitBox(Operand, Ty),
574
575    /// Creates a pointer/reference to the given thread local.
576    ///
577    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
578    /// `*const T`, and if neither of those apply a `&T`.
579    ///
580    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
581    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
582    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
583    ///
584    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
585    /// nature of this operation?
586    ThreadLocalRef(stable_mir::CrateItem),
587
588    /// Computes a value as described by the operation.
589    NullaryOp(NullOp, Ty),
590
591    /// Exactly like `BinaryOp`, but less operands.
592    ///
593    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
594    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
595    /// return a value with the same type as their operand.
596    UnaryOp(UnOp, Operand),
597
598    /// Yields the operand unchanged
599    Use(Operand),
600}
601
602impl Rvalue {
603    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
604        match self {
605            Rvalue::Use(operand) => operand.ty(locals),
606            Rvalue::Repeat(operand, count) => {
607                Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
608            }
609            Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
610            Rvalue::Ref(reg, bk, place) => {
611                let place_ty = place.ty(locals)?;
612                Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
613            }
614            Rvalue::AddressOf(mutability, place) => {
615                let place_ty = place.ty(locals)?;
616                Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
617            }
618            Rvalue::Len(..) => Ok(Ty::usize_ty()),
619            Rvalue::Cast(.., ty) => Ok(*ty),
620            Rvalue::BinaryOp(op, lhs, rhs) => {
621                let lhs_ty = lhs.ty(locals)?;
622                let rhs_ty = rhs.ty(locals)?;
623                Ok(op.ty(lhs_ty, rhs_ty))
624            }
625            Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
626                let lhs_ty = lhs.ty(locals)?;
627                let rhs_ty = rhs.ty(locals)?;
628                let ty = op.ty(lhs_ty, rhs_ty);
629                Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
630            }
631            Rvalue::UnaryOp(op, operand) => {
632                let arg_ty = operand.ty(locals)?;
633                Ok(op.ty(arg_ty))
634            }
635            Rvalue::Discriminant(place) => {
636                let place_ty = place.ty(locals)?;
637                place_ty
638                    .kind()
639                    .discriminant_ty()
640                    .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
641            }
642            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
643                Ok(Ty::usize_ty())
644            }
645            Rvalue::NullaryOp(NullOp::ContractChecks, _)
646            | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
647            Rvalue::Aggregate(ak, ops) => match *ak {
648                AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
649                AggregateKind::Tuple => Ok(Ty::new_tuple(
650                    &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
651                )),
652                AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
653                AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
654                AggregateKind::Coroutine(def, ref args, mov) => {
655                    Ok(Ty::new_coroutine(def, args.clone(), mov))
656                }
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, Serialize)]
669pub enum AggregateKind {
670    Array(Ty),
671    Tuple,
672    Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
673    Closure(ClosureDef, GenericArgs),
674    // FIXME(stable_mir): Movability here is redundant
675    Coroutine(CoroutineDef, GenericArgs, Movability),
676    CoroutineClosure(CoroutineClosureDef, GenericArgs),
677    RawPtr(Ty, Mutability),
678}
679
680#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
681pub enum Operand {
682    Copy(Place),
683    Move(Place),
684    Constant(ConstOperand),
685}
686
687#[derive(Clone, Eq, PartialEq, Serialize)]
688pub struct Place {
689    pub local: Local,
690    /// projection out of a place (access a field, deref a pointer, etc)
691    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, Serialize)]
701pub struct ConstOperand {
702    pub span: Span,
703    pub user_ty: Option<UserTypeAnnotationIndex>,
704    pub const_: MirConst,
705}
706
707/// Debug information pertaining to a user variable.
708#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
709pub struct VarDebugInfo {
710    /// The variable name.
711    pub name: Symbol,
712
713    /// Source info of the user variable, including the scope
714    /// within which the variable is visible (to debuginfo).
715    pub source_info: SourceInfo,
716
717    /// The user variable's data is split across several fragments,
718    /// each described by a `VarDebugInfoFragment`.
719    pub composite: Option<VarDebugInfoFragment>,
720
721    /// Where the data for this user variable is to be found.
722    pub value: VarDebugInfoContents,
723
724    /// When present, indicates what argument number this variable is in the function that it
725    /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
726    /// argument number in the original function before it was inlined.
727    pub argument_index: Option<u16>,
728}
729
730impl VarDebugInfo {
731    /// Return a local variable if this info is related to one.
732    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    /// Return a constant if this info is related to one.
740    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// In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This
769// is so it can be used for both Places (for which the projection elements are of type
770// ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements
771// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use
772// ProjectionElem for Places.
773#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
774pub enum ProjectionElem {
775    /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
776    Deref,
777
778    /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is
779    /// referenced by source-order index rather than the name of the field. The fields type is also
780    /// given.
781    Field(FieldIdx, Ty),
782
783    /// Index into a slice/array. The value of the index is computed at runtime using the `V`
784    /// argument.
785    ///
786    /// Note that this does not also dereference, and so it does not exactly correspond to slice
787    /// indexing in Rust. In other words, in the below Rust code:
788    ///
789    /// ```rust
790    /// let x = &[1, 2, 3, 4];
791    /// let i = 2;
792    /// x[i];
793    /// ```
794    ///
795    /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same
796    /// thing is true of the `ConstantIndex` and `Subslice` projections below.
797    Index(Local),
798
799    /// Index into a slice/array given by offsets.
800    ///
801    /// These indices are generated by slice patterns. Easiest to explain by example:
802    ///
803    /// ```ignore (illustrative)
804    /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false },
805    /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false },
806    /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true },
807    /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true },
808    /// ```
809    ConstantIndex {
810        /// index or -index (in Python terms), depending on from_end
811        offset: u64,
812        /// The thing being indexed must be at least this long -- otherwise, the
813        /// projection is UB.
814        ///
815        /// For arrays this is always the exact length.
816        min_length: u64,
817        /// Counting backwards from end? This is always false when indexing an
818        /// array.
819        from_end: bool,
820    },
821
822    /// Projects a slice from the base place.
823    ///
824    /// These indices are generated by slice patterns. If `from_end` is true, this represents
825    /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`.
826    Subslice {
827        from: u64,
828        to: u64,
829        /// Whether `to` counts from the start or end of the array/slice.
830        from_end: bool,
831    },
832
833    /// "Downcast" to a variant of an enum or a coroutine.
834    Downcast(VariantIdx),
835
836    /// Like an explicit cast from an opaque type to a concrete type, but without
837    /// requiring an intermediate variable.
838    OpaqueCast(Ty),
839
840    /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
841    /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
842    /// explicit during optimizations and codegen.
843    ///
844    /// This projection doesn't impact the runtime behavior of the program except for potentially changing
845    /// some type metadata of the interpreter or codegen backend.
846    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
860/// The source-order index of a field in a variant.
861///
862/// For example, in the following types,
863/// ```ignore(illustrative)
864/// enum Demo1 {
865///    Variant0 { a: bool, b: i32 },
866///    Variant1 { c: u8, d: u64 },
867/// }
868/// struct Demo2 { e: u8, f: u16, g: u8 }
869/// ```
870/// `a`'s `FieldIdx` is `0`,
871/// `b`'s `FieldIdx` is `1`,
872/// `c`'s `FieldIdx` is `0`, and
873/// `g`'s `FieldIdx` is `2`.
874pub type FieldIdx = usize;
875
876type UserTypeAnnotationIndex = usize;
877
878/// The possible branch sites of a [TerminatorKind::SwitchInt].
879#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
880pub struct SwitchTargets {
881    /// The conditional branches where the first element represents the value that guards this
882    /// branch, and the second element is the branch target.
883    branches: Vec<(u128, BasicBlockIdx)>,
884    /// The `otherwise` branch which will be taken in case none of the conditional branches are
885    /// satisfied.
886    otherwise: BasicBlockIdx,
887}
888
889impl SwitchTargets {
890    /// All possible targets including the `otherwise` target.
891    pub fn all_targets(&self) -> Successors {
892        self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
893    }
894
895    /// The `otherwise` branch target.
896    pub fn otherwise(&self) -> BasicBlockIdx {
897        self.otherwise
898    }
899
900    /// The conditional targets which are only taken if the pattern matches the given value.
901    pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
902        self.branches.iter().copied()
903    }
904
905    /// The number of targets including `otherwise`.
906    pub fn len(&self) -> usize {
907        self.branches.len() + 1
908    }
909
910    /// Create a new SwitchTargets from the given branches and `otherwise` target.
911    pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
912        SwitchTargets { branches, otherwise }
913    }
914}
915
916#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
917pub enum BorrowKind {
918    /// Data must be immutable and is aliasable.
919    Shared,
920
921    /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
922    /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
923    Fake(FakeBorrowKind),
924
925    /// Data is mutable and not aliasable.
926    Mut {
927        /// `true` if this borrow arose from method-call auto-ref
928        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            // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
938            BorrowKind::Fake(_) => Mutability::Not,
939        }
940    }
941}
942
943#[derive(Copy, Clone, Debug, Eq, PartialEq, 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            // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
956            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
957        }
958    }
959}
960
961#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
962pub enum MutBorrowKind {
963    Default,
964    TwoPhaseBorrow,
965    ClosureCapture,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
969pub enum FakeBorrowKind {
970    /// A shared (deep) borrow. Data must be immutable and is aliasable.
971    Deep,
972    /// The immediately borrowed place must be immutable, but projections from
973    /// it don't need to be. This is used to prevent match guards from replacing
974    /// the scrutinee. For example, a fake borrow of `a.b` doesn't
975    /// conflict with a mutable borrow of `a.b.c`.
976    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, Serialize)]
986pub enum Safety {
987    Safe,
988    Unsafe,
989}
990
991#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
992pub enum PointerCoercion {
993    /// Go from a fn-item type to a fn-pointer type.
994    ReifyFnPointer,
995
996    /// Go from a safe fn pointer to an unsafe fn pointer.
997    UnsafeFnPointer,
998
999    /// Go from a non-capturing closure to a fn pointer or an unsafe fn pointer.
1000    /// It cannot convert a closure that requires unsafe.
1001    ClosureFnPointer(Safety),
1002
1003    /// Go from a mut raw pointer to a const raw pointer.
1004    MutToConstPointer,
1005
1006    /// Go from `*const [T; N]` to `*const T`
1007    ArrayToPointer,
1008
1009    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
1010    /// `&[T]`. Note that the source could be a thin or wide pointer.
1011    /// This will do things like convert thin pointers to wide
1012    /// pointers, or convert structs containing thin pointers to
1013    /// structs containing wide pointers, or convert between wide
1014    /// pointers.
1015    Unsize,
1016}
1017
1018#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1019pub enum CastKind {
1020    // FIXME(smir-rename): rename this to PointerExposeProvenance
1021    PointerExposeAddress,
1022    PointerWithExposedProvenance,
1023    PointerCoercion(PointerCoercion),
1024    // FIXME(smir-rename): change this to PointerCoercion(DynStar)
1025    DynStar,
1026    IntToInt,
1027    FloatToInt,
1028    FloatToFloat,
1029    IntToFloat,
1030    PtrToPtr,
1031    FnPtrToPtr,
1032    Transmute,
1033}
1034
1035#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1036pub enum NullOp {
1037    /// Returns the size of a value of that type.
1038    SizeOf,
1039    /// Returns the minimum alignment of a type.
1040    AlignOf,
1041    /// Returns the offset of a field.
1042    OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1043    /// cfg!(ub_checks), but at codegen time
1044    UbChecks,
1045    /// cfg!(contract_checks), but at codegen time
1046    ContractChecks,
1047}
1048
1049impl Operand {
1050    /// Get the type of an operand relative to the local declaration.
1051    ///
1052    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1053    /// locals from the function body where this operand originates from.
1054    ///
1055    /// Errors indicate a malformed operand or incompatible locals list.
1056    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1057        match self {
1058            Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1059            Operand::Constant(c) => Ok(c.ty()),
1060        }
1061    }
1062}
1063
1064impl ConstOperand {
1065    pub fn ty(&self) -> Ty {
1066        self.const_.ty()
1067    }
1068}
1069
1070impl Place {
1071    /// Resolve down the chain of projections to get the type referenced at the end of it.
1072    /// E.g.:
1073    /// Calling `ty()` on `var.field` should return the type of `field`.
1074    ///
1075    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1076    /// locals from the function body where this place originates from.
1077    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1078        self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1079    }
1080}
1081
1082impl ProjectionElem {
1083    /// Get the expected type after applying this projection to a given place type.
1084    pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1085        let ty = place_ty;
1086        match &self {
1087            ProjectionElem::Deref => Self::deref_ty(ty),
1088            ProjectionElem::Field(_idx, fty) => Ok(*fty),
1089            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1090            ProjectionElem::Subslice { from, to, from_end } => {
1091                Self::subslice_ty(ty, *from, *to, *from_end)
1092            }
1093            ProjectionElem::Downcast(_) => Ok(ty),
1094            ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1095        }
1096    }
1097
1098    fn index_ty(ty: Ty) -> Result<Ty, Error> {
1099        ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1100    }
1101
1102    fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1103        let ty_kind = ty.kind();
1104        match ty_kind {
1105            TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1106            TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1107                inner,
1108                to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1109            ),
1110            TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1111                let size = size.eval_target_usize()?;
1112                let len = size - from - to;
1113                Ty::try_new_array(inner, len)
1114            }
1115            _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1116        }
1117    }
1118
1119    fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1120        let deref_ty = ty
1121            .kind()
1122            .builtin_deref(true)
1123            .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1124        Ok(deref_ty.ty)
1125    }
1126}