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#[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 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 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 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 #[track_caller]
106 pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Region<'tcx> {
107 tcx.intern_region(ty::ReError(guar))
108 }
109
110 #[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 #[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 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
182impl<'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 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 pub fn is_param(self) -> bool {
302 matches!(self.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_))
303 }
304
305 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 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 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)]
375pub struct LateParamRegion {
384 pub scope: DefId,
385 pub kind: LateParamRegionKind,
386}
387
388#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
393#[derive(HashStable)]
394pub enum LateParamRegionKind {
395 Anon(u32),
403
404 NamedAnon(u32, Symbol),
408
409 Named(DefId),
411
412 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 Anon,
455
456 NamedAnon(Symbol),
460
461 Named(DefId),
463
464 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#[cfg(target_pointer_width = "64")]
527mod size_asserts {
528 use rustc_data_structures::static_assert_size;
529
530 use super::*;
531 static_assert_size!(RegionKind<'_>, 20);
533 static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 48);
534 }