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

Account for type parameters in bound suggestion #134937

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

estebank
Copy link
Contributor

When encountering a missing bound that involves a type parameter, on associated functions we look at the generics to see if the type parameter is present. If so, we suggest the bound on the associated function instead of on the impl/trait. At the impl/trait doesn't have another type parameter of that name, then we don't suggest the bound at that item level.

error[E0277]: the trait bound `B: From<T>` is not satisfied
  --> $DIR/suggest-restriction-involving-type-param.rs:20:33
   |
LL |         B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
   |                                 ^ the trait `From<T>` is not implemented for `B`
   |
help: consider further restricting the type
   |
LL |     pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self where B: From<T> {
   |                                                             ++++++++++++++++

Fix #104089.

When encountering a missing bound that involves a type parameter, on associated functions we look at the generics to see if the type parameter is present. If so, we suggest the bound on the associated function instead of on the impl/trait. At the impl/trait doesn't have another type parameter of that name, then we don't suggest the bound at that item level.

```
error[E0277]: the trait bound `B: From<T>` is not satisfied
  --> $DIR/suggest-restriction-involving-type-param.rs:20:33
   |
LL |         B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
   |                                 ^ the trait `From<T>` is not implemented for `B`
   |
help: consider further restricting the type
   |
LL |     pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self where B: From<T> {
   |                                                             ++++++++++++++++
```

Fix rust-lang#104089.
@rustbot
Copy link
Collaborator

rustbot commented Dec 30, 2024

r? @Nadrieril

rustbot has assigned @Nadrieril.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 30, 2024
let mut v = ParamFinder { params: vec![] };
// Get all type parameters from the predicate. If the predicate references a type parameter
// at all, then we can only suggestion a bound on an item that has access to that parameter.
v.visit_predicate(UpcastFrom::upcast_from(trait_pred, self.tcx));
Copy link
Member

Choose a reason for hiding this comment

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

just use .upcast().

Copy link
Member

Choose a reason for hiding this comment

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

Also, what do you mean? We should never be suggesting a bound involving a parameter that we don't have "access to" --we shouldn't be checking predicates involving parameters that aren't in scope anyways?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We currently have a fallback where regardless of what the predicate that failed, we end up suggesting a bound (with weasel wording that there might be a better way). This is in place because there are some complex (if uncommon) bounds that are still useful to have that were given only by that. But in #104089, we had a report of that fallback doing the wrong thing (obvious in retrospect). The predicate might be something like Self: From<T>, where the T is a param only in the associated item and not at the trait/impl level. That's what this additional check guards against: If any part of the predicate references one of the generics of that item, we don't skip suggesting the bound at that level because it would be invalid in the parent item.

let mut v = ParamFinder { params: vec![] };
// Get all type parameters from the predicate. If the predicate references a type parameter
// at all, then we can only suggestion a bound on an item that has access to that parameter.
v.visit_predicate(UpcastFrom::upcast_from(trait_pred, self.tcx));
Copy link
Member

Choose a reason for hiding this comment

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

Also, what do you mean? We should never be suggesting a bound involving a parameter that we don't have "access to" --we shouldn't be checking predicates involving parameters that aren't in scope anyways?

Comment on lines +468 to +472
}) if !param_ty
&& (generics.params.iter().any(|param| {
v.params.iter().any(|p| p.name == param.name.ident().name)
}) || v.params.is_empty()) =>
{
Copy link
Member

Choose a reason for hiding this comment

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

Don't you want this?

Suggested change
}) if !param_ty
&& (generics.params.iter().any(|param| {
v.params.iter().any(|p| p.name == param.name.ident().name)
}) || v.params.is_empty()) =>
{
}) if !param_ty
&& v.params.iter().all(|param| {
generics.params.iter().any(|p| p.name == param.name.ident().name)
}) =>
{

Copy link
Member

Choose a reason for hiding this comment

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

I'm confused by the logic: what's a suggestion you're trying to avoid emitting by adding this condition?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

help clause points to adding where clause on impl when it should be on function
4 participants