1 //! See `README.md`. 2 3 use self::CombineMapType::*; 4 use self::UndoLog::*; 5 6 use super::{ 7 InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin, 8 }; 9 10 use rustc_data_structures::fx::FxHashMap; 11 use rustc_data_structures::intern::Interned; 12 use rustc_data_structures::sync::Lrc; 13 use rustc_data_structures::undo_log::UndoLogs; 14 use rustc_data_structures::unify as ut; 15 use rustc_index::IndexVec; 16 use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; 17 use rustc_middle::ty::ReStatic; 18 use rustc_middle::ty::{self, Ty, TyCtxt}; 19 use rustc_middle::ty::{ReLateBound, ReVar}; 20 use rustc_middle::ty::{Region, RegionVid}; 21 use rustc_span::Span; 22 23 use std::collections::BTreeMap; 24 use std::ops::Range; 25 use std::{cmp, fmt, mem}; 26 27 mod leak_check; 28 29 pub use rustc_middle::infer::MemberConstraint; 30 31 #[derive(Clone, Default)] 32 pub struct RegionConstraintStorage<'tcx> { 33 /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. 34 var_infos: IndexVec<RegionVid, RegionVariableInfo>, 35 36 data: RegionConstraintData<'tcx>, 37 38 /// For a given pair of regions (R1, R2), maps to a region R3 that 39 /// is designated as their LUB (edges R1 <= R3 and R2 <= R3 40 /// exist). This prevents us from making many such regions. 41 lubs: CombineMap<'tcx>, 42 43 /// For a given pair of regions (R1, R2), maps to a region R3 that 44 /// is designated as their GLB (edges R3 <= R1 and R3 <= R2 45 /// exist). This prevents us from making many such regions. 46 glbs: CombineMap<'tcx>, 47 48 /// When we add a R1 == R2 constraint, we currently add (a) edges 49 /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this 50 /// table. You can then call `opportunistic_resolve_var` early 51 /// which will map R1 and R2 to some common region (i.e., either 52 /// R1 or R2). This is important when fulfillment, dropck and other such 53 /// code is iterating to a fixed point, because otherwise we sometimes 54 /// would wind up with a fresh stream of region variables that have been 55 /// equated but appear distinct. 56 pub(super) unification_table: ut::UnificationTableStorage<RegionVidKey<'tcx>>, 57 58 /// a flag set to true when we perform any unifications; this is used 59 /// to micro-optimize `take_and_reset_data` 60 any_unifications: bool, 61 } 62 63 pub struct RegionConstraintCollector<'a, 'tcx> { 64 storage: &'a mut RegionConstraintStorage<'tcx>, 65 undo_log: &'a mut InferCtxtUndoLogs<'tcx>, 66 } 67 68 impl<'tcx> std::ops::Deref for RegionConstraintCollector<'_, 'tcx> { 69 type Target = RegionConstraintStorage<'tcx>; 70 #[inline] deref(&self) -> &RegionConstraintStorage<'tcx>71 fn deref(&self) -> &RegionConstraintStorage<'tcx> { 72 self.storage 73 } 74 } 75 76 impl<'tcx> std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { 77 #[inline] deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx>78 fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { 79 self.storage 80 } 81 } 82 83 pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>; 84 85 /// The full set of region constraints gathered up by the collector. 86 /// Describes constraints between the region variables and other 87 /// regions, as well as other conditions that must be verified, or 88 /// assumptions that can be made. 89 #[derive(Debug, Default, Clone)] 90 pub struct RegionConstraintData<'tcx> { 91 /// Constraints of the form `A <= B`, where either `A` or `B` can 92 /// be a region variable (or neither, as it happens). 93 pub constraints: BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>, 94 95 /// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that 96 /// `R0` must be equal to one of the regions `R1..Rn`. These occur 97 /// with `impl Trait` quite frequently. 98 pub member_constraints: Vec<MemberConstraint<'tcx>>, 99 100 /// A "verify" is something that we need to verify after inference 101 /// is done, but which does not directly affect inference in any 102 /// way. 103 /// 104 /// An example is a `A <= B` where neither `A` nor `B` are 105 /// inference variables. 106 pub verifys: Vec<Verify<'tcx>>, 107 } 108 109 /// Represents a constraint that influences the inference process. 110 #[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)] 111 pub enum Constraint<'tcx> { 112 /// A region variable is a subregion of another. 113 VarSubVar(RegionVid, RegionVid), 114 115 /// A concrete region is a subregion of region variable. 116 RegSubVar(Region<'tcx>, RegionVid), 117 118 /// A region variable is a subregion of a concrete region. This does not 119 /// directly affect inference, but instead is checked after 120 /// inference is complete. 121 VarSubReg(RegionVid, Region<'tcx>), 122 123 /// A constraint where neither side is a variable. This does not 124 /// directly affect inference, but instead is checked after 125 /// inference is complete. 126 RegSubReg(Region<'tcx>, Region<'tcx>), 127 } 128 129 impl Constraint<'_> { involves_placeholders(&self) -> bool130 pub fn involves_placeholders(&self) -> bool { 131 match self { 132 Constraint::VarSubVar(_, _) => false, 133 Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), 134 Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), 135 } 136 } 137 } 138 139 #[derive(Debug, Clone)] 140 pub struct Verify<'tcx> { 141 pub kind: GenericKind<'tcx>, 142 pub origin: SubregionOrigin<'tcx>, 143 pub region: Region<'tcx>, 144 pub bound: VerifyBound<'tcx>, 145 } 146 147 #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] 148 pub enum GenericKind<'tcx> { 149 Param(ty::ParamTy), 150 Alias(ty::AliasTy<'tcx>), 151 } 152 153 /// Describes the things that some `GenericKind` value `G` is known to 154 /// outlive. Each variant of `VerifyBound` can be thought of as a 155 /// function: 156 /// ```ignore (pseudo-rust) 157 /// fn(min: Region) -> bool { .. } 158 /// ``` 159 /// where `true` means that the region `min` meets that `G: min`. 160 /// (False means nothing.) 161 /// 162 /// So, for example, if we have the type `T` and we have in scope that 163 /// `T: 'a` and `T: 'b`, then the verify bound might be: 164 /// ```ignore (pseudo-rust) 165 /// fn(min: Region) -> bool { 166 /// ('a: min) || ('b: min) 167 /// } 168 /// ``` 169 /// This is described with an `AnyRegion('a, 'b)` node. 170 #[derive(Debug, Clone, TypeFoldable, TypeVisitable)] 171 pub enum VerifyBound<'tcx> { 172 /// See [`VerifyIfEq`] docs 173 IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>), 174 175 /// Given a region `R`, expands to the function: 176 /// 177 /// ```ignore (pseudo-rust) 178 /// fn(min) -> bool { 179 /// R: min 180 /// } 181 /// ``` 182 /// 183 /// This is used when we can establish that `G: R` -- therefore, 184 /// if `R: min`, then by transitivity `G: min`. 185 OutlivedBy(Region<'tcx>), 186 187 /// Given a region `R`, true if it is `'empty`. 188 IsEmpty, 189 190 /// Given a set of bounds `B`, expands to the function: 191 /// 192 /// ```ignore (pseudo-rust) 193 /// fn(min) -> bool { 194 /// exists (b in B) { b(min) } 195 /// } 196 /// ``` 197 /// 198 /// In other words, if we meet some bound in `B`, that suffices. 199 /// This is used when all the bounds in `B` are known to apply to `G`. 200 AnyBound(Vec<VerifyBound<'tcx>>), 201 202 /// Given a set of bounds `B`, expands to the function: 203 /// 204 /// ```ignore (pseudo-rust) 205 /// fn(min) -> bool { 206 /// forall (b in B) { b(min) } 207 /// } 208 /// ``` 209 /// 210 /// In other words, if we meet *all* bounds in `B`, that suffices. 211 /// This is used when *some* bound in `B` is known to suffice, but 212 /// we don't know which. 213 AllBounds(Vec<VerifyBound<'tcx>>), 214 } 215 216 /// This is a "conditional bound" that checks the result of inference 217 /// and supplies a bound if it ended up being relevant. It's used in situations 218 /// like this: 219 /// 220 /// ```rust,ignore (pseudo-Rust) 221 /// fn foo<'a, 'b, T: SomeTrait<'a>> 222 /// where 223 /// <T as SomeTrait<'a>>::Item: 'b 224 /// ``` 225 /// 226 /// If we have an obligation like `<T as SomeTrait<'?x>>::Item: 'c`, then 227 /// we don't know yet whether it suffices to show that `'b: 'c`. If `'?x` winds 228 /// up being equal to `'a`, then the where-clauses on function applies, and 229 /// in that case we can show `'b: 'c`. But if `'?x` winds up being something 230 /// else, the bound isn't relevant. 231 /// 232 /// In the [`VerifyBound`], this struct is enclosed in `Binder` to account 233 /// for cases like 234 /// 235 /// ```rust,ignore (pseudo-Rust) 236 /// where for<'a> <T as SomeTrait<'a>::Item: 'a 237 /// ``` 238 /// 239 /// The idea is that we have to find some instantiation of `'a` that can 240 /// make `<T as SomeTrait<'a>>::Item` equal to the final value of `G`, 241 /// the generic we are checking. 242 /// 243 /// ```ignore (pseudo-rust) 244 /// fn(min) -> bool { 245 /// exists<'a> { 246 /// if G == K { 247 /// B(min) 248 /// } else { 249 /// false 250 /// } 251 /// } 252 /// } 253 /// ``` 254 #[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable)] 255 pub struct VerifyIfEq<'tcx> { 256 /// Type which must match the generic `G` 257 pub ty: Ty<'tcx>, 258 259 /// Bound that applies if `ty` is equal. 260 pub bound: Region<'tcx>, 261 } 262 263 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 264 pub(crate) struct TwoRegions<'tcx> { 265 a: Region<'tcx>, 266 b: Region<'tcx>, 267 } 268 269 #[derive(Copy, Clone, PartialEq)] 270 pub(crate) enum UndoLog<'tcx> { 271 /// We added `RegionVid`. 272 AddVar(RegionVid), 273 274 /// We added the given `constraint`. 275 AddConstraint(Constraint<'tcx>), 276 277 /// We added the given `verify`. 278 AddVerify(usize), 279 280 /// We added a GLB/LUB "combination variable". 281 AddCombination(CombineMapType, TwoRegions<'tcx>), 282 } 283 284 #[derive(Copy, Clone, PartialEq)] 285 pub(crate) enum CombineMapType { 286 Lub, 287 Glb, 288 } 289 290 type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>; 291 292 #[derive(Debug, Clone, Copy)] 293 pub struct RegionVariableInfo { 294 pub origin: RegionVariableOrigin, 295 pub universe: ty::UniverseIndex, 296 } 297 298 pub struct RegionSnapshot { 299 any_unifications: bool, 300 } 301 302 impl<'tcx> RegionConstraintStorage<'tcx> { new() -> Self303 pub fn new() -> Self { 304 Self::default() 305 } 306 307 #[inline] with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, ) -> RegionConstraintCollector<'a, 'tcx>308 pub(crate) fn with_log<'a>( 309 &'a mut self, 310 undo_log: &'a mut InferCtxtUndoLogs<'tcx>, 311 ) -> RegionConstraintCollector<'a, 'tcx> { 312 RegionConstraintCollector { storage: self, undo_log } 313 } 314 rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>)315 fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { 316 match undo_entry { 317 AddVar(vid) => { 318 self.var_infos.pop().unwrap(); 319 assert_eq!(self.var_infos.len(), vid.index() as usize); 320 } 321 AddConstraint(ref constraint) => { 322 self.data.constraints.remove(constraint); 323 } 324 AddVerify(index) => { 325 self.data.verifys.pop(); 326 assert_eq!(self.data.verifys.len(), index); 327 } 328 AddCombination(Glb, ref regions) => { 329 self.glbs.remove(regions); 330 } 331 AddCombination(Lub, ref regions) => { 332 self.lubs.remove(regions); 333 } 334 } 335 } 336 } 337 338 impl<'tcx> RegionConstraintCollector<'_, 'tcx> { num_region_vars(&self) -> usize339 pub fn num_region_vars(&self) -> usize { 340 self.var_infos.len() 341 } 342 region_constraint_data(&self) -> &RegionConstraintData<'tcx>343 pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { 344 &self.data 345 } 346 347 /// Once all the constraints have been gathered, extract out the final data. 348 /// 349 /// Not legal during a snapshot. into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>)350 pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { 351 assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); 352 (mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data)) 353 } 354 355 /// Takes (and clears) the current set of constraints. Note that 356 /// the set of variables remains intact, but all relationships 357 /// between them are reset. This is used during NLL checking to 358 /// grab the set of constraints that arose from a particular 359 /// operation. 360 /// 361 /// We don't want to leak relationships between variables between 362 /// points because just because (say) `r1 == r2` was true at some 363 /// point P in the graph doesn't imply that it will be true at 364 /// some other point Q, in NLL. 365 /// 366 /// Not legal during a snapshot. take_and_reset_data(&mut self) -> RegionConstraintData<'tcx>367 pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> { 368 assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); 369 370 // If you add a new field to `RegionConstraintCollector`, you 371 // should think carefully about whether it needs to be cleared 372 // or updated in some way. 373 let RegionConstraintStorage { 374 var_infos: _, 375 data, 376 lubs, 377 glbs, 378 unification_table: _, 379 any_unifications, 380 } = self.storage; 381 382 // Clear the tables of (lubs, glbs), so that we will create 383 // fresh regions if we do a LUB operation. As it happens, 384 // LUB/GLB are not performed by the MIR type-checker, which is 385 // the one that uses this method, but it's good to be correct. 386 lubs.clear(); 387 glbs.clear(); 388 389 let data = mem::take(data); 390 391 // Clear all unifications and recreate the variables a "now 392 // un-unified" state. Note that when we unify `a` and `b`, we 393 // also insert `a <= b` and a `b <= a` edges, so the 394 // `RegionConstraintData` contains the relationship here. 395 if *any_unifications { 396 *any_unifications = false; 397 self.unification_table_mut().reset_unifications(|_| UnifiedRegion::new(None)); 398 } 399 400 data 401 } 402 data(&self) -> &RegionConstraintData<'tcx>403 pub fn data(&self) -> &RegionConstraintData<'tcx> { 404 &self.data 405 } 406 start_snapshot(&mut self) -> RegionSnapshot407 pub(super) fn start_snapshot(&mut self) -> RegionSnapshot { 408 debug!("RegionConstraintCollector: start_snapshot"); 409 RegionSnapshot { any_unifications: self.any_unifications } 410 } 411 rollback_to(&mut self, snapshot: RegionSnapshot)412 pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) { 413 debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); 414 self.any_unifications = snapshot.any_unifications; 415 } 416 new_region_var( &mut self, universe: ty::UniverseIndex, origin: RegionVariableOrigin, ) -> RegionVid417 pub(super) fn new_region_var( 418 &mut self, 419 universe: ty::UniverseIndex, 420 origin: RegionVariableOrigin, 421 ) -> RegionVid { 422 let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); 423 424 let u_vid = self.unification_table_mut().new_key(UnifiedRegion::new(None)); 425 assert_eq!(vid, u_vid.vid); 426 self.undo_log.push(AddVar(vid)); 427 debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin); 428 vid 429 } 430 431 /// Returns the universe for the given variable. var_universe(&self, vid: RegionVid) -> ty::UniverseIndex432 pub(super) fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { 433 self.var_infos[vid].universe 434 } 435 436 /// Returns the origin for the given variable. var_origin(&self, vid: RegionVid) -> RegionVariableOrigin437 pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { 438 self.var_infos[vid].origin 439 } 440 add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>)441 fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { 442 // cannot add constraints once regions are resolved 443 debug!("RegionConstraintCollector: add_constraint({:?})", constraint); 444 445 // never overwrite an existing (constraint, origin) - only insert one if it isn't 446 // present in the map yet. This prevents origins from outside the snapshot being 447 // replaced with "less informative" origins e.g., during calls to `can_eq` 448 let undo_log = &mut self.undo_log; 449 self.storage.data.constraints.entry(constraint).or_insert_with(|| { 450 undo_log.push(AddConstraint(constraint)); 451 origin 452 }); 453 } 454 add_verify(&mut self, verify: Verify<'tcx>)455 fn add_verify(&mut self, verify: Verify<'tcx>) { 456 // cannot add verifys once regions are resolved 457 debug!("RegionConstraintCollector: add_verify({:?})", verify); 458 459 // skip no-op cases known to be satisfied 460 if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() { 461 return; 462 } 463 464 let index = self.data.verifys.len(); 465 self.data.verifys.push(verify); 466 self.undo_log.push(AddVerify(index)); 467 } 468 make_eqregion( &mut self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, )469 pub(super) fn make_eqregion( 470 &mut self, 471 origin: SubregionOrigin<'tcx>, 472 sub: Region<'tcx>, 473 sup: Region<'tcx>, 474 ) { 475 if sub != sup { 476 // Eventually, it would be nice to add direct support for 477 // equating regions. 478 self.make_subregion(origin.clone(), sub, sup); 479 self.make_subregion(origin, sup, sub); 480 481 match (sub, sup) { 482 (Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => { 483 debug!("make_eqregion: unifying {:?} with {:?}", sub, sup); 484 self.unification_table_mut().union(*sub, *sup); 485 self.any_unifications = true; 486 } 487 (Region(Interned(ReVar(vid), _)), value) 488 | (value, Region(Interned(ReVar(vid), _))) => { 489 debug!("make_eqregion: unifying {:?} with {:?}", vid, value); 490 self.unification_table_mut().union_value(*vid, UnifiedRegion::new(Some(value))); 491 self.any_unifications = true; 492 } 493 (_, _) => {} 494 } 495 } 496 } 497 member_constraint( &mut self, key: ty::OpaqueTypeKey<'tcx>, definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, choice_regions: &Lrc<Vec<ty::Region<'tcx>>>, )498 pub(super) fn member_constraint( 499 &mut self, 500 key: ty::OpaqueTypeKey<'tcx>, 501 definition_span: Span, 502 hidden_ty: Ty<'tcx>, 503 member_region: ty::Region<'tcx>, 504 choice_regions: &Lrc<Vec<ty::Region<'tcx>>>, 505 ) { 506 debug!("member_constraint({:?} in {:#?})", member_region, choice_regions); 507 508 if choice_regions.iter().any(|&r| r == member_region) { 509 return; 510 } 511 512 self.data.member_constraints.push(MemberConstraint { 513 key, 514 definition_span, 515 hidden_ty, 516 member_region, 517 choice_regions: choice_regions.clone(), 518 }); 519 } 520 521 #[instrument(skip(self, origin), level = "debug")] make_subregion( &mut self, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, )522 pub(super) fn make_subregion( 523 &mut self, 524 origin: SubregionOrigin<'tcx>, 525 sub: Region<'tcx>, 526 sup: Region<'tcx>, 527 ) { 528 // cannot add constraints once regions are resolved 529 debug!("origin = {:#?}", origin); 530 531 match (*sub, *sup) { 532 (ReLateBound(..), _) | (_, ReLateBound(..)) => { 533 span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup); 534 } 535 (_, ReStatic) => { 536 // all regions are subregions of static, so we can ignore this 537 } 538 (ReVar(sub_id), ReVar(sup_id)) => { 539 self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); 540 } 541 (_, ReVar(sup_id)) => { 542 self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); 543 } 544 (ReVar(sub_id), _) => { 545 self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); 546 } 547 _ => { 548 self.add_constraint(Constraint::RegSubReg(sub, sup), origin); 549 } 550 } 551 } 552 verify_generic_bound( &mut self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, sub: Region<'tcx>, bound: VerifyBound<'tcx>, )553 pub(super) fn verify_generic_bound( 554 &mut self, 555 origin: SubregionOrigin<'tcx>, 556 kind: GenericKind<'tcx>, 557 sub: Region<'tcx>, 558 bound: VerifyBound<'tcx>, 559 ) { 560 self.add_verify(Verify { kind, origin, region: sub, bound }); 561 } 562 lub_regions( &mut self, tcx: TyCtxt<'tcx>, origin: SubregionOrigin<'tcx>, a: Region<'tcx>, b: Region<'tcx>, ) -> Region<'tcx>563 pub(super) fn lub_regions( 564 &mut self, 565 tcx: TyCtxt<'tcx>, 566 origin: SubregionOrigin<'tcx>, 567 a: Region<'tcx>, 568 b: Region<'tcx>, 569 ) -> Region<'tcx> { 570 // cannot add constraints once regions are resolved 571 debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b); 572 if a.is_static() || b.is_static() { 573 a // nothing lives longer than static 574 } else if a == b { 575 a // LUB(a,a) = a 576 } else { 577 self.combine_vars(tcx, Lub, a, b, origin) 578 } 579 } 580 glb_regions( &mut self, tcx: TyCtxt<'tcx>, origin: SubregionOrigin<'tcx>, a: Region<'tcx>, b: Region<'tcx>, ) -> Region<'tcx>581 pub(super) fn glb_regions( 582 &mut self, 583 tcx: TyCtxt<'tcx>, 584 origin: SubregionOrigin<'tcx>, 585 a: Region<'tcx>, 586 b: Region<'tcx>, 587 ) -> Region<'tcx> { 588 // cannot add constraints once regions are resolved 589 debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b); 590 if a.is_static() { 591 b // static lives longer than everything else 592 } else if b.is_static() { 593 a // static lives longer than everything else 594 } else if a == b { 595 a // GLB(a,a) = a 596 } else { 597 self.combine_vars(tcx, Glb, a, b, origin) 598 } 599 } 600 601 /// Resolves a region var to its value in the unification table, if it exists. 602 /// Otherwise, it is resolved to the root `ReVar` in the table. opportunistic_resolve_var( &mut self, tcx: TyCtxt<'tcx>, vid: ty::RegionVid, ) -> ty::Region<'tcx>603 pub fn opportunistic_resolve_var( 604 &mut self, 605 tcx: TyCtxt<'tcx>, 606 vid: ty::RegionVid, 607 ) -> ty::Region<'tcx> { 608 let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut 609 let root_vid = ut.find(vid).vid; 610 let resolved = ut 611 .probe_value(root_vid) 612 .get_value_ignoring_universes() 613 .unwrap_or_else(|| ty::Region::new_var(tcx, root_vid)); 614 615 // Don't resolve a variable to a region that it cannot name. 616 if self.var_universe(vid).can_name(self.universe(resolved)) { 617 resolved 618 } else { 619 ty::Region::new_var(tcx, vid) 620 } 621 } 622 combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx>623 fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { 624 match t { 625 Glb => &mut self.glbs, 626 Lub => &mut self.lubs, 627 } 628 } 629 combine_vars( &mut self, tcx: TyCtxt<'tcx>, t: CombineMapType, a: Region<'tcx>, b: Region<'tcx>, origin: SubregionOrigin<'tcx>, ) -> Region<'tcx>630 fn combine_vars( 631 &mut self, 632 tcx: TyCtxt<'tcx>, 633 t: CombineMapType, 634 a: Region<'tcx>, 635 b: Region<'tcx>, 636 origin: SubregionOrigin<'tcx>, 637 ) -> Region<'tcx> { 638 let vars = TwoRegions { a, b }; 639 if let Some(&c) = self.combine_map(t).get(&vars) { 640 return ty::Region::new_var(tcx, c); 641 } 642 let a_universe = self.universe(a); 643 let b_universe = self.universe(b); 644 let c_universe = cmp::max(a_universe, b_universe); 645 let c = self.new_region_var(c_universe, MiscVariable(origin.span())); 646 self.combine_map(t).insert(vars, c); 647 self.undo_log.push(AddCombination(t, vars)); 648 let new_r = ty::Region::new_var(tcx, c); 649 for old_r in [a, b] { 650 match t { 651 Glb => self.make_subregion(origin.clone(), new_r, old_r), 652 Lub => self.make_subregion(origin.clone(), old_r, new_r), 653 } 654 } 655 debug!("combine_vars() c={:?}", c); 656 new_r 657 } 658 universe(&self, region: Region<'tcx>) -> ty::UniverseIndex659 pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex { 660 match *region { 661 ty::ReStatic 662 | ty::ReErased 663 | ty::ReFree(..) 664 | ty::ReEarlyBound(..) 665 | ty::ReError(_) => ty::UniverseIndex::ROOT, 666 ty::RePlaceholder(placeholder) => placeholder.universe, 667 ty::ReVar(vid) => self.var_universe(vid), 668 ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region), 669 } 670 } 671 vars_since_snapshot( &self, value_count: usize, ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>)672 pub fn vars_since_snapshot( 673 &self, 674 value_count: usize, 675 ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) { 676 let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len()); 677 ( 678 range.clone(), 679 (range.start.index()..range.end.index()) 680 .map(|index| self.var_infos[ty::RegionVid::from(index)].origin) 681 .collect(), 682 ) 683 } 684 685 /// See `InferCtxt::region_constraints_added_in_snapshot`. region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool686 pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> bool { 687 self.undo_log 688 .region_constraints_in_snapshot(mark) 689 .any(|&elt| matches!(elt, AddConstraint(_))) 690 } 691 692 #[inline] unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>>693 fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> { 694 ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) 695 } 696 } 697 698 impl fmt::Debug for RegionSnapshot { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result699 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 700 write!(f, "RegionSnapshot") 701 } 702 } 703 704 impl<'tcx> fmt::Debug for GenericKind<'tcx> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 706 match *self { 707 GenericKind::Param(ref p) => write!(f, "{:?}", p), 708 GenericKind::Alias(ref p) => write!(f, "{:?}", p), 709 } 710 } 711 } 712 713 impl<'tcx> fmt::Display for GenericKind<'tcx> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result714 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 715 match *self { 716 GenericKind::Param(ref p) => write!(f, "{}", p), 717 GenericKind::Alias(ref p) => write!(f, "{}", p), 718 } 719 } 720 } 721 722 impl<'tcx> GenericKind<'tcx> { to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>723 pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { 724 match *self { 725 GenericKind::Param(ref p) => p.to_ty(tcx), 726 GenericKind::Alias(ref p) => p.to_ty(tcx), 727 } 728 } 729 } 730 731 impl<'tcx> VerifyBound<'tcx> { must_hold(&self) -> bool732 pub fn must_hold(&self) -> bool { 733 match self { 734 VerifyBound::IfEq(..) => false, 735 VerifyBound::OutlivedBy(re) => re.is_static(), 736 VerifyBound::IsEmpty => false, 737 VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()), 738 VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()), 739 } 740 } 741 cannot_hold(&self) -> bool742 pub fn cannot_hold(&self) -> bool { 743 match self { 744 VerifyBound::IfEq(..) => false, 745 VerifyBound::IsEmpty => false, 746 VerifyBound::OutlivedBy(_) => false, 747 VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()), 748 VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()), 749 } 750 } 751 or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx>752 pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { 753 if self.must_hold() || vb.cannot_hold() { 754 self 755 } else if self.cannot_hold() || vb.must_hold() { 756 vb 757 } else { 758 VerifyBound::AnyBound(vec![self, vb]) 759 } 760 } 761 } 762 763 impl<'tcx> RegionConstraintData<'tcx> { 764 /// Returns `true` if this region constraint data contains no constraints, and `false` 765 /// otherwise. is_empty(&self) -> bool766 pub fn is_empty(&self) -> bool { 767 let RegionConstraintData { constraints, member_constraints, verifys } = self; 768 constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty() 769 } 770 } 771 772 impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> { reverse(&mut self, undo: UndoLog<'tcx>)773 fn reverse(&mut self, undo: UndoLog<'tcx>) { 774 self.rollback_undo_entry(undo) 775 } 776 } 777