]> git.lizzy.rs Git - rust.git/commitdiff
extend NLL universe code to have >1 placeholder within one universe
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 27 Sep 2018 21:57:35 +0000 (17:57 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Thu, 4 Oct 2018 15:02:40 +0000 (11:02 -0400)
src/librustc/infer/higher_ranked/mod.rs
src/librustc/infer/mod.rs
src/librustc/infer/region_constraints/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc/util/ppaux.rs
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/values.rs
src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs

index 75f2e224dc1f444748bd3a0c7f93c6ee8b65a298..ba0f8af4f720e5568b53c54e44b3b6cc2db973dc 100644 (file)
@@ -586,15 +586,20 @@ fn region_vars_confined_to_snapshot(&self,
     /// the [rustc guide].
     ///
     /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html
-    pub fn replace_late_bound_regions_with_placeholders<T>(&self,
-                                           binder: &ty::Binder<T>)
-                                           -> (T, PlaceholderMap<'tcx>)
-        where T : TypeFoldable<'tcx>
+    pub fn replace_late_bound_regions_with_placeholders<T>(
+        &self,
+        binder: &ty::Binder<T>,
+    ) -> (T, PlaceholderMap<'tcx>)
+    where
+        T : TypeFoldable<'tcx>,
     {
         let new_universe = self.create_subuniverse();
 
         let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
-            self.tcx.mk_region(ty::RePlaceholder(new_universe, br))
+            self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+                universe: new_universe,
+                name: br,
+            }))
         });
 
         debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
@@ -758,7 +763,7 @@ pub fn plug_leaks<T>(&self,
                     assert!(
                         match *r {
                             ty::ReVar(_) => true,
-                            ty::RePlaceholder(_, ref br1) => br == br1,
+                            ty::RePlaceholder(index) => index.name == *br,
                             _ => false,
                         },
                         "leak-check would have us replace {:?} with {:?}",
index 0634e4017d1c396b27eb852cbe988f75a6b945f4..291b46edccfb2342b6b9f981fd4865d1d95ba4b7 100644 (file)
@@ -406,12 +406,14 @@ pub enum RegionVariableOrigin {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum NLLRegionVariableOrigin {
-    // During NLL region processing, we create variables for free
-    // regions that we encounter in the function signature and
-    // elsewhere. This origin indices we've got one of those.
+    /// During NLL region processing, we create variables for free
+    /// regions that we encounter in the function signature and
+    /// elsewhere. This origin indices we've got one of those.
     FreeRegion,
 
-    BoundRegion(ty::UniverseIndex),
+    /// "Universal" instantiation of a higher-ranked region (e.g.,
+    /// from a `for<'a> T` binder). Meant to represent "any region".
+    Placeholder(ty::Placeholder),
 
     Existential,
 }
@@ -420,7 +422,7 @@ impl NLLRegionVariableOrigin {
     pub fn is_universal(self) -> bool {
         match self {
             NLLRegionVariableOrigin::FreeRegion => true,
-            NLLRegionVariableOrigin::BoundRegion(..) => true,
+            NLLRegionVariableOrigin::Placeholder(..) => true,
             NLLRegionVariableOrigin::Existential => false,
         }
     }
index 929c8c541adceaf09f0bf0b2d68032437d00bae6..4040e6677e967874a00b9ca3d37eba4d9cf632d3 100644 (file)
@@ -830,7 +830,7 @@ fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
             | ty::ReErased
             | ty::ReFree(..)
             | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT,
-            ty::RePlaceholder(universe, _) => universe,
+            ty::RePlaceholder(placeholder) => placeholder.universe,
             ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid),
             ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
             ty::ReCanonical(..) => bug!(
index 9c7283e6d9fcdf1f6d5721f7869aaa4bc3a340ec..eb3b6f28202dd3f90ad86ca6539a785723e974a1 100644 (file)
@@ -1980,15 +1980,16 @@ fn assemble_candidates_from_impls(
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.probe(|this, snapshot| /* [1] */
-                    if let Ok(placeholder_map) = this.match_impl(impl_def_id, obligation, snapshot) {
+                self.probe(|this, snapshot| {
+                    if let Ok(placeholder_map) = this.match_impl(impl_def_id, obligation, snapshot)
+                    {
                         candidates.vec.push(ImplCandidate(impl_def_id));
 
                         // NB: we can safely drop the placeholder map
-                        // since we are in a probe [1]
+                        // since we are in a probe.
                         mem::drop(placeholder_map);
                     }
-                );
+                });
             },
         );
 
index 1fed4467d3227efbb57fc95990064de6999f8021..74a8ccd07c75f5fc5fad08542a310e25ca879694 100644 (file)
@@ -1553,6 +1553,18 @@ fn from(index: u32) -> Self {
     }
 }
 
+/// The "placeholder index" fully defines a placeholder region.
+/// Placeholder regions are identified by both a **universe** as well
+/// as a "bound-region" within that universe. The `bound_region` is
+/// basically a name -- distinct bound regions within the same
+/// universe are just two regions with an unknown relationship to one
+/// another.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)]
+pub struct Placeholder {
+    pub universe: UniverseIndex,
+    pub name: BoundRegion,
+}
+
 /// When type checking, we use the `ParamEnv` to track
 /// details about the set of where-clauses that are in scope at this
 /// particular point.
index f9174ece0024a173853b8e15a878d358bca60479..d8dd73da536d8e70217b1d94b5d208056ba5eacd 100644 (file)
@@ -1134,7 +1134,7 @@ pub enum RegionKind {
 
     /// A placeholder region - basically the higher-ranked version of ReFree.
     /// Should not exist after typeck.
-    RePlaceholder(ty::UniverseIndex, BoundRegion),
+    RePlaceholder(ty::Placeholder),
 
     /// Empty lifetime is for data that is never accessed.
     /// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -1338,7 +1338,7 @@ pub fn has_name(&self) -> bool {
             RegionKind::ReScope(..) => false,
             RegionKind::ReStatic => true,
             RegionKind::ReVar(..) => false,
-            RegionKind::RePlaceholder(_, br) => br.is_named(),
+            RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
             RegionKind::ReEmpty => false,
             RegionKind::ReErased => false,
             RegionKind::ReClosureBound(..) => false,
index b588b798f2b5bdb87af3cd2a9bd905d569c49e27..33534ab27f1470e125e0ba0afc6de37f4fa804aa 100644 (file)
@@ -803,7 +803,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 }
                 ty::ReLateBound(_, br) |
                 ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
-                ty::RePlaceholder(_, br) => {
+                ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
                     write!(f, "{}", br)
                 }
                 ty::ReScope(scope) if cx.identify_regions => {
@@ -872,8 +872,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     write!(f, "'?{}", c.index())
                 }
 
-                ty::RePlaceholder(universe, ref bound_region) => {
-                    write!(f, "RePlaceholder({:?}, {:?})", universe, bound_region)
+                ty::RePlaceholder(placeholder) => {
+                    write!(f, "RePlaceholder({:?})", placeholder)
                 }
 
                 ty::ReEmpty => write!(f, "ReEmpty"),
index 95bb4f8fdb2d8eb1d57ddba1dbd3dabd0ed924be..bc0729458031648d17bd7601157d14475e3c76ee 100644 (file)
@@ -1780,9 +1780,11 @@ fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
         // lifetimes without names with the value `'0`.
         match ty.sty {
             ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _)
-            | ty::TyKind::Ref(ty::RegionKind::RePlaceholder(_, br), _, _) => {
-                with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty))
-            }
+            | ty::TyKind::Ref(
+                ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }),
+                _,
+                _,
+            ) => with_highlight_region_for_bound_region(*br, counter, || format!("{}", ty)),
             _ => format!("{}", ty),
         }
     }
@@ -1792,7 +1794,8 @@ fn get_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
     fn get_region_name_for_ty(&self, ty: ty::Ty<'tcx>, counter: usize) -> String {
         match ty.sty {
             ty::TyKind::Ref(region, _, _) => match region {
-                ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::RePlaceholder(_, br) => {
+                ty::RegionKind::ReLateBound(_, br)
+                | ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => {
                     with_highlight_region_for_bound_region(*br, counter, || format!("{}", region))
                 }
                 _ => format!("{}", region),
index 2dbb5cd9deb144437a38fb9d9cbd9e236489f217..b11369116d4cd7188a5a6c10985ae49932c70f02 100644 (file)
@@ -11,7 +11,7 @@
 use super::universal_regions::UniversalRegions;
 use borrow_check::nll::constraints::graph::NormalConstraintGraph;
 use borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, OutlivesConstraint};
-use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
+use borrow_check::nll::region_infer::values::{PlaceholderIndices, RegionElement, ToElementIndex};
 use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
 use borrow_check::nll::type_check::Locations;
 use rustc::hir::def_id::DefId;
@@ -197,18 +197,21 @@ pub(crate) fn new(
             .collect();
 
         // Compute the max universe used anywhere amongst the regions.
-        let max_universe = definitions
+        let placeholder_indices: PlaceholderIndices = definitions
             .iter()
-            .map(|d| d.universe)
-            .max()
-            .unwrap_or(ty::UniverseIndex::ROOT);
+            .filter_map(|d| match d.origin {
+                NLLRegionVariableOrigin::Placeholder(placeholder) => Some(placeholder),
+                _ => None,
+            })
+            .collect();
 
         let constraints = Rc::new(outlives_constraints); // freeze constraints
         let constraint_graph = Rc::new(constraints.graph(definitions.len()));
         let fr_static = universal_regions.fr_static;
         let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static));
 
-        let mut scc_values = RegionValues::new(elements, universal_regions.len(), max_universe);
+        let mut scc_values =
+            RegionValues::new(elements, universal_regions.len(), placeholder_indices);
 
         for region in liveness_constraints.rows() {
             let scc = constraint_sccs.scc(region);
@@ -329,17 +332,14 @@ fn init_free_and_bound_regions(&mut self) {
                     self.scc_values.add_element(scc, variable);
                 }
 
-                NLLRegionVariableOrigin::BoundRegion(ui) => {
-                    // Each placeholder region X outlives its
-                    // associated universe but nothing else. Every
-                    // placeholder region is always in a universe that
-                    // contains `ui` -- but when placeholder regions
-                    // are placed into an SCC, that SCC may include
-                    // things from other universes that do not include
-                    // `ui`.
+                NLLRegionVariableOrigin::Placeholder(placeholder) => {
+                    // Each placeholder region is only visible from
+                    // its universe `ui` and its superuniverses. So we
+                    // can't just add it into `scc` unless the
+                    // universe of the scc can name this region.
                     let scc_universe = self.scc_universes[scc];
-                    if ui.is_subset_of(scc_universe) {
-                        self.scc_values.add_element(scc, ui);
+                    if placeholder.universe.is_subset_of(scc_universe) {
+                        self.scc_values.add_element(scc, placeholder);
                     } else {
                         self.add_incompatible_universe(scc);
                     }
@@ -544,8 +544,8 @@ fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccInd
         // B's value, and check whether all of them are nameable
         // from universe_a
         self.scc_values
-            .subuniverses_contained_in(scc_b)
-            .all(|u| u.is_subset_of(universe_a))
+            .placeholders_contained_in(scc_b)
+            .all(|p| p.universe.is_subset_of(universe_a))
     }
 
     /// Extend `scc` so that it can outlive some placeholder region
@@ -1076,8 +1076,8 @@ fn check_universal_regions<'gcx>(
                     );
                 }
 
-                NLLRegionVariableOrigin::BoundRegion(universe) => {
-                    self.check_bound_universal_region(infcx, mir, mir_def_id, fr, universe);
+                NLLRegionVariableOrigin::Placeholder(placeholder) => {
+                    self.check_bound_universal_region(infcx, mir, mir_def_id, fr, placeholder);
                 }
 
                 NLLRegionVariableOrigin::Existential => {
@@ -1113,7 +1113,7 @@ fn check_universal_region<'gcx>(
         assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT);
         debug_assert!(
             self.scc_values
-                .subuniverses_contained_in(longer_fr_scc)
+                .placeholders_contained_in(longer_fr_scc)
                 .next()
                 .is_none()
         );
@@ -1181,9 +1181,12 @@ fn check_bound_universal_region<'gcx>(
         mir: &Mir<'tcx>,
         _mir_def_id: DefId,
         longer_fr: RegionVid,
-        universe: ty::UniverseIndex,
+        placeholder: ty::Placeholder,
     ) {
-        debug!("check_bound_universal_region(fr={:?})", longer_fr);
+        debug!(
+            "check_bound_universal_region(fr={:?}, placeholder={:?})",
+            longer_fr, placeholder,
+        );
 
         let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
 
@@ -1196,7 +1199,7 @@ fn check_bound_universal_region<'gcx>(
                 .find(|element| match element {
                     RegionElement::Location(_) => true,
                     RegionElement::RootUniversalRegion(_) => true,
-                    RegionElement::SubUniversalRegion(ui) => *ui != universe,
+                    RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
                 })
         } {
             Some(v) => v,
@@ -1207,10 +1210,10 @@ fn check_bound_universal_region<'gcx>(
         let error_region = match error_element {
             RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
             RegionElement::RootUniversalRegion(r) => r,
-            RegionElement::SubUniversalRegion(error_ui) => self.definitions
+            RegionElement::PlaceholderRegion(error_placeholder) => self.definitions
                 .iter_enumerated()
                 .filter_map(|(r, definition)| match definition.origin {
-                    NLLRegionVariableOrigin::BoundRegion(ui) if error_ui == ui => Some(r),
+                    NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
                     _ => None,
                 })
                 .next()
index 8dc41a9b2d32d13df61fc6af0403527c6b51a8d9..6407661d2921f50178bade326383d3c781fbb50b 100644 (file)
@@ -11,6 +11,7 @@
 use rustc::mir::{BasicBlock, Location, Mir};
 use rustc::ty::{self, RegionVid};
 use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::fmt::Debug;
@@ -31,8 +32,7 @@
 impl RegionValueElements {
     crate fn new(mir: &Mir<'_>) -> Self {
         let mut num_points = 0;
-        let statements_before_block: IndexVec<BasicBlock, usize> = mir
-            .basic_blocks()
+        let statements_before_block: IndexVec<BasicBlock, usize> = mir.basic_blocks()
             .iter()
             .map(|block_data| {
                 let v = num_points;
@@ -48,7 +48,7 @@ impl RegionValueElements {
 
         let mut basic_blocks = IndexVec::with_capacity(num_points);
         for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
-            basic_blocks.extend((0 .. bb_data.statements.len() + 1).map(|_| bb));
+            basic_blocks.extend((0..bb_data.statements.len() + 1).map(|_| bb));
         }
 
         Self {
@@ -85,7 +85,10 @@ impl RegionValueElements {
         let block = self.basic_blocks[index];
         let start_index = self.statements_before_block[block];
         let statement_index = index.index() - start_index;
-        Location { block, statement_index }
+        Location {
+            block,
+            statement_index,
+        }
     }
 
     /// Sometimes we get point-indices back from bitsets that may be
@@ -103,13 +106,15 @@ impl RegionValueElements {
         index: PointIndex,
         stack: &mut Vec<PointIndex>,
     ) {
-        let Location { block, statement_index } = self.to_location(index);
+        let Location {
+            block,
+            statement_index,
+        } = self.to_location(index);
         if statement_index == 0 {
             // If this is a basic block head, then the predecessors are
             // the the terminators of other basic blocks
             stack.extend(
-                mir
-                    .predecessors_for(block)
+                mir.predecessors_for(block)
                     .iter()
                     .map(|&pred_bb| mir.terminator_loc(pred_bb))
                     .map(|pred_loc| self.point_from_location(pred_loc)),
@@ -127,10 +132,7 @@ impl RegionValueElements {
     pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
 }
 
-/// A single integer representing a (non-zero) `UniverseIndex`.
-/// Computed just by subtracting one from `UniverseIndex`; this is
-/// because the `0` value for `UniverseIndex` represents the root
-/// universe, and we don't need/want a bit for that one.
+/// A single integer representing a `ty::Placeholder`.
 newtype_index! {
     pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
 }
@@ -148,7 +150,7 @@ pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
 
     /// A subuniverse from a subuniverse (e.g., instantiated from a
     /// `for<'a> fn(&'a u32)` type).
-    SubUniversalRegion(ty::UniverseIndex),
+    PlaceholderRegion(ty::Placeholder),
 }
 
 /// When we initially compute liveness, we use a bit matrix storing
@@ -185,7 +187,10 @@ impl<N: Idx> LivenessValues<N> {
     /// Adds all the elements in the given bit array into the given
     /// region. Returns true if any of them are newly added.
     crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
-        debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
+        debug!(
+            "LivenessValues::add_elements(row={:?}, locations={:?})",
+            row, locations
+        );
         self.points.union_into_row(row, locations)
     }
 
@@ -214,6 +219,52 @@ impl<N: Idx> LivenessValues<N> {
     }
 }
 
+/// Maps from `ty::Placeholder` values that are used in the rest of
+/// rustc to the internal `PlaceholderIndex` values that are used in
+/// NLL.
+#[derive(Default)]
+crate struct PlaceholderIndices {
+    to_index: FxHashMap<ty::Placeholder, PlaceholderIndex>,
+    from_index: IndexVec<PlaceholderIndex, ty::Placeholder>,
+}
+
+impl PlaceholderIndices {
+    crate fn insert(&mut self, placeholder: ty::Placeholder) -> PlaceholderIndex {
+        let PlaceholderIndices {
+            to_index,
+            from_index,
+        } = self;
+        *to_index
+            .entry(placeholder)
+            .or_insert_with(|| from_index.push(placeholder))
+    }
+
+    crate fn lookup_index(&self, placeholder: ty::Placeholder) -> PlaceholderIndex {
+        self.to_index[&placeholder]
+    }
+
+    crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::Placeholder {
+        self.from_index[placeholder]
+    }
+
+    crate fn len(&self) -> usize {
+        self.from_index.len()
+    }
+}
+
+impl ::std::iter::FromIterator<ty::Placeholder> for PlaceholderIndices {
+    fn from_iter<I>(iter: I) -> Self
+    where
+        I: IntoIterator<Item = ty::Placeholder>,
+    {
+        let mut result = Self::default();
+        iter.into_iter().for_each(|p| {
+            result.insert(p);
+        });
+        result
+    }
+}
+
 /// Stores the full values for a set of regions (in contrast to
 /// `LivenessValues`, which only stores those points in the where a
 /// region is live). The full value for a region may contain points in
@@ -235,6 +286,7 @@ impl<N: Idx> LivenessValues<N> {
 #[derive(Clone)]
 crate struct RegionValues<N: Idx> {
     elements: Rc<RegionValueElements>,
+    placeholder_indices: Rc<PlaceholderIndices>,
     points: SparseBitMatrix<N, PointIndex>,
     free_regions: SparseBitMatrix<N, RegionVid>,
 
@@ -250,12 +302,13 @@ impl<N: Idx> RegionValues<N> {
     crate fn new(
         elements: &Rc<RegionValueElements>,
         num_universal_regions: usize,
-        max_universe: ty::UniverseIndex,
+        placeholder_indices: PlaceholderIndices,
     ) -> Self {
-        let num_placeholders = max_universe.as_usize();
+        let num_placeholders = placeholder_indices.len();
         Self {
             elements: elements.clone(),
             points: SparseBitMatrix::new(elements.num_points),
+            placeholder_indices: Rc::new(placeholder_indices),
             free_regions: SparseBitMatrix::new(num_universal_regions),
             placeholders: SparseBitMatrix::new(num_placeholders),
         }
@@ -313,14 +366,11 @@ impl<N: Idx> RegionValues<N> {
 
     /// Returns the locations contained within a given region `r`.
     crate fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
-        self.points
-            .row(r)
-            .into_iter()
-            .flat_map(move |set| {
-                set.iter()
-                    .take_while(move |&p| self.elements.point_in_range(p))
-                    .map(move |p| self.elements.to_location(p))
-            })
+        self.points.row(r).into_iter().flat_map(move |set| {
+            set.iter()
+                .take_while(move |&p| self.elements.point_in_range(p))
+                .map(move |p| self.elements.to_location(p))
+        })
     }
 
     /// Returns just the universal regions that are contained in a given region's value.
@@ -335,32 +385,30 @@ impl<N: Idx> RegionValues<N> {
     }
 
     /// Returns all the elements contained in a given region's value.
-    crate fn subuniverses_contained_in<'a>(
+    crate fn placeholders_contained_in<'a>(
         &'a self,
         r: N,
-    ) -> impl Iterator<Item = ty::UniverseIndex> + 'a {
+    ) -> impl Iterator<Item = ty::Placeholder> + 'a {
         self.placeholders
             .row(r)
             .into_iter()
             .flat_map(|set| set.iter())
-            .map(|p| ty::UniverseIndex::from_u32((p.index() + 1) as u32))
+            .map(move |p| self.placeholder_indices.lookup_placeholder(p))
     }
 
     /// Returns all the elements contained in a given region's value.
     crate fn elements_contained_in<'a>(&'a self, r: N) -> impl Iterator<Item = RegionElement> + 'a {
         let points_iter = self.locations_outlived_by(r).map(RegionElement::Location);
 
-        let free_regions_iter = self
-            .universal_regions_outlived_by(r)
+        let free_regions_iter = self.universal_regions_outlived_by(r)
             .map(RegionElement::RootUniversalRegion);
 
-        let subuniverses_iter = self
-            .subuniverses_contained_in(r)
-            .map(RegionElement::SubUniversalRegion);
+        let placeholder_universes_iter = self.placeholders_contained_in(r)
+            .map(RegionElement::PlaceholderRegion);
 
         points_iter
             .chain(free_regions_iter)
-            .chain(subuniverses_iter)
+            .chain(placeholder_universes_iter)
     }
 
     /// Returns a "pretty" string value of the region. Meant for debugging.
@@ -397,14 +445,14 @@ fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
     }
 }
 
-impl ToElementIndex for ty::UniverseIndex {
+impl ToElementIndex for ty::Placeholder {
     fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
-        let index = PlaceholderIndex::new(self.as_usize() - 1);
+        let index = values.placeholder_indices.lookup_index(self);
         values.placeholders.insert(row, index)
     }
 
     fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
-        let index = PlaceholderIndex::new(self.as_usize() - 1);
+        let index = values.placeholder_indices.lookup_index(self);
         values.placeholders.contains(row, index)
     }
 }
@@ -467,7 +515,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String
                 result.push_str(&format!("{:?}", fr));
             }
 
-            RegionElement::SubUniversalRegion(ur) => {
+            RegionElement::PlaceholderRegion(placeholder) => {
                 if let Some((location1, location2)) = open_location {
                     push_sep(&mut result);
                     push_location_range(&mut result, location1, location2);
@@ -475,7 +523,7 @@ fn region_value_str(elements: impl IntoIterator<Item = RegionElement>) -> String
                 }
 
                 push_sep(&mut result);
-                result.push_str(&format!("{:?}", ur));
+                result.push_str(&format!("{:?}", placeholder));
             }
         }
     }
index 13d59c3ba29c6707f52a3f2bbe7129dbc7252667..8addafaedadf7ab17cce0f62490b9b363ffcb7b4 100644 (file)
@@ -146,18 +146,27 @@ trait TypeRelatingDelegate<'tcx> {
     /// delegate.
     fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
 
-    /// Creates a new region variable representing an instantiated
-    /// higher-ranked region; this will be either existential or
-    /// universal depending on the context.  So e.g. if you have
-    /// `for<'a> fn(..) <: for<'b> fn(..)`, then we will first
-    /// instantiate `'b` with a universally quantitifed region and
-    /// then `'a` with an existentially quantified region (the order
-    /// is important so that the existential region `'a` can see the
-    /// universal one).
-    fn next_region_var(
-        &mut self,
-        universally_quantified: UniversallyQuantified,
-    ) -> ty::Region<'tcx>;
+    /// Creates a new universe index. Used when instantiating placeholders.
+    fn next_subuniverse(&mut self) -> ty::UniverseIndex;
+
+    /// Creates a new region variable representing a higher-ranked
+    /// region that is instantiated existentially. This creates an
+    /// inference variable, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'a` with an
+    /// inference variable (though `'b` would be instantiated first,
+    /// as a placeholder).
+    fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+
+    /// Creates a new region variable representing a
+    /// higher-ranked region that is instantiated universally.
+    /// This creates a new region placeholder, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'b` with a
+    /// placeholder region.
+    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
 
     /// Creates a new existential region in the given universe. This
     /// is used when handling subtyping and type variables -- if we
@@ -197,15 +206,17 @@ fn new(
 }
 
 impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
-    fn next_region_var(
-        &mut self,
-        universally_quantified: UniversallyQuantified,
-    ) -> ty::Region<'tcx> {
-        let origin = if universally_quantified.0 {
-            NLLRegionVariableOrigin::BoundRegion(self.infcx.create_subuniverse())
-        } else {
-            NLLRegionVariableOrigin::Existential
-        };
+    fn next_subuniverse(&mut self) -> ty::UniverseIndex {
+        self.infcx.create_subuniverse()
+    }
+
+    fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
+        let origin = NLLRegionVariableOrigin::Existential;
+        self.infcx.next_nll_region_var(origin)
+    }
+
+    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx> {
+        let origin = NLLRegionVariableOrigin::Placeholder(placeholder);
         self.infcx.next_nll_region_var(origin)
     }
 
@@ -286,12 +297,37 @@ fn create_scope(
         universally_quantified: UniversallyQuantified,
     ) -> BoundRegionScope<'tcx> {
         let mut scope = BoundRegionScope::default();
+
+        // Create a callback that creates (via the delegate) either an
+        // existential or placeholder region as needed.
+        let mut next_region = {
+            let delegate = &mut self.delegate;
+            let mut lazy_universe = None;
+            move |br: ty::BoundRegion| {
+                if universally_quantified.0 {
+                    // The first time this closure is called, create a
+                    // new universe for the placeholders we will make
+                    // from here out.
+                    let universe = lazy_universe.unwrap_or_else(|| {
+                        let universe = delegate.next_subuniverse();
+                        lazy_universe = Some(universe);
+                        universe
+                    });
+
+                    let placeholder = ty::Placeholder { universe, name: br };
+                    delegate.next_placeholder_region(placeholder)
+                } else {
+                    delegate.next_existential_region_var()
+                }
+            }
+        };
+
         value.skip_binder().visit_with(&mut ScopeInstantiator {
-            delegate: &mut self.delegate,
+            next_region: &mut next_region,
             target_index: ty::INNERMOST,
-            universally_quantified,
             bound_region_scope: &mut scope,
         });
+
         scope
     }
 
@@ -604,21 +640,14 @@ fn binders<T>(
 /// binder depth, and finds late-bound regions targeting the
 /// `for<..`>.  For each of those, it creates an entry in
 /// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx: 'me, D>
-where
-    D: TypeRelatingDelegate<'tcx> + 'me,
-{
-    delegate: &'me mut D,
+struct ScopeInstantiator<'me, 'tcx: 'me> {
+    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
     // The debruijn index of the scope we are instantiating.
     target_index: ty::DebruijnIndex,
-    universally_quantified: UniversallyQuantified,
     bound_region_scope: &'me mut BoundRegionScope<'tcx>,
 }
 
-impl<'me, 'tcx, D> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
+impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
     fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
         self.target_index.shift_in(1);
         t.super_visit_with(self);
@@ -629,9 +658,8 @@ fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         let ScopeInstantiator {
-            universally_quantified,
             bound_region_scope,
-            delegate,
+            next_region,
             ..
         } = self;
 
@@ -640,7 +668,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
                 bound_region_scope
                     .map
                     .entry(*br)
-                    .or_insert_with(|| delegate.next_region_var(*universally_quantified));
+                    .or_insert_with(|| next_region(*br));
             }
 
             _ => {}