• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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