rustc_middle/ty/
region.rs

1use rustc_data_structures::intern::Interned;
2use rustc_errors::MultiSpan;
3use rustc_hir::def_id::DefId;
4use rustc_macros::{HashStable, TyDecodable, TyEncodable};
5use rustc_span::{DUMMY_SP, ErrorGuaranteed, Symbol, kw, sym};
6use rustc_type_ir::RegionKind as IrRegionKind;
7pub use rustc_type_ir::RegionVid;
8use tracing::debug;
9
10use crate::ty::{self, BoundVar, TyCtxt, TypeFlags};
11
12pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
13
14/// Use this rather than `RegionKind`, whenever possible.
15#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
16#[rustc_pass_by_value]
17pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
18
19impl<'tcx> rustc_type_ir::inherent::IntoKind for Region<'tcx> {
20    type Kind = RegionKind<'tcx>;
21
22    fn kind(self) -> RegionKind<'tcx> {
23        *self.0.0
24    }
25}
26
27impl<'tcx> rustc_type_ir::Flags for Region<'tcx> {
28    fn flags(&self) -> TypeFlags {
29        self.type_flags()
30    }
31
32    fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
33        match self.kind() {
34            ty::ReBound(debruijn, _) => debruijn.shifted_in(1),
35            _ => ty::INNERMOST,
36        }
37    }
38}
39
40impl<'tcx> Region<'tcx> {
41    #[inline]
42    pub fn new_early_param(
43        tcx: TyCtxt<'tcx>,
44        early_bound_region: ty::EarlyParamRegion,
45    ) -> Region<'tcx> {
46        tcx.intern_region(ty::ReEarlyParam(early_bound_region))
47    }
48
49    #[inline]
50    pub fn new_bound(
51        tcx: TyCtxt<'tcx>,
52        debruijn: ty::DebruijnIndex,
53        bound_region: ty::BoundRegion,
54    ) -> Region<'tcx> {
55        // Use a pre-interned one when possible.
56        if let ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon } = bound_region
57            && let Some(inner) = tcx.lifetimes.anon_re_bounds.get(debruijn.as_usize())
58            && let Some(re) = inner.get(var.as_usize()).copied()
59        {
60            re
61        } else {
62            tcx.intern_region(ty::ReBound(debruijn, bound_region))
63        }
64    }
65
66    #[inline]
67    pub fn new_late_param(
68        tcx: TyCtxt<'tcx>,
69        scope: DefId,
70        kind: LateParamRegionKind,
71    ) -> Region<'tcx> {
72        let data = LateParamRegion { scope, kind };
73        tcx.intern_region(ty::ReLateParam(data))
74    }
75
76    #[inline]
77    pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> {
78        // Use a pre-interned one when possible.
79        tcx.lifetimes
80            .re_vars
81            .get(v.as_usize())
82            .copied()
83            .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v)))
84    }
85
86    #[inline]
87    pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> {
88        tcx.intern_region(ty::RePlaceholder(placeholder))
89    }
90
91    /// Constructs a `RegionKind::ReError` region.
92    #[track_caller]
93    pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Region<'tcx> {
94        tcx.intern_region(ty::ReError(guar))
95    }
96
97    /// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets
98    /// used.
99    #[track_caller]
100    pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
101        Region::new_error_with_message(
102            tcx,
103            DUMMY_SP,
104            "RegionKind::ReError constructed but no error reported",
105        )
106    }
107
108    /// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg`
109    /// to ensure it gets used.
110    #[track_caller]
111    pub fn new_error_with_message<S: Into<MultiSpan>>(
112        tcx: TyCtxt<'tcx>,
113        span: S,
114        msg: &'static str,
115    ) -> Region<'tcx> {
116        let reported = tcx.dcx().span_delayed_bug(span, msg);
117        Region::new_error(tcx, reported)
118    }
119
120    /// Avoid this in favour of more specific `new_*` methods, where possible,
121    /// to avoid the cost of the `match`.
122    pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
123        match kind {
124            ty::ReEarlyParam(region) => Region::new_early_param(tcx, region),
125            ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region),
126            ty::ReLateParam(ty::LateParamRegion { scope, kind }) => {
127                Region::new_late_param(tcx, scope, kind)
128            }
129            ty::ReStatic => tcx.lifetimes.re_static,
130            ty::ReVar(vid) => Region::new_var(tcx, vid),
131            ty::RePlaceholder(region) => Region::new_placeholder(tcx, region),
132            ty::ReErased => tcx.lifetimes.re_erased,
133            ty::ReError(reported) => Region::new_error(tcx, reported),
134        }
135    }
136}
137
138impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
139    fn new_bound(
140        interner: TyCtxt<'tcx>,
141        debruijn: ty::DebruijnIndex,
142        var: ty::BoundRegion,
143    ) -> Self {
144        Region::new_bound(interner, debruijn, var)
145    }
146
147    fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
148        Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon })
149    }
150
151    fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self {
152        Region::new_placeholder(tcx, placeholder)
153    }
154
155    fn new_static(tcx: TyCtxt<'tcx>) -> Self {
156        tcx.lifetimes.re_static
157    }
158}
159
160/// Region utilities
161impl<'tcx> Region<'tcx> {
162    pub fn kind(self) -> RegionKind<'tcx> {
163        *self.0.0
164    }
165
166    pub fn get_name(self, tcx: TyCtxt<'tcx>) -> Option<Symbol> {
167        match self.kind() {
168            ty::ReEarlyParam(ebr) => ebr.is_named().then_some(ebr.name),
169            ty::ReBound(_, br) => br.kind.get_name(tcx),
170            ty::ReLateParam(fr) => fr.kind.get_name(tcx),
171            ty::ReStatic => Some(kw::StaticLifetime),
172            ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(tcx),
173            _ => None,
174        }
175    }
176
177    pub fn get_name_or_anon(self, tcx: TyCtxt<'tcx>) -> Symbol {
178        match self.get_name(tcx) {
179            Some(name) => name,
180            None => sym::anon,
181        }
182    }
183
184    /// Is this region named by the user?
185    pub fn is_named(self, tcx: TyCtxt<'tcx>) -> bool {
186        match self.kind() {
187            ty::ReEarlyParam(ebr) => ebr.is_named(),
188            ty::ReBound(_, br) => br.kind.is_named(tcx),
189            ty::ReLateParam(fr) => fr.kind.is_named(tcx),
190            ty::ReStatic => true,
191            ty::ReVar(..) => false,
192            ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(tcx),
193            ty::ReErased => false,
194            ty::ReError(_) => false,
195        }
196    }
197
198    #[inline]
199    pub fn is_error(self) -> bool {
200        matches!(self.kind(), ty::ReError(_))
201    }
202
203    #[inline]
204    pub fn is_static(self) -> bool {
205        matches!(self.kind(), ty::ReStatic)
206    }
207
208    #[inline]
209    pub fn is_erased(self) -> bool {
210        matches!(self.kind(), ty::ReErased)
211    }
212
213    #[inline]
214    pub fn is_bound(self) -> bool {
215        matches!(self.kind(), ty::ReBound(..))
216    }
217
218    #[inline]
219    pub fn is_placeholder(self) -> bool {
220        matches!(self.kind(), ty::RePlaceholder(..))
221    }
222
223    #[inline]
224    pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
225        match self.kind() {
226            ty::ReBound(debruijn, _) => debruijn >= index,
227            _ => false,
228        }
229    }
230
231    pub fn type_flags(self) -> TypeFlags {
232        let mut flags = TypeFlags::empty();
233
234        match self.kind() {
235            ty::ReVar(..) => {
236                flags = flags | TypeFlags::HAS_FREE_REGIONS;
237                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
238                flags = flags | TypeFlags::HAS_RE_INFER;
239            }
240            ty::RePlaceholder(..) => {
241                flags = flags | TypeFlags::HAS_FREE_REGIONS;
242                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
243                flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
244            }
245            ty::ReEarlyParam(..) => {
246                flags = flags | TypeFlags::HAS_FREE_REGIONS;
247                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
248                flags = flags | TypeFlags::HAS_RE_PARAM;
249            }
250            ty::ReLateParam { .. } => {
251                flags = flags | TypeFlags::HAS_FREE_REGIONS;
252                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
253            }
254            ty::ReStatic => {
255                flags = flags | TypeFlags::HAS_FREE_REGIONS;
256            }
257            ty::ReBound(..) => {
258                flags = flags | TypeFlags::HAS_RE_BOUND;
259            }
260            ty::ReErased => {
261                flags = flags | TypeFlags::HAS_RE_ERASED;
262            }
263            ty::ReError(_) => {
264                flags = flags | TypeFlags::HAS_FREE_REGIONS;
265                flags = flags | TypeFlags::HAS_ERROR;
266            }
267        }
268
269        debug!("type_flags({:?}) = {:?}", self, flags);
270
271        flags
272    }
273
274    /// True for free regions other than `'static`.
275    pub fn is_param(self) -> bool {
276        matches!(self.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_))
277    }
278
279    /// True for free region in the current context.
280    ///
281    /// This is the case for `'static` and param regions.
282    pub fn is_free(self) -> bool {
283        match self.kind() {
284            ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true,
285            ty::ReVar(..)
286            | ty::RePlaceholder(..)
287            | ty::ReBound(..)
288            | ty::ReErased
289            | ty::ReError(..) => false,
290        }
291    }
292
293    pub fn is_var(self) -> bool {
294        matches!(self.kind(), ty::ReVar(_))
295    }
296
297    pub fn as_var(self) -> RegionVid {
298        match self.kind() {
299            ty::ReVar(vid) => vid,
300            _ => bug!("expected region {:?} to be of kind ReVar", self),
301        }
302    }
303
304    /// Given some item `binding_item`, check if this region is a generic parameter introduced by it
305    /// or one of the parent generics. Returns the `DefId` of the parameter definition if so.
306    pub fn opt_param_def_id(self, tcx: TyCtxt<'tcx>, binding_item: DefId) -> Option<DefId> {
307        match self.kind() {
308            ty::ReEarlyParam(ebr) => {
309                Some(tcx.generics_of(binding_item).region_param(ebr, tcx).def_id)
310            }
311            ty::ReLateParam(ty::LateParamRegion {
312                kind: ty::LateParamRegionKind::Named(def_id),
313                ..
314            }) => Some(def_id),
315            _ => None,
316        }
317    }
318}
319
320#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
321#[derive(HashStable)]
322pub struct EarlyParamRegion {
323    pub index: u32,
324    pub name: Symbol,
325}
326
327impl EarlyParamRegion {
328    /// Does this early bound region have a name? Early bound regions normally
329    /// always have names except when using anonymous lifetimes (`'_`).
330    pub fn is_named(&self) -> bool {
331        self.name != kw::UnderscoreLifetime
332    }
333}
334
335impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion {
336    fn index(self) -> u32 {
337        self.index
338    }
339}
340
341impl std::fmt::Debug for EarlyParamRegion {
342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343        write!(f, "{}/#{}", self.name, self.index)
344    }
345}
346
347#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
348#[derive(HashStable)]
349/// The parameter representation of late-bound function parameters, "some region
350/// at least as big as the scope `fr.scope`".
351///
352/// Similar to a placeholder region as we create `LateParam` regions when entering a binder
353/// except they are always in the root universe and instead of using a boundvar to distinguish
354/// between others we use the `DefId` of the parameter. For this reason the `bound_region` field
355/// should basically always be `BoundRegionKind::Named` as otherwise there is no way of telling
356/// different parameters apart.
357pub struct LateParamRegion {
358    pub scope: DefId,
359    pub kind: LateParamRegionKind,
360}
361
362/// When liberating bound regions, we map their [`BoundRegionKind`]
363/// to this as we need to track the index of anonymous regions. We
364/// otherwise end up liberating multiple bound regions to the same
365/// late-bound region.
366#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
367#[derive(HashStable)]
368pub enum LateParamRegionKind {
369    /// An anonymous region parameter for a given fn (&T)
370    ///
371    /// Unlike [`BoundRegionKind::Anon`], this tracks the index of the
372    /// liberated bound region.
373    ///
374    /// We should ideally never liberate anonymous regions, but do so for the
375    /// sake of diagnostics in `FnCtxt::sig_of_closure_with_expectation`.
376    Anon(u32),
377
378    /// An anonymous region parameter with a `Symbol` name.
379    ///
380    /// Used to give late-bound regions names for things like pretty printing.
381    NamedAnon(u32, Symbol),
382
383    /// Late-bound regions that appear in the AST.
384    Named(DefId),
385
386    /// Anonymous region for the implicit env pointer parameter
387    /// to a closure
388    ClosureEnv,
389}
390
391impl LateParamRegionKind {
392    pub fn from_bound(var: BoundVar, br: BoundRegionKind) -> LateParamRegionKind {
393        match br {
394            BoundRegionKind::Anon => LateParamRegionKind::Anon(var.as_u32()),
395            BoundRegionKind::Named(def_id) => LateParamRegionKind::Named(def_id),
396            BoundRegionKind::ClosureEnv => LateParamRegionKind::ClosureEnv,
397            BoundRegionKind::NamedAnon(name) => LateParamRegionKind::NamedAnon(var.as_u32(), name),
398        }
399    }
400
401    pub fn is_named(&self, tcx: TyCtxt<'_>) -> bool {
402        self.get_name(tcx).is_some()
403    }
404
405    pub fn get_name(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
406        match *self {
407            LateParamRegionKind::Named(def_id) => {
408                let name = tcx.item_name(def_id);
409                if name != kw::UnderscoreLifetime { Some(name) } else { None }
410            }
411            LateParamRegionKind::NamedAnon(_, name) => Some(name),
412            _ => None,
413        }
414    }
415
416    pub fn get_id(&self) -> Option<DefId> {
417        match *self {
418            LateParamRegionKind::Named(id) => Some(id),
419            _ => None,
420        }
421    }
422}
423
424#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
425#[derive(HashStable)]
426pub enum BoundRegionKind {
427    /// An anonymous region parameter for a given fn (&T)
428    Anon,
429
430    /// An anonymous region parameter with a `Symbol` name.
431    ///
432    /// Used to give late-bound regions names for things like pretty printing.
433    NamedAnon(Symbol),
434
435    /// Late-bound regions that appear in the AST.
436    Named(DefId),
437
438    /// Anonymous region for the implicit env pointer parameter
439    /// to a closure
440    ClosureEnv,
441}
442
443#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
444#[derive(HashStable)]
445pub struct BoundRegion {
446    pub var: BoundVar,
447    pub kind: BoundRegionKind,
448}
449
450impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion {
451    fn var(self) -> BoundVar {
452        self.var
453    }
454
455    fn assert_eq(self, var: ty::BoundVariableKind) {
456        assert_eq!(self.kind, var.expect_region())
457    }
458}
459
460impl core::fmt::Debug for BoundRegion {
461    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
462        match self.kind {
463            BoundRegionKind::Anon => write!(f, "{:?}", self.var),
464            BoundRegionKind::ClosureEnv => write!(f, "{:?}.Env", self.var),
465            BoundRegionKind::Named(def) => {
466                write!(f, "{:?}.Named({:?})", self.var, def)
467            }
468            BoundRegionKind::NamedAnon(symbol) => {
469                write!(f, "{:?}.NamedAnon({:?})", self.var, symbol)
470            }
471        }
472    }
473}
474
475impl BoundRegionKind {
476    pub fn is_named(&self, tcx: TyCtxt<'_>) -> bool {
477        self.get_name(tcx).is_some()
478    }
479
480    pub fn get_name(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
481        match *self {
482            BoundRegionKind::Named(def_id) => {
483                let name = tcx.item_name(def_id);
484                if name != kw::UnderscoreLifetime { Some(name) } else { None }
485            }
486            BoundRegionKind::NamedAnon(name) => Some(name),
487            _ => None,
488        }
489    }
490
491    pub fn get_id(&self) -> Option<DefId> {
492        match *self {
493            BoundRegionKind::Named(id) => Some(id),
494            _ => None,
495        }
496    }
497}
498
499// Some types are used a lot. Make sure they don't unintentionally get bigger.
500#[cfg(target_pointer_width = "64")]
501mod size_asserts {
502    use rustc_data_structures::static_assert_size;
503
504    use super::*;
505    // tidy-alphabetical-start
506    static_assert_size!(RegionKind<'_>, 20);
507    static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 48);
508    // tidy-alphabetical-end
509}