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

Do not suggest 'Trait<Assoc=arg>' when in trait impl #116553

Merged
merged 1 commit into from
Oct 26, 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 @@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
if self.missing_lifetimes() { "lifetime" } else { "generic" }
}

/// Returns true if the generic type is a trait
/// and is being referred to from one of its trait impls
fn is_in_trait_impl(&self) -> bool {
gurry marked this conversation as resolved.
Show resolved Hide resolved
if self.tcx.is_trait(self.def_id) {
// Here we check if the reference to the generic type
// is from the 'of_trait' field of the enclosing impl

let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
let parent_item = self
.tcx
.hir()
.get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);

// Get the HIR id of the trait ref
let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
return false;
};

// Get the HIR id of the 'of_trait' field of the impl
let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
..
}),
..
}) = parent_item
else {
return false;
};

// Check that trait is referred to from the of_trait field of impl
trait_ref_id == id_in_of_trait
} else {
false
}
}

fn num_provided_args(&self) -> usize {
if self.missing_lifetimes() {
self.num_provided_lifetime_args()
Expand Down Expand Up @@ -948,20 +986,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
// If there is a single unbound associated type and a single excess generic param
// suggest replacing the generic param with the associated type bound
if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
let suggestions = iter::zip(unused_generics, &unbound_types)
.map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
.collect::<Vec<_>>();

if !suggestions.is_empty() {
err.multipart_suggestion_verbose(
format!(
"replace the generic bound{s} with the associated type{s}",
s = pluralize!(unbound_types.len())
),
suggestions,
Applicability::MaybeIncorrect,
);
// Don't suggest if we're in a trait impl as
// that would result in invalid syntax (fixes #116464)
if !self.is_in_trait_impl() {
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
let suggestions = iter::zip(unused_generics, &unbound_types)
.map(|(potential, name)| {
(potential.span().shrink_to_lo(), format!("{name} = "))
})
.collect::<Vec<_>>();

if !suggestions.is_empty() {
err.multipart_suggestion_verbose(
format!(
"replace the generic bound{s} with the associated type{s}",
s = pluralize!(unbound_types.len())
),
suggestions,
Applicability::MaybeIncorrect,
);
}
}
} else if remove_entire_generics {
let span = self
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Regression test for #116464
// Checks that we do not suggest Trait<..., Assoc=arg> when the trait
// is referred to from one of its impls but do so at all other places

pub trait Trait<T> {
type Assoc;
}

impl<T, S> Trait<T> for i32 {
type Assoc = String;
}

// Should not not trigger suggestion here...
impl<T, S> Trait<T, S> for () {}
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied

//... but should do so in all of the below cases except the last one
fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
3
}

struct Struct<T: Trait<u32, String>> {
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
a: T
}

trait AnotherTrait<T: Trait<T, i32>> {}
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied

impl<T: Trait<u32, String>> Struct<T> {}
//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied

// Test for self type. Should not trigger suggestion as it doesn't have an
// associated type
trait YetAnotherTrait {}
impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied


fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12
|
LL | impl<T, S> Trait<T, S> for () {}
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -

error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12
|
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -
help: replace the generic bound with the associated type
|
LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> {
| +++++++

error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46
|
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -
help: replace the generic bound with the associated type
|
LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
| +++++++

error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18
|
LL | struct Struct<T: Trait<u32, String>> {
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -
help: replace the generic bound with the associated type
|
LL | struct Struct<T: Trait<u32, Assoc = String>> {
| +++++++

error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23
|
LL | trait AnotherTrait<T: Trait<T, i32>> {}
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -
help: replace the generic bound with the associated type
|
LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {}
| +++++++

error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9
|
LL | impl<T: Trait<u32, String>> Struct<T> {}
| ^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
|
LL | pub trait Trait<T> {
| ^^^^^ -
help: replace the generic bound with the associated type
|
LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {}
| +++++++

error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58
|
LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
| ^^^^^^ - help: remove this generic argument
| |
| expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `T`
--> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8
|
LL | struct Struct<T: Trait<u32, String>> {
| ^^^^^^ -

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0107`.
Loading