rustc_public/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 rustc_public's IR 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    /// Returns a mutable reference to the local that holds this function's return value.
81    pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl {
82        &mut self.locals[RETURN_LOCAL]
83    }
84
85    /// Returns a mutable slice of locals corresponding to this function's arguments.
86    pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] {
87        &mut self.locals[1..][..self.arg_count]
88    }
89
90    /// Returns a mutable slice of inner locals for this function.
91    /// Inner locals are those that are neither the return local nor the argument locals.
92    pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] {
93        &mut self.locals[self.arg_count + 1..]
94    }
95
96    /// Convenience function to get all the locals in this function.
97    ///
98    /// Locals are typically accessed via the more specific methods `ret_local`,
99    /// `arg_locals`, and `inner_locals`.
100    pub fn locals(&self) -> &[LocalDecl] {
101        &self.locals
102    }
103
104    /// Get the local declaration for this local.
105    pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> {
106        self.locals.get(local)
107    }
108
109    /// Get an iterator for all local declarations.
110    pub fn local_decls(&self) -> impl Iterator<Item = (Local, &LocalDecl)> {
111        self.locals.iter().enumerate()
112    }
113
114    /// Emit the body using the provided name for the signature.
115    pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
116        function_body(w, self, fn_name)
117    }
118
119    pub fn spread_arg(&self) -> Option<Local> {
120        self.spread_arg
121    }
122}
123
124type LocalDecls = Vec<LocalDecl>;
125
126#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
127pub struct LocalDecl {
128    pub ty: Ty,
129    pub span: Span,
130    pub mutability: Mutability,
131}
132
133#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
134pub struct BasicBlock {
135    pub statements: Vec<Statement>,
136    pub terminator: Terminator,
137}
138
139#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
140pub struct Terminator {
141    pub kind: TerminatorKind,
142    pub span: Span,
143}
144
145impl Terminator {
146    pub fn successors(&self) -> Successors {
147        self.kind.successors()
148    }
149}
150
151pub type Successors = Vec<BasicBlockIdx>;
152
153#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
154pub enum TerminatorKind {
155    Goto {
156        target: BasicBlockIdx,
157    },
158    SwitchInt {
159        discr: Operand,
160        targets: SwitchTargets,
161    },
162    Resume,
163    Abort,
164    Return,
165    Unreachable,
166    Drop {
167        place: Place,
168        target: BasicBlockIdx,
169        unwind: UnwindAction,
170    },
171    Call {
172        func: Operand,
173        args: Vec<Operand>,
174        destination: Place,
175        target: Option<BasicBlockIdx>,
176        unwind: UnwindAction,
177    },
178    Assert {
179        cond: Operand,
180        expected: bool,
181        msg: AssertMessage,
182        target: BasicBlockIdx,
183        unwind: UnwindAction,
184    },
185    InlineAsm {
186        template: String,
187        operands: Vec<InlineAsmOperand>,
188        options: String,
189        line_spans: String,
190        destination: Option<BasicBlockIdx>,
191        unwind: UnwindAction,
192    },
193}
194
195impl TerminatorKind {
196    pub fn successors(&self) -> Successors {
197        use self::TerminatorKind::*;
198        match *self {
199            Call { target: Some(t), unwind: UnwindAction::Cleanup(u), .. }
200            | Drop { target: t, unwind: UnwindAction::Cleanup(u), .. }
201            | Assert { target: t, unwind: UnwindAction::Cleanup(u), .. }
202            | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(u), .. } => {
203                vec![t, u]
204            }
205            Goto { target: t }
206            | Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
207            | Call { target: Some(t), unwind: _, .. }
208            | Drop { target: t, unwind: _, .. }
209            | Assert { target: t, unwind: _, .. }
210            | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
211            | InlineAsm { destination: Some(t), unwind: _, .. } => {
212                vec![t]
213            }
214
215            Return
216            | Resume
217            | Abort
218            | Unreachable
219            | Call { target: None, unwind: _, .. }
220            | InlineAsm { destination: None, unwind: _, .. } => {
221                vec![]
222            }
223            SwitchInt { ref targets, .. } => targets.all_targets(),
224        }
225    }
226
227    pub fn unwind(&self) -> Option<&UnwindAction> {
228        match *self {
229            TerminatorKind::Goto { .. }
230            | TerminatorKind::Return
231            | TerminatorKind::Unreachable
232            | TerminatorKind::Resume
233            | TerminatorKind::Abort
234            | TerminatorKind::SwitchInt { .. } => None,
235            TerminatorKind::Call { ref unwind, .. }
236            | TerminatorKind::Assert { ref unwind, .. }
237            | TerminatorKind::Drop { ref unwind, .. }
238            | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
239        }
240    }
241}
242
243#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
244pub struct InlineAsmOperand {
245    pub in_value: Option<Operand>,
246    pub out_place: Option<Place>,
247    // This field has a raw debug representation of MIR's InlineAsmOperand.
248    // For now we care about place/operand + the rest in a debug format.
249    pub raw_rpr: String,
250}
251
252#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
253pub enum UnwindAction {
254    Continue,
255    Unreachable,
256    Terminate,
257    Cleanup(BasicBlockIdx),
258}
259
260#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
261pub enum AssertMessage {
262    BoundsCheck { len: Operand, index: Operand },
263    Overflow(BinOp, Operand, Operand),
264    OverflowNeg(Operand),
265    DivisionByZero(Operand),
266    RemainderByZero(Operand),
267    ResumedAfterReturn(CoroutineKind),
268    ResumedAfterPanic(CoroutineKind),
269    ResumedAfterDrop(CoroutineKind),
270    MisalignedPointerDereference { required: Operand, found: Operand },
271    NullPointerDereference,
272    InvalidEnumConstruction(Operand),
273}
274
275impl AssertMessage {
276    pub fn description(&self) -> Result<&'static str, Error> {
277        match self {
278            AssertMessage::Overflow(BinOp::Add, _, _) => Ok("attempt to add with overflow"),
279            AssertMessage::Overflow(BinOp::Sub, _, _) => Ok("attempt to subtract with overflow"),
280            AssertMessage::Overflow(BinOp::Mul, _, _) => Ok("attempt to multiply with overflow"),
281            AssertMessage::Overflow(BinOp::Div, _, _) => Ok("attempt to divide with overflow"),
282            AssertMessage::Overflow(BinOp::Rem, _, _) => {
283                Ok("attempt to calculate the remainder with overflow")
284            }
285            AssertMessage::OverflowNeg(_) => Ok("attempt to negate with overflow"),
286            AssertMessage::Overflow(BinOp::Shr, _, _) => Ok("attempt to shift right with overflow"),
287            AssertMessage::Overflow(BinOp::Shl, _, _) => Ok("attempt to shift left with overflow"),
288            AssertMessage::Overflow(op, _, _) => Err(error!("`{:?}` cannot overflow", op)),
289            AssertMessage::DivisionByZero(_) => Ok("attempt to divide by zero"),
290            AssertMessage::RemainderByZero(_) => {
291                Ok("attempt to calculate the remainder with a divisor of zero")
292            }
293            AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
294                Ok("coroutine resumed after completion")
295            }
296            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
297                CoroutineDesugaring::Async,
298                _,
299            )) => Ok("`async fn` resumed after completion"),
300            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
301                CoroutineDesugaring::Gen,
302                _,
303            )) => Ok("`async gen fn` resumed after completion"),
304            AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared(
305                CoroutineDesugaring::AsyncGen,
306                _,
307            )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"),
308            AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
309                Ok("coroutine resumed after panicking")
310            }
311            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
312                CoroutineDesugaring::Async,
313                _,
314            )) => Ok("`async fn` resumed after panicking"),
315            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
316                CoroutineDesugaring::Gen,
317                _,
318            )) => Ok("`async gen fn` resumed after panicking"),
319            AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared(
320                CoroutineDesugaring::AsyncGen,
321                _,
322            )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after panicking"),
323
324            AssertMessage::ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
325                Ok("coroutine resumed after async drop")
326            }
327            AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
328                CoroutineDesugaring::Async,
329                _,
330            )) => Ok("`async fn` resumed after async drop"),
331            AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
332                CoroutineDesugaring::Gen,
333                _,
334            )) => Ok("`async gen fn` resumed after async drop"),
335            AssertMessage::ResumedAfterDrop(CoroutineKind::Desugared(
336                CoroutineDesugaring::AsyncGen,
337                _,
338            )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after async drop"),
339
340            AssertMessage::BoundsCheck { .. } => Ok("index out of bounds"),
341            AssertMessage::MisalignedPointerDereference { .. } => {
342                Ok("misaligned pointer dereference")
343            }
344            AssertMessage::NullPointerDereference => Ok("null pointer dereference occurred"),
345            AssertMessage::InvalidEnumConstruction(_) => {
346                Ok("trying to construct an enum from an invalid value")
347            }
348        }
349    }
350}
351
352#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
353pub enum BinOp {
354    Add,
355    AddUnchecked,
356    Sub,
357    SubUnchecked,
358    Mul,
359    MulUnchecked,
360    Div,
361    Rem,
362    BitXor,
363    BitAnd,
364    BitOr,
365    Shl,
366    ShlUnchecked,
367    Shr,
368    ShrUnchecked,
369    Eq,
370    Lt,
371    Le,
372    Ne,
373    Ge,
374    Gt,
375    Cmp,
376    Offset,
377}
378
379impl BinOp {
380    /// Return the type of this operation for the given input Ty.
381    /// This function does not perform type checking, and it currently doesn't handle SIMD.
382    pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
383        with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
384    }
385}
386
387#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
388pub enum UnOp {
389    Not,
390    Neg,
391    PtrMetadata,
392}
393
394impl UnOp {
395    /// Return the type of this operation for the given input Ty.
396    /// This function does not perform type checking, and it currently doesn't handle SIMD.
397    pub fn ty(&self, arg_ty: Ty) -> Ty {
398        with(|ctx| ctx.unop_ty(*self, arg_ty))
399    }
400}
401
402#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
403pub enum CoroutineKind {
404    Desugared(CoroutineDesugaring, CoroutineSource),
405    Coroutine(Movability),
406}
407
408#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
409pub enum CoroutineSource {
410    Block,
411    Closure,
412    Fn,
413}
414
415#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
416pub enum CoroutineDesugaring {
417    Async,
418
419    Gen,
420
421    AsyncGen,
422}
423
424pub(crate) type LocalDefId = Opaque;
425/// The rustc coverage data structures are heavily tied to internal details of the
426/// coverage implementation that are likely to change, and are unlikely to be
427/// useful to third-party tools for the foreseeable future.
428pub(crate) type Coverage = Opaque;
429
430/// The FakeReadCause describes the type of pattern why a FakeRead statement exists.
431#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
432pub enum FakeReadCause {
433    ForMatchGuard,
434    ForMatchedPlace(LocalDefId),
435    ForGuardBinding,
436    ForLet(LocalDefId),
437    ForIndex,
438}
439
440/// Describes what kind of retag is to be performed
441#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
442pub enum RetagKind {
443    FnEntry,
444    TwoPhase,
445    Raw,
446    Default,
447}
448
449#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
450pub enum Variance {
451    Covariant,
452    Invariant,
453    Contravariant,
454    Bivariant,
455}
456
457#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
458pub struct CopyNonOverlapping {
459    pub src: Operand,
460    pub dst: Operand,
461    pub count: Operand,
462}
463
464#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
465pub enum NonDivergingIntrinsic {
466    Assume(Operand),
467    CopyNonOverlapping(CopyNonOverlapping),
468}
469
470#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
471pub struct Statement {
472    pub kind: StatementKind,
473    pub span: Span,
474}
475
476#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
477pub enum StatementKind {
478    Assign(Place, Rvalue),
479    FakeRead(FakeReadCause, Place),
480    SetDiscriminant { place: Place, variant_index: VariantIdx },
481    Deinit(Place),
482    StorageLive(Local),
483    StorageDead(Local),
484    Retag(RetagKind, Place),
485    PlaceMention(Place),
486    AscribeUserType { place: Place, projections: UserTypeProjection, variance: Variance },
487    Coverage(Coverage),
488    Intrinsic(NonDivergingIntrinsic),
489    ConstEvalCounter,
490    Nop,
491}
492
493#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
494pub enum Rvalue {
495    /// Creates a pointer with the indicated mutability to the place.
496    ///
497    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
498    /// `&raw v` or `addr_of!(v)`.
499    AddressOf(RawPtrKind, Place),
500
501    /// Creates an aggregate value, like a tuple or struct.
502    ///
503    /// This is needed because dataflow analysis needs to distinguish
504    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
505    /// has a destructor.
506    ///
507    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
508    /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
509    Aggregate(AggregateKind, Vec<Operand>),
510
511    /// * `Offset` has the same semantics as `<*const T>::offset`, except that the second
512    ///   parameter may be a `usize` as well.
513    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
514    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
515    ///   matching, up to the usual caveat of the lifetimes in function pointers.
516    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
517    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
518    ///   truncated as needed.
519    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
520    ///   types and return a value of that type.
521    /// * The remaining operations accept signed integers, unsigned integers, or floats with
522    ///   matching types and return a value of that type.
523    BinaryOp(BinOp, Operand, Operand),
524
525    /// Performs essentially all of the casts that can be performed via `as`.
526    ///
527    /// This allows for casts from/to a variety of types.
528    Cast(CastKind, Operand, Ty),
529
530    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
531    ///
532    /// For addition, subtraction, and multiplication on integers the error condition is set when
533    /// the infinite precision result would not be equal to the actual result.
534    CheckedBinaryOp(BinOp, Operand, Operand),
535
536    /// A CopyForDeref is equivalent to a read from a place.
537    /// When such a read happens, it is guaranteed that the only use of the returned value is a
538    /// deref operation, immediately followed by one or more projections.
539    CopyForDeref(Place),
540
541    /// Computes the discriminant of the place, returning it as an integer.
542    /// Returns zero for types without discriminant.
543    ///
544    /// The validity requirements for the underlying value are undecided for this rvalue, see
545    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
546    /// variant index;
547    ///
548    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
549    Discriminant(Place),
550
551    /// Yields the length of the place, as a `usize`.
552    ///
553    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
554    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
555    /// ill-formed for places of other types.
556    Len(Place),
557
558    /// Creates a reference to the place.
559    Ref(Region, BorrowKind, Place),
560
561    /// Creates an array where each element is the value of the operand.
562    ///
563    /// This is the cause of a bug in the case where the repetition count is zero because the value
564    /// is not dropped, see [#74836].
565    ///
566    /// Corresponds to source code like `[x; 32]`.
567    ///
568    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
569    Repeat(Operand, TyConst),
570
571    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
572    ///
573    /// This is different from a normal transmute because dataflow analysis will treat the box as
574    /// initialized but its content as uninitialized. Like other pointer casts, this in general
575    /// affects alias analysis.
576    ShallowInitBox(Operand, Ty),
577
578    /// Creates a pointer/reference to the given thread local.
579    ///
580    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
581    /// `*const T`, and if neither of those apply a `&T`.
582    ///
583    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
584    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
585    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
586    ///
587    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
588    /// nature of this operation?
589    ThreadLocalRef(crate::CrateItem),
590
591    /// Computes a value as described by the operation.
592    NullaryOp(NullOp, Ty),
593
594    /// Exactly like `BinaryOp`, but less operands.
595    ///
596    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
597    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
598    /// return a value with the same type as their operand.
599    UnaryOp(UnOp, Operand),
600
601    /// Yields the operand unchanged
602    Use(Operand),
603}
604
605impl Rvalue {
606    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
607        match self {
608            Rvalue::Use(operand) => operand.ty(locals),
609            Rvalue::Repeat(operand, count) => {
610                Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone()))
611            }
612            Rvalue::ThreadLocalRef(did) => Ok(did.ty()),
613            Rvalue::Ref(reg, bk, place) => {
614                let place_ty = place.ty(locals)?;
615                Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy()))
616            }
617            Rvalue::AddressOf(mutability, place) => {
618                let place_ty = place.ty(locals)?;
619                Ok(Ty::new_ptr(place_ty, mutability.to_mutable_lossy()))
620            }
621            Rvalue::Len(..) => Ok(Ty::usize_ty()),
622            Rvalue::Cast(.., ty) => Ok(*ty),
623            Rvalue::BinaryOp(op, lhs, rhs) => {
624                let lhs_ty = lhs.ty(locals)?;
625                let rhs_ty = rhs.ty(locals)?;
626                Ok(op.ty(lhs_ty, rhs_ty))
627            }
628            Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
629                let lhs_ty = lhs.ty(locals)?;
630                let rhs_ty = rhs.ty(locals)?;
631                let ty = op.ty(lhs_ty, rhs_ty);
632                Ok(Ty::new_tuple(&[ty, Ty::bool_ty()]))
633            }
634            Rvalue::UnaryOp(op, operand) => {
635                let arg_ty = operand.ty(locals)?;
636                Ok(op.ty(arg_ty))
637            }
638            Rvalue::Discriminant(place) => {
639                let place_ty = place.ty(locals)?;
640                place_ty
641                    .kind()
642                    .discriminant_ty()
643                    .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}"))
644            }
645            Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
646                Ok(Ty::usize_ty())
647            }
648            Rvalue::NullaryOp(NullOp::ContractChecks, _)
649            | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
650            Rvalue::Aggregate(ak, ops) => match *ak {
651                AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
652                AggregateKind::Tuple => Ok(Ty::new_tuple(
653                    &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?,
654                )),
655                AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)),
656                AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())),
657                AggregateKind::Coroutine(def, ref args) => Ok(Ty::new_coroutine(def, args.clone())),
658                AggregateKind::CoroutineClosure(def, ref args) => {
659                    Ok(Ty::new_coroutine_closure(def, args.clone()))
660                }
661                AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
662            },
663            Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
664            Rvalue::CopyForDeref(place) => place.ty(locals),
665        }
666    }
667}
668
669#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
670pub enum AggregateKind {
671    Array(Ty),
672    Tuple,
673    Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
674    Closure(ClosureDef, GenericArgs),
675    Coroutine(CoroutineDef, GenericArgs),
676    CoroutineClosure(CoroutineClosureDef, GenericArgs),
677    RawPtr(Ty, Mutability),
678}
679
680#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
681pub enum Operand {
682    Copy(Place),
683    Move(Place),
684    Constant(ConstOperand),
685}
686
687#[derive(Clone, Eq, PartialEq, Hash, 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, Hash, 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<(), ()>).
772// In rustc_public's IR we don't need this generality, so we just use ProjectionElem for Places.
773#[derive(Clone, Debug, Eq, PartialEq, Hash, 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, Hash, 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, Hash, 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, Hash, Serialize)]
962pub enum MutBorrowKind {
963    Default,
964    TwoPhaseBorrow,
965    ClosureCapture,
966}
967
968#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, 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, Hash, Serialize)]
986pub enum Safety {
987    Safe,
988    Unsafe,
989}
990
991#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, 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, Hash, Serialize)]
1019pub enum CastKind {
1020    // FIXME(smir-rename): rename this to PointerExposeProvenance
1021    PointerExposeAddress,
1022    PointerWithExposedProvenance,
1023    PointerCoercion(PointerCoercion),
1024    IntToInt,
1025    FloatToInt,
1026    FloatToFloat,
1027    IntToFloat,
1028    PtrToPtr,
1029    FnPtrToPtr,
1030    Transmute,
1031}
1032
1033#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
1034pub enum NullOp {
1035    /// Returns the size of a value of that type.
1036    SizeOf,
1037    /// Returns the minimum alignment of a type.
1038    AlignOf,
1039    /// Returns the offset of a field.
1040    OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1041    /// cfg!(ub_checks), but at codegen time
1042    UbChecks,
1043    /// cfg!(contract_checks), but at codegen time
1044    ContractChecks,
1045}
1046
1047impl Operand {
1048    /// Get the type of an operand relative to the local declaration.
1049    ///
1050    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1051    /// locals from the function body where this operand originates from.
1052    ///
1053    /// Errors indicate a malformed operand or incompatible locals list.
1054    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1055        match self {
1056            Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
1057            Operand::Constant(c) => Ok(c.ty()),
1058        }
1059    }
1060}
1061
1062impl ConstOperand {
1063    pub fn ty(&self) -> Ty {
1064        self.const_.ty()
1065    }
1066}
1067
1068impl Place {
1069    /// Resolve down the chain of projections to get the type referenced at the end of it.
1070    /// E.g.:
1071    /// Calling `ty()` on `var.field` should return the type of `field`.
1072    ///
1073    /// In order to retrieve the correct type, the `locals` argument must match the list of all
1074    /// locals from the function body where this place originates from.
1075    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
1076        self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
1077    }
1078}
1079
1080impl ProjectionElem {
1081    /// Get the expected type after applying this projection to a given place type.
1082    pub fn ty(&self, place_ty: Ty) -> Result<Ty, Error> {
1083        let ty = place_ty;
1084        match &self {
1085            ProjectionElem::Deref => Self::deref_ty(ty),
1086            ProjectionElem::Field(_idx, fty) => Ok(*fty),
1087            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => Self::index_ty(ty),
1088            ProjectionElem::Subslice { from, to, from_end } => {
1089                Self::subslice_ty(ty, *from, *to, *from_end)
1090            }
1091            ProjectionElem::Downcast(_) => Ok(ty),
1092            ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
1093        }
1094    }
1095
1096    fn index_ty(ty: Ty) -> Result<Ty, Error> {
1097        ty.kind().builtin_index().ok_or_else(|| error!("Cannot index non-array type: {ty:?}"))
1098    }
1099
1100    fn subslice_ty(ty: Ty, from: u64, to: u64, from_end: bool) -> Result<Ty, Error> {
1101        let ty_kind = ty.kind();
1102        match ty_kind {
1103            TyKind::RigidTy(RigidTy::Slice(..)) => Ok(ty),
1104            TyKind::RigidTy(RigidTy::Array(inner, _)) if !from_end => Ty::try_new_array(
1105                inner,
1106                to.checked_sub(from).ok_or_else(|| error!("Subslice overflow: {from}..{to}"))?,
1107            ),
1108            TyKind::RigidTy(RigidTy::Array(inner, size)) => {
1109                let size = size.eval_target_usize()?;
1110                let len = size - from - to;
1111                Ty::try_new_array(inner, len)
1112            }
1113            _ => Err(Error(format!("Cannot subslice non-array type: `{ty_kind:?}`"))),
1114        }
1115    }
1116
1117    fn deref_ty(ty: Ty) -> Result<Ty, Error> {
1118        let deref_ty = ty
1119            .kind()
1120            .builtin_deref(true)
1121            .ok_or_else(|| error!("Cannot dereference type: {ty:?}"))?;
1122        Ok(deref_ty.ty)
1123    }
1124}