Skip to main content

rustc_type_ir/
lib.rs

1#![cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir")]
2// tidy-alphabetical-start
3#![allow(rustc::direct_use_of_rustc_type_ir)]
4#![allow(rustc::usage_of_ty_tykind)]
5#![allow(rustc::usage_of_type_ir_inherent)]
6#![allow(rustc::usage_of_type_ir_traits)]
7#![cfg_attr(feature = "nightly", allow(internal_features))]
8#![cfg_attr(feature = "nightly", feature(associated_type_defaults, rustc_attrs, negative_impls))]
9// tidy-alphabetical-end
10
11extern crate self as rustc_type_ir;
12
13use std::fmt;
14use std::hash::Hash;
15
16use rustc_abi::{FieldIdx, VariantIdx};
17#[cfg(feature = "nightly")]
18use rustc_macros::{Decodable, Encodable, StableHash};
19
20// These modules are `pub` since they are not glob-imported.
21pub mod data_structures;
22pub mod elaborate;
23pub mod error;
24pub mod fast_reject;
25#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_inherent")]
26pub mod inherent;
27pub mod ir_print;
28pub mod lang_items;
29pub mod lift;
30pub mod outlives;
31pub mod region_constraint;
32pub mod relate;
33pub mod search_graph;
34pub mod solve;
35pub mod walk;
36
37// These modules are not `pub` since they are glob-imported.
38#[macro_use]
39mod macros;
40mod binder;
41mod canonical;
42mod const_kind;
43mod flags;
44mod fold;
45mod generic_arg;
46#[cfg(not(feature = "nightly"))]
47mod generic_visit;
48mod infer_ctxt;
49mod interner;
50mod opaque_ty;
51mod pattern;
52mod predicate;
53mod predicate_kind;
54mod region_kind;
55mod term_kind;
56mod ty;
57mod ty_info;
58mod ty_kind;
59mod universe;
60mod unnormalized;
61mod upcast;
62mod visit;
63
64pub use AliasTyKind::*;
65pub use InferTy::*;
66pub use RegionKind::*;
67pub use TyKind::*;
68pub use Variance::*;
69pub use binder::{Placeholder, *};
70pub use canonical::*;
71pub use const_kind::*;
72pub use flags::*;
73pub use fold::*;
74pub use generic_arg::*;
75#[cfg(not(feature = "nightly"))]
76pub use generic_visit::*;
77pub use infer_ctxt::*;
78pub use interner::*;
79pub use opaque_ty::*;
80pub use pattern::*;
81pub use predicate::*;
82pub use predicate_kind::*;
83pub use region_kind::*;
84pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy};
85use rustc_type_ir_macros::GenericTypeVisitable;
86pub use term_kind::*;
87pub use ty::{Alias, *};
88pub use ty_info::*;
89pub use ty_kind::*;
90pub use universe::*;
91pub use unnormalized::Unnormalized;
92pub use upcast::*;
93pub use visit::*;
94
95impl ::std::fmt::Debug for DebruijnIndex {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("DebruijnIndex({0})", self.as_u32()))
    }
}rustc_index::newtype_index! {
96    /// A [De Bruijn index][dbi] is a standard means of representing
97    /// regions (and perhaps later types) in a higher-ranked setting. In
98    /// particular, imagine a type like this:
99    /// ```ignore (illustrative)
100    ///    for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
101    /// // ^          ^            |          |           |
102    /// // |          |            |          |           |
103    /// // |          +------------+ 0        |           |
104    /// // |                                  |           |
105    /// // +----------------------------------+ 1         |
106    /// // |                                              |
107    /// // +----------------------------------------------+ 0
108    /// ```
109    /// In this type, there are two binders (the outer fn and the inner
110    /// fn). We need to be able to determine, for any given region, which
111    /// fn type it is bound by, the inner or the outer one. There are
112    /// various ways you can do this, but a De Bruijn index is one of the
113    /// more convenient and has some nice properties. The basic idea is to
114    /// count the number of binders, inside out. Some examples should help
115    /// clarify what I mean.
116    ///
117    /// Let's start with the reference type `&'b isize` that is the first
118    /// argument to the inner function. This region `'b` is assigned a De
119    /// Bruijn index of 0, meaning "the innermost binder" (in this case, a
120    /// fn). The region `'a` that appears in the second argument type (`&'a
121    /// isize`) would then be assigned a De Bruijn index of 1, meaning "the
122    /// second-innermost binder". (These indices are written on the arrows
123    /// in the diagram).
124    ///
125    /// What is interesting is that De Bruijn index attached to a particular
126    /// variable will vary depending on where it appears. For example,
127    /// the final type `&'a char` also refers to the region `'a` declared on
128    /// the outermost fn. But this time, this reference is not nested within
129    /// any other binders (i.e., it is not an argument to the inner fn, but
130    /// rather the outer one). Therefore, in this case, it is assigned a
131    /// De Bruijn index of 0, because the innermost binder in that location
132    /// is the outer fn.
133    ///
134    /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
135    #[stable_hash]
136    #[encodable]
137    #[orderable]
138    #[debug_format = "DebruijnIndex({})"]
139    #[gate_rustc_only]
140    pub struct DebruijnIndex {
141        const INNERMOST = 0;
142    }
143}
144
145impl DebruijnIndex {
146    /// Returns the resulting index when this value is moved into
147    /// `amount` number of new binders. So, e.g., if you had
148    ///
149    ///    for<'a> fn(&'a x)
150    ///
151    /// and you wanted to change it to
152    ///
153    ///    for<'a> fn(for<'b> fn(&'a x))
154    ///
155    /// you would need to shift the index for `'a` into a new binder.
156    #[inline]
157    #[must_use]
158    pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
159        DebruijnIndex::from_u32(self.as_u32() + amount)
160    }
161
162    /// Update this index in place by shifting it "in" through
163    /// `amount` number of binders.
164    #[inline]
165    pub fn shift_in(&mut self, amount: u32) {
166        *self = self.shifted_in(amount);
167    }
168
169    /// Returns the resulting index when this value is moved out from
170    /// `amount` number of new binders.
171    #[inline]
172    #[must_use]
173    pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
174        DebruijnIndex::from_u32(self.as_u32() - amount)
175    }
176
177    /// Update in place by shifting out from `amount` binders.
178    #[inline]
179    pub fn shift_out(&mut self, amount: u32) {
180        *self = self.shifted_out(amount);
181    }
182
183    /// Adjusts any De Bruijn indices so as to make `to_binder` the
184    /// innermost binder. That is, if we have something bound at `to_binder`,
185    /// it will now be bound at INNERMOST. This is an appropriate thing to do
186    /// when moving a region out from inside binders:
187    ///
188    /// ```ignore (illustrative)
189    ///             for<'a>   fn(for<'b>   for<'c>   fn(&'a u32), _)
190    /// // Binder:  D3           D2        D1            ^^
191    /// ```
192    ///
193    /// Here, the region `'a` would have the De Bruijn index D3,
194    /// because it is the bound 3 binders out. However, if we wanted
195    /// to refer to that region `'a` in the second argument (the `_`),
196    /// those two binders would not be in scope. In that case, we
197    /// might invoke `shift_out_to_binder(D3)`. This would adjust the
198    /// De Bruijn index of `'a` to D1 (the innermost binder).
199    ///
200    /// If we invoke `shift_out_to_binder` and the region is in fact
201    /// bound by one of the binders we are shifting out of, that is an
202    /// error (and should fail an assertion failure).
203    #[inline]
204    pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
205        self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
206    }
207}
208
209pub fn debug_bound_var<T: std::fmt::Write>(
210    fmt: &mut T,
211    bound_index: BoundVarIndexKind,
212    var: impl std::fmt::Debug,
213) -> Result<(), std::fmt::Error> {
214    match bound_index {
215        BoundVarIndexKind::Bound(debruijn) => {
216            if debruijn == INNERMOST {
217                fmt.write_fmt(format_args!("^{0:?}", var))write!(fmt, "^{var:?}")
218            } else {
219                fmt.write_fmt(format_args!("^{0}_{1:?}", debruijn.index(), var))write!(fmt, "^{}_{:?}", debruijn.index(), var)
220            }
221        }
222        BoundVarIndexKind::Canonical => {
223            fmt.write_fmt(format_args!("^c_{0:?}", var))write!(fmt, "^c_{:?}", var)
224        }
225    }
226}
227
228#[derive(#[automatically_derived]
impl ::core::marker::Copy for Variance { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Variance {
    #[inline]
    fn clone(&self) -> Variance { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for Variance {
    #[inline]
    fn eq(&self, other: &Variance) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Variance {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for Variance {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash, GenericTypeVisitable)]
229#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for Variance {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { Variance::Covariant }
                    1usize => { Variance::Invariant }
                    2usize => { Variance::Contravariant }
                    3usize => { Variance::Bivariant }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `Variance`, expected 0..4, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for Variance {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        Variance::Covariant => { 0usize }
                        Variance::Invariant => { 1usize }
                        Variance::Contravariant => { 2usize }
                        Variance::Bivariant => { 3usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    Variance::Covariant => {}
                    Variance::Invariant => {}
                    Variance::Contravariant => {}
                    Variance::Bivariant => {}
                }
            }
        }
    };Encodable, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for Variance {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    Variance::Covariant => {}
                    Variance::Invariant => {}
                    Variance::Contravariant => {}
                    Variance::Bivariant => {}
                }
            }
        }
    };StableHash))]
230#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
231pub enum Variance {
232    Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
233    Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
234    Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
235    Bivariant,     // T<A> <: T<B>            -- e.g., unused type parameter
236}
237
238impl Variance {
239    /// `a.xform(b)` combines the variance of a context with the
240    /// variance of a type with the following meaning. If we are in a
241    /// context with variance `a`, and we encounter a type argument in
242    /// a position with variance `b`, then `a.xform(b)` is the new
243    /// variance with which the argument appears.
244    ///
245    /// Example 1:
246    /// ```ignore (illustrative)
247    /// *mut Vec<i32>
248    /// ```
249    /// Here, the "ambient" variance starts as covariant. `*mut T` is
250    /// invariant with respect to `T`, so the variance in which the
251    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
252    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
253    /// respect to its type argument `T`, and hence the variance of
254    /// the `i32` here is `Invariant.xform(Covariant)`, which results
255    /// (again) in `Invariant`.
256    ///
257    /// Example 2:
258    /// ```ignore (illustrative)
259    /// fn(*const Vec<i32>, *mut Vec<i32)
260    /// ```
261    /// The ambient variance is covariant. A `fn` type is
262    /// contravariant with respect to its parameters, so the variance
263    /// within which both pointer types appear is
264    /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
265    /// T` is covariant with respect to `T`, so the variance within
266    /// which the first `Vec<i32>` appears is
267    /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
268    /// is true for its `i32` argument. In the `*mut T` case, the
269    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
270    /// and hence the outermost type is `Invariant` with respect to
271    /// `Vec<i32>` (and its `i32` argument).
272    ///
273    /// Source: Figure 1 of "Taming the Wildcards:
274    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
275    pub fn xform(self, v: Variance) -> Variance {
276        match (self, v) {
277            // Figure 1, column 1.
278            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
279            (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
280            (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
281            (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
282
283            // Figure 1, column 2.
284            (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
285            (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
286            (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
287            (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
288
289            // Figure 1, column 3.
290            (Variance::Invariant, _) => Variance::Invariant,
291
292            // Figure 1, column 4.
293            (Variance::Bivariant, _) => Variance::Bivariant,
294        }
295    }
296}
297
298impl fmt::Debug for Variance {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        f.write_str(match *self {
301            Variance::Covariant => "+",
302            Variance::Contravariant => "-",
303            Variance::Invariant => "o",
304            Variance::Bivariant => "*",
305        })
306    }
307}
308
309impl ::std::fmt::Debug for UniverseIndex {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("U{0}", self.as_u32()))
    }
}rustc_index::newtype_index! {
310    /// "Universes" are used during type- and trait-checking in the
311    /// presence of `for<..>` binders to control what sets of names are
312    /// visible. Universes are arranged into a tree: the root universe
313    /// contains names that are always visible. Each child then adds a new
314    /// set of names that are visible, in addition to those of its parent.
315    /// We say that the child universe "extends" the parent universe with
316    /// new names.
317    ///
318    /// To make this more concrete, consider this program:
319    ///
320    /// ```ignore (illustrative)
321    /// struct Foo { }
322    /// fn bar<T>(x: T) {
323    ///   let y: for<'a> fn(&'a u8, Foo) = ...;
324    /// }
325    /// ```
326    ///
327    /// The struct name `Foo` is in the root universe U0. But the type
328    /// parameter `T`, introduced on `bar`, is in an extended universe U1
329    /// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
330    /// of `bar`, we cannot name `T`. Then, within the type of `y`, the
331    /// region `'a` is in a universe U2 that extends U1, because we can
332    /// name it inside the fn type but not outside.
333    ///
334    /// Universes are used to do type- and trait-checking around these
335    /// "forall" binders (also called **universal quantification**). The
336    /// idea is that when, in the body of `bar`, we refer to `T` as a
337    /// type, we aren't referring to any type in particular, but rather a
338    /// kind of "fresh" type that is distinct from all other types we have
339    /// actually declared. This is called a **placeholder** type, and we
340    /// use universes to talk about this. In other words, a type name in
341    /// universe 0 always corresponds to some "ground" type that the user
342    /// declared, but a type name in a non-zero universe is a placeholder
343    /// type -- an idealized representative of "types in general" that we
344    /// use for checking generic functions.
345    #[stable_hash]
346    #[encodable]
347    #[orderable]
348    #[debug_format = "U{}"]
349    #[gate_rustc_only]
350    pub struct UniverseIndex {}
351}
352
353impl UniverseIndex {
354    pub const ROOT: UniverseIndex = UniverseIndex::ZERO;
355
356    /// Returns the "next" universe index in order -- this new index
357    /// is considered to extend all previous universes. This
358    /// corresponds to entering a `forall` quantifier. So, for
359    /// example, suppose we have this type in universe `U`:
360    ///
361    /// ```ignore (illustrative)
362    /// for<'a> fn(&'a u32)
363    /// ```
364    ///
365    /// Once we "enter" into this `for<'a>` quantifier, we are in a
366    /// new universe that extends `U` -- in this new universe, we can
367    /// name the region `'a`, but that region was not nameable from
368    /// `U` because it was not in scope there.
369    pub fn next_universe(self) -> UniverseIndex {
370        UniverseIndex::from_u32(self.as_u32().checked_add(1).unwrap())
371    }
372
373    /// Returns `true` if `self` can name a name from `other` -- in other words,
374    /// if the set of names in `self` is a superset of those in
375    /// `other` (`self >= other`).
376    pub fn can_name(self, other: UniverseIndex) -> bool {
377        self >= other
378    }
379
380    /// Returns `true` if `self` cannot name some names from `other` -- in other
381    /// words, if the set of names in `self` is a strict subset of
382    /// those in `other` (`self < other`).
383    pub fn cannot_name(self, other: UniverseIndex) -> bool {
384        self < other
385    }
386
387    /// Returns `true` if `self` is the root universe, otherwise false.
388    pub fn is_root(self) -> bool {
389        self == Self::ROOT
390    }
391}
392
393impl Default for UniverseIndex {
394    fn default() -> Self {
395        Self::ROOT
396    }
397}
398
399impl ::std::fmt::Debug for BoundVar {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("{0}", self.as_u32()))
    }
}rustc_index::newtype_index! {
400    #[stable_hash]
401    #[encodable]
402    #[orderable]
403    #[debug_format = "{}"]
404    #[gate_rustc_only]
405    pub struct BoundVar {}
406}
407
408/// Represents the various closure traits in the language. This
409/// will determine the type of the environment (`self`, in the
410/// desugaring) argument that the closure expects.
411///
412/// You can get the environment type of a closure using
413/// `tcx.closure_env_ty()`.
414#[derive(#[automatically_derived]
impl ::core::clone::Clone for ClosureKind {
    #[inline]
    fn clone(&self) -> ClosureKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ClosureKind { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for ClosureKind {
    #[inline]
    fn eq(&self, other: &ClosureKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ClosureKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for ClosureKind {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for ClosureKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ClosureKind::Fn => "Fn",
                ClosureKind::FnMut => "FnMut",
                ClosureKind::FnOnce => "FnOnce",
            })
    }
}Debug)]
415#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for ClosureKind {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        ClosureKind::Fn => { 0usize }
                        ClosureKind::FnMut => { 1usize }
                        ClosureKind::FnOnce => { 2usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    ClosureKind::Fn => {}
                    ClosureKind::FnMut => {}
                    ClosureKind::FnOnce => {}
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for ClosureKind {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { ClosureKind::Fn }
                    1usize => { ClosureKind::FnMut }
                    2usize => { ClosureKind::FnOnce }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `ClosureKind`, expected 0..3, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for ClosureKind
            {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    ClosureKind::Fn => {}
                    ClosureKind::FnMut => {}
                    ClosureKind::FnOnce => {}
                }
            }
        }
    };StableHash))]
416pub enum ClosureKind {
417    Fn,
418    FnMut,
419    FnOnce,
420}
421
422impl ClosureKind {
423    /// This is the initial value used when doing upvar inference.
424    pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn;
425
426    pub const fn as_str(self) -> &'static str {
427        match self {
428            ClosureKind::Fn => "Fn",
429            ClosureKind::FnMut => "FnMut",
430            ClosureKind::FnOnce => "FnOnce",
431        }
432    }
433
434    /// Returns `true` if a type that impls this closure kind
435    /// must also implement `other`.
436    #[rustfmt::skip]
437    pub fn extends(self, other: ClosureKind) -> bool {
438        use ClosureKind::*;
439        match (self, other) {
440              (Fn, Fn | FnMut | FnOnce)
441            | (FnMut,   FnMut | FnOnce)
442            | (FnOnce,          FnOnce) => true,
443            _ => false,
444        }
445    }
446}
447
448impl fmt::Display for ClosureKind {
449    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450        self.as_str().fmt(f)
451    }
452}
453
454pub struct FieldInfo<I: Interner> {
455    pub base: I::Ty,
456    pub ty: I::Ty,
457    pub variant: Option<I::Symbol>,
458    pub variant_idx: VariantIdx,
459    pub name: I::Symbol,
460    pub field_idx: FieldIdx,
461}