Skip to content

Conversation

@y21
Copy link
Member

@y21 y21 commented Nov 26, 2024

Closes #12925.

The issue explains the two patterns it looks for, but to quickly summarize:

fn f1<T: Iterator>() where <I as Iterator>::Item: Copy {}
// and
fn f2<T: Iterator<Item = U>, U: Copy>() {}

can both be

fn f1<T: Iterator<Item: Copy>>() {}

This ended up far more involved than I originally expected and it's a bit annoying just how much code is required to have a proper machine applicable suggestion that can handle all the ways these bounds can be written.

TBH I'm not sure if it's worth all the complexity, but oh well (especially considering that something like <T as Trait>::Assoc: Copy, <T as Trait>::Assoc: Clone, which requires buffering the lint, is probably rather rare). The current suggestion still relies a bit on rustfmt to clean up, like a trailing comma because I didn't want to make it even more complicated than it already is, but I think it should be fine.

There's the question if we want to lint impl Trait types (<T: Iterator<Item = impl Copy>> -> <T: Iterator<Item: Copy>>). My initial implementation naturally linted them beacuse they're desugared to the pattern we already detect, but calling it a complexity issue is a stretch IMO as it barely saves a few characters so for now I just ignored them, and the lint description/messages would need some special casing.

changelog: new lint: could_be_assoc_type_bounds

@rustbot
Copy link
Collaborator

rustbot commented Nov 26, 2024

r? @Alexendoo

rustbot has assigned @Alexendoo.
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 the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Nov 26, 2024
{
}

fn ty_param<T: Iterator<Item: Clone>, >() {}
Copy link
Member Author

@y21 y21 Nov 26, 2024

Choose a reason for hiding this comment

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

One case where the lint relies on rustfmt to cleanup. Naively removing both the leading or trailing comma would create overlapping spans when trying to remove two bounds next to each other (removing the middle comma in T: Copy, U: Copy twice), so that's why it only tries to remove trailing commas

@bors
Copy link
Contributor

bors commented Dec 5, 2024

☔ The latest upstream changes (presumably a5e46a6) made this pull request unmergeable. Please resolve the merge conflicts.

@rustbot
Copy link
Collaborator

rustbot commented Mar 31, 2025

☔ The latest upstream changes (possibly d28d234) made this pull request unmergeable. Please resolve the merge conflicts.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Mar 31, 2025
@y21 y21 added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties and removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Apr 3, 2025
Comment on lines +660 to +661
&& let ty_param_def_id = ty_param_def_id.expect_local()
&& let ty_param_bound_at = cx.tcx.parent(ty_param_def_id.to_def_id()).expect_local()
Copy link
Member

Choose a reason for hiding this comment

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

I can't think of any situation where these would panic, but to be safe we can use as_local

Comment on lines +309 to +315
if emission.predicate(generics).origin == PredicateOrigin::WhereClause {
if exactly_one_where_bound {
suggestions.push((generics.where_clause_span, String::new()));
} else {
suggestions.push((emission.predicate_span_including_comma(generics), String::new()));
}
}
Copy link
Member

Choose a reason for hiding this comment

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

A shame we can't use https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Generics.html#method.span_for_predicate_removal here because it might have overlaps

Makes me wonder if we should add a fn remove_span_overlaps(&mut [Span]) for when it's intentional, it would be fine where we're just removing things

Comment on lines +63 to +72
error: this trait bound only exists to constrain another bound's associated type
--> tests/ui/could_be_assoc_type_bounds.rs:45:24
|
LL | fn impl_trait_generic<T: Copy>(_: impl Iterator<Item = T>) {}
| ^^^^^^ ------------------ merge it with this bound
|
help: remove any extra trait bounds add them directly to this trait bound using associated type bounds
|
LL - fn impl_trait_generic<T: Copy>(_: impl Iterator<Item = T>) {}
LL + fn impl_trait_generic(_: impl Iterator<Item: Copy>) {}
Copy link
Member

Choose a reason for hiding this comment

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

The where bound removal cases are a clear win but removing generic params is trickier since it allows e.g. impl_trait_generic::<u8>([].into_iter())

If we do lint them it should honour avoid-breaking-exported-api, but we may want to be conservative here

Comment on lines +585 to +598
fn hir_generics_of_item<'tcx>(item: &'tcx hir::Item<'tcx>) -> &'tcx hir::Generics<'tcx> {
match item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Fn(_, generics, _)
| hir::ItemKind::Const(_, generics, _)
| hir::ItemKind::Impl(&hir::Impl { generics, .. })
| hir::ItemKind::Struct(_, generics)
| hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::TraitAlias(generics, _)
| hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Union(_, generics) => generics,
_ => hir::Generics::empty(),
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Can use item.kind.generics() here

@Jarcho
Copy link
Contributor

Jarcho commented Sep 17, 2025

Ping @y21 from triage. Do you plan to return to working on this?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggest use of associated type bounds where possible

5 participants