hir_ty/
mir.rs

1//! MIR definitions and implementation
2
3use std::{collections::hash_map::Entry, fmt::Display, iter};
4
5use crate::{
6    CallableDefId, ClosureId, Const, ConstScalar, InferenceResult, Interner, MemoryMap,
7    Substitution, TraitEnvironment, Ty, TyExt, TyKind,
8    consteval::usize_const,
9    db::HirDatabase,
10    display::{DisplayTarget, HirDisplay},
11    infer::{PointerCast, normalize},
12    lang_items::is_box,
13    mapping::ToChalk,
14};
15use base_db::Crate;
16use chalk_ir::Mutability;
17use either::Either;
18use hir_def::{
19    DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId,
20    expr_store::Body,
21    hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId},
22};
23use la_arena::{Arena, ArenaMap, Idx, RawIdx};
24
25mod borrowck;
26mod eval;
27mod lower;
28mod monomorphization;
29mod pretty;
30
31pub use borrowck::{BorrowckResult, MutabilityReason, borrowck_query};
32pub use eval::{
33    Evaluator, MirEvalError, VTableMap, interpret_mir, pad16, render_const_using_debug_impl,
34};
35pub use lower::{MirLowerError, lower_to_mir, mir_body_for_closure_query, mir_body_query};
36pub use monomorphization::{
37    monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
38    monomorphized_mir_body_query,
39};
40use rustc_hash::FxHashMap;
41use smallvec::{SmallVec, smallvec};
42use stdx::{impl_from, never};
43
44pub(crate) use lower::mir_body_cycle_result;
45pub(crate) use monomorphization::monomorphized_mir_body_cycle_result;
46
47use super::consteval::{intern_const_scalar, try_const_usize};
48
49pub type BasicBlockId = Idx<BasicBlock>;
50pub type LocalId = Idx<Local>;
51
52fn return_slot() -> LocalId {
53    LocalId::from_raw(RawIdx::from(0))
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct Local {
58    pub ty: Ty,
59}
60
61/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
62/// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
63///
64/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
65///
66/// The most common way to create values is via loading a place. Loading a place is an operation
67/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed*
68/// operation. The nature of the value produced depends on the type of the conversion. Furthermore,
69/// there may be other effects: if the type has a validity constraint loading the place might be UB
70/// if the validity constraint is not met.
71///
72/// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
73/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
74/// something we can even decide without knowing more about Rust's memory model?
75///
76/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri
77/// currently implements it, but it seems like this may be something to check against in the
78/// validator.
79#[derive(Debug, PartialEq, Eq, Clone)]
80pub struct Operand {
81    kind: OperandKind,
82    // FIXME : This should actually just be of type `MirSpan`.
83    span: Option<MirSpan>,
84}
85
86#[derive(Debug, PartialEq, Eq, Clone)]
87pub enum OperandKind {
88    /// Creates a value by loading the given place.
89    ///
90    /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there
91    /// is no such requirement.
92    Copy(Place),
93
94    /// Creates a value by performing loading the place, just like the `Copy` operand.
95    ///
96    /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
97    /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
98    /// place without first re-initializing it.
99    ///
100    /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
101    Move(Place),
102    /// Constants are already semantically values, and remain unchanged.
103    Constant(Const),
104    /// NON STANDARD: This kind of operand returns an immutable reference to that static memory. Rustc
105    /// handles it with the `Constant` variant somehow.
106    Static(StaticId),
107}
108
109impl Operand {
110    fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap<'static>, ty: Ty) -> Self {
111        Operand {
112            kind: OperandKind::Constant(intern_const_scalar(
113                ConstScalar::Bytes(data, memory_map),
114                ty,
115            )),
116            span: None,
117        }
118    }
119
120    fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self {
121        Operand::from_concrete_const(data, MemoryMap::default(), ty)
122    }
123
124    fn const_zst(ty: Ty) -> Operand {
125        Self::from_bytes(Box::default(), ty)
126    }
127
128    fn from_fn(
129        db: &dyn HirDatabase,
130        func_id: hir_def::FunctionId,
131        generic_args: Substitution,
132    ) -> Operand {
133        let ty =
134            chalk_ir::TyKind::FnDef(CallableDefId::FunctionId(func_id).to_chalk(db), generic_args)
135                .intern(Interner);
136        Operand::from_bytes(Box::default(), ty)
137    }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Hash)]
141pub enum ProjectionElem<V, T> {
142    Deref,
143    Field(Either<FieldId, TupleFieldId>),
144    // FIXME: get rid of this, and use FieldId for tuples and closures
145    ClosureField(usize),
146    Index(V),
147    ConstantIndex { offset: u64, from_end: bool },
148    Subslice { from: u64, to: u64 },
149    //Downcast(Option<Symbol>, VariantIdx),
150    OpaqueCast(T),
151}
152
153impl<V, T> ProjectionElem<V, T> {
154    pub fn projected_ty(
155        &self,
156        mut base: Ty,
157        db: &dyn HirDatabase,
158        closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
159        krate: Crate,
160    ) -> Ty {
161        // we only bail on mir building when there are type mismatches
162        // but error types may pop up resulting in us still attempting to build the mir
163        // so just propagate the error type
164        if base.is_unknown() {
165            return TyKind::Error.intern(Interner);
166        }
167
168        if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
169            base = normalize(
170                db,
171                // FIXME: we should get this from caller
172                TraitEnvironment::empty(krate),
173                base,
174            );
175        }
176        match self {
177            ProjectionElem::Deref => match &base.kind(Interner) {
178                TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
179                TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
180                    subst.at(Interner, 0).assert_ty_ref(Interner).clone()
181                }
182                _ => {
183                    never!(
184                        "Overloaded deref on type {} is not a projection",
185                        base.display(db, DisplayTarget::from_crate(db, krate))
186                    );
187                    TyKind::Error.intern(Interner)
188                }
189            },
190            ProjectionElem::Field(Either::Left(f)) => match base.kind(Interner) {
191                TyKind::Adt(_, subst) => {
192                    db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
193                }
194                ty => {
195                    never!("Only adt has field, found {:?}", ty);
196                    TyKind::Error.intern(Interner)
197                }
198            },
199            ProjectionElem::Field(Either::Right(f)) => match &base.kind(Interner) {
200                TyKind::Tuple(_, subst) => subst
201                    .as_slice(Interner)
202                    .get(f.index as usize)
203                    .map(|x| x.assert_ty_ref(Interner))
204                    .cloned()
205                    .unwrap_or_else(|| {
206                        never!("Out of bound tuple field");
207                        TyKind::Error.intern(Interner)
208                    }),
209                ty => {
210                    never!("Only tuple has tuple field: {:?}", ty);
211                    TyKind::Error.intern(Interner)
212                }
213            },
214            ProjectionElem::ClosureField(f) => match &base.kind(Interner) {
215                TyKind::Closure(id, subst) => closure_field(*id, subst, *f),
216                _ => {
217                    never!("Only closure has closure field");
218                    TyKind::Error.intern(Interner)
219                }
220            },
221            ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
222                match &base.kind(Interner) {
223                    TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
224                    _ => {
225                        never!("Overloaded index is not a projection");
226                        TyKind::Error.intern(Interner)
227                    }
228                }
229            }
230            &ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
231                TyKind::Array(inner, c) => {
232                    let next_c = usize_const(
233                        db,
234                        match try_const_usize(db, c) {
235                            None => None,
236                            Some(x) => x.checked_sub(u128::from(from + to)),
237                        },
238                        krate,
239                    );
240                    TyKind::Array(inner.clone(), next_c).intern(Interner)
241                }
242                TyKind::Slice(_) => base.clone(),
243                _ => {
244                    never!("Subslice projection should only happen on slice and array");
245                    TyKind::Error.intern(Interner)
246                }
247            },
248            ProjectionElem::OpaqueCast(_) => {
249                never!("We don't emit these yet");
250                TyKind::Error.intern(Interner)
251            }
252        }
253    }
254}
255
256type PlaceElem = ProjectionElem<LocalId, Ty>;
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct ProjectionId(u32);
260
261#[derive(Debug, Clone, PartialEq, Eq)]
262pub struct ProjectionStore {
263    id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
264    proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
265}
266
267impl Default for ProjectionStore {
268    fn default() -> Self {
269        let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
270        // Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
271        this.intern(Box::new([]));
272        this
273    }
274}
275
276impl ProjectionStore {
277    pub fn shrink_to_fit(&mut self) {
278        self.id_to_proj.shrink_to_fit();
279        self.proj_to_id.shrink_to_fit();
280    }
281
282    pub fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
283        self.proj_to_id.get(projection).copied()
284    }
285
286    pub fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
287        let new_id = ProjectionId(self.proj_to_id.len() as u32);
288        match self.proj_to_id.entry(projection) {
289            Entry::Occupied(id) => *id.get(),
290            Entry::Vacant(e) => {
291                let key_clone = e.key().clone();
292                e.insert(new_id);
293                self.id_to_proj.insert(new_id, key_clone);
294                new_id
295            }
296        }
297    }
298}
299
300impl ProjectionId {
301    pub const EMPTY: ProjectionId = ProjectionId(0);
302
303    pub fn is_empty(self) -> bool {
304        self == ProjectionId::EMPTY
305    }
306
307    pub fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
308        store.id_to_proj.get(&self).unwrap()
309    }
310
311    pub fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
312        let mut current = self.lookup(store).to_vec();
313        current.push(projection);
314        store.intern(current.into())
315    }
316}
317
318#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
319pub struct Place {
320    pub local: LocalId,
321    pub projection: ProjectionId,
322}
323
324impl Place {
325    fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
326        self.local == child.local
327            && child.projection.lookup(store).starts_with(self.projection.lookup(store))
328    }
329
330    /// The place itself is not included
331    fn iterate_over_parents<'a>(
332        &'a self,
333        store: &'a ProjectionStore,
334    ) -> impl Iterator<Item = Place> + 'a {
335        let projection = self.projection.lookup(store);
336        (0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
337            Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
338        })
339    }
340
341    fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
342        Place { local: self.local, projection: self.projection.project(projection, store) }
343    }
344}
345
346impl From<LocalId> for Place {
347    fn from(local: LocalId) -> Self {
348        Self { local, projection: ProjectionId::EMPTY }
349    }
350}
351
352#[derive(Debug, PartialEq, Eq, Clone)]
353pub enum AggregateKind {
354    /// The type is of the element
355    Array(Ty),
356    /// The type is of the tuple
357    Tuple(Ty),
358    Adt(VariantId, Substitution),
359    Union(UnionId, FieldId),
360    Closure(Ty),
361    //Coroutine(LocalDefId, SubstsRef, Movability),
362}
363
364#[derive(Debug, Clone, Hash, PartialEq, Eq)]
365pub struct SwitchTargets {
366    /// Possible values. The locations to branch to in each case
367    /// are found in the corresponding indices from the `targets` vector.
368    values: SmallVec<[u128; 1]>,
369
370    /// Possible branch sites. The last element of this vector is used
371    /// for the otherwise branch, so targets.len() == values.len() + 1
372    /// should hold.
373    //
374    // This invariant is quite non-obvious and also could be improved.
375    // One way to make this invariant is to have something like this instead:
376    //
377    // branches: Vec<(ConstInt, BasicBlock)>,
378    // otherwise: Option<BasicBlock> // exhaustive if None
379    //
380    // However we’ve decided to keep this as-is until we figure a case
381    // where some other approach seems to be strictly better than other.
382    targets: SmallVec<[BasicBlockId; 2]>,
383}
384
385impl SwitchTargets {
386    /// Creates switch targets from an iterator of values and target blocks.
387    ///
388    /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
389    /// `goto otherwise;`.
390    pub fn new(
391        targets: impl Iterator<Item = (u128, BasicBlockId)>,
392        otherwise: BasicBlockId,
393    ) -> Self {
394        let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
395        targets.push(otherwise);
396        Self { values, targets }
397    }
398
399    /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
400    /// and to `else_` if not.
401    pub fn static_if(value: u128, then: BasicBlockId, else_: BasicBlockId) -> Self {
402        Self { values: smallvec![value], targets: smallvec![then, else_] }
403    }
404
405    /// Returns the fallback target that is jumped to when none of the values match the operand.
406    pub fn otherwise(&self) -> BasicBlockId {
407        *self.targets.last().unwrap()
408    }
409
410    /// Returns an iterator over the switch targets.
411    ///
412    /// The iterator will yield tuples containing the value and corresponding target to jump to, not
413    /// including the `otherwise` fallback target.
414    ///
415    /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
416    pub fn iter(&self) -> impl Iterator<Item = (u128, BasicBlockId)> + '_ {
417        iter::zip(&self.values, &self.targets).map(|(x, y)| (*x, *y))
418    }
419
420    /// Returns a slice with all possible jump targets (including the fallback target).
421    pub fn all_targets(&self) -> &[BasicBlockId] {
422        &self.targets
423    }
424
425    /// Finds the `BasicBlock` to which this `SwitchInt` will branch given the
426    /// specific value. This cannot fail, as it'll return the `otherwise`
427    /// branch if there's not a specific match for the value.
428    pub fn target_for_value(&self, value: u128) -> BasicBlockId {
429        self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
430    }
431}
432
433#[derive(Debug, PartialEq, Eq, Clone)]
434pub struct Terminator {
435    pub span: MirSpan,
436    pub kind: TerminatorKind,
437}
438
439#[derive(Debug, PartialEq, Eq, Clone)]
440pub enum TerminatorKind {
441    /// Block has one successor; we continue execution there.
442    Goto { target: BasicBlockId },
443
444    /// Switches based on the computed value.
445    ///
446    /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
447    /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
448    /// contains the computed value, continues execution at the associated basic block. Otherwise,
449    /// continues execution at the "otherwise" basic block.
450    ///
451    /// Target values may not appear more than once.
452    SwitchInt {
453        /// The discriminant value being tested.
454        discr: Operand,
455
456        targets: SwitchTargets,
457    },
458
459    /// Indicates that the landing pad is finished and that the process should continue unwinding.
460    ///
461    /// Like a return, this marks the end of this invocation of the function.
462    ///
463    /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
464    /// deaggregation runs.
465    UnwindResume,
466
467    /// Indicates that the landing pad is finished and that the process should abort.
468    ///
469    /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
470    /// cleanup blocks.
471    Abort,
472
473    /// Returns from the function.
474    ///
475    /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
476    /// likely at least assigns the value currently in the return place (`_0`) to the place
477    /// specified in the associated `Call` terminator in the calling function, as if assigned via
478    /// `dest = move _0`. It might additionally do other things, like have side-effects in the
479    /// aliasing model.
480    ///
481    /// If the body is a coroutine body, this has slightly different semantics; it instead causes a
482    /// `CoroutineState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
483    /// to the return place.
484    Return,
485
486    /// Indicates a terminator that can never be reached.
487    ///
488    /// Executing this terminator is UB.
489    Unreachable,
490
491    /// The behavior of this statement differs significantly before and after drop elaboration.
492    /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
493    /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
494    /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
495    /// issue tracking if drop glue has any interesting semantics in addition to those of a function
496    /// call?)
497    ///
498    /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
499    /// `Drop` will be executed if...
500    ///
501    /// **Needs clarification**: End of that sentence. This in effect should document the exact
502    /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
503    ///
504    /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
505    /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
506    /// > consider indirect assignments.
507    Drop { place: Place, target: BasicBlockId, unwind: Option<BasicBlockId> },
508
509    /// Drops the place and assigns a new value to it.
510    ///
511    /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
512    /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
513    /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
514    /// explained by the elaboration:
515    ///
516    /// ```ignore (MIR)
517    /// BB0 {
518    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
519    /// }
520    /// ```
521    ///
522    /// becomes
523    ///
524    /// ```ignore (MIR)
525    /// BB0 {
526    ///   Drop(P, goto BB1, unwind BB2)
527    /// }
528    /// BB1 {
529    ///   // P is now uninitialized
530    ///   P <- V
531    /// }
532    /// BB2 {
533    ///   // P is now uninitialized -- its dtor panicked
534    ///   P <- V
535    /// }
536    /// ```
537    ///
538    /// Disallowed after drop elaboration.
539    DropAndReplace {
540        place: Place,
541        value: Operand,
542        target: BasicBlockId,
543        unwind: Option<BasicBlockId>,
544    },
545
546    /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
547    /// the referred to function. The operand types must match the argument types of the function.
548    /// The return place type must match the return type. The type of the `func` operand must be
549    /// callable, meaning either a function pointer, a function type, or a closure type.
550    ///
551    /// **Needs clarification**: The exact semantics of this. Current backends rely on `move`
552    /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
553    /// [#71117].
554    ///
555    /// [#71117]: https://github.com/rust-lang/rust/issues/71117
556    Call {
557        /// The function that’s being called.
558        func: Operand,
559        /// Arguments the function is called with.
560        /// These are owned by the callee, which is free to modify them.
561        /// This allows the memory occupied by "by-value" arguments to be
562        /// reused across function calls without duplicating the contents.
563        args: Box<[Operand]>,
564        /// Where the returned value will be written
565        destination: Place,
566        /// Where to go after this call returns. If none, the call necessarily diverges.
567        target: Option<BasicBlockId>,
568        /// Cleanups to be done if the call unwinds.
569        cleanup: Option<BasicBlockId>,
570        /// `true` if this is from a call in HIR rather than from an overloaded
571        /// operator. True for overloaded function call.
572        from_hir_call: bool,
573        // This `Span` is the span of the function, without the dot and receiver
574        // (e.g. `foo(a, b)` in `x.foo(a, b)`
575        //fn_span: Span,
576    },
577
578    /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
579    /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
580    /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
581    /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
582    /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
583    /// assertion does not fail, execution continues at the specified basic block.
584    Assert {
585        cond: Operand,
586        expected: bool,
587        //msg: AssertMessage,
588        target: BasicBlockId,
589        cleanup: Option<BasicBlockId>,
590    },
591
592    /// Marks a suspend point.
593    ///
594    /// Like `Return` terminators in coroutine bodies, this computes `value` and then a
595    /// `CoroutineState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
596    /// the return place of the function calling this one, and execution continues in the calling
597    /// function. When next invoked with the same first argument, execution of this function
598    /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
599    /// place. If the coroutine is dropped before then, the `drop` basic block is invoked.
600    ///
601    /// Not permitted in bodies that are not coroutine bodies, or after coroutine lowering.
602    ///
603    /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
604    Yield {
605        /// The value to return.
606        value: Operand,
607        /// Where to resume to.
608        resume: BasicBlockId,
609        /// The place to store the resume argument in.
610        resume_arg: Place,
611        /// Cleanup to be done if the coroutine is dropped at this suspend point.
612        drop: Option<BasicBlockId>,
613    },
614
615    /// Indicates the end of dropping a coroutine.
616    ///
617    /// Semantically just a `return` (from the coroutines drop glue). Only permitted in the same situations
618    /// as `yield`.
619    ///
620    /// **Needs clarification**: Is that even correct? The coroutine drop code is always confusing
621    /// to me, because it's not even really in the current body.
622    ///
623    /// **Needs clarification**: Are there type system constraints on these terminators? Should
624    /// there be a "block type" like `cleanup` blocks for them?
625    CoroutineDrop,
626
627    /// A block where control flow only ever takes one real path, but borrowck needs to be more
628    /// conservative.
629    ///
630    /// At runtime this is semantically just a goto.
631    ///
632    /// Disallowed after drop elaboration.
633    FalseEdge {
634        /// The target normal control flow will take.
635        real_target: BasicBlockId,
636        /// A block control flow could conceptually jump to, but won't in
637        /// practice.
638        imaginary_target: BasicBlockId,
639    },
640
641    /// A terminator for blocks that only take one path in reality, but where we reserve the right
642    /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops
643    /// with no function calls for example.
644    ///
645    /// At runtime this is semantically just a goto.
646    ///
647    /// Disallowed after drop elaboration.
648    FalseUnwind {
649        /// The target normal control flow will take.
650        real_target: BasicBlockId,
651        /// The imaginary cleanup block link. This particular path will never be taken
652        /// in practice, but in order to avoid fragility we want to always
653        /// consider it in borrowck. We don't want to accept programs which
654        /// pass borrowck only when `panic=abort` or some assertions are disabled
655        /// due to release vs. debug mode builds. This needs to be an `Option` because
656        /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
657        unwind: Option<BasicBlockId>,
658    },
659}
660
661// Order of variants in this enum matter: they are used to compare borrow kinds.
662#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
663pub enum BorrowKind {
664    /// Data must be immutable and is aliasable.
665    Shared,
666
667    /// The immediately borrowed place must be immutable, but projections from
668    /// it don't need to be. For example, a shallow borrow of `a.b` doesn't
669    /// conflict with a mutable borrow of `a.b.c`.
670    ///
671    /// This is used when lowering matches: when matching on a place we want to
672    /// ensure that place have the same value from the start of the match until
673    /// an arm is selected. This prevents this code from compiling:
674    /// ```compile_fail,E0510
675    /// let mut x = &Some(0);
676    /// match *x {
677    ///     None => (),
678    ///     Some(_) if { x = &None; false } => (),
679    ///     Some(_) => (),
680    /// }
681    /// ```
682    /// This can't be a shared borrow because mutably borrowing (*x as Some).0
683    /// should not prevent `if let None = x { ... }`, for example, because the
684    /// mutating `(*x as Some).0` can't affect the discriminant of `x`.
685    /// We can also report errors with this kind of borrow differently.
686    Shallow,
687
688    /// Data is mutable and not aliasable.
689    Mut { kind: MutBorrowKind },
690}
691
692// Order of variants in this enum matter: they are used to compare borrow kinds.
693#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
694pub enum MutBorrowKind {
695    /// Data must be immutable but not aliasable. This kind of borrow cannot currently
696    /// be expressed by the user and is used only in implicit closure bindings.
697    ClosureCapture,
698    Default,
699    /// This borrow arose from method-call auto-ref
700    /// (i.e., adjustment::Adjust::Borrow).
701    TwoPhasedBorrow,
702}
703
704impl BorrowKind {
705    fn from_hir(m: hir_def::type_ref::Mutability) -> Self {
706        match m {
707            hir_def::type_ref::Mutability::Shared => BorrowKind::Shared,
708            hir_def::type_ref::Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
709        }
710    }
711
712    fn from_chalk(m: Mutability) -> Self {
713        match m {
714            Mutability::Not => BorrowKind::Shared,
715            Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
716        }
717    }
718}
719
720#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
721pub enum UnOp {
722    /// The `!` operator for logical inversion
723    Not,
724    /// The `-` operator for negation
725    Neg,
726}
727
728#[derive(Debug, PartialEq, Eq, Clone)]
729pub enum BinOp {
730    /// The `+` operator (addition)
731    Add,
732    /// The `-` operator (subtraction)
733    Sub,
734    /// The `*` operator (multiplication)
735    Mul,
736    /// The `/` operator (division)
737    ///
738    /// Division by zero is UB, because the compiler should have inserted checks
739    /// prior to this.
740    Div,
741    /// The `%` operator (modulus)
742    ///
743    /// Using zero as the modulus (second operand) is UB, because the compiler
744    /// should have inserted checks prior to this.
745    Rem,
746    /// The `^` operator (bitwise xor)
747    BitXor,
748    /// The `&` operator (bitwise and)
749    BitAnd,
750    /// The `|` operator (bitwise or)
751    BitOr,
752    /// The `<<` operator (shift left)
753    ///
754    /// The offset is truncated to the size of the first operand before shifting.
755    Shl,
756    /// The `>>` operator (shift right)
757    ///
758    /// The offset is truncated to the size of the first operand before shifting.
759    Shr,
760    /// The `==` operator (equality)
761    Eq,
762    /// The `<` operator (less than)
763    Lt,
764    /// The `<=` operator (less than or equal to)
765    Le,
766    /// The `!=` operator (not equal to)
767    Ne,
768    /// The `>=` operator (greater than or equal to)
769    Ge,
770    /// The `>` operator (greater than)
771    Gt,
772    /// The `ptr.offset` operator
773    Offset,
774}
775
776impl BinOp {
777    fn run_compare<T: PartialEq + PartialOrd>(&self, l: T, r: T) -> bool {
778        match self {
779            BinOp::Ge => l >= r,
780            BinOp::Gt => l > r,
781            BinOp::Le => l <= r,
782            BinOp::Lt => l < r,
783            BinOp::Eq => l == r,
784            BinOp::Ne => l != r,
785            x => panic!("`run_compare` called on operator {x:?}"),
786        }
787    }
788}
789
790impl Display for BinOp {
791    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
792        f.write_str(match self {
793            BinOp::Add => "+",
794            BinOp::Sub => "-",
795            BinOp::Mul => "*",
796            BinOp::Div => "/",
797            BinOp::Rem => "%",
798            BinOp::BitXor => "^",
799            BinOp::BitAnd => "&",
800            BinOp::BitOr => "|",
801            BinOp::Shl => "<<",
802            BinOp::Shr => ">>",
803            BinOp::Eq => "==",
804            BinOp::Lt => "<",
805            BinOp::Le => "<=",
806            BinOp::Ne => "!=",
807            BinOp::Ge => ">=",
808            BinOp::Gt => ">",
809            BinOp::Offset => "`offset`",
810        })
811    }
812}
813
814impl From<hir_def::hir::ArithOp> for BinOp {
815    fn from(value: hir_def::hir::ArithOp) -> Self {
816        match value {
817            hir_def::hir::ArithOp::Add => BinOp::Add,
818            hir_def::hir::ArithOp::Mul => BinOp::Mul,
819            hir_def::hir::ArithOp::Sub => BinOp::Sub,
820            hir_def::hir::ArithOp::Div => BinOp::Div,
821            hir_def::hir::ArithOp::Rem => BinOp::Rem,
822            hir_def::hir::ArithOp::Shl => BinOp::Shl,
823            hir_def::hir::ArithOp::Shr => BinOp::Shr,
824            hir_def::hir::ArithOp::BitXor => BinOp::BitXor,
825            hir_def::hir::ArithOp::BitOr => BinOp::BitOr,
826            hir_def::hir::ArithOp::BitAnd => BinOp::BitAnd,
827        }
828    }
829}
830
831impl From<hir_def::hir::CmpOp> for BinOp {
832    fn from(value: hir_def::hir::CmpOp) -> Self {
833        match value {
834            hir_def::hir::CmpOp::Eq { negated: false } => BinOp::Eq,
835            hir_def::hir::CmpOp::Eq { negated: true } => BinOp::Ne,
836            hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: false } => BinOp::Ge,
837            hir_def::hir::CmpOp::Ord { ordering: Ordering::Greater, strict: true } => BinOp::Gt,
838            hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: false } => BinOp::Le,
839            hir_def::hir::CmpOp::Ord { ordering: Ordering::Less, strict: true } => BinOp::Lt,
840        }
841    }
842}
843
844impl From<Operand> for Rvalue {
845    fn from(x: Operand) -> Self {
846        Self::Use(x)
847    }
848}
849
850#[derive(Debug, PartialEq, Eq, Clone)]
851pub enum CastKind {
852    /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
853    /// between a function pointer and an integer type.
854    /// See the docs on `expose_addr` for more details.
855    PointerExposeAddress,
856    /// An address-to-pointer cast that picks up an exposed provenance.
857    /// See the docs on `from_exposed_addr` for more details.
858    PointerFromExposedAddress,
859    /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
860    /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
861    PtrToPtr,
862    /// Pointer related casts that are done by coercions.
863    PointerCoercion(PointerCast),
864    /// Cast into a dyn* object.
865    DynStar,
866    IntToInt,
867    FloatToInt,
868    FloatToFloat,
869    IntToFloat,
870    FnPtrToPtr,
871}
872
873#[derive(Debug, PartialEq, Eq, Clone)]
874pub enum Rvalue {
875    /// Yields the operand unchanged
876    Use(Operand),
877
878    /// Creates an array where each element is the value of the operand.
879    ///
880    /// Corresponds to source code like `[x; 32]`.
881    Repeat(Operand, Const),
882
883    /// Creates a reference of the indicated kind to the place.
884    ///
885    /// There is not much to document here, because besides the obvious parts the semantics of this
886    /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
887    /// exactly what the behavior of this operation should be.
888    ///
889    /// `Shallow` borrows are disallowed after drop lowering.
890    Ref(BorrowKind, Place),
891
892    /// Creates a pointer/reference to the given thread local.
893    ///
894    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
895    /// `*const T`, and if neither of those apply a `&T`.
896    ///
897    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
898    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
899    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
900    ///
901    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
902    /// nature of this operation?
903    // ThreadLocalRef(DefId),
904    ThreadLocalRef(std::convert::Infallible),
905
906    /// Creates a pointer with the indicated mutability to the place.
907    ///
908    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
909    /// `&raw v` or `addr_of!(v)`.
910    ///
911    /// Like with references, the semantics of this operation are heavily dependent on the aliasing
912    /// model.
913    // AddressOf(Mutability, Place),
914    AddressOf(std::convert::Infallible),
915
916    /// Yields the length of the place, as a `usize`.
917    ///
918    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
919    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
920    /// ill-formed for places of other types.
921    Len(Place),
922
923    /// Performs essentially all of the casts that can be performed via `as`.
924    ///
925    /// This allows for casts from/to a variety of types.
926    ///
927    /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
928    /// `ArrayToPointer` and `MutToConstPointer` are special.
929    Cast(CastKind, Operand, Ty),
930
931    // FIXME link to `pointer::offset` when it hits stable.
932    /// * `Offset` has the same semantics as `pointer::offset`, except that the second
933    ///   parameter may be a `usize` as well.
934    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
935    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
936    ///   matching, up to the usual caveat of the lifetimes in function pointers.
937    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
938    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
939    ///   truncated as needed.
940    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
941    ///   types and return a value of that type.
942    /// * The remaining operations accept signed integers, unsigned integers, or floats with
943    ///   matching types and return a value of that type.
944    //BinaryOp(BinOp, Box<(Operand, Operand)>),
945    BinaryOp(std::convert::Infallible),
946
947    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
948    ///
949    /// When overflow checking is disabled and we are generating run-time code, the error condition
950    /// is false. Otherwise, and always during CTFE, the error condition is determined as described
951    /// below.
952    ///
953    /// For addition, subtraction, and multiplication on integers the error condition is set when
954    /// the infinite precision result would be unequal to the actual result.
955    ///
956    /// For shift operations on integers the error condition is set when the value of right-hand
957    /// side is greater than or equal to the number of bits in the type of the left-hand side, or
958    /// when the value of right-hand side is negative.
959    ///
960    /// Other combinations of types and operators are unsupported.
961    CheckedBinaryOp(BinOp, Operand, Operand),
962
963    /// Computes a value as described by the operation.
964    //NullaryOp(NullOp, Ty),
965    NullaryOp(std::convert::Infallible),
966
967    /// Exactly like `BinaryOp`, but less operands.
968    ///
969    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
970    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
971    /// return a value with the same type as their operand.
972    UnaryOp(UnOp, Operand),
973
974    /// Computes the discriminant of the place, returning it as an integer of type
975    /// [`discriminant_ty`]. Returns zero for types without discriminant.
976    ///
977    /// The validity requirements for the underlying value are undecided for this rvalue, see
978    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
979    /// variant index; use [`discriminant_for_variant`] to convert.
980    ///
981    /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
982    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
983    /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
984    Discriminant(Place),
985
986    /// Creates an aggregate value, like a tuple or struct.
987    ///
988    /// This is needed because dataflow analysis needs to distinguish
989    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
990    /// has a destructor.
991    ///
992    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Coroutine`. After
993    /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
994    Aggregate(AggregateKind, Box<[Operand]>),
995
996    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
997    ///
998    /// This is different from a normal transmute because dataflow analysis will treat the box as
999    /// initialized but its content as uninitialized. Like other pointer casts, this in general
1000    /// affects alias analysis.
1001    ShallowInitBox(Operand, Ty),
1002
1003    /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer.
1004    ShallowInitBoxWithAlloc(Ty),
1005
1006    /// A CopyForDeref is equivalent to a read from a place at the
1007    /// codegen level, but is treated specially by drop elaboration. When such a read happens, it
1008    /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
1009    /// that the only use of the returned value is a deref operation, immediately
1010    /// followed by one or more projections. Drop elaboration treats this rvalue as if the
1011    /// read never happened and just projects further. This allows simplifying various MIR
1012    /// optimizations and codegen backends that previously had to handle deref operations anywhere
1013    /// in a place.
1014    CopyForDeref(Place),
1015}
1016
1017#[derive(Debug, PartialEq, Eq, Clone)]
1018pub enum StatementKind {
1019    Assign(Place, Rvalue),
1020    FakeRead(Place),
1021    //SetDiscriminant {
1022    //    place: Box<Place>,
1023    //    variant_index: VariantIdx,
1024    //},
1025    Deinit(Place),
1026    StorageLive(LocalId),
1027    StorageDead(LocalId),
1028    //Retag(RetagKind, Box<Place>),
1029    //AscribeUserType(Place, UserTypeProjection, Variance),
1030    //Intrinsic(Box<NonDivergingIntrinsic>),
1031    Nop,
1032}
1033impl StatementKind {
1034    fn with_span(self, span: MirSpan) -> Statement {
1035        Statement { kind: self, span }
1036    }
1037}
1038
1039#[derive(Debug, PartialEq, Eq, Clone)]
1040pub struct Statement {
1041    pub kind: StatementKind,
1042    pub span: MirSpan,
1043}
1044
1045#[derive(Debug, Default, Clone, PartialEq, Eq)]
1046pub struct BasicBlock {
1047    /// List of statements in this block.
1048    pub statements: Vec<Statement>,
1049
1050    /// Terminator for this block.
1051    ///
1052    /// N.B., this should generally ONLY be `None` during construction.
1053    /// Therefore, you should generally access it via the
1054    /// `terminator()` or `terminator_mut()` methods. The only
1055    /// exception is that certain passes, such as `simplify_cfg`, swap
1056    /// out the terminator temporarily with `None` while they continue
1057    /// to recurse over the set of basic blocks.
1058    pub terminator: Option<Terminator>,
1059
1060    /// If true, this block lies on an unwind path. This is used
1061    /// during codegen where distinct kinds of basic blocks may be
1062    /// generated (particularly for MSVC cleanup). Unwind blocks must
1063    /// only branch to other unwind blocks.
1064    pub is_cleanup: bool,
1065}
1066
1067#[derive(Debug, Clone, PartialEq, Eq)]
1068pub struct MirBody {
1069    pub projection_store: ProjectionStore,
1070    pub basic_blocks: Arena<BasicBlock>,
1071    pub locals: Arena<Local>,
1072    pub start_block: BasicBlockId,
1073    pub owner: DefWithBodyId,
1074    pub binding_locals: ArenaMap<BindingId, LocalId>,
1075    pub param_locals: Vec<LocalId>,
1076    /// This field stores the closures directly owned by this body. It is used
1077    /// in traversing every mir body.
1078    pub closures: Vec<ClosureId>,
1079}
1080
1081impl MirBody {
1082    pub fn local_to_binding_map(&self) -> ArenaMap<LocalId, BindingId> {
1083        self.binding_locals.iter().map(|(it, y)| (*y, it)).collect()
1084    }
1085
1086    fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
1087        fn for_operand(
1088            op: &mut Operand,
1089            f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
1090            store: &mut ProjectionStore,
1091        ) {
1092            match &mut op.kind {
1093                OperandKind::Copy(p) | OperandKind::Move(p) => {
1094                    f(p, store);
1095                }
1096                OperandKind::Constant(_) | OperandKind::Static(_) => (),
1097            }
1098        }
1099        for (_, block) in self.basic_blocks.iter_mut() {
1100            for statement in &mut block.statements {
1101                match &mut statement.kind {
1102                    StatementKind::Assign(p, r) => {
1103                        f(p, &mut self.projection_store);
1104                        match r {
1105                            Rvalue::ShallowInitBoxWithAlloc(_) => (),
1106                            Rvalue::ShallowInitBox(o, _)
1107                            | Rvalue::UnaryOp(_, o)
1108                            | Rvalue::Cast(_, o, _)
1109                            | Rvalue::Repeat(o, _)
1110                            | Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
1111                            Rvalue::CopyForDeref(p)
1112                            | Rvalue::Discriminant(p)
1113                            | Rvalue::Len(p)
1114                            | Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
1115                            Rvalue::CheckedBinaryOp(_, o1, o2) => {
1116                                for_operand(o1, &mut f, &mut self.projection_store);
1117                                for_operand(o2, &mut f, &mut self.projection_store);
1118                            }
1119                            Rvalue::Aggregate(_, ops) => {
1120                                for op in ops.iter_mut() {
1121                                    for_operand(op, &mut f, &mut self.projection_store);
1122                                }
1123                            }
1124                            Rvalue::ThreadLocalRef(n)
1125                            | Rvalue::AddressOf(n)
1126                            | Rvalue::BinaryOp(n)
1127                            | Rvalue::NullaryOp(n) => match *n {},
1128                        }
1129                    }
1130                    StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
1131                        f(p, &mut self.projection_store)
1132                    }
1133                    StatementKind::StorageLive(_)
1134                    | StatementKind::StorageDead(_)
1135                    | StatementKind::Nop => (),
1136                }
1137            }
1138            match &mut block.terminator {
1139                Some(x) => match &mut x.kind {
1140                    TerminatorKind::SwitchInt { discr, .. } => {
1141                        for_operand(discr, &mut f, &mut self.projection_store)
1142                    }
1143                    TerminatorKind::FalseEdge { .. }
1144                    | TerminatorKind::FalseUnwind { .. }
1145                    | TerminatorKind::Goto { .. }
1146                    | TerminatorKind::UnwindResume
1147                    | TerminatorKind::CoroutineDrop
1148                    | TerminatorKind::Abort
1149                    | TerminatorKind::Return
1150                    | TerminatorKind::Unreachable => (),
1151                    TerminatorKind::Drop { place, .. } => {
1152                        f(place, &mut self.projection_store);
1153                    }
1154                    TerminatorKind::DropAndReplace { place, value, .. } => {
1155                        f(place, &mut self.projection_store);
1156                        for_operand(value, &mut f, &mut self.projection_store);
1157                    }
1158                    TerminatorKind::Call { func, args, destination, .. } => {
1159                        for_operand(func, &mut f, &mut self.projection_store);
1160                        args.iter_mut()
1161                            .for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
1162                        f(destination, &mut self.projection_store);
1163                    }
1164                    TerminatorKind::Assert { cond, .. } => {
1165                        for_operand(cond, &mut f, &mut self.projection_store);
1166                    }
1167                    TerminatorKind::Yield { value, resume_arg, .. } => {
1168                        for_operand(value, &mut f, &mut self.projection_store);
1169                        f(resume_arg, &mut self.projection_store);
1170                    }
1171                },
1172                None => (),
1173            }
1174        }
1175    }
1176
1177    fn shrink_to_fit(&mut self) {
1178        let MirBody {
1179            basic_blocks,
1180            locals,
1181            start_block: _,
1182            owner: _,
1183            binding_locals,
1184            param_locals,
1185            closures,
1186            projection_store,
1187        } = self;
1188        projection_store.shrink_to_fit();
1189        basic_blocks.shrink_to_fit();
1190        locals.shrink_to_fit();
1191        binding_locals.shrink_to_fit();
1192        param_locals.shrink_to_fit();
1193        closures.shrink_to_fit();
1194        for (_, b) in basic_blocks.iter_mut() {
1195            let BasicBlock { statements, terminator: _, is_cleanup: _ } = b;
1196            statements.shrink_to_fit();
1197        }
1198    }
1199}
1200
1201#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1202pub enum MirSpan {
1203    ExprId(ExprId),
1204    PatId(PatId),
1205    BindingId(BindingId),
1206    SelfParam,
1207    Unknown,
1208}
1209
1210impl MirSpan {
1211    pub fn is_ref_span(&self, body: &Body) -> bool {
1212        match *self {
1213            MirSpan::ExprId(expr) => matches!(body[expr], Expr::Ref { .. }),
1214            // FIXME: Figure out if this is correct wrt. match ergonomics.
1215            MirSpan::BindingId(binding) => {
1216                matches!(body[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)
1217            }
1218            MirSpan::PatId(_) | MirSpan::SelfParam | MirSpan::Unknown => false,
1219        }
1220    }
1221}
1222
1223impl_from!(ExprId, PatId for MirSpan);
1224
1225impl From<&ExprId> for MirSpan {
1226    fn from(value: &ExprId) -> Self {
1227        (*value).into()
1228    }
1229}