Today, I got confused by the following code:
use std::any::Any;
use std::sync::Arc;
fn foo(value: &Arc<dyn Any>) {
if (&**value).is::<i32>() {
println!("Passed value is an i32.");
}
if (&*value).is::<i32>() {
println!("Works also.");
}
if value.is::<i32>() {
println!("This too.");
}
if (&&&&value).is::<i32>() {
println!("That too.");
}
if <dyn Any>::is::<i32>(&**value) {
println!("Here it's more strict.");
}
if <dyn Any>::is::<i32>(&*value) {
println!("This won't happen."); // This is the only line which doesn't get executed.
}
}
fn main() {
let x: Arc<dyn Any> = Arc::new(1i32);
foo(&x);
}
Output:
Passed value is an i32.
Works also.
This too.
That too.
Here it's more strict.
My understanding is that the is
method is only implemented for dyn Any
and not for Any
. So when I write value.is::<i32>()
, then it cannot be executed on &Arc<dyn Any>
, and deref-coercion is performed twice? I can rely on that, I guess, because the receiver of a method isn't a coercion site?
However, the Rust reference states:
For method calls, the receiver (
self
parameter) can only take advantage of unsized coercions.
And going from T
to dyn U
is an unsized coercion. I guess that's what happens when I write <dyn Any>::is::<i32>
in regard to the function argument (e.g. &*value
).
I'm still confused. What does that cited sentence in the reference mean? How and when is the receiver "unsized coerced"?