Skip to content

Diagnostics for cloning references are terrible #34896

Closed
@Manishearth

Description

@Manishearth
struct Foo;
fn main() {
    let x = Some(Foo);
    if let Some(ref y) = x {
        foo(y.clone());
    }
}

fn foo(x: Foo) {}

https://is.gd/f2AX0B

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.D-confusingDiagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions