reference icon indicating copy to clipboard operation
reference copied to clipboard

Missing precedence when several coercions are possible

Open JanBeh opened this issue 2 years ago • 1 comments

~~As transitive coercions are at least partially supported,~~ it currently doesn't seem to be clear which coercion(s) will be performed when there are several possibilities.

Consider the following code:

use std::ops::Deref;

struct A;
struct B;

impl Deref for A {
    type Target = B;
    fn deref(&self) -> &B {
        &B
    }
}

trait Trt {
    fn name(&self) -> &'static str;
}

impl Trt for A {
    fn name(&self) -> &'static str {
        "A"
    }
}

impl Trt for B {
    fn name(&self) -> &'static str {
        "B"
    }
}

impl dyn Trt {
    fn foo(&self) {
        println!("dyn {}", self.name());
    }
}

fn main() {
    let a = A;
    <dyn Trt>::foo(&a); // prints `dyn A`
     // but how can we deduce from the documentation that this doesn't happen internally?
    <dyn Trt>::foo(&a as &B as &dyn Trt);
}

(Playground)

See also this thread on URLO.

JanBeh avatar Nov 10 '22 20:11 JanBeh

Note that this isn't just an issue with transitive coercions; consider this example where two direct coercions are possible.

fn foo(value: &Arc<dyn Any>) {
    // Unsized coercion and deref coercion are both possible to go from
    // `&Arc<dyn Any>` to `&dyn Any`, but the results differ.
    assert!(<dyn Any>::is::<Arc<dyn Any>>( value as &dyn Any ));
    assert!(<dyn Any>::is::<i32>( <Arc<dyn Any> as Deref>::deref(value) ));

    // There's no documented precedence or other rules that I'm aware of to
    // indicate which actually occurs.
    if <dyn Any>::is::<Arc<dyn Any>>(value) {
        println!("Arc");
    }
    if <dyn Any>::is::<i32>(value) {
        println!("i32");
    }
}

QuineDot avatar Nov 11 '22 05:11 QuineDot