rustc_middle/ty/
region.rs

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