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