Arc::clone(&s) vs s.clone() and trait object dyn SomeTrait


I recently came across something i don't understand while using Arc<dyn SomeTrait> in my code.

Here is a minimal piece of code that reproduce the exact same conditions, with the error given by the compiler in comment:

use std::sync::Arc;

trait A {
    fn a(&self) -> bool;

struct S<T> {
    t: T,

impl<T> S<T> {
    pub fn new(t: T) -> Self {
        Self { t: t }

impl<T> A for S<T> {
    fn a(&self) -> bool {

type AArc = Arc<dyn A + Send + Sync>;

struct Coll {
    c: Vec<AArc>,

impl Coll {
    pub fn new() -> Self {
        Self { c: vec![] }
    pub fn add(&mut self, c: AArc) {

fn main() {
    let mut c = Coll::new();
    let s = Arc::new(S::new(0));

    error[E0308]: mismatched types
    36 |         c.add(Arc::clone(&s));
       |                          ^^ expected trait object `dyn A`, found struct `S`
       = note: expected reference `&Arc<dyn A + Send + Sync>`
                  found reference `&Arc<S<{integer}>>`

    error: aborting due to previous error

    For more information about this error, try `rustc --explain E0308`.

    // this is ok

    println!("{:?}", s);

The error happen when using Arc::clone(&s) but not when using s.clone().

The question is: why is that? :sweat_smile:


I think this is some interaction between method call resolution, trait impl resolution, and coercion. In this version:


I believe the compiler is going to go figure out the method call first, and decide it must be Arc<S<_>>::clone, and the result of that is an Arc<S<_>>. Then it coerces that into the Arc<dyn ...>.

But in this version:


There is no method call resolution. And my guess is that

  • Since the type of the argument is known (Arc<dyn ...>)
  • This influences the trait impl resolution for Clone to find Arc::<dyn ...> as Clone
  • And it can't coerce behind the & in the call to clone
  • And hence the error
    • The message finds one way that this could have worked: s was a dyn ...

These both compile:

    // No pre-ascribed type to influence which `Clone` impl to use
    let t = Arc::clone(&s);
    // Just be explicit about which `Clone` impl to use

I don't know how feasible it would be to improve the error reporting to point out either of these work-arounds.


It also works with an inferred type cast:

    c.add(Arc::clone(&s) as _);

Ah, nice. I guess the as _ "throws out" the argument context, and everything proceeds as in the temporary variable case.

See also.

1 Like

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.