So, this is due to method resolution. The type &Team
is not the receiver type for any existing method called "clone", because Team
does not implement Clone
and there's no other trait or direct impl
offering a method with this name either (note that Clone::clone
is a &self
method, so that a Clone for Foo
implementation gives rise to a clone
method with receiver type &Foo
, not Foo
, and it is this receiver type that method resolution is concerned with).
See this reference page for more details on the way the compiler performs method resolution.
Since &Team
has no clone
method, the compiler keeps searching for more alternative receiver types, as listed in the reference linked above, which can be obtained via implicit automatic referencing and dereferencing. In particular, for any type T
of an expression EXP
, when resolving a method call EXP.foo()
, also the receiver types &T
and &mut T
are considered, which makes &self
and &mut self
methods still convenient to call even on owned values. This step is sometimes called automatic referencing. Automatic dereferencing does not come into play in these code examples, it would be a subsequent step of the automatic referencing does not find any suitable receiver type either.
In this case, after &Team
, the compiler thus considers &&Team
next, and does find a clone
implementation (due to &T
implementing Copy
and Clone
genetically for all types T
, and the &self
receiver type of this Clone::clone
implementation is therefore &&T
which matches our type at hand, &&Team
). The call x2.clone()
thus ultimately desugars to Clone::clone(&x2)
.
And there you have the double reference that Clippy is linting against, &x2
is of type &&Team
. That being said, it looks like the lint designers didn't consider this case very well either, as the actual lint message is hard to understand and contains fairly useless automatic suggestions (at least the first suggestion seems to be unaware of the automatic referencing) as "help"
error: using `clone` on a double-reference; this will copy the reference of type `&Team` instead of cloning the inner type
--> src/main.rs:10:26
|
10 | let result2: &Team = x2.clone(); // clone A warning appears
| ^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
= note: `#[deny(clippy::clone_double_ref)]` on by default
help: try dereferencing it
|
10 | let result2: &Team = &(*x2).clone(); // clone A warning appears
| ~~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
|
10 | let result2: &Team = <&Team>::clone(x2); // clone A warning appears
| ~~~~~~~~~~~~~~~~~~
For the example involving String
since String
does implement Clone
, when resolving x1.clone()
the type &String
, which is the type of x1
, already has a clone
method. The same kind of thing happens if you were to add derive(Clone)
to Team
.