Repository navigation
Diagnostics for cloning references are terrible #34896
Description
struct Foo;
fn main() {
let x = Some(Foo);
if let Some(ref y) = x {
foo(y.clone());
}
}
fn foo(x: Foo) {}This gives the very unintuitive error:
error: mismatched types [--explain E0308]
--> <anon>:5:13
5 |> foo(y.clone());
|> ^^^^^^^^^ expected struct `Foo`, found &-ptr
note: expected type `Foo`
note: found type `&Foo`
You expect y.clone() to return (*y).clone(), i.e. a Foo. It mysteriously returns an &Foo instead.
Because &T has a clone impl, it too, can be cloned (really, copied), returning a reference of the same lifetime. This is an operation you rarely want to do explicitly, except when dealing with generics.
This error can crop up when you've forgotten to implement Clone on Foo, and have a reference (which could have been silently inserted using ref, as in the code above). However, it's not very obvious what's happening here. It can also crop up if you forget a T: Clone bound
We should hint that Foo itself isn't cloneable and thus we fell back to cloning &Foo here.
This could be a lint on hitting the clone impl for references, but lints run too late.
I'm not sure how this can be implemented, since we need to see the source of a value and that's a bit tricky.
Activity
Manishearth commentedon Jul 18, 2016
cc @nikomatsakis @jonathandturner
[-]Diagnostics for cloning references is terrible[/-][+]Diagnostics for cloning references are terrible[/+]nikomatsakis commentedon Jul 18, 2016
Interesting. This does seem like it would require some pretty special-case code to achieve, but I agree it'd be a nice case to capture.
Manishearth commentedon Jul 19, 2016
A relatively easy way to catch most instances of this is to
<&T as Clone>::cloneThis will miss things, but I think the majority of such bugs will be due to this. As it stands this feels like an incredibly easy case to hit (we've all forgotten to decorate structs).
antoyo commentedon Aug 18, 2017
cc @GuillaumeGomez
estebank commentedon Jan 2, 2019
CC #34629
estebank commentedon May 17, 2019
As reported in #60875:
This reports:
estebank commentedon Jan 25, 2020
Current output is even worse for the original report:
The last comment's code is marginally different:
estebank commentedon Dec 14, 2022
Current output:
The last case should suggest constraining
T: Clone.Edit: that was easier than I thought (we already had the suggestion machinery):
Suggest constraining type parameter with `Clone`
Rollup merge of rust-lang#105679 - estebank:suggest-clone, r=compiler…
Rollup merge of rust-lang#105679 - estebank:suggest-clone, r=compiler…
Rollup merge of rust-lang#105679 - estebank:suggest-clone, r=compiler…
Suggest constraining type parameter with `Clone`
Rollup merge of rust-lang#105679 - estebank:suggest-clone, r=compiler…