diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 91dbbfb4973..6f2fe8bddb2 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -72,7 +72,7 @@ pub struct RegionInferenceContext<'tcx> { /// The SCC computed from `constraints` and the constraint /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to /// compute the values of each region. - pub constraint_sccs: Rc, + constraint_sccs: Rc, /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required @@ -397,6 +397,39 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// and (b) any universally quantified regions that it outlives, /// which in this case is just itself. R1 (`'b`) in contrast also /// outlives `'a` and hence contains R0 and R1. + /// + /// This bit of logic also handles invalid universe relations + /// for higher-kinded types. + /// + // We Walk each SCC `A` and `B` such that `A: B` + // and ensure that universe(A) can see universe(B). + // + // This serves to enforce the 'empty/placeholder' hierarchy + // (described in more detail on `RegionKind`): + // + // ``` + // static -----+ + // | | + // empty(U0) placeholder(U1) + // | / + // empty(U1) + // ``` + // + // In particular, imagine we have variables R0 in U0 and R1 + // created in U1, and constraints like this; + // + // ``` + // R1: !1 // R1 outlives the placeholder in U1 + // R1: R0 // R1 outlives R0 + // ``` + // + // Here, we wish for R1 to be `'static`, because it + // cannot outlive `placeholder(U1)` and `empty(U0)` any other way. + // + // Thanks to this loop, what happens is that the `R1: R0` + // constraint has lowered the universe of `R1` to `U0`, which in turn + // means that the `R1: !1` constraint here will cause + // `R1` to become `'static`. fn init_free_and_bound_regions(&mut self) { // Update the names (if any) // This iterator has unstable order but we collect it all into an IndexVec @@ -1412,6 +1445,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// The minimum universe of any variable reachable from this + /// SCC, inside or outside of it. fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { self.constraint_sccs().annotation(scc).universe() } @@ -2151,6 +2186,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Returns the representative `RegionVid` for a given SCC. /// See `RegionTracker` for how a region variable ID is chosen. + /// + /// It is a hacky way to manage checking regions for equality, + /// since we can 'canonicalize' each region to the representative + /// of its SCC and be sure that -- if they have the same repr -- + /// they *must* be equal (though not having the same repr does not + /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { self.constraint_sccs.annotation(scc).representative }