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#[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 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 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 #[track_caller]
95 pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Region<'tcx> {
96 tcx.intern_region(ty::ReError(guar))
97 }
98
99 #[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 #[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 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
158impl<'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 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 pub fn is_param(self) -> bool {
278 matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_))
279 }
280
281 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 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)]
352pub struct LateParamRegion {
361 pub scope: DefId,
362 pub kind: LateParamRegionKind,
363}
364
365#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
370#[derive(HashStable)]
371pub enum LateParamRegionKind {
372 Anon(u32),
380
381 Named(DefId, Symbol),
386
387 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 Anon,
434
435 Named(DefId, Symbol),
440
441 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}