Deeply normalize obligations in BestObligation
This commit is contained in:
parent
62d5fb85ac
commit
decd7ecd1e
11 changed files with 172 additions and 60 deletions
|
@ -13,9 +13,9 @@ use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as
|
||||||
use rustc_type_ir::solve::NoSolution;
|
use rustc_type_ir::solve::NoSolution;
|
||||||
use tracing::{instrument, trace};
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use crate::solve::Certainty;
|
|
||||||
use crate::solve::delegate::SolverDelegate;
|
use crate::solve::delegate::SolverDelegate;
|
||||||
use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||||
|
use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
|
||||||
use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
|
use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
|
||||||
|
|
||||||
pub(super) fn fulfillment_error_for_no_solution<'tcx>(
|
pub(super) fn fulfillment_error_for_no_solution<'tcx>(
|
||||||
|
@ -151,7 +151,7 @@ fn find_best_leaf_obligation<'tcx>(
|
||||||
//
|
//
|
||||||
// We should probably fix the visitor to not do so instead, as this also
|
// We should probably fix the visitor to not do so instead, as this also
|
||||||
// means the leaf obligation may be incorrect.
|
// means the leaf obligation may be incorrect.
|
||||||
infcx
|
let obligation = infcx
|
||||||
.fudge_inference_if_ok(|| {
|
.fudge_inference_if_ok(|| {
|
||||||
infcx
|
infcx
|
||||||
.visit_proof_tree(
|
.visit_proof_tree(
|
||||||
|
@ -161,7 +161,8 @@ fn find_best_leaf_obligation<'tcx>(
|
||||||
.break_value()
|
.break_value()
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
})
|
})
|
||||||
.unwrap_or(obligation)
|
.unwrap_or(obligation);
|
||||||
|
deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BestObligation<'tcx> {
|
struct BestObligation<'tcx> {
|
||||||
|
@ -298,7 +299,7 @@ impl<'tcx> BestObligation<'tcx> {
|
||||||
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
|
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
|
||||||
/// that should catch when a projection goal fails due to an unsatisfied trait
|
/// that should catch when a projection goal fails due to an unsatisfied trait
|
||||||
/// goal.
|
/// goal.
|
||||||
fn detect_error_in_higher_ranked_projection(
|
fn detect_trait_error_in_higher_ranked_projection(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: &inspect::InspectGoal<'_, 'tcx>,
|
goal: &inspect::InspectGoal<'_, 'tcx>,
|
||||||
) -> ControlFlow<PredicateObligation<'tcx>> {
|
) -> ControlFlow<PredicateObligation<'tcx>> {
|
||||||
|
@ -307,7 +308,13 @@ impl<'tcx> BestObligation<'tcx> {
|
||||||
&& !projection_clause.bound_vars().is_empty()
|
&& !projection_clause.bound_vars().is_empty()
|
||||||
{
|
{
|
||||||
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
|
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
|
||||||
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
|
let obligation = Obligation::new(
|
||||||
|
tcx,
|
||||||
|
self.obligation.cause.clone(),
|
||||||
|
goal.goal().param_env,
|
||||||
|
deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
|
||||||
|
);
|
||||||
|
self.with_derived_obligation(obligation, |this| {
|
||||||
goal.infcx().visit_proof_tree_at_depth(
|
goal.infcx().visit_proof_tree_at_depth(
|
||||||
goal.goal().with(tcx, pred),
|
goal.goal().with(tcx, pred),
|
||||||
goal.depth() + 1,
|
goal.depth() + 1,
|
||||||
|
@ -526,7 +533,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.detect_error_in_higher_ranked_projection(goal)?;
|
self.detect_trait_error_in_higher_ranked_projection(goal)?;
|
||||||
|
|
||||||
ControlFlow::Break(self.obligation.clone())
|
ControlFlow::Break(self.obligation.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,20 +253,28 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
deeply_normalize_with_skipped_universes(
|
let infcx = self.at.infcx;
|
||||||
self.at,
|
infcx
|
||||||
ty,
|
.commit_if_ok(|_| {
|
||||||
vec![None; ty.outer_exclusive_binder().as_usize()],
|
deeply_normalize_with_skipped_universes(
|
||||||
)
|
self.at,
|
||||||
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
|
ty,
|
||||||
|
vec![None; ty.outer_exclusive_binder().as_usize()],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
deeply_normalize_with_skipped_universes(
|
let infcx = self.at.infcx;
|
||||||
self.at,
|
infcx
|
||||||
ct,
|
.commit_if_ok(|_| {
|
||||||
vec![None; ct.outer_exclusive_binder().as_usize()],
|
deeply_normalize_with_skipped_universes(
|
||||||
)
|
self.at,
|
||||||
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
|
ct,
|
||||||
|
vec![None; ct.outer_exclusive_binder().as_usize()],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||||
--> $DIR/as_expression.rs:56:21
|
--> $DIR/as_expression.rs:56:21
|
||||||
|
|
|
|
||||||
LL | SelectInt.check("bar");
|
LL | SelectInt.check("bar");
|
||||||
| ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
|
| ----- ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `AsExpression<Text>` is implemented for `&str`
|
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
|
||||||
|
but trait `AsExpression<Text>` is implemented for it
|
||||||
|
= help: for that trait implementation, expected `Text`, found `Integer`
|
||||||
note: required by a bound in `Foo::check`
|
note: required by a bound in `Foo::check`
|
||||||
--> $DIR/as_expression.rs:47:12
|
--> $DIR/as_expression.rs:47:12
|
||||||
|
|
|
|
||||||
|
@ -16,11 +18,11 @@ LL | where
|
||||||
LL | T: AsExpression<Self::SqlType>,
|
LL | T: AsExpression<Self::SqlType>,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
|
||||||
|
|
||||||
error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
|
error[E0271]: type mismatch resolving `Integer == Text`
|
||||||
--> $DIR/as_expression.rs:56:5
|
--> $DIR/as_expression.rs:56:5
|
||||||
|
|
|
|
||||||
LL | SelectInt.check("bar");
|
LL | SelectInt.check("bar");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
|
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,6 @@ impl<T> Foo for T where T: Expression {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
SelectInt.check("bar");
|
SelectInt.check("bar");
|
||||||
//[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
|
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
|
||||||
//[next]~^^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
|
|
||||||
//[next]~| ERROR type mismatch
|
//[next]~| ERROR type mismatch
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,30 +6,134 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
|
||||||
|
|
|
|
||||||
= help: remove one of these features
|
= help: remove one of these features
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: const Trait` is not satisfied
|
error[E0391]: cycle detected when evaluating type-level constant
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:37
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires elaborating drops for `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires borrow-checking `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires const checking `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building MIR for `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building an abstract representation for `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building THIR for `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires type-checking `accept0::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
= note: ...which again requires evaluating type-level constant, completing the cycle
|
||||||
|
note: cycle used when checking that `accept0` is well-formed
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:1
|
||||||
|
|
|
||||||
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: const Trait` is not satisfied
|
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:50
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
|
||||||
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:22:15
|
|
||||||
|
|
|
|
||||||
LL | require::<Ty>();
|
note: ...which requires elaborating drops for `accept1::{constant#0}`...
|
||||||
| ^^
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
|
||||||
note: required by a bound in `require`
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:8:15
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires borrow-checking `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
|
||||||
LL | fn require<T: const Trait>() {}
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^^^^^^^^^^^ required by this bound in `require`
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires const checking `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building MIR for `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building an abstract representation for `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires building THIR for `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires type-checking `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires evaluating type-level constant...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
= note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
|
||||||
|
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
|
||||||
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
||||||
|
|
|
||||||
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
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 E0391`.
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
|
error[E0271]: type mismatch resolving `() == i32`
|
||||||
--> $DIR/async.rs:12:17
|
--> $DIR/async.rs:12:17
|
||||||
|
|
|
|
||||||
LL | needs_async(async {});
|
LL | needs_async(async {});
|
||||||
| ----------- ^^^^^^^^ expected `i32`, found `()`
|
| ----------- ^^^^^^^^ types differ
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
|
||||||
#[cfg(fail)]
|
#[cfg(fail)]
|
||||||
fn main() {
|
fn main() {
|
||||||
needs_async(async {});
|
needs_async(async {});
|
||||||
//[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
|
//[fail]~^ ERROR type mismatch resolving `() == i32`
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(pass)]
|
#[cfg(pass)]
|
||||||
|
|
|
@ -10,7 +10,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
|
||||||
|
|
||||||
fn transmute<A, B>(x: A) -> B {
|
fn transmute<A, B>(x: A) -> B {
|
||||||
foo::<A, B, dyn Trait<A = A, B = B>>(x)
|
foo::<A, B, dyn Trait<A = A, B = B>>(x)
|
||||||
//~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
|
//~^ ERROR type mismatch resolving `A == B`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo<A, B, T: ?Sized>(x: T::A) -> B
|
fn foo<A, B, T: ?Sized>(x: T::A) -> B
|
||||||
|
|
|
@ -1,17 +1,9 @@
|
||||||
error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
|
error[E0271]: type mismatch resolving `A == B`
|
||||||
--> $DIR/more-object-bound.rs:12:5
|
--> $DIR/more-object-bound.rs:12:5
|
||||||
|
|
|
|
||||||
LL | fn transmute<A, B>(x: A) -> B {
|
|
||||||
| - - expected type parameter
|
|
||||||
| |
|
|
||||||
| found type parameter
|
|
||||||
LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
|
LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||||
|
|
|
|
||||||
= note: expected type parameter `B`
|
|
||||||
found type parameter `A`
|
|
||||||
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
|
|
||||||
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
|
||||||
= note: required because it appears within the type `dyn Trait<A = A, B = B>`
|
= note: required because it appears within the type `dyn Trait<A = A, B = B>`
|
||||||
note: required by a bound in `foo`
|
note: required by a bound in `foo`
|
||||||
--> $DIR/more-object-bound.rs:18:8
|
--> $DIR/more-object-bound.rs:18:8
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn needs_bar<S: Bar>() {}
|
||||||
|
|
||||||
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
|
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
|
||||||
needs_bar::<T::Assoc1>();
|
needs_bar::<T::Assoc1>();
|
||||||
//~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
|
//~^ ERROR the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
|
error[E0277]: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
|
||||||
--> $DIR/recursive-self-normalization-2.rs:15:17
|
--> $DIR/recursive-self-normalization-2.rs:15:17
|
||||||
|
|
|
|
||||||
LL | needs_bar::<T::Assoc1>();
|
LL | needs_bar::<T::Assoc1>();
|
||||||
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
|
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo2>::Assoc2`
|
||||||
|
|
|
|
||||||
note: required by a bound in `needs_bar`
|
note: required by a bound in `needs_bar`
|
||||||
--> $DIR/recursive-self-normalization-2.rs:12:17
|
--> $DIR/recursive-self-normalization-2.rs:12:17
|
||||||
|
@ -11,7 +11,7 @@ LL | fn needs_bar<S: Bar>() {}
|
||||||
| ^^^ required by this bound in `needs_bar`
|
| ^^^ required by this bound in `needs_bar`
|
||||||
help: consider further restricting the associated type
|
help: consider further restricting the associated type
|
||||||
|
|
|
|
||||||
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
|
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Bar {
|
||||||
| ++++++++++++++++++++++++++++++
|
| ++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue