Skip to content

*x == *y for trait objects produce move error, so it is not equivalent to PartialEq::eq(&*x, &*y) even though the reference says it is #127215

Open
@estebank

Description

@estebank
Contributor

The following code produces a move error:

trait Animal {
    fn noise(&self) -> String;
}

impl PartialEq for dyn Animal {
    fn eq(&self, other: &Self) -> bool {
        self.noise() == other.noise()
    }
}

fn f(a1: &Box<dyn Animal>, a2: &Box<dyn Animal>) {
    println!("{}", *a1 == *a2); // doesn't work
}
error[E0507]: cannot move out of `*a2` which is behind a shared reference
  --> src/lib.rs:12:27
   |
12 |     println!("{}", *a1 == *a2); // doesn't work
   |                           ^^^ move occurs because `*a2` has type `Box<dyn Animal>`, which does not implement the `Copy` trait

But according to the reference, it should be equivalent to the following, which does work:

fn f(a1: &Box<dyn Animal>, a2: &Box<dyn Animal>) {
    println!("{}", PartialEq::eq(&*a1, &*a2)); // works
}

It seems to be specific to trait objects; e.g. replacing Box<dyn Animal> with Box<[String]> will make both versions of f compile.

Originally reported in #123056 (comment)

Activity

added
A-diagnosticsArea: Messages for errors, warnings, and lints
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
A-docsArea: Documentation for any part of the project, including the compiler, standard library, and tools
A-dyn-traitArea: trait objects, vtable layout
on Jul 1, 2024
eggyal

eggyal commented on Jul 2, 2024

@eggyal
Contributor

Interestingly it works if the arguments to f are Box<dyn Animal> or &dyn Animal rather than &Box<dyn Animal>.

finnbear

finnbear commented on Aug 11, 2024

@finnbear
Contributor

Same issue occurs if the container, in this case RcPtrEq, implements PartialEq independently of the dyn trait object:

#![feature(coerce_unsized)]
#![feature(unsize)]

use std::rc::Rc;
use std::marker::Unsize;
use std::ops::{CoerceUnsized};

pub fn main() {
    //#[derive(PartialEq)]
    struct Foo {
        field: RcPtrEq<dyn Fn()>,
    }
    
    // Doesn't compile.
    #[automatically_derived]
    impl ::core::cmp::PartialEq for Foo {
        #[inline]
        // error[E0507]: cannot move out of `other.field` which is behind a shared reference
        fn eq(&self, other: &Foo) -> bool { self.field == other.field }
    }
    
    // Works.
    /*
    impl PartialEq for Foo {
        #[inline]
        fn eq(&self, other: &Foo) -> bool { PartialEq::eq(&self.field, &other.field) }
    }
    */
}

pub struct RcPtrEq<T: ?Sized>(Rc<T>);

impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RcPtrEq<U>> for RcPtrEq<T> {}

impl<T: ?Sized> PartialEq for RcPtrEq<T> {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.0, &other.0)
    }
}

Playground link

Strangely, removing CoercedUnized makes it compile.

Artikae

Artikae commented on Sep 12, 2024

@Artikae

This also breaks the PartialEq derive macro when used on structs.

use std::rc::Rc;
trait Trait {}
impl PartialEq for dyn Trait {
    fn eq(&self, _: &Self) -> bool { todo!() }
}
#[derive(PartialEq)]
struct User(Rc<dyn Trait>);

Playground link

SaltyKitkat

SaltyKitkat commented on Oct 31, 2024

@SaltyKitkat
Contributor

This also breaks the PartialEq derive macro when used on structs.

use std::rc::Rc;
trait Trait {}
impl PartialEq for dyn Trait {
fn eq(&self, _: &Self) -> bool { todo!() }
}
#[derive(PartialEq)]
struct User(Rc);
Playground link

I met this problem. It's quite annoying for me since I cannot use PartialEq derive macro.

So is there any progress on this recently?

QuineDot

QuineDot commented on Dec 31, 2024

@QuineDot

An earlier duplicate:

#31740

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-borrow-checkerArea: The borrow checkerA-diagnosticsArea: Messages for errors, warnings, and lintsA-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsA-dyn-traitArea: trait objects, vtable layoutC-bugCategory: This is a bug.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

        Participants

        @estebank@eggyal@Artikae@finnbear@SaltyKitkat

        Issue actions

          `*x == *y` for trait objects produce move error, so it is not equivalent to `PartialEq::eq(&*x, &*y)` even though the reference says it is · Issue #127215 · rust-lang/rust