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

Prelude collision lint: invalid suggestion for T::from_iter when T is generic. #86940

Closed
m-ou-se opened this issue Jul 7, 2021 · 9 comments · Fixed by #87557
Closed

Prelude collision lint: invalid suggestion for T::from_iter when T is generic. #86940

m-ou-se opened this issue Jul 7, 2021 · 9 comments · Fixed by #87557
Assignees
Labels
A-edition-2021 Area: The 2021 edition D-edition Diagnostics: An error or lint that should account for edition differences. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@m-ou-se
Copy link
Member

m-ou-se commented Jul 7, 2021

For generic types, the prelude collision lint can produce suggestions that do not compile:

Code:

struct Generic<T>(T);

trait Hey { fn from_iter(_: i32) -> Self; }

impl Hey for Generic<i32> { fn from_iter(x: i32) -> Self { Self(x) } }

impl std::iter::FromIterator<i32> for Generic<i32> { fn from_iter<T: IntoIterator<Item = i32>>(_: T) -> Self { todo!() } }

fn main() {
    Generic::from_iter(1);
}

Suggestion from the prelude collision lint:

warning: trait-associated function `from_iter` will become ambiguous in Rust 2021
  --> src/main.rs:10:5
   |
10 |     Generic::from_iter(1);
   |     ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<Generic as Hey>::from_iter`
   |
   = note: `-W rust-2021-prelude-collisions` implied by `-W rust-2021-compatibility`
   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
   = note: for more information, see issue #85684 <https://github.com/rust-lang/rust/issues/85684>

Error after applying the suggestion:

error[E0107]: missing generics for struct `Generic`
  --> src/main.rs:10:6
   |
10 |     <Generic as Hey>::from_iter(1);
   |      ^^^^^^^ expected 1 generic argument
   |
@m-ou-se m-ou-se added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. D-edition Diagnostics: An error or lint that should account for edition differences. A-edition-2021 Area: The 2021 edition labels Jul 7, 2021
@m-ou-se
Copy link
Member Author

m-ou-se commented Jul 7, 2021

cc @nikomatsakis @jam1garner

@jam1garner
Copy link
Contributor

My guess is this should be a simple fix, just copying the code the lint already uses for adding unspecified generics (Foo<_, _>). Will try implementing a fix soon.

@nikomatsakis
Copy link
Contributor

@rustbot assign @jam1garner

@nikomatsakis
Copy link
Contributor

@rustbot release-assignment

@nikomatsakis
Copy link
Contributor

Mentoring notes

The code related to this lint lives in the prelude2021 module.

The relevant suggestion is generated here:

lint.span_suggestion(
span,
"disambiguate the associated function",
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
Applicability::MachineApplicable,
);

The "self type" string comes from here:

let self_ty = self
.sess()
.source_map()
.span_to_snippet(self_ty_span)
.unwrap_or_else(|_| self_ty.to_string());

The code for traits is here:

let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
let trait_name = if parameter_count == 0 {
trait_path
} else {
format!(
"{}<{}>",
trait_path,
std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
)
};

This is actually just a touch tricky, because currently we are getting the "self type" just by copying the text the user wrote. Probably the most correct thing for us to do would be to examine the 'self expression' HIR and, if it is a plain path, then to append the <_> and otherwise skip it.

Specifically, the other case that I am thinking about is code like this:

#![warn(rust_2021_compatibility)]

struct Generic<T>(T);

trait Hey { fn from_iter(_: i32) -> Self; }

impl Hey for Generic<i32> { fn from_iter(x: i32) -> Self { Self(x) } }

impl std::iter::FromIterator<i32> for Generic<i32> { fn from_iter<T: IntoIterator<Item = i32>>(_: T) -> Self { todo!() } }

fn main() {
    <Generic<_>>::from_iter(1);
}

Currently this test works, meaning that it offers the suggestion "disambiguate the associated function: <Generic<_> as Hey>::from_iter".

@FinnRG
Copy link

FinnRG commented Jul 16, 2021

@rustbot claim

@nikomatsakis
Copy link
Contributor

@Pyther99 great! Let us know if you need anything or make progress. This issue is fairly time sensitive.

@FinnRG
Copy link

FinnRG commented Jul 20, 2021

@rustbot release-assignment

@rylev
Copy link
Member

rylev commented Jul 26, 2021

@rustbot claim

JohnTitor added a commit to JohnTitor/rust that referenced this issue Jul 30, 2021
…-error, r=nikomatsakis

Fix issue with autofix for ambiguous associated function from Rust 2021 prelude when struct is generic

Fixes rust-lang#86940

The test cases and associated issue should make it clear what specifically this is meant to fix. The fix is slightly hacky in that we check against the literal source code of the call site for the presence of `<` in order to determine if the user has included the generics for the struct (meaning we don't need to include them for them).

r? `@nikomatsakis`
@bors bors closed this as completed in fb27c4c Jul 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2021 Area: The 2021 edition D-edition Diagnostics: An error or lint that should account for edition differences. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
5 participants