This is how I gather you can define and implement a trait over an existing type:
use std::collections::BTreeSet;
trait SetLike {
fn contains(&self, v: &i32) -> bool;
}
impl SetLike for BTreeSet<i32> {
fn contains(&self, v: &i32) -> bool {
self.contains(v)
}
}
fn main() {
let s: &dyn SetLike = &BTreeSet::new();
assert!(!s.contains(&0));
}
(Playground )
Works fine, but these days clippy complains:
warning: parameter is only used in recursion
--> src/main.rs:8:24
|
8 | fn contains(&self, v: &i32) -> bool {
| ^ help: if this is intentional, prefix with an underscore: `_v`
|
Why? This is not recursion, just an implementation of a trait method .
I agree though it looks like recursion and an endless loop. Is there a neater way to write the example?
There's an issue for the false positive:
opened 05:51PM - 17 Mar 22 UTC
closed 04:29PM - 19 Aug 22 UTC
C-bug
I-false-positive
### Summary
Clippy seems to get confused about recursion when checking agains… t methods with the same name but which are resolved differently. If we define a trait and a struct with methods named identically and implement the trait on that struct clippy will sometimes believe that the implementation will perform recursion. In the case when the struct is defined in a different module than the trait, clippy will report a false-positive, and if they are defined in the same module, it will not report a warning (the correct behavior).
### Lint Name
only_used_in_recursion
### Reproducer
I tried this code:
```rust
//! Nightly Clippy False-Positive
/// Base Trait
trait Trait {
/// Target Method
fn method(&mut self, arg: usize);
}
/// Foreign Module
mod module {
/// Foreign Structure
pub struct Struct(pub usize);
impl Struct {
/// Implementation of Target Method
pub fn method(&mut self, arg: usize) {
self.0 += arg;
}
}
}
impl Trait for module::Struct {
/// Implementation of Trait Method using Target Method.
fn method(&mut self, arg: usize) {
self.method(arg);
}
}
fn main() {
let mut value = module::Struct(4);
Trait::method(&mut value, 3);
assert_eq!(value.0, 7);
}
```
I saw this happen:
```
warning: parameter is only used in recursion
--> src/main.rs:24:26
|
24 | fn method(&mut self, arg: usize) {
| ^^^ help: if this is intentional, prefix with an underscore: `_arg`
|
= note: `#[warn(clippy::only_used_in_recursion)]` on by default
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
```
I expected no warning since method resolution will find the `struct` method first. However, this false-positive only occurs when `Struct` comes from a module different from the module where `Trait` is defined.
With false-positive: https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=5091defb5bbd631f501cf0ee4b9ca634
Without false-positive: https://play.rust-lang.org/?version=nightly&mode=release&edition=2021&gist=681c30742b8253d9cc94a0c11faca36a
### Version
```text
rustc 1.61.0-nightly (461e80780 2022-03-16)
binary: rustc
commit-hash: 461e8078010433ff7de2db2aaae8a3cfb0847215
commit-date: 2022-03-16
host: x86_64-apple-darwin
release: 1.61.0-nightly
LLVM version: 14.0.0
```
### Additional Labels
_N/A_
3 Likes
Maybe it'd be better to desugar the method call, to make it explicit that this is the inherent method and not the trait method?
impl SetLike for BTreeSet<i32> {
fn contains(&self, v: &i32) -> bool {
BTreeSet::contains(self, v)
}
}
2 Likes
Cerber-Ursi:
desugar the method call
That does look neater, and it calms down clippy too.
That form avoids auto-deref, but it may still resolve to a trait method if there isn't one inherent.
2 Likes
True, though the compiler does tell you off with warning: function cannot return without recursing
, unless the default #[warn(unconditional_recursion)]
is disabled (and why would you?). And is there any alternative, apart from picking (somewhat awkward) unique names for the trait methods?
Unfortunately, I don't know any way to write a strictly inherent call. I could imagine this being something like <Self as Self>::contains
or fully <BTreeSet<i32> as BTreeSet<i32>>::contains
, but no:
error[E0576]: cannot find method or associated constant `contains` in `BTreeSet`
So that syntax is sort of accepted, but I'm guessing it's looking at that type like a trait.
1 Like
system
Closed
July 26, 2022, 6:07pm
8
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.