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(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(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 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 #[track_caller]
93 pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Region<'tcx> {
94 tcx.intern_region(ty::ReError(guar))
95 }
96
97 #[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 #[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 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
160impl<'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 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 pub fn is_param(self) -> bool {
276 matches!(self.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_))
277 }
278
279 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 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 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)]
349pub struct LateParamRegion {
358 pub scope: DefId,
359 pub kind: LateParamRegionKind,
360}
361
362#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
367#[derive(HashStable)]
368pub enum LateParamRegionKind {
369 Anon(u32),
377
378 NamedAnon(u32, Symbol),
382
383 Named(DefId),
385
386 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 Anon,
429
430 NamedAnon(Symbol),
434
435 Named(DefId),
437
438 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#[cfg(target_pointer_width = "64")]
501mod size_asserts {
502 use rustc_data_structures::static_assert_size;
503
504 use super::*;
505 static_assert_size!(RegionKind<'_>, 20);
507 static_assert_size!(ty::WithCachedTypeInfo<RegionKind<'_>>, 48);
508 }