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 --
// 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);
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
self.inner.borrow_mut().unwrap_region_constraints().leak_check(
self.tcx,
overly_polymorphic,
- placeholder_map,
+ self.universe(),
snapshot,
)
}
}
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())
}))
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(())
})
}
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))
+ }
}
#![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)]
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)
})
}
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)
+ }
}
}
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;
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: \
obligation,
bound,
placeholder_trait_predicate.trait_ref,
- &placeholder_map,
snapshot,
)
}) {
obligation,
bound,
placeholder_trait_predicate.trait_ref,
- &placeholder_map,
snapshot,
);
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());
.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>(
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;
.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(());
}
}
fn depth(&self) -> usize {
- if let Some(head) = self.head { head.depth } else { 0 }
+ if let Some(head) = self.head {
+ head.depth
+ } else {
+ 0
+ }
}
}
| ------------- 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
| ------------- 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
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>`
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)>`
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 | | }
| |_^
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 | | }
| |_^
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)>`
-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`.
-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`.
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 | | }
| |_^
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>>`
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>)>`
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 | | }
| |_^
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
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 | | }
| |_^
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
// 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
//[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
// 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
}
//
// 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> {}
// - `?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
}
+++ /dev/null
-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`.
// 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 {
}
// Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
panic!()
}
fn supply_F() {
want_F(foo);
- want_F(bar); //~ ERROR mismatched types
+ want_F(bar);
want_F(baz);
}
want_G(baz); //~ ERROR mismatched types
}
-pub fn main() {
-}
+pub fn main() {}
-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
|
= 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`.
// *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 {
}
// Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
panic!()
}
fn supply_F() {
want_F(foo);
- want_F(bar); //~ ERROR mismatched types
+ want_F(bar);
want_F(baz);
}
-pub fn main() {
-}
+pub fn main() {}
+++ /dev/null
-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`.
--> $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>`