Skip to main content

hir_ty/
mir.rs

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