]> git.lizzy.rs Git - rust.git/commitdiff
rewrite leak check to be based on universes
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 19 May 2020 01:09:40 +0000 (01:09 +0000)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 22 Jun 2020 14:33:44 +0000 (14:33 +0000)
In the new leak check, instead of getting a list of placeholders to
track, we look for any placeholder that is part of a universe which
was created during the snapshot.

We are looking for the following error patterns:

* P1: P2, where P1 != P2
* P1: R, where R is in some universe that cannot name P1

This new leak check is more precise than before, in that it accepts
this patterns:

* R: P1, even if R cannot name P1, because R = 'static is a valid
sol'n
* R: P1, R: P2, as above

Note that this leak check, when running during subtyping, is less
efficient than before in some sense because it is going to check and
re-check all the universes created since the snapshot. We're going to
move when the leak check runs to try and correct that.

29 files changed:
src/librustc_infer/infer/higher_ranked/mod.rs
src/librustc_infer/infer/mod.rs
src/librustc_infer/infer/region_constraints/leak_check.rs
src/librustc_infer/lib.rs
src/librustc_trait_selection/traits/project.rs
src/librustc_trait_selection/traits/select/mod.rs
src/test/ui/associated-types/associated-types-eq-hr.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
src/test/ui/hr-subtype/hr-subtype.rs
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr [deleted file]
src/test/ui/regions-fn-subtyping-return-static-fail.rs
src/test/ui/regions-fn-subtyping-return-static-fail.stderr
src/test/ui/regions/regions-fn-subtyping-return-static.rs
src/test/ui/regions/regions-fn-subtyping-return-static.stderr [deleted file]
src/test/ui/rfc1623.stderr

index 0499dc9ed2232ee8f2f39015a672fa00d6973cc0..b94221785ae755b4a15dd4d32239dab74b0207df 100644 (file)
@@ -33,7 +33,7 @@ pub fn higher_ranked_sub<T>(
         self.infcx.commit_if_ok(|snapshot| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
+            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
@@ -48,7 +48,7 @@ pub fn higher_ranked_sub<T>(
             // Compare types now that bound regions have been replaced.
             let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-            self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
+            self.infcx.leak_check(!a_is_expected, snapshot)?;
 
             debug!("higher_ranked_sub: OK result={:?}", result);
 
@@ -119,7 +119,6 @@ pub fn replace_bound_vars_with_placeholders<T>(
     pub fn leak_check(
         &self,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
         // If the user gave `-Zno-leak-check`, or we have been
@@ -135,7 +134,7 @@ pub fn leak_check(
         self.inner.borrow_mut().unwrap_region_constraints().leak_check(
             self.tcx,
             overly_polymorphic,
-            placeholder_map,
+            self.universe(),
             snapshot,
         )
     }
index 91f4b3323f30efc82a5e2f21e3c3b73cbc221e4d..0e569be34aa66dc0ce7258236fdd22f88944205d 100644 (file)
@@ -992,12 +992,12 @@ pub fn subtype_predicate(
         }
 
         Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+            let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
-            self.leak_check(false, &placeholder_map, snapshot)?;
+            self.leak_check(false, snapshot)?;
 
             Ok(ok.unit())
         }))
@@ -1009,13 +1009,13 @@ pub fn region_outlives_predicate(
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) -> UnitResult<'tcx> {
         self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+            let (ty::OutlivesPredicate(r_a, r_b), _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
                 RelateRegionParamBound(cause.span)
             });
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, &placeholder_map, snapshot)?;
+            self.leak_check(false, snapshot)?;
             Ok(())
         })
     }
index 91c39a0e78ffb732ef8340a2cc8b4512b6983013..f3b78909b42d890328127eadb47c3df349145365 100644 (file)
 use super::*;
-use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use rustc_data_structures::undo_log::UndoLogs;
+use crate::infer::CombinedSnapshot;
+use rustc_data_structures::{
+    graph::{scc::Sccs, vec_graph::VecGraph},
+    undo_log::UndoLogs,
+};
+use rustc_index::vec::Idx;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 
 impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
-    /// Searches region constraints created since `snapshot` that
-    /// affect one of the placeholders in `placeholder_map`, returning
-    /// an error if any of the placeholders are related to another
-    /// placeholder or would have to escape into some parent universe
-    /// that cannot name them.
+    /// Searches new universes created during `snapshot`, looking for
+    /// placeholders that may "leak" out from the universes they are contained
+    /// in. If any leaking placeholders are found, then an `Err` is returned
+    /// (typically leading to the snapshot being reversed).
     ///
-    /// This is a temporary backwards compatibility measure to try and
-    /// retain the older (arguably incorrect) behavior of the
-    /// compiler.
+    /// The leak check *used* to be the only way we had to handle higher-ranked
+    /// obligations. Now that we have integrated universes into the region
+    /// solvers, this is no longer the case, but we retain the leak check for
+    /// backwards compatibility purposes. In particular, it lets us make "early"
+    /// decisions about whether a region error will be reported that are used in
+    /// coherence and elsewhere -- see #56105 and #59490 for more details. The
+    /// eventual fate of the leak checker is not yet settled.
     ///
-    /// NB. Although `_snapshot` isn't used, it's passed in to prove
-    /// that we are in a snapshot, which guarantees that we can just
-    /// search the "undo log" for edges. This is mostly an efficiency
-    /// thing -- we could search *all* region constraints, but that'd be
-    /// a bigger set and the data structures are not setup for that. If
-    /// we wind up keeping some form of this check long term, it would
-    /// probably be better to remove the snapshot parameter and to
-    /// refactor the constraint set.
+    /// The leak checker works by searching for the following error patterns:
+    ///
+    /// * P1: P2, where P1 != P2
+    /// * P1: R, where R is in some universe that cannot name P1
+    ///
+    /// The idea here is that each of these patterns represents something that
+    /// the region solver would eventually report as an error, so we can detect
+    /// the error early. There is a fly in the ointment, though, in that this is
+    /// not entirely true. In particular, in the future, we may extend the
+    /// environment with implied bounds or other info about how placeholders
+    /// relate to regions in outer universes. In that case, `P1: R` for example
+    /// might become solveable.
+    ///
+    /// # Summary of the implementation
+    ///
+    /// The leak checks as follows. First, we construct a graph where `R2: R1`
+    /// implies `R2 -> R1`, and we compute the SCCs.
+    ///
+    /// For each SCC S, we compute:
+    ///
+    /// * what placeholder P it must be equal to, if any
+    ///   * if there are multiple placeholders that must be equal, report an error because `P1: P2`
+    /// * the minimum universe of its constituents
+    ///
+    /// Then we walk the SCCs in dependency order and compute
+    ///
+    /// * what placeholder they must outlive transitively
+    ///   * if they must also be equal to a placeholder, report an error because `P1: P2`
+    /// * minimum universe U of all SCCs they must outlive
+    ///   * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
+    ///     indicates `P: R` and `R` is in an incompatible universe
+    ///
+    /// # Historical note
+    ///
+    /// Older variants of the leak check used to report errors for these
+    /// patterns, but we no longer do:
+    ///
+    /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
+    /// * R: P1, R: P2, as above
     pub fn leak_check(
         &mut self,
         tcx: TyCtxt<'tcx>,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+        max_universe: ty::UniverseIndex,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
-        debug!("leak_check(placeholders={:?})", placeholder_map);
+        debug!(
+            "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
+            max_universe, snapshot.universe, overly_polymorphic
+        );
 
         assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
 
-        // Go through each placeholder that we created.
-        for &placeholder_region in placeholder_map.values() {
-            // Find the universe this placeholder inhabits.
-            let placeholder = match placeholder_region {
-                ty::RePlaceholder(p) => p,
-                _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,),
-            };
-
-            // Find all regions that are related to this placeholder
-            // in some way. This means any region that either outlives
-            // or is outlived by a placeholder.
-            let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
-            taint_set.fixed_point(
-                tcx,
-                self.undo_log.region_constraints(),
-                &self.storage.data.verifys,
-            );
-            let tainted_regions = taint_set.into_set();
-
-            // Report an error if two placeholders in the same universe
-            // are related to one another, or if a placeholder is related
-            // to something from a parent universe.
-            for &tainted_region in &tainted_regions {
-                if let ty::RePlaceholder(_) = tainted_region {
-                    // Two placeholders cannot be related:
-                    if tainted_region == placeholder_region {
-                        continue;
-                    }
-                } else if self.universe(tainted_region).can_name(placeholder.universe) {
-                    continue;
-                }
-
-                return Err(if overly_polymorphic {
-                    debug!("overly polymorphic!");
-                    TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
-                } else {
-                    debug!("not as polymorphic!");
-                    TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
-                });
-            }
+        let universe_at_start_of_snapshot = snapshot.universe;
+        if universe_at_start_of_snapshot == max_universe {
+            return Ok(());
         }
 
+        let mini_graph =
+            &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
+
+        let mut leak_check = LeakCheck::new(
+            tcx,
+            universe_at_start_of_snapshot,
+            max_universe,
+            overly_polymorphic,
+            mini_graph,
+            self,
+        );
+        leak_check.assign_placeholder_values()?;
+        leak_check.propagate_scc_value()?;
         Ok(())
     }
 }
 
-#[derive(Debug)]
-struct TaintSet<'tcx> {
-    directions: TaintDirections,
-    regions: FxHashSet<ty::Region<'tcx>>,
+struct LeakCheck<'me, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    universe_at_start_of_snapshot: ty::UniverseIndex,
+    overly_polymorphic: bool,
+    mini_graph: &'me MiniGraph<'tcx>,
+    rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+
+    // Initially, for each SCC S, stores a placeholder `P` such that `S = P`
+    // must hold.
+    //
+    // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
+    // is repurposed to store some placeholder `P` such that the weaker
+    // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
+    // = P`.)
+    scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
+
+    // For each SCC S, track the minimum universe that flows into it. Note that
+    // this is both the minimum of the universes for every region that is a
+    // member of the SCC, but also if you have `R1: R2`, then the universe of
+    // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
+    // see that, imagine that you have `P1: R` -- in that case, `R` must be
+    // either the placeholder `P1` or the empty region in that same universe.
+    //
+    // To detect errors, we look for an SCC S where the values in
+    // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
+    scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
 }
 
-impl<'tcx> TaintSet<'tcx> {
-    fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
-        let mut regions = FxHashSet::default();
-        regions.insert(initial_region);
-        TaintSet { directions, regions }
+impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        universe_at_start_of_snapshot: ty::UniverseIndex,
+        max_universe: ty::UniverseIndex,
+        overly_polymorphic: bool,
+        mini_graph: &'me MiniGraph<'tcx>,
+        rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+    ) -> Self {
+        let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
+        Self {
+            tcx,
+            universe_at_start_of_snapshot,
+            overly_polymorphic,
+            mini_graph,
+            rcc,
+            scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
+            scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
+        }
+    }
+
+    /// Compute what placeholders (if any) each SCC must be equal to.
+    /// Also compute the minimum universe of all the regions in each SCC.
+    fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
+        // First walk: find each placeholder that is from a newly created universe.
+        for (region, leak_check_node) in &self.mini_graph.nodes {
+            let scc = self.mini_graph.sccs.scc(*leak_check_node);
+
+            // Set the universe of each SCC to be the minimum of its constituent universes
+            let universe = self.rcc.universe(region);
+            debug!(
+                "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
+                scc, universe, region
+            );
+            self.scc_universes[scc].take_min(universe, region);
+
+            // Detect those SCCs that directly contain a placeholder
+            if let ty::RePlaceholder(placeholder) = region {
+                if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
+                    self.assign_scc_value(scc, *placeholder)?;
+                }
+            }
+        }
+
+        Ok(())
     }
 
-    fn fixed_point<'a>(
+    // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
+    // This may create an error.
+    fn assign_scc_value(
         &mut self,
-        tcx: TyCtxt<'tcx>,
-        undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
-        verifys: &[Verify<'tcx>],
-    ) where
-        'tcx: 'a,
-    {
-        let mut prev_len = 0;
-        while prev_len < self.len() {
-            debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
-
-            prev_len = self.len();
-
-            for undo_entry in undo_log.clone() {
-                match undo_entry {
-                    &AddConstraint(Constraint::VarSubVar(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::RegSubVar(a, b)) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::VarSubReg(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), b);
-                    }
-                    &AddConstraint(Constraint::RegSubReg(a, b)) => {
-                        self.add_edge(a, b);
-                    }
-                    &AddGiven(a, b) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddVerify(i) => span_bug!(
-                        verifys[i].origin.span(),
-                        "we never add verifications while doing higher-ranked things",
-                    ),
-                    &AddCombination(..) | &AddVar(..) => {}
+        scc: LeakCheckScc,
+        placeholder: ty::PlaceholderRegion,
+    ) -> RelateResult<'tcx, ()> {
+        match self.scc_placeholders[scc] {
+            Some(p) => {
+                assert_ne!(p, placeholder);
+                return Err(self.placeholder_error(p, placeholder));
+            }
+            None => {
+                self.scc_placeholders[scc] = Some(placeholder);
+            }
+        };
+
+        Ok(())
+    }
+
+    /// For each SCC S, iterate over each successor S1 where `S: S1`:
+    ///
+    /// * Compute
+    /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
+    /// `universe(S) <= universe(S1)`. This executes after
+    /// `assign_placeholder_values`, so `universe(S)` is already the minimum
+    /// universe of any of its direct constituents.
+    fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
+        // Loop invariants:
+        //
+        // On start of the loop iteration for `scc1`:
+        //
+        // * `scc_universes[scc1]` contains the minimum universe of the
+        //   constituents of `scc1`
+        // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
+        //   be equal to (if any)
+        //
+        // For each succssor `scc2` where `scc1: scc2`:
+        //
+        // * `scc_placeholder[scc2]` stores some placeholder `P` where
+        //   `scc2: P` (if any)
+        // * `scc_universes[scc2]` contains the minimum universe of the
+        //   constituents of `scc2` and any of its successors
+        for scc1 in self.mini_graph.sccs.all_sccs() {
+            debug!(
+                "propagate_scc_value: scc={:?} with universe {:?}",
+                scc1, self.scc_universes[scc1]
+            );
+
+            // Walk over each `scc2` such that `scc1: scc2` and compute:
+            //
+            // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
+            // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
+            //   we pick one arbitrarily)
+            let mut scc1_universe = self.scc_universes[scc1];
+            let mut succ_bound = None;
+            for &scc2 in self.mini_graph.sccs.successors(scc1) {
+                let SccUniverse { universe: scc2_universe, region: scc2_region } =
+                    self.scc_universes[scc2];
+
+                scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
+
+                if let Some(b) = self.scc_placeholders[scc2] {
+                    succ_bound = Some(b);
                 }
             }
+
+            // Update minimum universe of scc1.
+            self.scc_universes[scc1] = scc1_universe;
+
+            // At this point, `scc_placholder[scc1]` stores the placeholder that
+            // `scc1` must be equal to, if any.
+            if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
+                debug!(
+                    "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
+                    scc1, scc1_placeholder, scc1_universe
+                );
+
+                // Check if `P1: R` for some `R` in a universe that cannot name
+                // P1. That's an error.
+                if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
+                    return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
+                }
+
+                // Check if we have some placeholder where `S: P2`
+                // (transitively). In that case, since `S = P1`, that implies
+                // `P1: P2`, which is an error condition.
+                if let Some(scc2_placeholder) = succ_bound {
+                    assert_ne!(scc1_placeholder, scc2_placeholder);
+                    return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
+                }
+            } else {
+                // Otherwise, we can reach a placeholder if some successor can.
+                self.scc_placeholders[scc1] = succ_bound;
+            }
+
+            // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
         }
+        Ok(())
     }
 
-    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
-        self.regions
+    fn placeholder_error(
+        &self,
+        placeholder1: ty::PlaceholderRegion,
+        placeholder2: ty::PlaceholderRegion,
+    ) -> TypeError<'tcx> {
+        self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
     }
 
-    fn len(&self) -> usize {
-        self.regions.len()
+    fn error(
+        &self,
+        placeholder: ty::PlaceholderRegion,
+        other_region: ty::Region<'tcx>,
+    ) -> TypeError<'tcx> {
+        if self.overly_polymorphic {
+            return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+        } else {
+            return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+        }
     }
+}
 
-    fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
-        if self.directions.incoming {
-            if self.regions.contains(&target) {
-                self.regions.insert(source);
-            }
+// States we need to distinguish:
+//
+// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
+//     * it could conflict with some other regions in the SCC in different universes
+//     * or a different placeholder
+// * `P1: S` and `S` must be equal to a placeholder
+// * `P1: S` and `S` is in an incompatible universe
+//
+// So if we
+//
+// (a) compute which placeholder (if any) each SCC must be equal to
+// (b) compute its minimum universe
+// (c) compute *some* placeholder where `S: P1` (any one will do)
+//
+// then we get an error if:
+//
+// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
+// - `S: P1` and minimum universe cannot name `P1`
+// - `S: P1` and we must be equal to `P2`
+//
+// So we want to track:
+//
+// * Equal placeholder (if any)
+// * Some bounding placeholder (if any)
+// * Minimum universe
+//
+// * We compute equal placeholder + minimum universe of constituents in first pass
+// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
+//   * bounding placeholder (if any)
+//   * minimum universe
+// * And if we must be equal to a placeholder then we check it against
+//   * minimum universe
+//   * no bounding placeholder
+
+/// Tracks the "minimum universe" for each SCC, along with some region that
+/// caused it to change.
+#[derive(Copy, Clone, Debug)]
+struct SccUniverse<'tcx> {
+    /// For some SCC S, the minimum universe of:
+    ///
+    /// * each region R in S
+    /// * each SCC S1 such that S: S1
+    universe: ty::UniverseIndex,
+
+    /// Some region that caused `universe` to be what it is.
+    region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> SccUniverse<'tcx> {
+    /// If `universe` is less than our current universe, then update
+    /// `self.universe` and `self.region`.
+    fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
+        if universe < self.universe || self.region.is_none() {
+            self.universe = universe;
+            self.region = Some(region);
         }
+    }
+}
+
+rustc_index::newtype_index! {
+    struct LeakCheckNode {
+        DEBUG_FORMAT = "LeakCheckNode({})"
+    }
+}
 
-        if self.directions.outgoing {
-            if self.regions.contains(&source) {
-                self.regions.insert(target);
+rustc_index::newtype_index! {
+    struct LeakCheckScc {
+        DEBUG_FORMAT = "LeakCheckScc({})"
+    }
+}
+
+/// Represents the graph of constraints. For each `R1: R2` constraint we create
+/// an edge `R1 -> R2` in the graph.
+struct MiniGraph<'tcx> {
+    /// Map from a region to the index of the node in the graph.
+    nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+
+    /// Map from node index to SCC, and stores the successors of each SCC. All
+    /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
+    /// then `S1: S2`.
+    sccs: Sccs<LeakCheckNode, LeakCheckScc>,
+}
+
+impl<'tcx> MiniGraph<'tcx> {
+    fn new<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+    ) -> Self
+    where
+        'tcx: 'a,
+    {
+        let mut nodes = FxHashMap::default();
+        let mut edges = Vec::new();
+
+        // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
+        Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
+            let source_node = Self::add_node(&mut nodes, source);
+            let target_node = Self::add_node(&mut nodes, target);
+            edges.push((source_node, target_node));
+        });
+        let graph = VecGraph::new(nodes.len(), edges);
+        let sccs = Sccs::new(&graph);
+        Self { nodes, sccs }
+    }
+
+    /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
+    fn iterate_undo_log<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+        mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
+    ) where
+        'tcx: 'a,
+    {
+        for undo_entry in undo_log {
+            match undo_entry {
+                &AddConstraint(Constraint::VarSubVar(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::RegSubVar(a, b)) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::VarSubReg(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), b);
+                }
+                &AddConstraint(Constraint::RegSubReg(a, b)) => {
+                    each_edge(a, b);
+                }
+                &AddGiven(a, b) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddVerify(i) => span_bug!(
+                    verifys[i].origin.span(),
+                    "we never add verifications while doing higher-ranked things",
+                ),
+                &AddCombination(..) | &AddVar(..) => {}
             }
         }
     }
+
+    fn add_node(
+        nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+        r: ty::Region<'tcx>,
+    ) -> LeakCheckNode {
+        let l = nodes.len();
+        *nodes.entry(r).or_insert(LeakCheckNode::new(l))
+    }
 }
index ed04ee02b7203c6028ec3329d4401e4250873867..0f3f3db8679596d1e7ab990c2ccdf6a4fd7fdee2 100644 (file)
@@ -16,6 +16,9 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(const_fn)]
+#![feature(const_if_match)]
+#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(never_type)]
 #![feature(or_patterns)]
index 574d50a4fccc2b970c05aa35e2e7886e149e4bfc..4bc58fbaadcda8b516fd265b3f7f9655281d04c8 100644 (file)
@@ -150,14 +150,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>(
 
     let infcx = selcx.infcx();
     infcx.commit_if_ok(|snapshot| {
-        let (placeholder_predicate, placeholder_map) =
+        let (placeholder_predicate, _) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
         let result = project_and_unify_type(selcx, &placeholder_obligation)?;
-        infcx
-            .leak_check(false, &placeholder_map, snapshot)
-            .map_err(|err| MismatchedProjectionTypes { err })?;
+        infcx.leak_check(false, snapshot).map_err(|err| MismatchedProjectionTypes { err })?;
         Ok(result)
     })
 }
@@ -300,7 +298,11 @@ fn new(
     fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
         let value = self.selcx.infcx().resolve_vars_if_possible(value);
 
-        if !value.has_projections() { value } else { value.fold_with(self) }
+        if !value.has_projections() {
+            value
+        } else {
+            value.fold_with(self)
+        }
     }
 }
 
index 076bdad423ab868439baa45740b2f056056a09e8..e90acbbce67ba17643d3674309e03ff7463f6a12 100644 (file)
@@ -21,7 +21,7 @@
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{Overflow, SelectionError, Unimplemented};
 
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectionCacheKeyExt;
 use rustc_ast::attr;
@@ -1265,7 +1265,7 @@ fn match_projection_obligation_against_definition_bounds(
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, placeholder_map) =
+        let (placeholder_trait_predicate, _) =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
@@ -1297,7 +1297,6 @@ fn match_projection_obligation_against_definition_bounds(
                         obligation,
                         bound,
                         placeholder_trait_predicate.trait_ref,
-                        &placeholder_map,
                         snapshot,
                     )
                 }) {
@@ -1320,7 +1319,6 @@ fn match_projection_obligation_against_definition_bounds(
                     obligation,
                     bound,
                     placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
                     snapshot,
                 );
 
@@ -1335,7 +1333,6 @@ fn match_projection(
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &PlaceholderMap<'tcx>,
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
@@ -1343,7 +1340,7 @@ fn match_projection(
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
-            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
+            && self.infcx.leak_check(false, snapshot).is_ok()
     }
 
     fn evaluate_where_clause<'o>(
@@ -1837,7 +1834,7 @@ fn match_impl(
             return Err(());
         }
 
-        let (placeholder_obligation, placeholder_map) =
+        let (placeholder_obligation, _) =
             self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
@@ -1869,7 +1866,7 @@ fn match_impl(
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
 
-        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
+        if let Err(e) = self.infcx.leak_check(false, snapshot) {
             debug!("match_impl: failed leak check due to `{}`", e);
             return Err(());
         }
@@ -2405,7 +2402,11 @@ fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
     }
 
     fn depth(&self) -> usize {
-        if let Some(head) = self.head { head.depth } else { 0 }
+        if let Some(head) = self.head {
+            head.depth
+        } else {
+            0
+        }
     }
 }
 
index 58d72746e76aa3c3c4c4ec7f003b142a52c51af1..50f1d07142f8c8ee18f43bd8411c0be3e326acba 100644 (file)
@@ -49,7 +49,7 @@ LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
    |                                                           ------------- required by this bound in `tuple_one`
 ...
 LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime
 
 error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
   --> $DIR/associated-types-eq-hr.rs:97:17
@@ -74,7 +74,7 @@ LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
    |                                                           ------------- required by this bound in `tuple_two`
 ...
 LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'y, found concrete lifetime
 
 error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
   --> $DIR/associated-types-eq-hr.rs:107:18
index b91798fa1237913a168ea43df13fb5f4eebd4c95..1da224a3e85e090fb4df252402381bcefd25d02b 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-LL | |                                             for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
-   | |_________________________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
               found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
index 45f53d4fe99db100ec221ad503ca80717c510b44..880a8c7be8305d3e3f1426a44a0a40c86f9b6ed0 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-LL | |                                 for<'a>    fn(&'a u32, &'a u32)) }
-   | |__________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(&'a u32, &'a u32)) }
+   | |__________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
               found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:104:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:104:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index c3e4f6d2ed0c1c91e348822f324bcacb0e28f386..d2abcc4a66091d7800655a40411949384180ebe3 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-LL | |                              fn(&'x u32)) }
-   | |___________________________________________- in this macro invocation
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a> fn(&'a u32)>`
               found enum `std::option::Option<fn(&'x u32)>`
index 4d7b86027f56463d68b380b4bd73d51b354d1f93..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:104:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-LL | |                                       for<'a>    fn(Co<'a>, Co<'a>)) }
-   | |______________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 7f0a4197dd7fe412d5602ba145b5a0c8970e48bc..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:104:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-LL | |                                         for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
-   | |______________________________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:104:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index c12e543a44e79e29a8cd21449e220cbfd0a96864..e1a16f5149cc6069d241a1a8f5a94ce2021e60ee 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-LL | |                                             for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
-   | |______________________________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+   | |__________________________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
               found enum `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
index 460356856bd562cd9f229b1f832c5cb04982635d..5fec1e9a92eaecbee6332c74d0b6ac80062223fa 100644 (file)
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-LL | |                                         for<'a>    fn(Inv<'a>, Inv<'a>)) }
-   | |__________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
               found enum `std::option::Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:104:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index fc3643306e628cf0a1cb0185a1a674f495df2557..3c8af20e50cef383296b4663c454839320917791 100644 (file)
@@ -1,65 +1,65 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:33:26
+  --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t2>(None::<$t1>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'y>)>`
               found enum `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime `'x` as defined on the function body at 32:20...
-  --> $DIR/hr-subtype.rs:32:20
+note: the lifetime `'x` as defined on the function body at 38:20...
+  --> $DIR/hr-subtype.rs:38:20
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
    |                      ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
-  --> $DIR/hr-subtype.rs:32:23
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24
+  --> $DIR/hr-subtype.rs:38:24
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                         ^^
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                          ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'x>)>`
               found enum `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
index 6aba6466fada53b920ef1bcd13d0eaf27a98ebec..0cc30e479c7b9ace3702125858f51407ee3b0460 100644 (file)
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:104:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
index 0dde27788f6296212d46f897aa762803c7ea0fcc..7b4cdd4a419b4f4856e7f7409f71e5f5766a5af8 100644 (file)
@@ -1,33 +1,33 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(&'x u32)>`
               found enum `std::option::Option<fn(&'y u32)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
index b31f198bd97bf8cee87182f5f2efae6780ce8870..9e9c2ce9c61d71aa143854a262664fe0e054a389 100644 (file)
 // revisions: bound_inv_a_b_vs_bound_inv_a
 // revisions: bound_a_b_ret_a_vs_bound_a_ret_a
 
-fn gimme<T>(_: Option<T>) { }
+fn gimme<T>(_: Option<T>) {}
 
-struct Inv<'a> { x: *mut &'a u32 }
+struct Inv<'a> {
+    x: *mut &'a u32,
+}
 
-struct Co<'a> { x: fn(&'a u32) }
+struct Co<'a> {
+    x: fn(&'a u32),
+}
 
-struct Contra<'a> { x: &'a u32 }
+struct Contra<'a> {
+    x: &'a u32,
+}
 
 macro_rules! check {
     ($rev:ident: ($t1:ty, $t2:ty)) => {
         #[cfg($rev)]
-        fn subtype<'x,'y:'x,'z:'y>() {
+        fn subtype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t2>(None::<$t1>);
             //[free_inv_x_vs_free_inv_y]~^ ERROR
         }
 
         #[cfg($rev)]
-        fn supertype<'x,'y:'x,'z:'y>() {
+        fn supertype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t1>(None::<$t2>);
             //[bound_a_vs_free_x]~^ ERROR
             //[free_x_vs_free_y]~^^ ERROR
@@ -43,35 +49,33 @@ fn supertype<'x,'y:'x,'z:'y>() {
             //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
             //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
             //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
-            //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
-            //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR
-            //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR
+            //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^ ERROR
         }
-    }
+    };
 }
 
 // If both have bound regions, they are equivalent, regardless of
 // variant.
 check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
-                              for<'a> fn(&'a u32)) }
+for<'a> fn(&'a u32)) }
 check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
-                              for<'b> fn(&'b u32)) }
+for<'b> fn(&'b u32)) }
 check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
-                                      for<'b> fn(Inv<'b>)) }
+for<'b> fn(Inv<'b>)) }
 check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
-                                    for<'b> fn(Co<'b>)) }
+for<'b> fn(Co<'b>)) }
 
 // Bound is a subtype of free.
 check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-                             fn(&'x u32)) }
+fn(&'x u32)) }
 
 // Two free regions are relatable if subtyping holds.
 check! { free_x_vs_free_x: (fn(&'x u32),
-                            fn(&'x u32)) }
+fn(&'x u32)) }
 check! { free_x_vs_free_y: (fn(&'x u32),
-                            fn(&'y u32)) }
+fn(&'y u32)) }
 check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-                                    fn(Inv<'y>)) }
+fn(Inv<'y>)) }
 
 // Somewhat surprisingly, a fn taking two distinct bound lifetimes and
 // a fn taking one bound lifetime can be interchangeable, but only if
@@ -82,25 +86,27 @@ fn supertype<'x,'y:'x,'z:'y>() {
 //   intersection;
 // - if we are contravariant, then 'a can be inferred to 'static.
 check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-                                for<'a>    fn(&'a u32, &'a u32)) }
+for<'a>    fn(&'a u32, &'a u32)) }
 check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-                                      for<'a>    fn(Co<'a>, Co<'a>)) }
+for<'a>    fn(Co<'a>, Co<'a>)) }
 check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-                                            for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
 check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-                                        for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
 
 // If we make those lifetimes invariant, then the two types are not interchangeable.
 check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-                                        for<'a>    fn(Inv<'a>, Inv<'a>)) }
+for<'a>    fn(Inv<'a>, Inv<'a>)) }
 check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-                                            for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
 
 #[rustc_error]
 fn main() {
-//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
-//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
-//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR
+    //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
 }
index 95b57d6c5bb5ed2998209f67667575d0ff262c6a..f95496a6c3cc0dc5845f83dfede498241dd2632f 100644 (file)
@@ -2,6 +2,8 @@
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
+//
+// check-pass
 
 trait Trait<T> {}
 
@@ -30,9 +32,6 @@ fn main() {
     //         - `?b: ?a` -- solveable if `?b` is inferred to `'static`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'static`.
-    //
-    // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
deleted file mode 100644 (file)
index 1e335f9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11
-   |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(fn(&'b u32))>,
-   |        ------------------------------ required by this bound in `foo`
-...
-LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(fn(&'b u32))>` is not implemented for `()`
-   |
-   = help: the following implementations were found:
-             <() as Trait<fn(fn(&'a u32))>>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
index 2dd0c9796e2584eaa12fb5a23b90a0e05d859d4e..539221b5a046c20c694430ab05cb46f77305282c 100644 (file)
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -25,7 +25,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
@@ -48,5 +48,4 @@ fn supply_G() {
     want_G(baz); //~ ERROR mismatched types
 }
 
-pub fn main() {
-}
+pub fn main() {}
index 27704b3e0a8c7421414764b1fb62e28d74f11b33..6d75ace3c469814ac21e13a1848bc689e57ee72c 100644 (file)
@@ -1,12 +1,3 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
 error[E0308]: mismatched types
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
    |
@@ -16,6 +7,6 @@ LL |     want_G(baz);
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
                  found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0308`.
index fa2cc37d05b2b917b060b7271a78ab6573f34068..de14d5ba82a1b7dfc10348ceafbfb012c771034e 100644 (file)
@@ -5,6 +5,8 @@
 // *ANY* lifetime and returns a reference with the 'static lifetime.
 // This can safely be considered to be an instance of `F` because all
 // lifetimes are sublifetimes of 'static.
+//
+// check-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -26,7 +28,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -38,10 +40,9 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
deleted file mode 100644 (file)
index a8a7e97..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
index ca956004ef76f5aac107abaf37c30600b4abd5fa..75df99137179b6b08d7c18a81a4d46a6c00ff2d1 100644 (file)
@@ -36,7 +36,7 @@ error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std:
   --> $DIR/rfc1623.rs:25:8
    |
 LL |     f: &id,
-   |        ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |        ^^^ expected bound lifetime parameter 'b, found concrete lifetime
    |
    = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`