Skip to content
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

Explain HRTB + infer limitations of old solver #115625

Merged
merged 1 commit into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}

self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);

// Return early if the trait is Debug or Display and the invocation
// originates within a standard library macro, because the output
// is otherwise overwhelming and unhelpful (see #85844 for an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,14 @@ pub trait TypeErrCtxtExt<'tcx> {
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
);

fn explain_hrtb_projection(
&self,
diag: &mut Diagnostic,
pred: ty::PolyTraitPredicate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: &ObligationCause<'tcx>,
);
}

fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
Expand Down Expand Up @@ -4027,6 +4035,71 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}

fn explain_hrtb_projection(
&self,
diag: &mut Diagnostic,
pred: ty::PolyTraitPredicate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: &ObligationCause<'tcx>,
) {
if pred.skip_binder().has_escaping_bound_vars() && pred.skip_binder().has_non_region_infer()
{
self.probe(|_| {
let ocx = ObligationCtxt::new(self);
let pred = self.instantiate_binder_with_placeholders(pred);
let pred = ocx.normalize(&ObligationCause::dummy(), param_env, pred);
ocx.register_obligation(Obligation::new(
self.tcx,
ObligationCause::dummy(),
param_env,
pred,
));
if !ocx.select_where_possible().is_empty() {
// encountered errors.
return;
}

if let ObligationCauseCode::FunctionArgumentObligation {
call_hir_id,
arg_hir_id,
parent_code: _,
} = cause.code()
{
let arg_span = self.tcx.hir().span(*arg_hir_id);
let mut sp: MultiSpan = arg_span.into();

sp.push_span_label(
arg_span,
"the trait solver is unable to infer the \
generic types that should be inferred from this argument",
);
sp.push_span_label(
self.tcx.hir().span(*call_hir_id),
"add turbofish arguments to this call to \
specify the types manually, even if it's redundant",
);
diag.span_note(
sp,
"this is a known limitation of the trait solver that \
will be lifted in the future",
);
} else {
let mut sp: MultiSpan = cause.span.into();
sp.push_span_label(
cause.span,
"try adding turbofish arguments to this expression to \
specify the types manually, even if it's redundant",
);
diag.span_note(
sp,
"this is a known limitation of the trait solver that \
will be lifted in the future",
);
}
});
}
}
}

/// Add a hint to add a missing borrow or remove an unnecessary one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ LL | build(Bar);
| required by a bound introduced by this call
|
= help: the trait `for<'a> Send` is not implemented for `impl Future<Output = ()> { <_ as Foo>::bar() }`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11
|
LL | build(Bar);
| ------^^^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `build`
--> $DIR/normalizing-self-auto-trait-issue-109924.rs:20:39
|
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/generic-associated-types/bugs/issue-88460.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ LL | test(Foo);
| required by a bound introduced by this call
|
= help: the trait `Marker` is implemented for `()`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/issue-88460.rs:28:10
|
LL | test(Foo);
| -----^^^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
Comment on lines +16 to +17
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a half-lie. It's not that Rust isn't able to infer the generic types constrained from this arg, but instead that Rust is attempting to prove predicates before constraining any generics that would be constrained by this argument.

I chose to state it like this because it's a bit clearer to the user. Not everyone knows the exact order the typeck does signature instantiation -> normalization -> unification of args -> fulfillment, nor do I think they need to. They just need to know that if they have a signature like:

fn foo<T: Trait>(t: T) where for<'a> T::Gat<'a>: Send {}

They should turbofish foo::<MyTypeGoesHere>(t).

note: required by a bound in `test`
--> $DIR/issue-88460.rs:15:27
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ LL | call(f, ());
|
= note: expected a closure with arguments `((),)`
found a closure with arguments `(<_ as ATC<'a>>::Type,)`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/issue-62529-3.rs:25:14
|
LL | call(f, ());
| -----^-----
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `call`
--> $DIR/issue-62529-3.rs:9:36
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ LL | upcast(y)
| required by a bound introduced by this call
|
= help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>`
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/issue-90950.rs:50:12
|
LL | upcast(y)
| -------^-
| | |
| | the trait solver is unable to infer the generic types that should be inferred from this argument
| add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `upcast`
--> $DIR/issue-90950.rs:27:42
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satis
LL | let _: () = weird_bound();
| ^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out`
|
note: this is a known limitation of the trait solver that will be lifted in the future
--> $DIR/norm-before-method-resolution.rs:22:17
|
LL | let _: () = weird_bound();
| ^^^^^^^^^^^ try adding turbofish arguments to this expression to specify the types manually, even if it's redundant
note: required by a bound in `weird_bound`
--> $DIR/norm-before-method-resolution.rs:18:40
|
Expand Down