Apply nested goals certainty to InspectGoals for normalizes-to

This commit is contained in:
Michael Goulet
2025-06-06 16:28:05 +00:00
parent 14863ea077
commit cd1d84e304
21 changed files with 154 additions and 94 deletions

View File

@@ -120,15 +120,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
// No need to walk into goal subtrees that certainly hold, since they // No need to walk into goal subtrees that certainly hold, since they
// wouldn't then be stalled on an infer var. // wouldn't then be stalled on an infer var.
// FIXME: We also walk into normalizes-to goals since their certainty if inspect_goal.result() == Ok(Certainty::Yes) {
// is forced to `Certainty::Yes` since they pass down ambiguous subgoals
// to their parent.
if inspect_goal.result() == Ok(Certainty::Yes)
&& !matches!(
inspect_goal.goal().predicate.kind().skip_binder(),
ty::PredicateKind::NormalizesTo(_)
)
{
return; return;
} }

View File

@@ -11,7 +11,8 @@
use std::assert_matches::assert_matches; use std::assert_matches::assert_matches;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::Obligation;
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
@@ -20,7 +21,7 @@ use rustc_middle::{bug, ty};
use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::resolve::eager_resolve_vars;
use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
use rustc_span::{DUMMY_SP, Span}; use rustc_span::Span;
use tracing::instrument; use tracing::instrument;
use crate::solve::delegate::SolverDelegate; use crate::solve::delegate::SolverDelegate;
@@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
/// Relate the `term` with the new `unconstrained_term` created /// Relate the `term` with the new `unconstrained_term` created
/// when computing the proof tree for this `NormalizesTo` goals. /// when computing the proof tree for this `NormalizesTo` goals.
/// This handles nested obligations. /// This handles nested obligations.
fn constrain( fn constrain_and(
self, &self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
span: Span, span: Span,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
f: impl FnOnce(&ObligationCtxt<'_, 'tcx>),
) -> Result<Certainty, NoSolution> { ) -> Result<Certainty, NoSolution> {
infcx let ocx = ObligationCtxt::new(infcx);
.at(&ObligationCause::dummy_with_span(span), param_env) ocx.eq(
.eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term) &ObligationCause::dummy_with_span(span),
.map_err(|_| NoSolution) param_env,
.and_then(|InferOk { value: (), obligations }| { self.term,
let ocx = ObligationCtxt::new(infcx); self.unconstrained_term,
ocx.register_obligations(obligations); )?;
let errors = ocx.select_all_or_error(); f(&ocx);
if errors.is_empty() { let errors = ocx.select_all_or_error();
Ok(Certainty::Yes) if errors.is_empty() {
} else if errors.iter().all(|e| !e.is_true_error()) { Ok(Certainty::Yes)
Ok(Certainty::AMBIGUOUS) } else if errors.iter().all(|e| !e.is_true_error()) {
} else { Ok(Certainty::AMBIGUOUS)
Err(NoSolution) } else {
} Err(NoSolution)
}) }
} }
} }
@@ -160,11 +162,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
let () = let () =
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
if let Some(term_hack) = self.goal.normalizes_to_term_hack { if let Some(term_hack) = &self.goal.normalizes_to_term_hack {
// FIXME: We ignore the expected term of `NormalizesTo` goals // FIXME: We ignore the expected term of `NormalizesTo` goals
// when computing the result of its candidates. This is // when computing the result of its candidates. This is
// scuffed. // scuffed.
let _ = term_hack.constrain(infcx, span, param_env); let _ = term_hack.constrain_and(infcx, span, param_env, |_| {});
} }
instantiated_goals instantiated_goals
@@ -240,13 +242,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
// building their proof tree, the expected term was unconstrained, but when // building their proof tree, the expected term was unconstrained, but when
// instantiating the candidate it is already constrained to the result of another // instantiating the candidate it is already constrained to the result of another
// candidate. // candidate.
let proof_tree = infcx let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term };
.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1); let (proof_tree, nested_goals_result) = infcx.probe(|_| {
// Here, if we have any nested goals, then we make sure to apply them
// considering the constrained RHS, and pass the resulting certainty to
// `InspectGoal::new` so that the goal has the right result (and maintains
// the impression that we don't do this normalizes-to infer hack at all).
let (nested, proof_tree) =
infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None);
let proof_tree = proof_tree.unwrap();
let nested_goals_result = nested.and_then(|(nested, _)| {
normalizes_to_term_hack.constrain_and(
infcx,
span,
proof_tree.uncanonicalized_goal.param_env,
|ocx| {
ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| {
Obligation::new(
infcx.tcx,
ObligationCause::dummy_with_span(span),
goal.param_env,
goal.predicate,
)
}));
},
)
});
(proof_tree, nested_goals_result)
});
InspectGoal::new( InspectGoal::new(
infcx, infcx,
self.goal.depth + 1, self.goal.depth + 1,
proof_tree.unwrap(), proof_tree,
Some(NormalizesToTermHack { term, unconstrained_term }), Some((normalizes_to_term_hack, nested_goals_result)),
source, source,
) )
} }
@@ -393,20 +421,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>, infcx: &'a InferCtxt<'tcx>,
depth: usize, depth: usize,
root: inspect::GoalEvaluation<TyCtxt<'tcx>>, root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, term_hack_and_nested_certainty: Option<(
NormalizesToTermHack<'tcx>,
Result<Certainty, NoSolution>,
)>,
source: GoalSource, source: GoalSource,
) -> Self { ) -> Self {
let infcx = <&SolverDelegate<'tcx>>::from(infcx); let infcx = <&SolverDelegate<'tcx>>::from(infcx);
let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
// If there's a normalizes-to goal, AND the evaluation result with the result of
// constraining the normalizes-to RHS and computing the nested goals.
let result = evaluation.result.and_then(|ok| { let result = evaluation.result.and_then(|ok| {
if let Some(term_hack) = normalizes_to_term_hack { let nested_goals_certainty =
infcx term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?;
.probe(|_| term_hack.constrain(infcx, DUMMY_SP, uncanonicalized_goal.param_env)) Ok(ok.value.certainty.and(nested_goals_certainty))
.map(|certainty| ok.value.certainty.and(certainty))
} else {
Ok(ok.value.certainty)
}
}); });
InspectGoal { InspectGoal {
@@ -416,7 +445,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
goal: eager_resolve_vars(infcx, uncanonicalized_goal), goal: eager_resolve_vars(infcx, uncanonicalized_goal),
result, result,
evaluation_kind: evaluation.kind, evaluation_kind: evaluation.kind,
normalizes_to_term_hack, normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n),
source, source,
} }
} }

View File

@@ -1,9 +1,22 @@
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` error[E0283]: type annotations needed
--> $DIR/auto-trait-selection-freeze.rs:19:5 --> $DIR/auto-trait-selection-freeze.rs:19:16
| |
LL | if false { is_trait(foo()) } else { Default::default() } LL | if false { is_trait(foo()) } else { Default::default() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` | ^^^^^^^^ ----- type must be known at this point
| |
| cannot infer type of the type parameter `T` declared on the function `is_trait`
|
= note: cannot satisfy `_: Trait<_>`
note: required by a bound in `is_trait`
--> $DIR/auto-trait-selection-freeze.rs:11:16
|
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
| ^^^^^^^^ required by this bound in `is_trait`
help: consider specifying the generic arguments
|
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
| ++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0283`.

View File

@@ -1,9 +1,22 @@
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` error[E0283]: type annotations needed
--> $DIR/auto-trait-selection.rs:15:5 --> $DIR/auto-trait-selection.rs:15:16
| |
LL | if false { is_trait(foo()) } else { Default::default() } LL | if false { is_trait(foo()) } else { Default::default() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` | ^^^^^^^^ ----- type must be known at this point
| |
| cannot infer type of the type parameter `T` declared on the function `is_trait`
|
= note: cannot satisfy `_: Trait<_>`
note: required by a bound in `is_trait`
--> $DIR/auto-trait-selection.rs:7:16
|
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
| ^^^^^^^^ required by this bound in `is_trait`
help: consider specifying the generic arguments
|
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
| ++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0283`.

View File

@@ -25,7 +25,7 @@ LL | type LineStream<'c, 'd> = impl Stream;
| |
= note: `LineStream` must be used in combination with a concrete type within the same impl = note: `LineStream` must be used in combination with a concrete type within the same impl
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43 --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43
| |
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}

View File

@@ -29,7 +29,7 @@ impl X for Y {
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
//~^ ERROR method `line_stream` is not a member of trait `X` //~^ ERROR method `line_stream` is not a member of trait `X`
//[current]~^^ ERROR `()` is not a future //[current]~^^ ERROR `()` is not a future
//[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
} }

View File

@@ -1,8 +1,8 @@
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}`
--> $DIR/recursive-in-exhaustiveness.rs:19:17 --> $DIR/recursive-in-exhaustiveness.rs:20:5
| |
LL | let (x,) = (build(x),); LL | build(x)
| ^^^^^^^^ cannot satisfy `impl Sized == _` | ^^^^^^^^ cannot normalize `build<_>::{opaque#0}`
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
--> $DIR/recursive-in-exhaustiveness.rs:30:6 --> $DIR/recursive-in-exhaustiveness.rs:30:6

View File

@@ -17,8 +17,8 @@
fn build<T>(x: T) -> impl Sized { fn build<T>(x: T) -> impl Sized {
//[current]~^ ERROR cannot resolve opaque type //[current]~^ ERROR cannot resolve opaque type
let (x,) = (build(x),); let (x,) = (build(x),);
//[next]~^ ERROR type annotations needed
build(x) build(x)
//[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}`
} }
// Opaque<T> = (Opaque<T>,) // Opaque<T> = (Opaque<T>,)

View File

@@ -1,9 +1,9 @@
error[E0284]: type annotations needed: cannot satisfy `_ == A` error[E0282]: type annotations needed
--> $DIR/two_tait_defining_each_other2.rs:12:8 --> $DIR/two_tait_defining_each_other2.rs:12:11
| |
LL | fn muh(x: A) -> B { LL | fn muh(x: A) -> B {
| ^ cannot satisfy `_ == A` | ^ cannot infer type
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0282`.

View File

@@ -10,7 +10,7 @@ trait Foo {}
#[define_opaque(A, B)] #[define_opaque(A, B)]
fn muh(x: A) -> B { fn muh(x: A) -> B {
//[next]~^ ERROR: cannot satisfy `_ == A` //[next]~^ ERROR: type annotations needed
x // B's hidden type is A (opaquely) x // B's hidden type is A (opaquely)
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type //[current]~^ ERROR opaque type's hidden type cannot be another opaque type
} }

View File

@@ -13,9 +13,9 @@ fn main() {
} }
fn weird0() -> impl Sized + !Sized {} fn weird0() -> impl Sized + !Sized {}
//~^ ERROR type mismatch resolving //~^ ERROR the trait bound `(): !Sized` is not satisfied
fn weird1() -> impl !Sized + Sized {} fn weird1() -> impl !Sized + Sized {}
//~^ ERROR type mismatch resolving //~^ ERROR the trait bound `(): !Sized` is not satisfied
fn weird2() -> impl !Sized {} fn weird2() -> impl !Sized {}
//~^ ERROR type mismatch resolving //~^ ERROR the trait bound `(): !Sized` is not satisfied
//~| ERROR the size for values of type //~| ERROR the size for values of type

View File

@@ -7,23 +7,23 @@ LL | fn weird2() -> impl !Sized {}
= help: the trait `Sized` is not implemented for `impl !Sized` = help: the trait `Sized` is not implemented for `impl !Sized`
= note: the return type of a function must have a statically known size = note: the return type of a function must have a statically known size
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` error[E0277]: the trait bound `(): !Sized` is not satisfied
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16 --> $DIR/opaque-type-unsatisfied-bound.rs:15:16
| |
LL | fn weird0() -> impl Sized + !Sized {} LL | fn weird0() -> impl Sized + !Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` error[E0277]: the trait bound `(): !Sized` is not satisfied
--> $DIR/opaque-type-unsatisfied-bound.rs:17:16 --> $DIR/opaque-type-unsatisfied-bound.rs:17:16
| |
LL | fn weird1() -> impl !Sized + Sized {} LL | fn weird1() -> impl !Sized + Sized {}
| ^^^^^^^^^^^^^^^^^^^ types differ | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
error[E0271]: type mismatch resolving `impl !Sized == ()` error[E0277]: the trait bound `(): !Sized` is not satisfied
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16 --> $DIR/opaque-type-unsatisfied-bound.rs:19:16
| |
LL | fn weird2() -> impl !Sized {} LL | fn weird2() -> impl !Sized {}
| ^^^^^^^^^^^ types differ | ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
--> $DIR/opaque-type-unsatisfied-bound.rs:12:13 --> $DIR/opaque-type-unsatisfied-bound.rs:12:13
@@ -41,5 +41,4 @@ LL | fn consume(_: impl Trait) {}
error: aborting due to 5 previous errors error: aborting due to 5 previous errors
Some errors have detailed explanations: E0271, E0277. For more information about this error, try `rustc --explain E0277`.
For more information about an error, try `rustc --explain E0271`.

View File

@@ -3,6 +3,6 @@
#![feature(negative_bounds, unboxed_closures)] #![feature(negative_bounds, unboxed_closures)]
fn produce() -> impl !Fn<(u32,)> {} fn produce() -> impl !Fn<(u32,)> {}
//~^ ERROR type mismatch resolving //~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied
fn main() {} fn main() {}

View File

@@ -1,9 +1,9 @@
error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()` error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
| |
LL | fn produce() -> impl !Fn<(u32,)> {} LL | fn produce() -> impl !Fn<(u32,)> {}
| ^^^^^^^^^^^^^^^^ types differ | ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0271`. For more information about this error, try `rustc --explain E0277`.

View File

@@ -1,9 +1,16 @@
error[E0284]: type annotations needed: cannot satisfy `Foo == _` error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ cannot satisfy `Foo == _` | ^^^
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0283`.

View File

@@ -1,9 +1,16 @@
error[E0284]: type annotations needed: cannot satisfy `Foo == _` error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
| |
LL | needs_send::<Foo>(); LL | needs_send::<Foo>();
| ^^^ cannot satisfy `Foo == _` | ^^^
|
= note: cannot satisfy `Foo: Send`
note: required by a bound in `needs_send`
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
|
LL | fn needs_send<T: Send>() {}
| ^^^^ required by this bound in `needs_send`
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0283`.

View File

@@ -14,7 +14,7 @@ fn needs_send<T: Send>() {}
#[define_opaque(Foo)] #[define_opaque(Foo)]
fn test(_: Foo) { fn test(_: Foo) {
needs_send::<Foo>(); needs_send::<Foo>();
//~^ ERROR type annotations needed: cannot satisfy `Foo == _` //~^ ERROR type annotations needed
} }
#[define_opaque(Foo)] #[define_opaque(Foo)]

View File

@@ -7,7 +7,7 @@ LL | impl<In, Out> Trait<Bar, In> for Out {
LL | impl<In, Out> Trait<(), In> for Out { LL | impl<In, Out> Trait<(), In> for Out {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error[E0284]: type annotations needed: cannot satisfy `Bar == _` error[E0282]: type annotations needed
--> $DIR/issue-84660-unsoundness.rs:24:37 --> $DIR/issue-84660-unsoundness.rs:24:37
| |
LL | fn convert(_i: In) -> Self::Out { LL | fn convert(_i: In) -> Self::Out {
@@ -16,9 +16,9 @@ LL | |
LL | | LL | |
LL | | unreachable!(); LL | | unreachable!();
LL | | } LL | | }
| |_____^ cannot satisfy `Bar == _` | |_____^ cannot infer type
error: aborting due to 2 previous errors error: aborting due to 2 previous errors
Some errors have detailed explanations: E0119, E0284. Some errors have detailed explanations: E0119, E0282.
For more information about an error, try `rustc --explain E0119`. For more information about an error, try `rustc --explain E0119`.

View File

@@ -22,7 +22,7 @@ impl<In, Out> Trait<Bar, In> for Out {
type Out = Out; type Out = Out;
#[define_opaque(Bar)] #[define_opaque(Bar)]
fn convert(_i: In) -> Self::Out { fn convert(_i: In) -> Self::Out {
//[next]~^ ERROR: type annotations needed: cannot satisfy `Bar == _` //[next]~^ ERROR: type annotations needed
//[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}` //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}`
unreachable!(); unreachable!();
} }

View File

@@ -1,9 +1,9 @@
error[E0284]: type annotations needed: cannot satisfy `impl Foo<FooX> == ()` error[E0282]: type annotations needed
--> $DIR/nested-tait-inference2.rs:20:5 --> $DIR/nested-tait-inference2.rs:20:5
| |
LL | () LL | ()
| ^^ cannot satisfy `impl Foo<FooX> == ()` | ^^ cannot infer type
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0284`. For more information about this error, try `rustc --explain E0282`.

View File

@@ -18,7 +18,7 @@ impl Foo<u32> for () {}
fn foo() -> impl Foo<FooX> { fn foo() -> impl Foo<FooX> {
//[current]~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied //[current]~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
() ()
//[next]~^ ERROR: cannot satisfy `impl Foo<FooX> == ()` //[next]~^ ERROR: type annotations needed
} }
fn main() {} fn main() {}