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    MisalignedPointerDereference { required: Operand, found: Operand },
271    NullPointerDereference,
272}
273
274impl AssertMessage {
275    pub fn description(&self) -> Result<&'static str, Error> {
276        match self {
277            AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
278            AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
279            AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
280            AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
281            AssertMessage::Overflow(BinOp::Rem, _, _) => {
282                Ok("attempt to calculate the remainder with overflow")
283            }
284            AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
285            AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
286            AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
287            AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
288            AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
289            AssertMessage::RemainderByZero(_) => {
290                Ok("attempt to calculate the remainder with a divisor of zero")
291            }
292            AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
293                Ok("coroutine resumed after completion")
294            }
295            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
296                CoroutineDesugaring::Async,
297                _,
298            )) => Ok("`async fn` resumed after completion"),
299            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
300                CoroutineDesugaring::Gen,
301                _,
302            )) => Ok("`async gen fn` resumed after completion"),
303            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
304                CoroutineDesugaring::AsyncGen,
305                _,
306            )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
307            AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
308                Ok("coroutine resumed after panicking")
309            }
310            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
311                CoroutineDesugaring::Async,
312                _,
313            )) => Ok("`async fn` resumed after panicking"),
314            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
315                CoroutineDesugaring::Gen,
316                _,
317            )) => Ok("`async gen fn` resumed after panicking"),
318            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
319                CoroutineDesugaring::AsyncGen,
320                _,
321            )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
322
323            AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
324            AssertMessage::MisalignedPointerDereference { .. } => {
325                Ok("misaligned pointer dereference")
326            }
327            AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
328        }
329    }
330}
331
332#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
333pub enum BinOp {
334    Add,
335    AddUnchecked,
336    Sub,
337    SubUnchecked,
338    Mul,
339    MulUnchecked,
340    Div,
341    Rem,
342    BitXor,
343    BitAnd,
344    BitOr,
345    Shl,
346    ShlUnchecked,
347    Shr,
348    ShrUnchecked,
349    Eq,
350    Lt,
351    Le,
352    Ne,
353    Ge,
354    Gt,
355    Cmp,
356    Offset,
357}
358
359impl BinOp {
360    /// Return the type of this operation for the given input Ty.
361    /// This function does not perform type checking, and it currently doesn't handle SIMD.
362    pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
363        with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
364    }
365}
366
367#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
368pub enum UnOp {
369    Not,
370    Neg,
371    PtrMetadata,
372}
373
374impl UnOp {
375    /// Return the type of this operation for the given input Ty.
376    /// This function does not perform type checking, and it currently doesn't handle SIMD.
377    pub fn ty(&self, arg_ty: Ty) -> Ty {
378        with(|ctx| ctx.unop_ty(*self, arg_ty))
379    }
380}
381
382#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
383pub enum CoroutineKind {
384    Desugared(CoroutineDesugaring, CoroutineSource),
385    Coroutine(Movability),
386}
387
388#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
389pub enum CoroutineSource {
390    Block,
391    Closure,
392    Fn,
393}
394
395#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
396pub enum CoroutineDesugaring {
397    Async,
398
399    Gen,
400
401    AsyncGen,
402}
403
404pub(crate) type LocalDefId = Opaque;
405/// The rustc coverage data structures are heavily tied to internal details of the
406/// coverage implementation that are likely to change, and are unlikely to be
407/// useful to third-party tools for the foreseeable future.
408pub(crate) type Coverage = Opaque;
409
410/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
411#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
412pub enum FakeReadCause {
413    ForMatchGuard,
414    ForMatchedPlace(LocalDefId),
415    ForGuardBinding,
416    ForLet(LocalDefId),
417    ForIndex,
418}
419
420/// Describes what kind of retag is to be performed
421#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
422pub enum RetagKind {
423    FnEntry,
424    TwoPhase,
425    Raw,
426    Default,
427}
428
429#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
430pub enum Variance {
431    Covariant,
432    Invariant,
433    Contravariant,
434    Bivariant,
435}
436
437#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
438pub struct CopyNonOverlapping {
439    pub src: Operand,
440    pub dst: Operand,
441    pub count: Operand,
442}
443
444#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
445pub enum NonDivergingIntrinsic {
446    Assume(Operand),
447    CopyNonOverlapping(CopyNonOverlapping),
448}
449
450#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
451pub struct Statement {
452    pub kind: StatementKind,
453    pub span: Span,
454}
455
456#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
457pub enum StatementKind {
458    Assign(Place, Rvalue),
459    FakeRead(FakeReadCause, Place),
460    SetDiscriminant { place: Place, variant_index: VariantIdx },
461    Deinit(Place),
462    StorageLive(Local),
463    StorageDead(Local),
464    Retag(RetagKind, Place),
465    PlaceMention(Place),
466    AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
467    Coverage(Coverage),
468    Intrinsic(NonDivergingIntrinsic),
469    ConstEvalCounter,
470    Nop,
471}
472
473#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
474pub enum Rvalue {
475    /// Creates a pointer with the indicated mutability to the place.
476    ///
477    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
478    /// `&raw v` or `addr_of!(v)`.
479    AddressOf(RawPtrKind, Place),
480
481    /// Creates an aggregate value, like a tuple or struct.
482    ///
483    /// This is needed because dataflow analysis needs to distinguish
484    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
485    /// has a destructor.
486    ///
487    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
488    /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
489    Aggregate(AggregateKind, Vec<Operand>),
490
491    /// * `Offset` has the same semantics as `<*const T>::offset`, except that the second
492    ///   parameter may be a `usize` as well.
493    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
494    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
495    ///   matching, up to the usual caveat of the lifetimes in function pointers.
496    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
497    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
498    ///   truncated as needed.
499    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
500    ///   types and return a value of that type.
501    /// * The remaining operations accept signed integers, unsigned integers, or floats with
502    ///   matching types and return a value of that type.
503    BinaryOp(BinOp, Operand, Operand),
504
505    /// Performs essentially all of the casts that can be performed via `as`.
506    ///
507    /// This allows for casts from/to a variety of types.
508    Cast(CastKind, Operand, Ty),
509
510    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
511    ///
512    /// For addition, subtraction, and multiplication on integers the error condition is set when
513    /// the infinite precision result would not be equal to the actual result.
514    CheckedBinaryOp(BinOp, Operand, Operand),
515
516    /// A CopyForDeref is equivalent to a read from a place.
517    /// When such a read happens, it is guaranteed that the only use of the returned value is a
518    /// deref operation, immediately followed by one or more projections.
519    CopyForDeref(Place),
520
521    /// Computes the discriminant of the place, returning it as an integer.
522    /// Returns zero for types without discriminant.
523    ///
524    /// The validity requirements for the underlying value are undecided for this rvalue, see
525    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
526    /// variant index;
527    ///
528    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
529    Discriminant(Place),
530
531    /// Yields the length of the place, as a `usize`.
532    ///
533    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
534    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
535    /// ill-formed for places of other types.
536    Len(Place),
537
538    /// Creates a reference to the place.
539    Ref(Region, BorrowKind, Place),
540
541    /// Creates an array where each element is the value of the operand.
542    ///
543    /// This is the cause of a bug in the case where the repetition count is zero because the value
544    /// is not dropped, see [#74836].
545    ///
546    /// Corresponds to source code like `[x; 32]`.
547    ///
548    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
549    Repeat(Operand, TyConst),
550
551    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
552    ///
553    /// This is different from a normal transmute because dataflow analysis will treat the box as
554    /// initialized but its content as uninitialized. Like other pointer casts, this in general
555    /// affects alias analysis.
556    ShallowInitBox(Operand, Ty),
557
558    /// Creates a pointer/reference to the given thread local.
559    ///
560    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
561    /// `*const T`, and if neither of those apply a `&T`.
562    ///
563    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
564    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
565    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
566    ///
567    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
568    /// nature of this operation?
569    ThreadLocalRef(stable_mir::CrateItem),
570
571    /// Computes a value as described by the operation.
572    NullaryOp(NullOp, Ty),
573
574    /// Exactly like `BinaryOp`, but less operands.
575    ///
576    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
577    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
578    /// return a value with the same type as their operand.
579    UnaryOp(UnOp, Operand),
580
581    /// Yields the operand unchanged
582    Use(Operand),
583}
584
585impl Rvalue {
586    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
587        match self {
588            Rvalue::Use(operand) => operand.ty(locals),
589            Rvalue::Repeat(operand, count) => {
590                Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
591            }
592            Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
593            Rvalue::Ref(reg, bk, place) => {
594                let place_ty = place.ty(locals)?;
595                Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
596            }
597            Rvalue::AddressOf(mutability, place) => {
598                let place_ty = place.ty(locals)?;
599                Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
600            }
601            Rvalue::Len(..) => Ok(Ty::usize_ty()),
602            Rvalue::Cast(.., ty) => Ok(*ty),
603            Rvalue::BinaryOp(op, lhs, rhs) => {
604                let lhs_ty = lhs.ty(locals)?;
605                let rhs_ty = rhs.ty(locals)?;
606                Ok(op.ty(lhs_ty, rhs_ty))
607            }
608            Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
609                let lhs_ty = lhs.ty(locals)?;
610                let rhs_ty = rhs.ty(locals)?;
611                let ty = op.ty(lhs_ty, rhs_ty);
612                Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
613            }
614            Rvalue::UnaryOp(op, operand) => {
615                let arg_ty = operand.ty(locals)?;
616                Ok(op.ty(arg_ty))
617            }
618            Rvalue::Discriminant(place) => {
619                let place_ty = place.ty(locals)?;
620                place_ty
621                    .kind()
622                    .discriminant_ty()
623                    .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
624            }
625            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
626                Ok(Ty::usize_ty())
627            }
628            Rvalue::NullaryOp(NullOp::ContractChecks, _)
629            | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
630            Rvalue::Aggregate(ak, ops) => match *ak {
631                AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
632                AggregateKind::Tuple => Ok(Ty::new_tuple(
633                    &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
634                )),
635                AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
636                AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
637                AggregateKind::Coroutine(def, ref args, mov) => {
638                    Ok(Ty::new_coroutine(def, args.clone(), mov))
639                }
640                AggregateKind::CoroutineClosure(def, ref args) => {
641                    Ok(Ty::new_coroutine_closure(def, args.clone()))
642                }
643                AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
644            },
645            Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
646            Rvalue::CopyForDeref(place) => place.ty(locals),
647        }
648    }
649}
650
651#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
652pub enum AggregateKind {
653    Array(Ty),
654    Tuple,
655    Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
656    Closure(ClosureDef, GenericArgs),
657    // FIXME(stable_mir): Movability here is redundant
658    Coroutine(CoroutineDef, GenericArgs, Movability),
659    CoroutineClosure(CoroutineClosureDef, GenericArgs),
660    RawPtr(Ty, Mutability),
661}
662
663#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
664pub enum Operand {
665    Copy(Place),
666    Move(Place),
667    Constant(ConstOperand),
668}
669
670#[derive(Clone, Eq, PartialEq, Serialize)]
671pub struct Place {
672    pub local: Local,
673    /// projection out of a place (access a field, deref a pointer, etc)
674    pub projection: Vec<ProjectionElem>,
675}
676
677impl From<Local> for Place {
678    fn from(local: Local) -> Self {
679        Place { local, projection: vec![] }
680    }
681}
682
683#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
684pub struct ConstOperand {
685    pub span: Span,
686    pub user_ty: Option<UserTypeAnnotationIndex>,
687    pub const_: MirConst,
688}
689
690/// Debug information pertaining to a user variable.
691#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
692pub struct VarDebugInfo {
693    /// The variable name.
694    pub name: Symbol,
695
696    /// Source info of the user variable, including the scope
697    /// within which the variable is visible (to debuginfo).
698    pub source_info: SourceInfo,
699
700    /// The user variable's data is split across several fragments,
701    /// each described by a `VarDebugInfoFragment`.
702    pub composite: Option<VarDebugInfoFragment>,
703
704    /// Where the data for this user variable is to be found.
705    pub value: VarDebugInfoContents,
706
707    /// When present, indicates what argument number this variable is in the function that it
708    /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
709    /// argument number in the original function before it was inlined.
710    pub argument_index: Option<u16>,
711}
712
713impl VarDebugInfo {
714    /// Return a local variable if this info is related to one.
715    pub fn local(&self) -> Option<Local> {
716        match &self.value {
717            VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
718            VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
719        }
720    }
721
722    /// Return a constant if this info is related to one.
723    pub fn constant(&self) -> Option<&ConstOperand> {
724        match &self.value {
725            VarDebugInfoContents::Place(_) => None,
726            VarDebugInfoContents::Const(const_op) => Some(const_op),
727        }
728    }
729}
730
731pub type SourceScope = u32;
732
733#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
734pub struct SourceInfo {
735    pub span: Span,
736    pub scope: SourceScope,
737}
738
739#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
740pub struct VarDebugInfoFragment {
741    pub ty: Ty,
742    pub projection: Vec<ProjectionElem>,
743}
744
745#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
746pub enum VarDebugInfoContents {
747    Place(Place),
748    Const(ConstOperand),
749}
750
751// In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This
752// is so it can be used for both Places (for which the projection elements are of type
753// ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements
754// are of type ProjectionElem<(), ()>). In SMIR we don't need this generality, so we just use
755// ProjectionElem for Places.
756#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
757pub enum ProjectionElem {
758    /// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
759    Deref,
760
761    /// A field projection (e.g., `f` in `_1.f`) project to a field in the base place. The field is
762    /// referenced by source-order index rather than the name of the field. The fields type is also
763    /// given.
764    Field(FieldIdx, Ty),
765
766    /// Index into a slice/array. The value of the index is computed at runtime using the `V`
767    /// argument.
768    ///
769    /// Note that this does not also dereference, and so it does not exactly correspond to slice
770    /// indexing in Rust. In other words, in the below Rust code:
771    ///
772    /// ```rust
773    /// let x = &[1, 2, 3, 4];
774    /// let i = 2;
775    /// x[i];
776    /// ```
777    ///
778    /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same
779    /// thing is true of the `ConstantIndex` and `Subslice` projections below.
780    Index(Local),
781
782    /// Index into a slice/array given by offsets.
783    ///
784    /// These indices are generated by slice patterns. Easiest to explain by example:
785    ///
786    /// ```ignore (illustrative)
787    /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false },
788    /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false },
789    /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true },
790    /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true },
791    /// ```
792    ConstantIndex {
793        /// index or -index (in Python terms), depending on from_end
794        offset: u64,
795        /// The thing being indexed must be at least this long -- otherwise, the
796        /// projection is UB.
797        ///
798        /// For arrays this is always the exact length.
799        min_length: u64,
800        /// Counting backwards from end? This is always false when indexing an
801        /// array.
802        from_end: bool,
803    },
804
805    /// Projects a slice from the base place.
806    ///
807    /// These indices are generated by slice patterns. If `from_end` is true, this represents
808    /// `slice[from..slice.len() - to]`. Otherwise it represents `array[from..to]`.
809    Subslice {
810        from: u64,
811        to: u64,
812        /// Whether `to` counts from the start or end of the array/slice.
813        from_end: bool,
814    },
815
816    /// "Downcast" to a variant of an enum or a coroutine.
817    Downcast(VariantIdx),
818
819    /// Like an explicit cast from an opaque type to a concrete type, but without
820    /// requiring an intermediate variable.
821    OpaqueCast(Ty),
822
823    /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
824    /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
825    /// explicit during optimizations and codegen.
826    ///
827    /// This projection doesn't impact the runtime behavior of the program except for potentially changing
828    /// some type metadata of the interpreter or codegen backend.
829    Subtype(Ty),
830}
831
832#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
833pub struct UserTypeProjection {
834    pub base: UserTypeAnnotationIndex,
835
836    pub projection: Opaque,
837}
838
839pub type Local = usize;
840
841pub const RETURN_LOCAL: Local = 0;
842
843/// The source-order index of a field in a variant.
844///
845/// For example, in the following types,
846/// ```ignore(illustrative)
847/// enum Demo1 {
848///    Variant0 { a: bool, b: i32 },
849///    Variant1 { c: u8, d: u64 },
850/// }
851/// struct Demo2 { e: u8, f: u16, g: u8 }
852/// ```
853/// `a`'s `FieldIdx` is `0`,
854/// `b`'s `FieldIdx` is `1`,
855/// `c`'s `FieldIdx` is `0`, and
856/// `g`'s `FieldIdx` is `2`.
857pub type FieldIdx = usize;
858
859type UserTypeAnnotationIndex = usize;
860
861/// The possible branch sites of a [TerminatorKind::SwitchInt].
862#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
863pub struct SwitchTargets {
864    /// The conditional branches where the first element represents the value that guards this
865    /// branch, and the second element is the branch target.
866    branches: Vec<(u128, BasicBlockIdx)>,
867    /// The `otherwise` branch which will be taken in case none of the conditional branches are
868    /// satisfied.
869    otherwise: BasicBlockIdx,
870}
871
872impl SwitchTargets {
873    /// All possible targets including the `otherwise` target.
874    pub fn all_targets(&self) -> Successors {
875        self.branches.iter().map(|(_, target)| *target).chain(Some(self.otherwise)).collect()
876    }
877
878    /// The `otherwise` branch target.
879    pub fn otherwise(&self) -> BasicBlockIdx {
880        self.otherwise
881    }
882
883    /// The conditional targets which are only taken if the pattern matches the given value.
884    pub fn branches(&self) -> impl Iterator<Item = (u128, BasicBlockIdx)> {
885        self.branches.iter().copied()
886    }
887
888    /// The number of targets including `otherwise`.
889    pub fn len(&self) -> usize {
890        self.branches.len() + 1
891    }
892
893    /// Create a new SwitchTargets from the given branches and `otherwise` target.
894    pub fn new(branches: Vec<(u128, BasicBlockIdx)>, otherwise: BasicBlockIdx) -> SwitchTargets {
895        SwitchTargets { branches, otherwise }
896    }
897}
898
899#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
900pub enum BorrowKind {
901    /// Data must be immutable and is aliasable.
902    Shared,
903
904    /// An immutable, aliasable borrow that is discarded after borrow-checking. Can behave either
905    /// like a normal shared borrow or like a special shallow borrow (see [`FakeBorrowKind`]).
906    Fake(FakeBorrowKind),
907
908    /// Data is mutable and not aliasable.
909    Mut {
910        /// `true` if this borrow arose from method-call auto-ref
911        kind: MutBorrowKind,
912    },
913}
914
915impl BorrowKind {
916    pub fn to_mutable_lossy(self) -> Mutability {
917        match self {
918            BorrowKind::Mut { .. } => Mutability::Mut,
919            BorrowKind::Shared => Mutability::Not,
920            // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
921            BorrowKind::Fake(_) => Mutability::Not,
922        }
923    }
924}
925
926#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
927pub enum RawPtrKind {
928    Mut,
929    Const,
930    FakeForPtrMetadata,
931}
932
933impl RawPtrKind {
934    pub fn to_mutable_lossy(self) -> Mutability {
935        match self {
936            RawPtrKind::Mut { .. } => Mutability::Mut,
937            RawPtrKind::Const => Mutability::Not,
938            // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation.
939            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
940        }
941    }
942}
943
944#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
945pub enum MutBorrowKind {
946    Default,
947    TwoPhaseBorrow,
948    ClosureCapture,
949}
950
951#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
952pub enum FakeBorrowKind {
953    /// A shared (deep) borrow. Data must be immutable and is aliasable.
954    Deep,
955    /// The immediately borrowed place must be immutable, but projections from
956    /// it don't need to be. This is used to prevent match guards from replacing
957    /// the scrutinee. For example, a fake borrow of `a.b` doesn't
958    /// conflict with a mutable borrow of `a.b.c`.
959    Shallow,
960}
961
962#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize)]
963pub enum Mutability {
964    Not,
965    Mut,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
969pub enum Safety {
970    Safe,
971    Unsafe,
972}
973
974#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
975pub enum PointerCoercion {
976    /// Go from a fn-item type to a fn-pointer type.
977    ReifyFnPointer,
978
979    /// Go from a safe fn pointer to an unsafe fn pointer.
980    UnsafeFnPointer,
981
982    /// Go from a non-capturing closure to a fn pointer or an unsafe fn pointer.
983    /// It cannot convert a closure that requires unsafe.
984    ClosureFnPointer(Safety),
985
986    /// Go from a mut raw pointer to a const raw pointer.
987    MutToConstPointer,
988
989    /// Go from `*const [T; N]` to `*const T`
990    ArrayToPointer,
991
992    /// Unsize a pointer/reference value, e.g., `&[T; n]` to
993    /// `&[T]`. Note that the source could be a thin or wide pointer.
994    /// This will do things like convert thin pointers to wide
995    /// pointers, or convert structs containing thin pointers to
996    /// structs containing wide pointers, or convert between wide
997    /// pointers.
998    Unsize,
999}
1000
1001#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
1002pub enum CastKind {
1003    // FIXME(smir-rename): rename this to PointerExposeProvenance
1004    PointerExposeAddress,
1005    PointerWithExposedProvenance,
1006    PointerCoercion(PointerCoercion),
1007    // FIXME(smir-rename): change this to PointerCoercion(DynStar)
1008    DynStar,
1009    IntToInt,
1010    FloatToInt,
1011    FloatToFloat,
1012    IntToFloat,
1013    PtrToPtr,
1014    FnPtrToPtr,
1015    Transmute,
1016}
1017
1018#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1019pub enum NullOp {
1020    /// Returns the size of a value of that type.
1021    SizeOf,
1022    /// Returns the minimum alignment of a type.
1023    AlignOf,
1024    /// Returns the offset of a field.
1025    OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1026    /// cfg!(ub_checks), but at codegen time
1027    UbChecks,
1028    /// cfg!(contract_checks), but at codegen time
1029    ContractChecks,
1030}
1031
1032impl Operand {
1033    /// Get the type of an operand relative to the local declaration.
1034    ///
1035    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1036    /// locals from the function body where this operand originates from.
1037    ///
1038    /// Errors indicate a malformed operand or incompatible locals list.
1039    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1040        match self {
1041            Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1042            Operand::Constant(c) => Ok(c.ty()),
1043        }
1044    }
1045}
1046
1047impl ConstOperand {
1048    pub fn ty(&self) -> Ty {
1049        self.const_.ty()
1050    }
1051}
1052
1053impl Place {
1054    /// Resolve down the chain of projections to get the type referenced at the end of it.
1055    /// E.g.:
1056    /// Calling `ty()` on `var.field` should return the type of `field`.
1057    ///
1058    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1059    /// locals from the function body where this place originates from.
1060    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1061        self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1062    }
1063}
1064
1065impl ProjectionElem {
1066    /// Get the expected type after applying this projection to a given place type.
1067    pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1068        let ty = place_ty;
1069        match &self {
1070            ProjectionElem::Deref => Self::deref_ty(ty),
1071            ProjectionElem::Field(_idx, fty) => Ok(*fty),
1072            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1073            ProjectionElem::Subslice { from, to, from_end } => {
1074                Self::subslice_ty(ty, *from, *to, *from_end)
1075            }
1076            ProjectionElem::Downcast(_) => Ok(ty),
1077            ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1078        }
1079    }
1080
1081    fn index_ty(ty: Ty) -> Result<Ty, Error> {
1082        ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1083    }
1084
1085    fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1086        let ty_kind = ty.kind();
1087        match ty_kind {
1088            TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1089            TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1090                inner,
1091                to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1092            ),
1093            TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1094                let size = size.eval_target_usize()?;
1095                let len = size - from - to;
1096                Ty::try_new_array(inner, len)
1097            }
1098            _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1099        }
1100    }
1101
1102    fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1103        let deref_ty = ty
1104            .kind()
1105            .builtin_deref(true)
1106            .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1107        Ok(deref_ty.ty)
1108    }
1109}