Skip to content

Omitting Clone bound on &impl Trait leads to correct but unhelpful error #121524

Closed

Description

Code

#[derive(Clone)]
struct ThingThatDoesAThing {}

trait DoesAThing {}

impl DoesAThing for ThingThatDoesAThing {}

fn clones_impl_ref_inline(thing: &impl DoesAThing) {
    drops_impl_owned(thing.clone());
}

fn drops_impl_owned(_thing: impl DoesAThing) { }

Current output

error[E0277]: the trait bound `&impl DoesAThing: DoesAThing` is not satisfied
  --> src/lib.rs:9:22
   |
9  |     drops_impl_owned(thing.clone());
   |     ---------------- ^^^^^^^^^^^^^ the trait `DoesAThing` is not implemented for `&impl DoesAThing`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `DoesAThing` is implemented for `ThingThatDoesAThing`
note: required by a bound in `drops_impl_owned`
  --> src/lib.rs:12:34
   |
12 | fn drops_impl_owned(_thing: impl DoesAThing) { }
   |                                  ^^^^^^^^^^ required by this bound in `drops_impl_owned`

Desired output

error[E0277]: the trait bound `&impl DoesAThing: DoesAThing` is not satisfied
  --> src/lib.rs:12:22
   |
 9 |     drops_impl_owned(thing.clone());
   |     ---------------- ^^^^^^^^^^^^^ the trait `DoesAThing` is not implemented for `&impl DoesAThing`
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `DoesAThing` is implemented for `ThingThatDoesAThing`
help: the type `&impl DoesAThing` does not implement `Clone`, so calling `clone` on `&impl DoesAThing` copies the reference, which does not do anything. Consider further restricting this bound
   |
 8 | fn clones_impl_ref_inline(thing: &impl DoesAThing + Clone) {
   |                                                      +++++++
note: required by a bound in `drops_impl_owned`
  --> src/lib.rs:33:34
   |
12 | fn drops_impl_owned(_thing: impl DoesAThing) { }
   |                                  ^^^^^^^^^^ required by this bound in `drops_impl_owned`

Rationale and extra context

The current error message does not guide the programmer to the correct solution, which is to add a Clone bound to the type constraints of the generic parameter.

Other cases

Moving the inline call to thing.clone() onto its own line improves the error, but it's still misleading:

fn clones_impl_ref_statement(thing: &impl DoesAThing) {
    let thing_clone = thing.clone();
    drops_impl_owned(thing_clone);
}
error[E0277]: the trait bound `&impl DoesAThing: DoesAThing` is not satisfied
  --> src/lib.rs:18:22
   |
18 |     drops_impl_owned(thing_clone);
   |                      ^^^^^^^^^^^ the trait `DoesAThing` is not implemented for `&impl DoesAThing`
   |
help: consider further restricting this bound
   |
16 | fn clones_impl_ref_statement(thing: &impl DoesAThing + Clone) {
   |                                                      +++++++
help: consider using clone here
   |
18 |     drops_impl_owned(thing_clone.clone());
   |                                 ++++++++

Removing the call to drops_impl_owned() allows compilation to proceed to the warning stage, which generates a warning that actually explains the problem (incorporated into Desired output, above):

fn clones_and_drops_impl_ref(thing: &impl DoesAThing) {
    let _ = thing.clone();
}
warning: call to `.clone()` on a reference in this situation does nothing
  --> src/lib.rs:23:18
   |
23 |     let _ = thing.clone();
   |                  ^^^^^^^^ help: remove this redundant call
   |
   = note: the type `impl DoesAThing` does not implement `Clone`, so calling `clone` on `&impl DoesAThing` copies the reference, which does not do anything and can be removed
   = note: `#[warn(noop_method_call)]` on by default

Rust Version

rustc 1.78.0-nightly (397937d81 2024-02-22)
binary: rustc
commit-hash: 397937d812852f9bbeb671005cb399dbcb357cde
commit-date: 2024-02-22
host: aarch64-apple-darwin
release: 1.78.0-nightly
LLVM version: 18.1.0

Anything else?

I've set up a minimal reproducer repo for each of the above cases at https://github.com/overhacked/impl-ref-reproducer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsD-confusingDiagnostics: Confusing error or lint that should be reworked.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueT-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