|
| 1 | +use polonius_engine::Atom; |
| 2 | +use rustc_data_structures::intern::Interned; |
| 3 | +use rustc_errors::MultiSpan; |
| 4 | +use rustc_hir::def_id::DefId; |
| 5 | +use rustc_index::Idx; |
| 6 | +use rustc_span::symbol::sym; |
| 7 | +use rustc_span::symbol::{kw, Symbol}; |
| 8 | +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; |
| 9 | +use rustc_type_ir::RegionKind as IrRegionKind; |
| 10 | +use std::ops::Deref; |
| 11 | + |
| 12 | +use crate::ty::{self, BoundVar, TyCtxt, TypeFlags}; |
| 13 | + |
| 14 | +pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; |
| 15 | + |
| 16 | +/// Use this rather than `RegionKind`, whenever possible. |
| 17 | +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] |
| 18 | +#[rustc_pass_by_value] |
| 19 | +pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); |
| 20 | + |
| 21 | +impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> { |
| 22 | + type Kind = RegionKind<'tcx>; |
| 23 | + |
| 24 | + fn kind(self) -> RegionKind<'tcx> { |
| 25 | + *self |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +impl<'tcx> Region<'tcx> { |
| 30 | + #[inline] |
| 31 | + pub fn new_early_param( |
| 32 | + tcx: TyCtxt<'tcx>, |
| 33 | + early_bound_region: ty::EarlyParamRegion, |
| 34 | + ) -> Region<'tcx> { |
| 35 | + tcx.intern_region(ty::ReEarlyParam(early_bound_region)) |
| 36 | + } |
| 37 | + |
| 38 | + #[inline] |
| 39 | + pub fn new_bound( |
| 40 | + tcx: TyCtxt<'tcx>, |
| 41 | + debruijn: ty::DebruijnIndex, |
| 42 | + bound_region: ty::BoundRegion, |
| 43 | + ) -> Region<'tcx> { |
| 44 | + // Use a pre-interned one when possible. |
| 45 | + if let ty::BoundRegion { var, kind: ty::BrAnon } = bound_region |
| 46 | + && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) |
| 47 | + && let Some(re) = inner.get(var.as_usize()).copied() |
| 48 | + { |
| 49 | + re |
| 50 | + } else { |
| 51 | + tcx.intern_region(ty::ReBound(debruijn, bound_region)) |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + #[inline] |
| 56 | + pub fn new_late_param( |
| 57 | + tcx: TyCtxt<'tcx>, |
| 58 | + scope: DefId, |
| 59 | + bound_region: ty::BoundRegionKind, |
| 60 | + ) -> Region<'tcx> { |
| 61 | + tcx.intern_region(ty::ReLateParam(ty::LateParamRegion { scope, bound_region })) |
| 62 | + } |
| 63 | + |
| 64 | + #[inline] |
| 65 | + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { |
| 66 | + // Use a pre-interned one when possible. |
| 67 | + tcx.lifetimes |
| 68 | + .re_vars |
| 69 | + .get(v.as_usize()) |
| 70 | + .copied() |
| 71 | + .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) |
| 72 | + } |
| 73 | + |
| 74 | + #[inline] |
| 75 | + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { |
| 76 | + tcx.intern_region(ty::RePlaceholder(placeholder)) |
| 77 | + } |
| 78 | + |
| 79 | + /// Constructs a `RegionKind::ReError` region. |
| 80 | + #[track_caller] |
| 81 | + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { |
| 82 | + tcx.intern_region(ty::ReError(reported)) |
| 83 | + } |
| 84 | + |
| 85 | + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it |
| 86 | + /// gets used. |
| 87 | + #[track_caller] |
| 88 | + pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { |
| 89 | + Region::new_error_with_message( |
| 90 | + tcx, |
| 91 | + DUMMY_SP, |
| 92 | + "RegionKind::ReError constructed but no error reported", |
| 93 | + ) |
| 94 | + } |
| 95 | + |
| 96 | + /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given |
| 97 | + /// `msg` to ensure it gets used. |
| 98 | + #[track_caller] |
| 99 | + pub fn new_error_with_message<S: Into<MultiSpan>>( |
| 100 | + tcx: TyCtxt<'tcx>, |
| 101 | + span: S, |
| 102 | + msg: &'static str, |
| 103 | + ) -> Region<'tcx> { |
| 104 | + let reported = tcx.dcx().span_delayed_bug(span, msg); |
| 105 | + Region::new_error(tcx, reported) |
| 106 | + } |
| 107 | + |
| 108 | + /// Avoid this in favour of more specific `new_*` methods, where possible, |
| 109 | + /// to avoid the cost of the `match`. |
| 110 | + pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { |
| 111 | + match kind { |
| 112 | + ty::ReEarlyParam(region) => Region::new_early_param(tcx, region), |
| 113 | + ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region), |
| 114 | + ty::ReLateParam(ty::LateParamRegion { scope, bound_region }) => { |
| 115 | + Region::new_late_param(tcx, scope, bound_region) |
| 116 | + } |
| 117 | + ty::ReStatic => tcx.lifetimes.re_static, |
| 118 | + ty::ReVar(vid) => Region::new_var(tcx, vid), |
| 119 | + ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), |
| 120 | + ty::ReErased => tcx.lifetimes.re_erased, |
| 121 | + ty::ReError(reported) => Region::new_error(tcx, reported), |
| 122 | + } |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +/// Region utilities |
| 127 | +impl<'tcx> Region<'tcx> { |
| 128 | + pub fn kind(self) -> RegionKind<'tcx> { |
| 129 | + *self.0.0 |
| 130 | + } |
| 131 | + |
| 132 | + pub fn get_name(self) -> Option<Symbol> { |
| 133 | + if self.has_name() { |
| 134 | + match *self { |
| 135 | + ty::ReEarlyParam(ebr) => Some(ebr.name), |
| 136 | + ty::ReBound(_, br) => br.kind.get_name(), |
| 137 | + ty::ReLateParam(fr) => fr.bound_region.get_name(), |
| 138 | + ty::ReStatic => Some(kw::StaticLifetime), |
| 139 | + ty::RePlaceholder(placeholder) => placeholder.bound.kind.get_name(), |
| 140 | + _ => None, |
| 141 | + } |
| 142 | + } else { |
| 143 | + None |
| 144 | + } |
| 145 | + } |
| 146 | + |
| 147 | + pub fn get_name_or_anon(self) -> Symbol { |
| 148 | + match self.get_name() { |
| 149 | + Some(name) => name, |
| 150 | + None => sym::anon, |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + /// Is this region named by the user? |
| 155 | + pub fn has_name(self) -> bool { |
| 156 | + match *self { |
| 157 | + ty::ReEarlyParam(ebr) => ebr.has_name(), |
| 158 | + ty::ReBound(_, br) => br.kind.is_named(), |
| 159 | + ty::ReLateParam(fr) => fr.bound_region.is_named(), |
| 160 | + ty::ReStatic => true, |
| 161 | + ty::ReVar(..) => false, |
| 162 | + ty::RePlaceholder(placeholder) => placeholder.bound.kind.is_named(), |
| 163 | + ty::ReErased => false, |
| 164 | + ty::ReError(_) => false, |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + #[inline] |
| 169 | + pub fn is_error(self) -> bool { |
| 170 | + matches!(*self, ty::ReError(_)) |
| 171 | + } |
| 172 | + |
| 173 | + #[inline] |
| 174 | + pub fn is_static(self) -> bool { |
| 175 | + matches!(*self, ty::ReStatic) |
| 176 | + } |
| 177 | + |
| 178 | + #[inline] |
| 179 | + pub fn is_erased(self) -> bool { |
| 180 | + matches!(*self, ty::ReErased) |
| 181 | + } |
| 182 | + |
| 183 | + #[inline] |
| 184 | + pub fn is_bound(self) -> bool { |
| 185 | + matches!(*self, ty::ReBound(..)) |
| 186 | + } |
| 187 | + |
| 188 | + #[inline] |
| 189 | + pub fn is_placeholder(self) -> bool { |
| 190 | + matches!(*self, ty::RePlaceholder(..)) |
| 191 | + } |
| 192 | + |
| 193 | + #[inline] |
| 194 | + pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { |
| 195 | + match *self { |
| 196 | + ty::ReBound(debruijn, _) => debruijn >= index, |
| 197 | + _ => false, |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + pub fn type_flags(self) -> TypeFlags { |
| 202 | + let mut flags = TypeFlags::empty(); |
| 203 | + |
| 204 | + match *self { |
| 205 | + ty::ReVar(..) => { |
| 206 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 207 | + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; |
| 208 | + flags = flags | TypeFlags::HAS_RE_INFER; |
| 209 | + } |
| 210 | + ty::RePlaceholder(..) => { |
| 211 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 212 | + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; |
| 213 | + flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; |
| 214 | + } |
| 215 | + ty::ReEarlyParam(..) => { |
| 216 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 217 | + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; |
| 218 | + flags = flags | TypeFlags::HAS_RE_PARAM; |
| 219 | + } |
| 220 | + ty::ReLateParam { .. } => { |
| 221 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 222 | + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; |
| 223 | + } |
| 224 | + ty::ReStatic => { |
| 225 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 226 | + } |
| 227 | + ty::ReBound(..) => { |
| 228 | + flags = flags | TypeFlags::HAS_RE_BOUND; |
| 229 | + } |
| 230 | + ty::ReErased => { |
| 231 | + flags = flags | TypeFlags::HAS_RE_ERASED; |
| 232 | + } |
| 233 | + ty::ReError(_) => { |
| 234 | + flags = flags | TypeFlags::HAS_FREE_REGIONS; |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + debug!("type_flags({:?}) = {:?}", self, flags); |
| 239 | + |
| 240 | + flags |
| 241 | + } |
| 242 | + |
| 243 | + /// Given an early-bound or free region, returns the `DefId` where it was bound. |
| 244 | + /// For example, consider the regions in this snippet of code: |
| 245 | + /// |
| 246 | + /// ```ignore (illustrative) |
| 247 | + /// impl<'a> Foo { |
| 248 | + /// // ^^ -- early bound, declared on an impl |
| 249 | + /// |
| 250 | + /// fn bar<'b, 'c>(x: &self, y: &'b u32, z: &'c u64) where 'static: 'c |
| 251 | + /// // ^^ ^^ ^ anonymous, late-bound |
| 252 | + /// // | early-bound, appears in where-clauses |
| 253 | + /// // late-bound, appears only in fn args |
| 254 | + /// {..} |
| 255 | + /// } |
| 256 | + /// ``` |
| 257 | + /// |
| 258 | + /// Here, `free_region_binding_scope('a)` would return the `DefId` |
| 259 | + /// of the impl, and for all the other highlighted regions, it |
| 260 | + /// would return the `DefId` of the function. In other cases (not shown), this |
| 261 | + /// function might return the `DefId` of a closure. |
| 262 | + pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { |
| 263 | + match *self { |
| 264 | + ty::ReEarlyParam(br) => tcx.parent(br.def_id), |
| 265 | + ty::ReLateParam(fr) => fr.scope, |
| 266 | + _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), |
| 267 | + } |
| 268 | + } |
| 269 | + |
| 270 | + /// True for free regions other than `'static`. |
| 271 | + pub fn is_param(self) -> bool { |
| 272 | + matches!(*self, ty::ReEarlyParam(_) | ty::ReLateParam(_)) |
| 273 | + } |
| 274 | + |
| 275 | + /// True for free region in the current context. |
| 276 | + /// |
| 277 | + /// This is the case for `'static` and param regions. |
| 278 | + pub fn is_free(self) -> bool { |
| 279 | + match *self { |
| 280 | + ty::ReStatic | ty::ReEarlyParam(..) | ty::ReLateParam(..) => true, |
| 281 | + ty::ReVar(..) |
| 282 | + | ty::RePlaceholder(..) |
| 283 | + | ty::ReBound(..) |
| 284 | + | ty::ReErased |
| 285 | + | ty::ReError(..) => false, |
| 286 | + } |
| 287 | + } |
| 288 | + |
| 289 | + pub fn is_var(self) -> bool { |
| 290 | + matches!(self.kind(), ty::ReVar(_)) |
| 291 | + } |
| 292 | + |
| 293 | + pub fn as_var(self) -> RegionVid { |
| 294 | + match self.kind() { |
| 295 | + ty::ReVar(vid) => vid, |
| 296 | + _ => bug!("expected region {:?} to be of kind ReVar", self), |
| 297 | + } |
| 298 | + } |
| 299 | +} |
| 300 | + |
| 301 | +impl<'tcx> Deref for Region<'tcx> { |
| 302 | + type Target = RegionKind<'tcx>; |
| 303 | + |
| 304 | + #[inline] |
| 305 | + fn deref(&self) -> &RegionKind<'tcx> { |
| 306 | + self.0.0 |
| 307 | + } |
| 308 | +} |
| 309 | + |
| 310 | +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] |
| 311 | +#[derive(HashStable)] |
| 312 | +pub struct EarlyParamRegion { |
| 313 | + pub def_id: DefId, |
| 314 | + pub index: u32, |
| 315 | + pub name: Symbol, |
| 316 | +} |
| 317 | + |
| 318 | +impl std::fmt::Debug for EarlyParamRegion { |
| 319 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 320 | + write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) |
| 321 | + } |
| 322 | +} |
| 323 | + |
| 324 | +rustc_index::newtype_index! { |
| 325 | + /// A **region** (lifetime) **v**ariable **ID**. |
| 326 | + #[derive(HashStable)] |
| 327 | + #[encodable] |
| 328 | + #[orderable] |
| 329 | + #[debug_format = "'?{}"] |
| 330 | + pub struct RegionVid {} |
| 331 | +} |
| 332 | + |
| 333 | +impl Atom for RegionVid { |
| 334 | + fn index(self) -> usize { |
| 335 | + Idx::index(self) |
| 336 | + } |
| 337 | +} |
| 338 | + |
| 339 | +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] |
| 340 | +#[derive(HashStable)] |
| 341 | +/// The parameter representation of late-bound function parameters, "some region |
| 342 | +/// at least as big as the scope `fr.scope`". |
| 343 | +pub struct LateParamRegion { |
| 344 | + pub scope: DefId, |
| 345 | + pub bound_region: BoundRegionKind, |
| 346 | +} |
| 347 | + |
| 348 | +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] |
| 349 | +#[derive(HashStable)] |
| 350 | +pub enum BoundRegionKind { |
| 351 | + /// An anonymous region parameter for a given fn (&T) |
| 352 | + BrAnon, |
| 353 | + |
| 354 | + /// Named region parameters for functions (a in &'a T) |
| 355 | + /// |
| 356 | + /// The `DefId` is needed to distinguish free regions in |
| 357 | + /// the event of shadowing. |
| 358 | + BrNamed(DefId, Symbol), |
| 359 | + |
| 360 | + /// Anonymous region for the implicit env pointer parameter |
| 361 | + /// to a closure |
| 362 | + BrEnv, |
| 363 | +} |
| 364 | + |
| 365 | +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] |
| 366 | +#[derive(HashStable)] |
| 367 | +pub struct BoundRegion { |
| 368 | + pub var: BoundVar, |
| 369 | + pub kind: BoundRegionKind, |
| 370 | +} |
| 371 | + |
| 372 | +impl BoundRegionKind { |
| 373 | + pub fn is_named(&self) -> bool { |
| 374 | + match *self { |
| 375 | + BoundRegionKind::BrNamed(_, name) => { |
| 376 | + name != kw::UnderscoreLifetime && name != kw::Empty |
| 377 | + } |
| 378 | + _ => false, |
| 379 | + } |
| 380 | + } |
| 381 | + |
| 382 | + pub fn get_name(&self) -> Option<Symbol> { |
| 383 | + if self.is_named() { |
| 384 | + match *self { |
| 385 | + BoundRegionKind::BrNamed(_, name) => return Some(name), |
| 386 | + _ => unreachable!(), |
| 387 | + } |
| 388 | + } |
| 389 | + |
| 390 | + None |
| 391 | + } |
| 392 | + |
| 393 | + pub fn get_id(&self) -> Option<DefId> { |
| 394 | + match *self { |
| 395 | + BoundRegionKind::BrNamed(id, _) => return Some(id), |
| 396 | + _ => None, |
| 397 | + } |
| 398 | + } |
| 399 | +} |
0 commit comments