rust-lang / rust-lang/rust-clippy
Warn against having multiple `impl` blocks for the same struct and with the same bounds(?)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
What it does
I'm not a weathered crustacean, but I got bitten the other day because I mistakenly created the same impl block twice in the same file but with different functions, and I didn't realise it for ages but kept on getting strange inconsistencies because of it.
So my file looked something like
struct Foo<'a> {
i: &'a mut i32,
}
// lots of code here
impl Foo<'_> {
fn bar(&mut self) {
*self.i += 1;
}
}
// lots of code here
impl Foo<'_> {
fn baz(&mut self) {
*self.i += 2;
}
}
// lots of code here
fn main() {
println!("Hello world");
// And more code here
}
I'm not sure if this is worth linting for to warn the user that this probably isn't a thing they intended? It's probably more common in larger projects with new people joining and not knowing if something's been impl-ed yet.
If someone more knowledgeable knows of a situation in which you would use two impl blocks with identical headers, I'd be interested to hear it as well.
Lint Name
duplicate-impl-headers
Category
suspicious, style, complexity
Advantage
- Remove confusion introduced in bigger projects
- Guide the user away from creating an
implblock for every single function they want for their struct - Make it clear that different
implblocks are actually different in what they allow or what they can contain
Drawbacks
- Maybe a bit picky
- I don't think it would crop up very often
- There might be a legitimate use case for multiple
impls - I'm not sure if
impls which are duplicated but in different files should be flagged or not
Example
From the description:
struct Foo<'a> {
i: &'a mut i32,
// j: &'b mut i32,
}
// lots of code here
impl Foo<'_> {
// --------- note bar in this impl ---------
fn bar(&mut self) {
*self.i += 1;
}
}
// lots of code here
impl Foo<'_> {
// --------- note baz in this impl ---------
fn baz(&mut self) {
*self.i += 2;
}
}
// lots of code here
fn main() {
println!("Hello world");
// And more code here
}
Could be written as:
struct Foo<'a> {
i: &'a mut i32,
}
// lots of code here
// --------- note bar and baz now in one impl ---------
impl Foo<'_> {
fn bar(&mut self) {
*self.i += 1;
}
fn baz(&mut self) {
*self.i += 2;
}
}
// lots of code here
fn main() {
println!("Hello world");
// And more code here
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the issue's duplicate-impl examples and the proposed lint name, then investigate whether identical impl headers have legitimate uses and whether separate files should be included. Done means the lint's scope, exceptions, category, and expected diagnostics are agreed, with implementation and tests identified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100