Rollup merge of #116553 - gurry:116464-assoc-type-invalid-suggestion, r=compiler-errors

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

Fixes #116464

We now skip the suggestion if we're in an impl of the trait.
This commit is contained in:
Matthias Krüger 2023-10-25 23:37:09 +02:00 committed by GitHub
commit 824dbb53fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 209 additions and 13 deletions

View file

@ -129,6 +129,44 @@ fn kind(&self) -> &str {
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 {
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()
@ -955,20 +993,26 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
// 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<_>>();
// 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,
);
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

View file

@ -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() {
}

View file

@ -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`.