stable_mir/mir/
body.rs

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