Skip to content

instantiate higher ranked goals outside of candidate selection #119820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 62 additions & 14 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
mod candidate_assembly;
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)]
pub enum IntercrateAmbiguityCause<'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;

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;
break;
}
@@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// is needed for specialization. Propagate overflow if it occurs.
let mut candidates = candidates
.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(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
}
@@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
debug_assert!(!self.infcx.next_trait_solver());
self.evaluation_probe(|this| {
self.evaluation_probe(|this, _outer_universe| {
let goal =
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
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(
&mut self,
op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result<EvaluationResult, OverflowError>,
) -> Result<EvaluationResult, OverflowError> {
self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
let outer_universe = self.infcx.universe();
let result = op(self)?;
let mut outer_universe = self.infcx.universe();
let result = op(self, &mut outer_universe)?;

match self.infcx.leak_check(outer_universe, Some(snapshot)) {
Ok(()) => {}
@@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
})
}

/// Evaluates the predicates in `predicates` recursively. Note that
/// this applies projections in the predicates, and therefore
/// Evaluates the predicates in `predicates` recursively. This may
/// guide inference. If this is not desired, run it inside of a
/// is run within an inference probe.
/// `probe`.
#[instrument(skip(self, stack), level = "debug")]
fn evaluate_predicates_recursively<'o, I>(
&mut self,
@@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

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),
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
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
/// obligations are met. Returns whether `candidate` remains viable after this further
/// 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(
level = "debug",
skip(self, stack),
@@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
candidate: &SelectionCandidate<'tcx>,
leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal,
) -> Result<EvaluationResult, OverflowError> {
let mut result = self.evaluation_probe(|this| {
let candidate = (*candidate).clone();
match this.confirm_candidate(stack.obligation, candidate) {
let mut result = self.evaluation_probe(|this, outer_universe| {
// We eagerly instantiate higher ranked goals to prevent universe errors
// 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) => {
debug!(?selection);
this.evaluate_predicates_recursively(
@@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
stack: &TraitObligationStack<'o, 'tcx>,
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
self.evaluation_probe(|this| {
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
self.evaluation_probe(|this, outer_universe| {
// 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),
Err(()) => Ok(EvaluatedToErr),
}
1 change: 0 additions & 1 deletion src/tools/tidy/src/issues.txt
Original file line number Diff line number Diff line change
@@ -1129,7 +1129,6 @@
"ui/generics/issue-98432.rs",
"ui/higher-ranked/trait-bounds/issue-100689.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-39292.rs",
"ui/higher-ranked/trait-bounds/issue-42114.rs",
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
18 changes: 18 additions & 0 deletions tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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`.
39 changes: 39 additions & 0 deletions tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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::<(), _>()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@ 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;
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
// have such an item.
@@ -97,10 +97,6 @@ where

impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}

fn identity<T>(x: &T) -> &T {
x
}

fn variant1() {
let source = Repeat(10);

@@ -118,19 +114,7 @@ fn variant1() {
// guess.
let map = source.mapx(|x: &_| x);
let filter = map.filterx(|x: &_| true);
//~^ ERROR the method
}

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
//~^ ERROR the method `filterx` exists for struct
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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 changes: 116 additions & 0 deletions tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
error: implementation of `Bar` is not general enough
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
|
LL | want_bar_for_any_ccx(b);
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
note: required by a bound in `want_bar_for_any_ccx`
--> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
|
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>
| +++++++++++++++++++++
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Bar<'static>`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
// Test a trait (`Bar`) with a higher-ranked supertrait.
#![allow(unconditional_recursion)]

trait Foo<'tcx>
{
trait Foo<'tcx> {
fn foo(&'tcx self) -> &'tcx isize;
}

trait Bar<'ccx>
: for<'tcx> Foo<'tcx>
{
trait Bar<'ccx>: for<'tcx> Foo<'tcx> {
fn bar(&'ccx self) -> &'ccx isize;
}

fn want_foo_for_some_tcx<'x,F>(f: &'x F)
where F : Foo<'x>
{
fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x 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
where F : for<'tcx> Foo<'tcx>
{
fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
want_foo_for_some_tcx(f);
want_foo_for_any_tcx(f);
}

fn want_bar_for_some_ccx<'x,B>(b: &B)
where B : Bar<'x>
{
fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
want_foo_for_some_tcx(b);
want_foo_for_any_tcx(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
where B : for<'ccx> Bar<'ccx>
{
fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
want_foo_for_some_tcx(b);
want_foo_for_any_tcx(b);

Original file line number Diff line number Diff line change
@@ -1,68 +1,50 @@
error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
--> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
error: lifetime may not live long enough
--> $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);
| -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
|
note: required by a bound in `want_foo_for_any_tcx`
--> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
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>(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>
| +++++++++++++++++++++
LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) {
| ^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
|
LL | want_bar_for_any_ccx(b);
| -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
| |
| required by a bound introduced by this call
error: implementation of `Foo` is not general enough
--> $DIR/hrtb-higher-ranker-supertraits.rs:14:5
|
note: required by a bound in `want_bar_for_any_ccx`
--> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
|
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 | want_foo_for_any_tcx(f);
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
LL | where B : Bar<'x> + for<'ccx> Bar<'ccx>
| +++++++++++++++++++++
= note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`

warning: function cannot return without recursing
--> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
error: lifetime may not live long enough
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
|
LL | / fn want_foo_for_any_tcx<F>(f: &F)
LL | | where F : for<'tcx> Foo<'tcx>
| |_________________________________^ cannot return without recursing
LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) {
| -- lifetime `'x` defined here
...
LL | want_foo_for_any_tcx(f);
| ----------------------- recursive call site
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
|
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) {
| ^^^^^^^^^^^^^^^^^^^

warning: function cannot return without recursing
--> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
error: implementation of `Bar` is not general enough
--> $DIR/hrtb-higher-ranker-supertraits.rs:29:5
|
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
LL | want_bar_for_any_ccx(b);
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
|
= help: a `loop` may express intention better if this is on purpose
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`

error: aborting due to 2 previous errors; 2 warnings emitted
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0277`.
51 changes: 0 additions & 51 deletions tests/ui/higher-ranked/trait-bounds/issue-30786.stderr

This file was deleted.

11 changes: 4 additions & 7 deletions tests/ui/implied-bounds/issue-100690.rs
Original file line number Diff line number Diff line change
@@ -4,11 +4,8 @@
use std::io;

fn real_dispatch<T, F>(f: F) -> Result<(), io::Error>
//~^ NOTE required by a bound in this
where
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!()
}
@@ -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,
{
real_dispatch(f)
//~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
//~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
//~| NOTE expected a closure with arguments
//~| NOTE required by a bound introduced by this call
//~^ ERROR lifetime may not live long enough
//~| ERROR implementation of `FnOnce` is not general enough
//~| ERROR mismatched types
//
}
}

49 changes: 34 additions & 15 deletions tests/ui/implied-bounds/issue-100690.stderr
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F`
--> $DIR/issue-100690.rs:37:23
error: lifetime may not live long enough
--> $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)
| ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
|
= note: expected a closure with arguments `(&mut UIView<'a, _>,)`
found a closure with arguments `(&mut UIView<'_, _>,)`
note: required by a bound in `real_dispatch`
--> $DIR/issue-100690.rs:9:8
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)
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`...
= note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1`

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,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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`.