move leak check out of candidate evaluation

this prevents higher ranked goals from guiding selection
This commit is contained in:
lcnr 2024-04-03 22:27:13 +01:00 committed by Boxy
parent 98efd808e1
commit 4fa5fb684e
28 changed files with 872 additions and 200 deletions

View File

@ -60,6 +60,20 @@
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 @@ fn candidate_from_obligation_no_cache<'o>(
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 @@ fn candidate_from_obligation_no_cache<'o>(
// 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 @@ pub fn evaluate_root_obligation(
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 @@ pub fn evaluate_root_obligation(
})
}
/// 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 @@ fn evaluation_probe(
})
}
/// 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 @@ fn evaluate_stack<'o>(
}
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 @@ pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool
/// 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 @@ fn evaluate_candidate<'o>(
&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 @@ fn where_clause_may_apply<'o>(
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),
}

View File

@ -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() {}

View File

@ -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`.

View File

@ -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

View File

@ -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`.

View File

@ -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`.

View File

@ -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() {}

View File

@ -0,0 +1,54 @@
error: implementation of `Trait` is not general enough
--> $DIR/candidate-from-env-universe-err-project.rs:31: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:41: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:41: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:21:42
|
LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
| ^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/candidate-from-env-universe-err-project.rs:56: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:56: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`.

View File

@ -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:31: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:20: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:41: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:21: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:41: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:17:18
|
LL | type Assoc = usize;
| ^^^^^
note: required by a bound in `projection_bound`
--> $DIR/candidate-from-env-universe-err-project.rs:21: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:56: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:56: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`.

View File

@ -0,0 +1,61 @@
//@ 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.
//
// FIXME(-Znext-solver): We currently prefer the impl over the where-bound
// for trait goals because the impl does not result in any constraints.
//
// 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>>() {
// 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>();
//[current]~^ ERROR mismatched types
}
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`
//[current]~^^ ERROR mismatched types
//[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) = |_| ();
//[current]~^ ERROR mismatched types
//[current]~| ERROR mismatched types
}
fn main() {}

View File

@ -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`.

View File

@ -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`.

View File

@ -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
}

View File

@ -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`.

View File

@ -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`.

View File

@ -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() {}

View File

@ -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::<(), _>()
}

View File

@ -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`.

View File

@ -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);

View File

@ -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);
| ^^^^^^^^^^^^^^^^^^^^^^^ 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);
| -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
|
note: required by a bound in `want_foo_for_any_tcx`
--> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
|
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>
| +++++++++++++++++++++
= note: `F` must implement `Foo<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1`
error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
--> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
error: lifetime may not live long enough
--> $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);
| -------------------- ^ 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.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 | where B : Bar<'x> + for<'ccx> Bar<'ccx>
| +++++++++++++++++++++
= note: `B` must implement `Bar<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1`
warning: function cannot return without recursing
--> $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
error: aborting due to 4 previous errors
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`.

View File

@ -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 @@ fn countx(mut self) -> usize
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() {}

View File

@ -0,0 +1,27 @@
error[E0599]: the method `filterx` exists for struct `Map<Repeat, {closure@issue-30786-1.rs:115:27}>`, but its trait bounds were not satisfied
--> $DIR/issue-30786-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 on `Map<Repeat, {closure@issue-30786-1.rs:115:27}>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
`&'a mut &mut Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
`&'a mut Map<Repeat, {closure@$DIR/issue-30786-1.rs:115:27: 115:34}>: Stream`
--> $DIR/issue-30786-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/issue-30786-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`.

View 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() {}

View File

@ -0,0 +1,27 @@
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, fn(&u64) -> &u64 {identity::<u64>}>, {closure@issue-30786-2.rs:111:30}>`, but its trait bounds were not satisfied
--> $DIR/issue-30786-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/issue-30786-2.rs:111:30: 111:37}>: Stream`
`&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream`
`&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream`
--> $DIR/issue-30786-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/issue-30786-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`.

View File

@ -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`.

View File

@ -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 @@ fn dispatch<F>(&self, f: F) -> Result<(), io::Error>
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
//
}
}

View File

@ -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)
| ^^^^^^^^^^^^^^^^ 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)
| ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= 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: `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`.