Auto merge of #119820 - lcnr:leak-check-2, r=jackh726
instantiate higher ranked goals outside of candidate selection This PR modifies `evaluate` to more eagerly instantiate higher-ranked goals, preventing the `leak_check` during candidate selection from detecting placeholder errors involving that binder. For a general background regarding higher-ranked region solving and the leak check, see https://hackmd.io/qd9Wp03cQVy06yOLnro2Kg. > The first is something called the **leak check**. You can think of it as a "quick and dirty" approximation for the region check, which will come later. The leak check detects some kinds of errors early, essentially deciding between "this set of outlives constraints are guaranteed to result in an error eventually" or "this set of outlives constraints may be solvable". ## The ideal future We would like to end up with the following idealized design to handle universal binders: ```rust fn enter_forall<'tcx, T, R>( forall: Binder<'tcx, T>, f: impl FnOnce(T) -> R, ) -> R { let new_universe = infcx.increment_universe_index(); let value = instantiate_binder_with_placeholders_in(new_universe, forall); let result = f(value); eagerly_handle_higher_ranked_region_constraints_in(new_universe); infcx.decrement_universe_index(); assert!(!result.has_placeholders_in_or_above(new_universe)); result } ``` That is, when universally instantiating a binder, anything using the placeholders has to happen inside of a limited scope (the closure `f`). After this closure has completed, all constraints involving placeholders are known. We then handle any *external constraints* which name these placeholders. We destructure `TypeOutlives` constraints involving placeholders and eagerly handle any region constraints involving these placeholders. We do not return anything mentioning the placeholders created inside of this function to the caller. Being able to eagerly handle *all* region constraints involving placeholders will be difficult due to complex `TypeOutlives` constraints, involving inference variables or alias types, and higher ranked implied bounds. The exact issues and possible solutions are out of scope of this FCP. #### How does the leak check fit into this The `leak_check` is an underapproximation of `eagerly_handle_higher_ranked_region_constraints_in`. It detects some kinds of errors involving placeholders from `new_universe`, but not all of them. It only looks at region outlives constraints, ignoring `TypeOutlives`, and checks whether one of the following two conditions are met for **placeholders in or above `new_universe`**, in which case it results in an error: - `'!p1: '!p2` a placeholder `'!p2` outlives a different placeholder `'!p1` - `'!p1: '?2` an inference variable `'?2` outlives a placeholder `'!p1` *which it cannot name* It does not handle all higher ranked region constraints, so we still return constraints involving placeholders from `new_universe` which are then (re)checked by `lexical_region_resolve` or MIR borrowck. As we check higher ranked constraints in the full regionck anyways, the `leak_check` is not soundness critical. It's current only purpose is to move some higher ranked region errors earlier, enabling it to guide type inference and trait solving. Adding additional uses of the `leak_check` in the future would only strengthen inference and is therefore not breaking. ## Where do we use currently use the leak check The `leak_check` is currently used in two places: Coherence does not use a proper regionck, only relying on the `leak_check` called [at the end of the implicit negative overlap check](8b94152af6/compiler/rustc_trait_selection/src/traits/coherence.rs (L235-L238)
). During coherence all parameters are instantiated with inference variables, so the only possible region errors are higher-ranked. We currently also sometimes make guesses when destructuring `TypeOutlives` constraints which can theoretically result in incorrect errors. This could result in overlapping impls. We also use the `leak_check` [at the end of `fn evaluation_probe`](8b94152af6/compiler/rustc_trait_selection/src/traits/select/mod.rs (L607-L610)
). This function is used during candidate assembly for `Trait` goals. Most notably we use [inside of `evaluate_candidate` during winnowing](0e4243538b/compiler/rustc_trait_selection/src/traits/select/mod.rs (L491-L502)
). Conceptionally, it is as if we compute each candidate in a separate `enter_forall`. ## The current use in `fn evaluation_probe` is undesirable Because we only instantiate a higher-ranked goal once inside of `fn evaluation_probe`, errors involving placeholders from that binder can impact selection. This results in inconsistent behavior ([playground]( *[playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dac60ebdd517201788899ffa77364831)*)): ```rust trait Leak<'a> {} impl Leak<'_> for Box<u32> {} impl Leak<'static> for Box<u16> {} fn impls_leak<T: for<'a> Leak<'a>>() {} trait IndirectLeak<'a> {} impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {} fn main() { // ok // // The `Box<u16>` impls fails the leak check, // meaning that we apply the `Box<u32>` impl. impls_leak::<Box<_>>(); // error: type annotations needed // // While the `Box<u16>` impl would fail the leak check // we have already instantiated the binder while applying // the generic `IndirectLeak` impl, so during candidate // selection of `Leak` we do not detect the placeholder error. // Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous, // resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous. impls_indirect_leak::<Box<_>>(); } ``` We generally prefer `where`-bounds over implementations during candidate selection, both for [trait goals](11f32b73e0/compiler/rustc_trait_selection/src/traits/select/mod.rs (L1863-L1887)
) and during [normalization](11f32b73e0/compiler/rustc_trait_selection/src/traits/project.rs (L184-L198)
). However, we currently **do not** use the `leak_check` during candidate assembly in normalizing. This can result in inconsistent behavior: ```rust trait Trait<'a> { type Assoc; } impl<'a, T> Trait<'a> for T { type Assoc = usize; } fn trait_bound<T: for<'a> Trait<'a>>() {} fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {} // A function with a trivial where-bound which is more // restrictive than the impl. fn function<T: Trait<'static, Assoc = usize>>() { // ok // // Proving `for<'a> T: Trait<'a>` using the where-bound results // in a leak check failure, so we use the more general impl, // causing this to succeed. trait_bound::<T>(); // error // // Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>` // does not use the leak check when trying the where-bound, causing us // to prefer it over the impl, resulting in a placeholder error. projection_bound::<T>(); // error // // Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)` // only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already // instantiated, causing us to prefer the where-bound over the impl // resulting in a placeholder error. Even if were were to also use the // leak check during candidate selection for normalization, this // case would still not compile. let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); } ``` This is also likely to be more performant. It enables more caching in the new trait solver by simply [recursively calling the canonical query][new solver] after instantiating the higher-ranked goal. It is also unclear how to add the leak check to normalization in the new solver. To handle https://github.com/rust-lang/trait-system-refactor-initiative/issues/1 `Projection` goals are implemented via `AliasRelate`. This again means that we instantiate the binder before ever normalizing any alias. Even if we were to avoid this, we lose the ability to [cache normalization by itself, ignoring the expected `term`](5bd5d214ef/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs (L34-L49)
). We cannot replace the `term` with an inference variable before instantiating the binder, as otherwise `for<'a> T: Trait<Assoc<'a> = &'a ()>` breaks. If we only replace the term after instantiating the binder, we cannot easily evaluate the goal in a separate context, as [we'd then lose the information necessary for the leak check](11f32b73e0/compiler/rustc_next_trait_solver/src/canonicalizer.rs (L230-L232)
). Adding this information to the canonical input also seems non-trivial. ## Proposed solution I propose to instantiate the binder outside of candidate assembly, causing placeholders from higher-ranked goals to get ignored while selecting their candidate. This mostly[^1] matches the [current behavior of the new solver][new solver]. The impact of this change is therefore as follows: ```rust trait Leak<'a> {} impl Leak<'_> for Box<u32> {} impl Leak<'static> for Box<u16> {} fn impls_leak<T: for<'a> Leak<'a>>() {} trait IndirectLeak<'a> {} impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {} fn guide_selection() { // ok -> ambiguous impls_leak::<Box<_>>(); // ambiguous impls_indirect_leak::<Box<_>>(); } trait Trait<'a> { type Assoc; } impl<'a, T> Trait<'a> for T { type Assoc = usize; } fn trait_bound<T: for<'a> Trait<'a>>() {} fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {} // A function which a trivial where-bound which is more // restrictive than the impl. fn function<T: Trait<'static, Assoc = usize>>() { // ok -> error trait_bound::<T>(); // error projection_bound::<T>(); // error let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| (); } ``` This does not change the behavior if candidates have higher ranked nested goals, as in this case the `leak_check` causes the nested goal to result in an error ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a74c25300b23db9022226de99d8a2fa6)): ```rust trait LeakCheckFailure<'a> {} impl LeakCheckFailure<'static> for () {} trait Trait<T> {} impl Trait<u32> for () where for<'a> (): LeakCheckFailure<'a> {} impl Trait<u16> for () {} fn impls_trait<T: Trait<U>, U>() {} fn main() { // ok // // It does not matter whether candidate assembly // considers the placeholders from higher-ranked goal. // // Either `for<'a> (): LeakCheckFailure<'a>` has no // applicable candidate or it has a single applicable candidate // when then later results in an error. This allows us to // infer `U` to `u16`. impls_trait::<(), _>() } ``` ## Impact on existing crates This is a **breaking change**. [A crater run](https://github.com/rust-lang/rust/pull/119820#issuecomment-1926862174) found 17 regressed crates with 7 root causes. For a full analysis of all affected crates, see https://gist.github.com/lcnr/7c1c652f30567048ea240554a36ed95c. --- I believe this breakage to be acceptable and would merge this change. I am confident that the new position of the leak check matches our idealized future and cannot envision any other consistent alternative. Where possible, I intend to open PRs fixing/avoiding the regressions before landing this PR. I originally intended to remove the `coherence_leak_check` lint in the same PR. However, while I am confident in the *position* of the leak check, deciding on its exact behavior is left as future work, cc #112999. This PR therefore only moves the leak check while keeping the lint when relying on it in coherence. [new solver]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs#L479-L484 [^1]: the new solver has a separate cause of inconsistent behavior rn https://github.com/rust-lang/trait-system-refactor-initiative/issues/53#issuecomment-1914310171 r? `@nikomatsakis`
This commit is contained in:
commit
43f4f2a3b1
29 changed files with 873 additions and 201 deletions
|
@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
mod candidate_assembly;
|
mod candidate_assembly;
|
||||||
mod confirmation;
|
mod confirmation;
|
||||||
|
|
||||||
|
/// Whether to consider the binder of higher ranked goals for the `leak_check` when
|
||||||
|
/// evaluating higher-ranked goals. See #119820 for more info.
|
||||||
|
///
|
||||||
|
/// While this is a bit hacky, it is necessary to match the behavior of the new solver:
|
||||||
|
/// We eagerly instantiate binders in the new solver, outside of candidate selection, so
|
||||||
|
/// the leak check inside of candidates does not consider any bound vars from the higher
|
||||||
|
/// ranked goal. However, we do exit the binder once we're completely finished with a goal,
|
||||||
|
/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum LeakCheckHigherRankedGoal {
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum IntercrateAmbiguityCause<'tcx> {
|
pub enum IntercrateAmbiguityCause<'tcx> {
|
||||||
DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
|
DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> },
|
||||||
|
@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let mut no_candidates_apply = true;
|
let mut no_candidates_apply = true;
|
||||||
|
|
||||||
for c in candidate_set.vec.iter() {
|
for c in candidate_set.vec.iter() {
|
||||||
if self.evaluate_candidate(stack, c)?.may_apply() {
|
if self
|
||||||
|
.evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)?
|
||||||
|
.may_apply()
|
||||||
|
{
|
||||||
no_candidates_apply = false;
|
no_candidates_apply = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// is needed for specialization. Propagate overflow if it occurs.
|
// is needed for specialization. Propagate overflow if it occurs.
|
||||||
let mut candidates = candidates
|
let mut candidates = candidates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| match self.evaluate_candidate(stack, &c) {
|
.map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) {
|
||||||
Ok(eval) if eval.may_apply() => {
|
Ok(eval) if eval.may_apply() => {
|
||||||
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
||||||
}
|
}
|
||||||
|
@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
debug_assert!(!self.infcx.next_trait_solver());
|
debug_assert!(!self.infcx.next_trait_solver());
|
||||||
self.evaluation_probe(|this| {
|
self.evaluation_probe(|this, _outer_universe| {
|
||||||
let goal =
|
let goal =
|
||||||
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
|
||||||
let mut result = this.evaluate_predicate_recursively(
|
let mut result = this.evaluate_predicate_recursively(
|
||||||
|
@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Computes the evaluation result of `op`, discarding any constraints.
|
||||||
|
///
|
||||||
|
/// This also runs for leak check to allow higher ranked region errors to impact
|
||||||
|
/// selection. By default it checks for leaks from all universes created inside of
|
||||||
|
/// `op`, but this can be overwritten if necessary.
|
||||||
fn evaluation_probe(
|
fn evaluation_probe(
|
||||||
&mut self,
|
&mut self,
|
||||||
op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
|
op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
|
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
|
||||||
let outer_universe = self.infcx.universe();
|
let mut outer_universe = self.infcx.universe();
|
||||||
let result = op(self)?;
|
let result = op(self, &mut outer_universe)?;
|
||||||
|
|
||||||
match self.infcx.leak_check(outer_universe, Some(snapshot)) {
|
match self.infcx.leak_check(outer_universe, Some(snapshot)) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
|
@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the predicates in `predicates` recursively. Note that
|
/// Evaluates the predicates in `predicates` recursively. This may
|
||||||
/// this applies projections in the predicates, and therefore
|
/// guide inference. If this is not desired, run it inside of a
|
||||||
/// is run within an inference probe.
|
/// is run within an inference probe.
|
||||||
|
/// `probe`.
|
||||||
#[instrument(skip(self, stack), level = "debug")]
|
#[instrument(skip(self, stack), level = "debug")]
|
||||||
fn evaluate_predicates_recursively<'o, I>(
|
fn evaluate_predicates_recursively<'o, I>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.candidate_from_obligation(stack) {
|
match self.candidate_from_obligation(stack) {
|
||||||
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes),
|
||||||
Ok(None) => Ok(EvaluatedToAmbig),
|
Ok(None) => Ok(EvaluatedToAmbig),
|
||||||
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
|
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
|
||||||
Err(..) => Ok(EvaluatedToErr),
|
Err(..) => Ok(EvaluatedToErr),
|
||||||
|
@ -1219,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
/// Further evaluates `candidate` to decide whether all type parameters match and whether nested
|
/// Further evaluates `candidate` to decide whether all type parameters match and whether nested
|
||||||
/// obligations are met. Returns whether `candidate` remains viable after this further
|
/// obligations are met. Returns whether `candidate` remains viable after this further
|
||||||
/// scrutiny.
|
/// scrutiny.
|
||||||
|
///
|
||||||
|
/// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal
|
||||||
|
/// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for
|
||||||
|
/// more info.
|
||||||
#[instrument(
|
#[instrument(
|
||||||
level = "debug",
|
level = "debug",
|
||||||
skip(self, stack),
|
skip(self, stack),
|
||||||
|
@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
stack: &TraitObligationStack<'o, 'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
candidate: &SelectionCandidate<'tcx>,
|
candidate: &SelectionCandidate<'tcx>,
|
||||||
|
leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
let mut result = self.evaluation_probe(|this| {
|
let mut result = self.evaluation_probe(|this, outer_universe| {
|
||||||
let candidate = (*candidate).clone();
|
// We eagerly instantiate higher ranked goals to prevent universe errors
|
||||||
match this.confirm_candidate(stack.obligation, candidate) {
|
// from impacting candidate selection. This matches the behavior of the new
|
||||||
|
// solver. This slightly weakens type inference.
|
||||||
|
//
|
||||||
|
// In case there are no unresolved type or const variables this
|
||||||
|
// should still not be necessary to select a unique impl as any overlap
|
||||||
|
// relying on a universe error from higher ranked goals should have resulted
|
||||||
|
// in an overlap error in coherence.
|
||||||
|
let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
|
||||||
|
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
|
||||||
|
match leak_check_higher_ranked_goal {
|
||||||
|
LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(),
|
||||||
|
LeakCheckHigherRankedGoal::Yes => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match this.confirm_candidate(&obligation, candidate.clone()) {
|
||||||
Ok(selection) => {
|
Ok(selection) => {
|
||||||
debug!(?selection);
|
debug!(?selection);
|
||||||
this.evaluate_predicates_recursively(
|
this.evaluate_predicates_recursively(
|
||||||
|
@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
stack: &TraitObligationStack<'o, 'tcx>,
|
stack: &TraitObligationStack<'o, 'tcx>,
|
||||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
|
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
self.evaluation_probe(|this| {
|
self.evaluation_probe(|this, outer_universe| {
|
||||||
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
// Eagerly instantiate higher ranked goals.
|
||||||
|
//
|
||||||
|
// See the comment in `evaluate_candidate` to see why.
|
||||||
|
let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate);
|
||||||
|
let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p));
|
||||||
|
*outer_universe = self.infcx.universe();
|
||||||
|
match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) {
|
||||||
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
|
Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
|
||||||
Err(()) => Ok(EvaluatedToErr),
|
Err(()) => Ok(EvaluatedToErr),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1132,7 +1132,6 @@
|
||||||
"ui/generics/issue-98432.rs",
|
"ui/generics/issue-98432.rs",
|
||||||
"ui/higher-ranked/trait-bounds/issue-100689.rs",
|
"ui/higher-ranked/trait-bounds/issue-100689.rs",
|
||||||
"ui/higher-ranked/trait-bounds/issue-102899.rs",
|
"ui/higher-ranked/trait-bounds/issue-102899.rs",
|
||||||
"ui/higher-ranked/trait-bounds/issue-30786.rs",
|
|
||||||
"ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs",
|
"ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs",
|
||||||
"ui/higher-ranked/trait-bounds/issue-39292.rs",
|
"ui/higher-ranked/trait-bounds/issue-39292.rs",
|
||||||
"ui/higher-ranked/trait-bounds/issue-42114.rs",
|
"ui/higher-ranked/trait-bounds/issue-42114.rs",
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// cc #119820
|
||||||
|
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
impl<T: Trait> Trait for &T {}
|
||||||
|
impl Trait for u32 {}
|
||||||
|
|
||||||
|
fn hr_bound<T>()
|
||||||
|
where
|
||||||
|
for<'a> &'a T: Trait,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T>()
|
||||||
|
where
|
||||||
|
T: Trait,
|
||||||
|
for<'a> &'a &'a T: Trait,
|
||||||
|
{
|
||||||
|
// We get a universe error when using the `param_env` candidate
|
||||||
|
// but are able to successfully use the impl candidate. Without
|
||||||
|
// the leak check both candidates may apply and we prefer the
|
||||||
|
// `param_env` candidate in winnowing.
|
||||||
|
hr_bound::<&T>();
|
||||||
|
//~^ ERROR the parameter type `T` may not live long enough
|
||||||
|
//~| ERROR implementation of `Trait` is not general enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,26 @@
|
||||||
|
error[E0310]: the parameter type `T` may not live long enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-1.rs:23:5
|
||||||
|
|
|
||||||
|
LL | hr_bound::<&T>();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| the parameter type `T` must be valid for the static lifetime...
|
||||||
|
| ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
|
||||||
|
help: consider adding an explicit lifetime bound
|
||||||
|
|
|
||||||
|
LL | T: Trait + 'static,
|
||||||
|
| +++++++++
|
||||||
|
|
||||||
|
error: implementation of `Trait` is not general enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-1.rs:23:5
|
||||||
|
|
|
||||||
|
LL | hr_bound::<&T>();
|
||||||
|
| ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
|
||||||
|
|
|
||||||
|
= note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`...
|
||||||
|
= note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0310`.
|
|
@ -0,0 +1,25 @@
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
|
||||||
|
|
|
||||||
|
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
LL | impl_hr::<T>();
|
||||||
|
| ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
|
||||||
|
|
|
||||||
|
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: implementation of `Trait` is not general enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
|
||||||
|
|
|
||||||
|
LL | impl_hr::<T>();
|
||||||
|
| ^^^^^^^^^^^^ implementation of `Trait` is not general enough
|
||||||
|
|
|
||||||
|
= note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`...
|
||||||
|
= note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
|
||||||
|
|
|
||||||
|
LL | impl_hr::<T>();
|
||||||
|
| ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
|
||||||
|
|
|
||||||
|
note: required by a bound in `impl_hr`
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
|
||||||
|
|
|
||||||
|
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr`
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() {
|
||||||
|
| +++++++++++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
|
@ -0,0 +1,26 @@
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
|
||||||
|
|
|
||||||
|
LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
LL | impl_hr::<T>();
|
||||||
|
| ^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:11:19
|
||||||
|
|
|
||||||
|
LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/candidate-from-env-universe-err-2.rs:14:5
|
||||||
|
|
|
||||||
|
LL | impl_hr::<T>();
|
||||||
|
| ^^^^^^^^^^^^ one type is more general than the other
|
||||||
|
|
|
||||||
|
= note: expected trait `for<'a> Trait<'a, '_>`
|
||||||
|
found trait `for<'b> Trait<'_, 'b>`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,20 @@
|
||||||
|
//@ revisions: current next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// cc #119820
|
||||||
|
|
||||||
|
trait Trait<'a, 'b> {}
|
||||||
|
|
||||||
|
trait OtherTrait<'b> {}
|
||||||
|
impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {}
|
||||||
|
|
||||||
|
fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {}
|
||||||
|
|
||||||
|
fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() {
|
||||||
|
impl_hr::<T>();
|
||||||
|
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
|
||||||
|
//[current]~^^ERROR lifetime may not live long enough
|
||||||
|
//[current]~| ERROR implementation of `Trait` is not general enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,54 @@
|
||||||
|
error: implementation of `Trait` is not general enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:28:5
|
||||||
|
|
|
||||||
|
LL | trait_bound::<T>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
|
||||||
|
|
|
||||||
|
= note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
|
||||||
|
= note: ...but it actually implements `Trait<'static>`
|
||||||
|
|
||||||
|
error: implementation of `Trait` is not general enough
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:39:5
|
||||||
|
|
|
||||||
|
LL | projection_bound::<T>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
|
||||||
|
|
|
||||||
|
= note: `T` must implement `Trait<'0>`, for any lifetime `'0`...
|
||||||
|
= note: ...but it actually implements `Trait<'static>`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:39:5
|
||||||
|
|
|
||||||
|
LL | projection_bound::<T>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||||
|
|
|
||||||
|
= note: expected associated type `<T as Trait<'static>>::Assoc`
|
||||||
|
found associated type `<T as Trait<'a>>::Assoc`
|
||||||
|
note: the lifetime requirement is introduced here
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
|
||||||
|
|
|
||||||
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:55:30
|
||||||
|
|
|
||||||
|
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||||
|
|
|
||||||
|
= note: expected associated type `<T as Trait<'static>>::Assoc`
|
||||||
|
found associated type `<T as Trait<'a>>::Assoc`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:55:30
|
||||||
|
|
|
||||||
|
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||||
|
|
|
||||||
|
= note: expected associated type `<T as Trait<'static>>::Assoc`
|
||||||
|
found associated type `<T as Trait<'a>>::Assoc`
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -0,0 +1,67 @@
|
||||||
|
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:28:19
|
||||||
|
|
|
||||||
|
LL | trait_bound::<T>();
|
||||||
|
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
|
||||||
|
|
|
||||||
|
note: required by a bound in `trait_bound`
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:17:19
|
||||||
|
|
|
||||||
|
LL | fn trait_bound<T: for<'a> Trait<'a>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound`
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | fn function1<T: Trait<'static> + for<'a> Trait<'a>>() {
|
||||||
|
| +++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:39:24
|
||||||
|
|
|
||||||
|
LL | projection_bound::<T>();
|
||||||
|
| ^ the trait `for<'a> Trait<'a>` is not implemented for `T`
|
||||||
|
|
|
||||||
|
note: required by a bound in `projection_bound`
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:18:24
|
||||||
|
|
|
||||||
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
|
||||||
|
help: consider further restricting this bound
|
||||||
|
|
|
||||||
|
LL | fn function2<T: Trait<'static, Assoc = usize> + for<'a> Trait<'a>>() {
|
||||||
|
| +++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:39:24
|
||||||
|
|
|
||||||
|
LL | projection_bound::<T>();
|
||||||
|
| ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
|
||||||
|
|
|
||||||
|
note: types differ
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:14:18
|
||||||
|
|
|
||||||
|
LL | type Assoc = usize;
|
||||||
|
| ^^^^^
|
||||||
|
note: required by a bound in `projection_bound`
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:18:42
|
||||||
|
|
|
||||||
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
|
||||||
|
| ^^^^^^^^^^^^^ required by this bound in `projection_bound`
|
||||||
|
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:55:30
|
||||||
|
|
|
||||||
|
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/candidate-from-env-universe-err-project.rs:55:30
|
||||||
|
|
|
||||||
|
LL | let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0271, E0277.
|
||||||
|
For more information about an error, try `rustc --explain E0271`.
|
|
@ -0,0 +1,62 @@
|
||||||
|
//@ revisions: next current
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// cc #119820 the previous behavior here was inconsistent as we discarded
|
||||||
|
// the where-bound candidate for trait goals due to the leak check, but did
|
||||||
|
// not do so for projection candidates and during normalization.
|
||||||
|
//
|
||||||
|
// This results in an inconsistency between `Trait` and `Projection` goals as
|
||||||
|
// normalizing always constraints the normalized-to term.
|
||||||
|
trait Trait<'a> {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl<'a, T> Trait<'a> for T {
|
||||||
|
type Assoc = usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_bound<T: for<'a> Trait<'a>>() {}
|
||||||
|
fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
|
||||||
|
|
||||||
|
// We use a function with a trivial where-bound which is more
|
||||||
|
// restrictive than the impl.
|
||||||
|
fn function1<T: Trait<'static>>() {
|
||||||
|
// err
|
||||||
|
//
|
||||||
|
// Proving `for<'a> T: Trait<'a>` using the where-bound does not
|
||||||
|
// result in a leak check failure even though it does not apply.
|
||||||
|
// We prefer env candidates over impl candidatescausing this to succeed.
|
||||||
|
trait_bound::<T>();
|
||||||
|
//[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
|
||||||
|
//[current]~^^ ERROR implementation of `Trait` is not general enough
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function2<T: Trait<'static, Assoc = usize>>() {
|
||||||
|
// err
|
||||||
|
//
|
||||||
|
// Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>`
|
||||||
|
// does not use the leak check when trying the where-bound, causing us
|
||||||
|
// to prefer it over the impl, resulting in a placeholder error.
|
||||||
|
projection_bound::<T>();
|
||||||
|
//[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
|
||||||
|
//[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
|
||||||
|
//[current]~^^^ ERROR implementation of `Trait` is not general enough
|
||||||
|
//[current]~| ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function3<T: Trait<'static, Assoc = usize>>() {
|
||||||
|
// err
|
||||||
|
//
|
||||||
|
// Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
|
||||||
|
// only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
|
||||||
|
// instantiated, causing us to prefer the where-bound over the impl
|
||||||
|
// resulting in a placeholder error. Even if were were to also use the
|
||||||
|
// leak check during candidate selection for normalization, this
|
||||||
|
// case would still not compile.
|
||||||
|
let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
|
||||||
|
//[next]~^ ERROR higher-ranked subtype error
|
||||||
|
//[next]~| ERROR higher-ranked subtype error
|
||||||
|
//[current]~^^^ ERROR mismatched types
|
||||||
|
//[current]~| ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:16:5
|
||||||
|
|
|
||||||
|
LL | impls_trait::<(), _>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
||||||
|
|
|
||||||
|
note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:9:1
|
||||||
|
|
|
||||||
|
LL | impl<'a> Trait<&'a str, &'a str> for () {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | impl<'a> Trait<&'a str, String> for () {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: required by a bound in `impls_trait`
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:13:19
|
||||||
|
|
|
||||||
|
LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:16:5
|
||||||
|
|
|
||||||
|
LL | impls_trait::<(), _>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait`
|
||||||
|
|
|
||||||
|
note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:9:1
|
||||||
|
|
|
||||||
|
LL | impl<'a> Trait<&'a str, &'a str> for () {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL |
|
||||||
|
LL | impl<'a> Trait<&'a str, String> for () {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: required by a bound in `impls_trait`
|
||||||
|
--> $DIR/leak-check-in-selection-2.rs:13:19
|
||||||
|
|
|
||||||
|
LL | fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
|
@ -0,0 +1,18 @@
|
||||||
|
//@ revisions: old next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// cc #119820
|
||||||
|
|
||||||
|
trait Trait<T, U> {}
|
||||||
|
|
||||||
|
// using this impl results in a higher-ranked region error.
|
||||||
|
impl<'a> Trait<&'a str, &'a str> for () {}
|
||||||
|
|
||||||
|
impl<'a> Trait<&'a str, String> for () {}
|
||||||
|
|
||||||
|
fn impls_trait<T: for<'a> Trait<&'a str, U>, U>() {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
impls_trait::<(), _>();
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:18:5
|
||||||
|
|
|
||||||
|
LL | impls_leak::<Box<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
|
||||||
|
|
|
||||||
|
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:9:1
|
||||||
|
|
|
||||||
|
LL | impl Leak<'_> for Box<u32> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | impl Leak<'static> for Box<u16> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: required by a bound in `impls_leak`
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:12:18
|
||||||
|
|
|
||||||
|
LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
|
||||||
|
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:35:5
|
||||||
|
|
|
||||||
|
LL | impls_indirect_leak::<Box<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
|
||||||
|
|
|
||||||
|
= note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>`
|
||||||
|
note: required by a bound in `impls_indirect_leak`
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:25:27
|
||||||
|
|
|
||||||
|
LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
|
@ -0,0 +1,48 @@
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:18:5
|
||||||
|
|
|
||||||
|
LL | impls_leak::<Box<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak`
|
||||||
|
|
|
||||||
|
note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:9:1
|
||||||
|
|
|
||||||
|
LL | impl Leak<'_> for Box<u32> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | impl Leak<'static> for Box<u16> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: required by a bound in `impls_leak`
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:12:18
|
||||||
|
|
|
||||||
|
LL | fn impls_leak<T: for<'a> Leak<'a>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak`
|
||||||
|
|
||||||
|
error[E0283]: type annotations needed
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:35:5
|
||||||
|
|
|
||||||
|
LL | impls_indirect_leak::<Box<_>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak`
|
||||||
|
|
|
||||||
|
note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:9:1
|
||||||
|
|
|
||||||
|
LL | impl Leak<'_> for Box<u32> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | impl Leak<'static> for Box<u16> {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>`
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:23:23
|
||||||
|
|
|
||||||
|
LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
|
||||||
|
| -------- ^^^^^^^^^^^^^^^^ ^
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
note: required by a bound in `impls_indirect_leak`
|
||||||
|
--> $DIR/leak-check-in-selection-3.rs:25:27
|
||||||
|
|
|
||||||
|
LL | fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0283`.
|
|
@ -0,0 +1,39 @@
|
||||||
|
//@ revisions: old next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
// cc #119820, the previous behavior here was inconsistent,
|
||||||
|
// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>`
|
||||||
|
// but not for `for<'a> Box<_>: IndirectLeak<'a>`
|
||||||
|
|
||||||
|
trait Leak<'a> {}
|
||||||
|
impl Leak<'_> for Box<u32> {}
|
||||||
|
impl Leak<'static> for Box<u16> {}
|
||||||
|
|
||||||
|
fn impls_leak<T: for<'a> Leak<'a>>() {}
|
||||||
|
fn direct() {
|
||||||
|
// ok
|
||||||
|
//
|
||||||
|
// The `Box<u16>` impls fails the leak check,
|
||||||
|
// meaning that we apply the `Box<u32>` impl.
|
||||||
|
impls_leak::<Box<_>>();
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
trait IndirectLeak<'a> {}
|
||||||
|
impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {}
|
||||||
|
|
||||||
|
fn impls_indirect_leak<T: for<'a> IndirectLeak<'a>>() {}
|
||||||
|
fn indirect() {
|
||||||
|
// error: type annotations needed
|
||||||
|
//
|
||||||
|
// While the `Box<u16>` impl would fail the leak check
|
||||||
|
// we have already instantiated the binder while applying
|
||||||
|
// the generic `IndirectLeak` impl, so during candidate
|
||||||
|
// selection of `Leak` we do not detect the placeholder error.
|
||||||
|
// Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous,
|
||||||
|
// resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous.
|
||||||
|
impls_indirect_leak::<Box<_>>();
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,29 @@
|
||||||
|
//@ revisions: old next
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// cc #119820. While the leak check does not consider the binder
|
||||||
|
// of the current goal, leaks from higher-ranked nested goals are
|
||||||
|
// considered.
|
||||||
|
//
|
||||||
|
// We enter and exit the binder of the nested goal while evaluating
|
||||||
|
// the candidate.
|
||||||
|
|
||||||
|
trait LeakCheckFailure<'a> {}
|
||||||
|
impl LeakCheckFailure<'static> for () {}
|
||||||
|
|
||||||
|
trait Trait<T> {}
|
||||||
|
impl Trait<u32> for () where for<'a> (): LeakCheckFailure<'a> {}
|
||||||
|
impl Trait<u16> for () {}
|
||||||
|
fn impls_trait<T: Trait<U>, U>() {}
|
||||||
|
fn main() {
|
||||||
|
// ok
|
||||||
|
//
|
||||||
|
// It does not matter whether candidate assembly
|
||||||
|
// considers the placeholders from higher-ranked goal.
|
||||||
|
//
|
||||||
|
// Either `for<'a> (): LeakCheckFailure<'a>` has no applicable
|
||||||
|
// candidate or it has a single applicable candidate which then later
|
||||||
|
// results in an error. This allows us to infer `U` to `u16`.
|
||||||
|
impls_trait::<(), _>()
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
||||||
|
|
||||||
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
|
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T>`
|
||||||
// should act as assertion that item does not borrow from its stream;
|
// should act as assertion that item does not borrow from its stream;
|
||||||
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
|
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
|
||||||
// have such an item.
|
// have such an item.
|
||||||
|
@ -97,10 +97,6 @@ where
|
||||||
|
|
||||||
impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
|
|
||||||
fn identity<T>(x: &T) -> &T {
|
|
||||||
x
|
|
||||||
}
|
|
||||||
|
|
||||||
fn variant1() {
|
fn variant1() {
|
||||||
let source = Repeat(10);
|
let source = Repeat(10);
|
||||||
|
|
||||||
|
@ -118,19 +114,7 @@ fn variant1() {
|
||||||
// guess.
|
// guess.
|
||||||
let map = source.mapx(|x: &_| x);
|
let map = source.mapx(|x: &_| x);
|
||||||
let filter = map.filterx(|x: &_| true);
|
let filter = map.filterx(|x: &_| true);
|
||||||
//~^ ERROR the method
|
//~^ ERROR the method `filterx` exists for struct
|
||||||
}
|
|
||||||
|
|
||||||
fn variant2() {
|
|
||||||
let source = Repeat(10);
|
|
||||||
|
|
||||||
// Here, we use a function, which is not subject to the vagaries
|
|
||||||
// of closure signature inference. In this case, we get the error
|
|
||||||
// on `countx` as, I think, the test originally expected.
|
|
||||||
let map = source.mapx(identity);
|
|
||||||
let filter = map.filterx(|x: &_| true);
|
|
||||||
let count = filter.countx();
|
|
||||||
//~^ ERROR the method
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@hrtb-doesnt-borrow-self-1.rs:115:27}>`, but its trait bounds were not satisfied
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-1.rs:116:22
|
||||||
|
|
|
||||||
|
LL | pub struct Map<S, F> {
|
||||||
|
| -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
|
||||||
|
...
|
||||||
|
LL | let filter = map.filterx(|x: &_| true);
|
||||||
|
| ^^^^^^^ method cannot be called due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
note: the following trait bounds were not satisfied:
|
||||||
|
`&'a mut &Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
|
||||||
|
`&'a mut &mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
|
||||||
|
`&'a mut Map<Repeat, {closure@$DIR/hrtb-doesnt-borrow-self-1.rs:115:27: 115:34}>: Stream`
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-1.rs:98:50
|
||||||
|
|
|
||||||
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
|
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-1.rs:66:1
|
||||||
|
|
|
||||||
|
LL | pub trait StreamExt
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
116
tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
Normal file
116
tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
|
||||||
|
|
||||||
|
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
|
||||||
|
// should act as assertion that item does not borrow from its stream;
|
||||||
|
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
|
||||||
|
// have such an item.
|
||||||
|
//
|
||||||
|
// This tests double-checks that we do not allow such behavior to leak
|
||||||
|
// through again.
|
||||||
|
|
||||||
|
pub trait Stream {
|
||||||
|
type Item;
|
||||||
|
fn next(self) -> Option<Self::Item>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example stream
|
||||||
|
pub struct Repeat(u64);
|
||||||
|
|
||||||
|
impl<'a> Stream for &'a mut Repeat {
|
||||||
|
type Item = &'a u64;
|
||||||
|
fn next(self) -> Option<Self::Item> {
|
||||||
|
Some(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Map<S, F> {
|
||||||
|
stream: S,
|
||||||
|
func: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A, F, T> Stream for &'a mut Map<A, F>
|
||||||
|
where
|
||||||
|
&'a mut A: Stream,
|
||||||
|
F: FnMut(<&'a mut A as Stream>::Item) -> T,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
fn next(self) -> Option<T> {
|
||||||
|
match self.stream.next() {
|
||||||
|
Some(item) => Some((self.func)(item)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Filter<S, F> {
|
||||||
|
stream: S,
|
||||||
|
func: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
|
||||||
|
where
|
||||||
|
for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
|
||||||
|
F: FnMut(&T) -> bool,
|
||||||
|
{
|
||||||
|
type Item = <&'a mut A as Stream>::Item;
|
||||||
|
fn next(self) -> Option<Self::Item> {
|
||||||
|
while let Some(item) = self.stream.next() {
|
||||||
|
if (self.func)(&item) {
|
||||||
|
return Some(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait StreamExt
|
||||||
|
where
|
||||||
|
for<'b> &'b mut Self: Stream,
|
||||||
|
{
|
||||||
|
fn mapx<F>(self, func: F) -> Map<Self, F>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
for<'a> &'a mut Map<Self, F>: Stream,
|
||||||
|
{
|
||||||
|
Map { func: func, stream: self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filterx<F>(self, func: F) -> Filter<Self, F>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
for<'a> &'a mut Filter<Self, F>: Stream,
|
||||||
|
{
|
||||||
|
Filter { func: func, stream: self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn countx(mut self) -> usize
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let mut count = 0;
|
||||||
|
while let Some(_) = self.next() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
|
|
||||||
|
fn identity<T>(x: &T) -> &T {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn variant2() {
|
||||||
|
let source = Repeat(10);
|
||||||
|
|
||||||
|
// Here, we use a function, which is not subject to the vagaries
|
||||||
|
// of closure signature inference. In this case, we get the error
|
||||||
|
// on `countx` as, I think, the test originally expected.
|
||||||
|
let map = source.mapx(identity);
|
||||||
|
let filter = map.filterx(|x: &_| true);
|
||||||
|
let count = filter.countx();
|
||||||
|
//~^ ERROR the method
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,27 @@
|
||||||
|
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@hrtb-doesnt-borrow-self-2.rs:111:30}>`, but its trait bounds were not satisfied
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24
|
||||||
|
|
|
||||||
|
LL | pub struct Filter<S, F> {
|
||||||
|
| ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
|
||||||
|
...
|
||||||
|
LL | let count = filter.countx();
|
||||||
|
| ^^^^^^ method cannot be called due to unsatisfied trait bounds
|
||||||
|
|
|
||||||
|
note: the following trait bounds were not satisfied:
|
||||||
|
`&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
|
||||||
|
`&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
|
||||||
|
`&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream`
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50
|
||||||
|
|
|
||||||
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
||||||
|
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `StreamExt` defines an item `countx`, perhaps you need to implement it
|
||||||
|
--> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1
|
||||||
|
|
|
||||||
|
LL | pub trait StreamExt
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
|
@ -1,23 +1,11 @@
|
||||||
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
|
error: implementation of `Bar` is not general enough
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
|
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
|
||||||
|
|
|
|
||||||
LL | want_bar_for_any_ccx(b);
|
LL | want_bar_for_any_ccx(b);
|
||||||
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
||||||
| |
|
|
||||||
| required by a bound introduced by this call
|
|
||||||
|
|
|
|
||||||
note: required by a bound in `want_bar_for_any_ccx`
|
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
|
= note: ...but it actually implements `Bar<'static>`
|
||||||
|
|
|
||||||
LL | fn want_bar_for_any_ccx<B>(b: &B)
|
|
||||||
| -------------------- required by a bound in this function
|
|
||||||
LL | where B : for<'ccx> Bar<'ccx>
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
|
|
||||||
help: consider further restricting this bound
|
|
||||||
|
|
|
||||||
LL | where B : Qux + for<'ccx> Bar<'ccx>
|
|
||||||
| +++++++++++++++++++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
|
||||||
|
|
|
@ -1,43 +1,37 @@
|
||||||
// Test a trait (`Bar`) with a higher-ranked supertrait.
|
// Test a trait (`Bar`) with a higher-ranked supertrait.
|
||||||
|
#![allow(unconditional_recursion)]
|
||||||
|
|
||||||
trait Foo<'tcx>
|
trait Foo<'tcx> {
|
||||||
{
|
|
||||||
fn foo(&'tcx self) -> &'tcx isize;
|
fn foo(&'tcx self) -> &'tcx isize;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Bar<'ccx>
|
trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
|
||||||
: for<'tcx> Foo<'tcx>
|
|
||||||
{
|
|
||||||
fn bar(&'ccx self) -> &'ccx isize;
|
fn bar(&'ccx self) -> &'ccx isize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn want_foo_for_some_tcx<'x,F>(f: &'x F)
|
fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
|
||||||
where F : Foo<'x>
|
|
||||||
{
|
|
||||||
want_foo_for_some_tcx(f);
|
want_foo_for_some_tcx(f);
|
||||||
want_foo_for_any_tcx(f); //~ ERROR not satisfied
|
want_foo_for_any_tcx(f);
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
//~| ERROR implementation of `Foo` is not general enough
|
||||||
}
|
}
|
||||||
|
|
||||||
fn want_foo_for_any_tcx<F>(f: &F) //~ WARN cannot return without recursing
|
fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
|
||||||
where F : for<'tcx> Foo<'tcx>
|
|
||||||
{
|
|
||||||
want_foo_for_some_tcx(f);
|
want_foo_for_some_tcx(f);
|
||||||
want_foo_for_any_tcx(f);
|
want_foo_for_any_tcx(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn want_bar_for_some_ccx<'x,B>(b: &B)
|
fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
|
||||||
where B : Bar<'x>
|
|
||||||
{
|
|
||||||
want_foo_for_some_tcx(b);
|
want_foo_for_some_tcx(b);
|
||||||
want_foo_for_any_tcx(b);
|
want_foo_for_any_tcx(b);
|
||||||
|
|
||||||
want_bar_for_some_ccx(b);
|
want_bar_for_some_ccx(b);
|
||||||
want_bar_for_any_ccx(b); //~ ERROR not satisfied
|
want_bar_for_any_ccx(b);
|
||||||
|
//~^ ERROR lifetime may not live long enough
|
||||||
|
//~| ERROR implementation of `Bar` is not general enough
|
||||||
}
|
}
|
||||||
|
|
||||||
fn want_bar_for_any_ccx<B>(b: &B) //~ WARN cannot return without recursing
|
fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
|
||||||
where B : for<'ccx> Bar<'ccx>
|
|
||||||
{
|
|
||||||
want_foo_for_some_tcx(b);
|
want_foo_for_some_tcx(b);
|
||||||
want_foo_for_any_tcx(b);
|
want_foo_for_any_tcx(b);
|
||||||
|
|
||||||
|
|
|
@ -1,68 +1,50 @@
|
||||||
error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
|
error: lifetime may not live long enough
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
|
||||||
|
|
|
||||||
|
LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) {
|
||||||
|
| -- lifetime `'x` defined here
|
||||||
|
LL | want_foo_for_some_tcx(f);
|
||||||
|
LL | want_foo_for_any_tcx(f);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:19:28
|
||||||
|
|
|
||||||
|
LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: implementation of `Foo` is not general enough
|
||||||
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
|
||||||
|
|
|
|
||||||
LL | want_foo_for_any_tcx(f);
|
LL | want_foo_for_any_tcx(f);
|
||||||
| -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
||||||
| |
|
|
||||||
| required by a bound introduced by this call
|
|
||||||
|
|
|
|
||||||
note: required by a bound in `want_foo_for_any_tcx`
|
= note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
|
= note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`
|
||||||
|
|
|
||||||
LL | fn want_foo_for_any_tcx<F>(f: &F)
|
|
||||||
| -------------------- required by a bound in this function
|
|
||||||
LL | where F : for<'tcx> Foo<'tcx>
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
|
|
||||||
help: consider further restricting this bound
|
|
||||||
|
|
|
||||||
LL | where F : Foo<'x> + for<'tcx> Foo<'tcx>
|
|
||||||
| +++++++++++++++++++++
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
|
error: lifetime may not live long enough
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
|
||||||
|
|
|
||||||
|
LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
|
||||||
|
| -- lifetime `'x` defined here
|
||||||
|
...
|
||||||
|
LL | want_bar_for_any_ccx(b);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:34:28
|
||||||
|
|
|
||||||
|
LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: implementation of `Bar` is not general enough
|
||||||
|
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
|
||||||
|
|
|
|
||||||
LL | want_bar_for_any_ccx(b);
|
LL | want_bar_for_any_ccx(b);
|
||||||
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
||||||
| |
|
|
||||||
| required by a bound introduced by this call
|
|
||||||
|
|
|
|
||||||
note: required by a bound in `want_bar_for_any_ccx`
|
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
|
= note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`
|
||||||
|
|
|
||||||
LL | fn want_bar_for_any_ccx<B>(b: &B)
|
|
||||||
| -------------------- required by a bound in this function
|
|
||||||
LL | where B : for<'ccx> Bar<'ccx>
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
|
|
||||||
help: consider further restricting this bound
|
|
||||||
|
|
|
||||||
LL | where B : Bar<'x> + for<'ccx> Bar<'ccx>
|
|
||||||
| +++++++++++++++++++++
|
|
||||||
|
|
||||||
warning: function cannot return without recursing
|
error: aborting due to 4 previous errors
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
|
|
||||||
|
|
|
||||||
LL | / fn want_foo_for_any_tcx<F>(f: &F)
|
|
||||||
LL | | where F : for<'tcx> Foo<'tcx>
|
|
||||||
| |_________________________________^ cannot return without recursing
|
|
||||||
...
|
|
||||||
LL | want_foo_for_any_tcx(f);
|
|
||||||
| ----------------------- recursive call site
|
|
||||||
|
|
|
||||||
= help: a `loop` may express intention better if this is on purpose
|
|
||||||
= note: `#[warn(unconditional_recursion)]` on by default
|
|
||||||
|
|
||||||
warning: function cannot return without recursing
|
|
||||||
--> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
|
|
||||||
|
|
|
||||||
LL | / fn want_bar_for_any_ccx<B>(b: &B)
|
|
||||||
LL | | where B : for<'ccx> Bar<'ccx>
|
|
||||||
| |_________________________________^ cannot return without recursing
|
|
||||||
...
|
|
||||||
LL | want_bar_for_any_ccx(b);
|
|
||||||
| ----------------------- recursive call site
|
|
||||||
|
|
|
||||||
= help: a `loop` may express intention better if this is on purpose
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors; 2 warnings emitted
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@issue-30786.rs:119:27}>`, but its trait bounds were not satisfied
|
|
||||||
--> $DIR/issue-30786.rs:120:22
|
|
||||||
|
|
|
||||||
LL | pub struct Map<S, F> {
|
|
||||||
| -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt`
|
|
||||||
...
|
|
||||||
LL | let filter = map.filterx(|x: &_| true);
|
|
||||||
| ^^^^^^^ method cannot be called on `Map<Repeat, {closure@issue-30786.rs:119:27}>` due to unsatisfied trait bounds
|
|
||||||
|
|
|
||||||
note: the following trait bounds were not satisfied:
|
|
||||||
`&'a mut &Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
|
|
||||||
`&'a mut &mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
|
|
||||||
`&'a mut Map<Repeat, {closure@$DIR/issue-30786.rs:119:27: 119:34}>: Stream`
|
|
||||||
--> $DIR/issue-30786.rs:98:50
|
|
||||||
|
|
|
||||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
|
||||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
|
||||||
note: `StreamExt` defines an item `filterx`, perhaps you need to implement it
|
|
||||||
--> $DIR/issue-30786.rs:66:1
|
|
||||||
|
|
|
||||||
LL | pub trait StreamExt
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied
|
|
||||||
--> $DIR/issue-30786.rs:132:24
|
|
||||||
|
|
|
||||||
LL | pub struct Filter<S, F> {
|
|
||||||
| ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt`
|
|
||||||
...
|
|
||||||
LL | let count = filter.countx();
|
|
||||||
| ^^^^^^ method cannot be called due to unsatisfied trait bounds
|
|
||||||
|
|
|
||||||
note: the following trait bounds were not satisfied:
|
|
||||||
`&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
|
|
||||||
`&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
|
|
||||||
`&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream`
|
|
||||||
--> $DIR/issue-30786.rs:98:50
|
|
||||||
|
|
|
||||||
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
|
|
||||||
| --------- - ^^^^^^ unsatisfied trait bound introduced here
|
|
||||||
= help: items from traits can only be used if the trait is implemented and in scope
|
|
||||||
note: `StreamExt` defines an item `countx`, perhaps you need to implement it
|
|
||||||
--> $DIR/issue-30786.rs:66:1
|
|
||||||
|
|
|
||||||
LL | pub trait StreamExt
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0599`.
|
|
|
@ -4,11 +4,8 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
|
fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
|
||||||
//~^ NOTE required by a bound in this
|
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
//~^ NOTE required by this bound in `real_dispatch`
|
|
||||||
//~| NOTE required by a bound in `real_dispatch`
|
|
||||||
{
|
{
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl
|
||||||
F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
|
F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
{
|
{
|
||||||
real_dispatch(f)
|
real_dispatch(f)
|
||||||
//~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
|
//~^ ERROR lifetime may not live long enough
|
||||||
//~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
|
//~| ERROR implementation of `FnOnce` is not general enough
|
||||||
//~| NOTE expected a closure with arguments
|
//~| ERROR mismatched types
|
||||||
//~| NOTE required by a bound introduced by this call
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,41 @@
|
||||||
error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
|
error: lifetime may not live long enough
|
||||||
--> $DIR/issue-100690.rs:37:23
|
--> $DIR/issue-100690.rs:34:9
|
||||||
|
|
|
||||||
|
LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle<T> {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | real_dispatch(f)
|
||||||
|
| ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
||||||
|
|
|
||||||
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||||
|
--> $DIR/issue-100690.rs:8:8
|
||||||
|
|
|
||||||
|
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: implementation of `FnOnce` is not general enough
|
||||||
|
--> $DIR/issue-100690.rs:34:9
|
||||||
|
|
|
|
||||||
LL | real_dispatch(f)
|
LL | real_dispatch(f)
|
||||||
| ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
|
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
||||||
| |
|
|
||||||
| required by a bound introduced by this call
|
|
||||||
|
|
|
|
||||||
= note: expected a closure with arguments `(&mut UIView<'a, _>,)`
|
= note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`...
|
||||||
found a closure with arguments `(&mut UIView<'_, _>,)`
|
= note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1`
|
||||||
note: required by a bound in `real_dispatch`
|
|
||||||
--> $DIR/issue-100690.rs:9:8
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-100690.rs:34:9
|
||||||
|
|
|
||||||
|
LL | real_dispatch(f)
|
||||||
|
| ^^^^^^^^^^^^^^^^ one type is more general than the other
|
||||||
|
|
|
||||||
|
= note: expected associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
|
||||||
|
found associated type `<F as FnOnce<(&mut UIView<'_, T>,)>>::Output`
|
||||||
|
note: the lifetime requirement is introduced here
|
||||||
|
--> $DIR/issue-100690.rs:8:34
|
||||||
|
|
|
|
||||||
LL | fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
|
|
||||||
| ------------- required by a bound in this function
|
|
||||||
...
|
|
||||||
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
LL | F: FnOnce(&mut UIView<T>) -> Result<(), io::Error> + Send + 'static,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch`
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue