Skip to main content

rustc_type_ir/
region_kind.rs

1use std::fmt;
2
3use derive_where::derive_where;
4#[cfg(feature = "nightly")]
5use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
6#[cfg(feature = "nightly")]
7use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8use rustc_type_ir_macros::GenericTypeVisitable;
9
10use self::RegionKind::*;
11use crate::{BoundRegion, BoundVarIndexKind, Interner, PlaceholderRegion};
12
13impl ::std::fmt::Debug for RegionVid {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_fmt(format_args!("\'?{0}", self.as_u32()))
    }
}rustc_index::newtype_index! {
14    /// A **region** **v**ariable **ID**.
15    #[encodable]
16    #[orderable]
17    #[debug_format = "'?{}"]
18    #[gate_rustc_only]
19    #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
20    pub struct RegionVid {}
21}
22
23/// Representation of regions. Note that the NLL checker uses a distinct
24/// representation of regions. For this reason, it internally replaces all the
25/// regions with inference variables -- the index of the variable is then used
26/// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
27/// module for more information.
28///
29/// Note: operations are on the wrapper `Region` type, which is interned,
30/// rather than this type.
31///
32/// ## The Region lattice within a given function
33///
34/// In general, the region lattice looks like
35///
36/// ```text
37/// static ----------+-----...------+       (greatest)
38/// |                |              |
39/// param regions    |              |
40/// |                |              |
41/// |                |              |
42/// |                |              |
43/// empty(root)   placeholder(U1)   |
44/// |            /                  |
45/// |           /         placeholder(Un)
46/// empty(U1) --         /
47/// |                   /
48/// ...                /
49/// |                 /
50/// empty(Un) --------                      (smallest)
51/// ```
52///
53/// Early-bound/free regions are the named lifetimes in scope from the
54/// function declaration. They have relationships to one another
55/// determined based on the declared relationships from the
56/// function.
57///
58/// Note that inference variables and bound regions are not included
59/// in this diagram. In the case of inference variables, they should
60/// be inferred to some other region from the diagram. In the case of
61/// bound regions, they are excluded because they don't make sense to
62/// include -- the diagram indicates the relationship between free
63/// regions.
64///
65/// ## Inference variables
66///
67/// During region inference, we sometimes create inference variables,
68/// represented as `ReVar`. These will be inferred by the code in
69/// `infer::lexical_region_resolve` to some free region from the
70/// lattice above (the minimal region that meets the
71/// constraints).
72///
73/// During NLL checking, where regions are defined differently, we
74/// also use `ReVar` -- in that case, the index is used to index into
75/// the NLL region checker's data structures. The variable may in fact
76/// represent either a free region or an inference variable, in that
77/// case.
78///
79/// ## Bound Regions
80///
81/// These are regions that are stored behind a binder and must be instantiated
82/// with some concrete region before being used. There are two kind of
83/// bound regions: early-bound, which are bound in an item's `Generics`,
84/// and are instantiated by an `GenericArgs`, and late-bound, which are part of
85/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are instantiated by
86/// the likes of `liberate_late_bound_regions`. The distinction exists
87/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
88///
89/// Unlike `Param`s, bound regions are not supposed to exist "in the wild"
90/// outside their binder, e.g., in types passed to type inference, and
91/// should first be instantiated (by placeholder regions, free regions,
92/// or region variables).
93///
94/// ## Placeholder and Free Regions
95///
96/// One often wants to work with bound regions without knowing their precise
97/// identity. For example, when checking a function, the lifetime of a borrow
98/// can end up being assigned to some region parameter. In these cases,
99/// it must be ensured that bounds on the region can't be accidentally
100/// assumed without being checked.
101///
102/// To do this, we replace the bound regions with placeholder markers,
103/// which don't satisfy any relation not explicitly provided.
104///
105/// There are two kinds of placeholder regions in rustc: `ReLateParam` and
106/// `RePlaceholder`. When checking an item's body, `ReLateParam` is supposed
107/// to be used. These also support explicit bounds: both the internally-stored
108/// *scope*, which the region is assumed to outlive, as well as other
109/// relations stored in the `FreeRegionMap`. Note that these relations
110/// aren't checked when you `make_subregion` (or `eq_types`), only by
111/// `resolve_regions_and_report_errors`.
112///
113/// When working with higher-ranked types, some region relations aren't
114/// yet known, so you can't just call `resolve_regions_and_report_errors`.
115/// `RePlaceholder` is designed for this purpose. In these contexts,
116/// there's also the risk that some inference variable laying around will
117/// get unified with your placeholder region: if you want to check whether
118/// `for<'a> Foo<'_>: 'a`, and you instantiate your bound region `'a`
119/// with a placeholder region `'%a`, the variable `'_` would just be
120/// instantiated to the placeholder region `'%a`, which is wrong because
121/// the inference variable is supposed to satisfy the relation
122/// *for every value of the placeholder region*. To ensure that doesn't
123/// happen, you can use `leak_check`. This is more clearly explained
124/// by the [rustc dev guide].
125///
126/// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
127/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
128/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
129#[automatically_derived]
impl<I: Interner> ::core::cmp::PartialEq for RegionKind<I> where I: Interner {
    #[inline]
    fn eq(&self, __other: &Self) -> bool {
        if ::core::mem::discriminant(self) ==
                ::core::mem::discriminant(__other) {
            match (self, __other) {
                (RegionKind::ReEarlyParam(ref __field_0),
                    RegionKind::ReEarlyParam(ref __other_field_0)) =>
                    true &&
                        ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
                (RegionKind::ReBound(ref __field_0, ref __field_1),
                    RegionKind::ReBound(ref __other_field_0,
                    ref __other_field_1)) =>
                    true &&
                            ::core::cmp::PartialEq::eq(__field_0, __other_field_0) &&
                        ::core::cmp::PartialEq::eq(__field_1, __other_field_1),
                (RegionKind::ReLateParam(ref __field_0),
                    RegionKind::ReLateParam(ref __other_field_0)) =>
                    true &&
                        ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
                (RegionKind::ReVar(ref __field_0),
                    RegionKind::ReVar(ref __other_field_0)) =>
                    true &&
                        ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
                (RegionKind::RePlaceholder(ref __field_0),
                    RegionKind::RePlaceholder(ref __other_field_0)) =>
                    true &&
                        ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
                (RegionKind::ReError(ref __field_0),
                    RegionKind::ReError(ref __other_field_0)) =>
                    true &&
                        ::core::cmp::PartialEq::eq(__field_0, __other_field_0),
                _ => true,
            }
        } else { false }
    }
}#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
130#[derive(GenericTypeVisitable)]
131#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<I: Interner, __E: ::rustc_serialize::Encoder>
            ::rustc_serialize::Encodable<__E> for RegionKind<I> where
            I::EarlyParamRegion: ::rustc_serialize::Encodable<__E>,
            BoundRegion<I>: ::rustc_serialize::Encodable<__E>,
            I::LateParamRegion: ::rustc_serialize::Encodable<__E>,
            PlaceholderRegion<I>: ::rustc_serialize::Encodable<__E>,
            I::ErrorGuaranteed: ::rustc_serialize::Encodable<__E> {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        RegionKind::ReEarlyParam(ref __binding_0) => { 0usize }
                        RegionKind::ReBound(ref __binding_0, ref __binding_1) => {
                            1usize
                        }
                        RegionKind::ReLateParam(ref __binding_0) => { 2usize }
                        RegionKind::ReStatic => { 3usize }
                        RegionKind::ReVar(ref __binding_0) => { 4usize }
                        RegionKind::RePlaceholder(ref __binding_0) => { 5usize }
                        RegionKind::ReErased => { 6usize }
                        RegionKind::ReError(ref __binding_0) => { 7usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    RegionKind::ReEarlyParam(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    RegionKind::ReBound(ref __binding_0, ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    RegionKind::ReLateParam(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    RegionKind::ReStatic => {}
                    RegionKind::ReVar(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    RegionKind::RePlaceholder(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    RegionKind::ReErased => {}
                    RegionKind::ReError(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };Encodable_NoContext, const _: () =
    {
        impl<I: Interner, __D: ::rustc_serialize::Decoder>
            ::rustc_serialize::Decodable<__D> for RegionKind<I> where
            I::EarlyParamRegion: ::rustc_serialize::Decodable<__D>,
            BoundRegion<I>: ::rustc_serialize::Decodable<__D>,
            I::LateParamRegion: ::rustc_serialize::Decodable<__D>,
            PlaceholderRegion<I>: ::rustc_serialize::Decodable<__D>,
            I::ErrorGuaranteed: ::rustc_serialize::Decodable<__D> {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        RegionKind::ReEarlyParam(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        RegionKind::ReBound(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        RegionKind::ReLateParam(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    3usize => { RegionKind::ReStatic }
                    4usize => {
                        RegionKind::ReVar(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    5usize => {
                        RegionKind::RePlaceholder(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    6usize => { RegionKind::ReErased }
                    7usize => {
                        RegionKind::ReError(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `RegionKind`, expected 0..8, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable_NoContext))]
132pub enum RegionKind<I: Interner> {
133    /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
134    ///
135    /// There are some important differences between region and type parameters.
136    /// Not all region parameters in the source are represented via `ReEarlyParam`:
137    /// late-bound function parameters are instead lowered to a `ReBound`. Late-bound
138    /// regions get eagerly replaced with `ReLateParam` which behaves in the same way as
139    /// `ReEarlyParam`. Region parameters are also sometimes implicit,
140    /// e.g. in `impl Trait for &()`.
141    ReEarlyParam(I::EarlyParamRegion),
142
143    /// A higher-ranked region. These represent either late-bound function parameters
144    /// or bound variables from a `for<'a>`-binder.
145    ///
146    /// While inside of a function, e.g. during typeck, the late-bound function parameters
147    /// can be converted to `ReLateParam` by calling `tcx.liberate_late_bound_regions`.
148    ///
149    /// Bound regions inside of types **must not** be erased, as they impact trait
150    /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and
151    /// `fn(&'static ())` are different types and have to be treated as such.
152    ReBound(BoundVarIndexKind, BoundRegion<I>),
153
154    /// Late-bound function parameters are represented using a `ReBound`. When
155    /// inside of a function, we convert these bound variables to placeholder
156    /// parameters via `tcx.liberate_late_bound_regions`. They are then treated
157    /// the same way as `ReEarlyParam` while inside of the function.
158    ///
159    /// See <https://rustc-dev-guide.rust-lang.org/early_late_parameters.html> for
160    /// more info about early and late bound lifetime parameters.
161    ReLateParam(I::LateParamRegion),
162
163    /// Static data that has an "infinite" lifetime. Top in the region lattice.
164    ReStatic,
165
166    /// A region variable. Should not exist outside of type inference.
167    ReVar(RegionVid),
168
169    /// A placeholder region -- the higher-ranked version of `ReLateParam`.
170    /// Should not exist outside of type inference.
171    ///
172    /// Used when instantiating a `forall` binder via `infcx.enter_forall`.
173    RePlaceholder(PlaceholderRegion<I>),
174
175    /// Erased region, used by trait selection, in MIR and during codegen.
176    ReErased,
177
178    /// A region that resulted from some other error. Used exclusively for diagnostics.
179    ReError(I::ErrorGuaranteed),
180}
181
182impl<I: Interner> Eq for RegionKind<I> {}
183
184impl<I: Interner> fmt::Debug for RegionKind<I> {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        match self {
187            ReEarlyParam(data) => f.write_fmt(format_args!("{0:?}", data))write!(f, "{data:?}"),
188
189            ReBound(binder_id, bound_region) => {
190                f.write_fmt(format_args!("\'"))write!(f, "'")?;
191                crate::debug_bound_var(f, *binder_id, bound_region)
192            }
193
194            ReLateParam(fr) => f.write_fmt(format_args!("{0:?}", fr))write!(f, "{fr:?}"),
195
196            ReStatic => f.write_str("'static"),
197
198            ReVar(vid) => f.write_fmt(format_args!("{0:?}", vid))write!(f, "{vid:?}"),
199
200            RePlaceholder(placeholder) => f.write_fmt(format_args!("\'{0:?}", placeholder))write!(f, "'{placeholder:?}"),
201
202            // Use `'{erased}` as the output instead of `'erased` so that its more obviously distinct from
203            // a `ReEarlyParam` named `'erased`. Technically that would print as `'erased/#IDX` so this is
204            // not strictly necessary but *shrug*
205            ReErased => f.write_str("'{erased}"),
206
207            ReError(_) => f.write_str("'{region error}"),
208        }
209    }
210}
211
212#[cfg(feature = "nightly")]
213// This is not a derived impl because a derive would require `I: HashStable`
214impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I>
215where
216    I::EarlyParamRegion: HashStable<CTX>,
217    I::LateParamRegion: HashStable<CTX>,
218    I::DefId: HashStable<CTX>,
219    I::Symbol: HashStable<CTX>,
220{
221    #[inline]
222    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
223        std::mem::discriminant(self).hash_stable(hcx, hasher);
224        match self {
225            ReErased | ReStatic | ReError(_) => {
226                // No variant fields to hash for these ...
227            }
228            ReBound(d, r) => {
229                d.hash_stable(hcx, hasher);
230                r.hash_stable(hcx, hasher);
231            }
232            ReEarlyParam(r) => {
233                r.hash_stable(hcx, hasher);
234            }
235            ReLateParam(r) => {
236                r.hash_stable(hcx, hasher);
237            }
238            RePlaceholder(r) => {
239                r.hash_stable(hcx, hasher);
240            }
241            ReVar(_) => {
242                {
    ::core::panicking::panic_fmt(format_args!("region variables should not be hashed: {0:?}",
            self));
}panic!("region variables should not be hashed: {self:?}")
243            }
244        }
245    }
246}