Method calling and Derefing to a trait

I am a little bit confused by Deref and method call matching.

The Rust book says:

When the Deref trait is defined for the types involved, Rust will
analyze the types and use Deref::deref as many times as necessary to
get a reference to match the parameter’s type. The number of times
that Deref::deref needs to be inserted is resolved at compile time, so
there is no runtime penalty for taking advantage of deref coercion!

Seems fine, but then I am confused by this code:

fn any<T:Fred>(t:T){

}

trait Fred {
}

impl Fred for i64{}

fn main(){
    let b = Box::new(10);
    let c = &b;
    any(10);
    any(*b);
    any(**c);
    any(*Box::new(10));

    any(b);
    any(c);
}

playground

We can call the any method with and only with 10. My attempts to
use the Box number fail, unless I explicitly deref the Box. Why is
Rust not performing the deref for me, so that the trait bound matches?

And is there a way to get this to work? To have rust call a method
with a boxed or unboxed object without lots of deref'ing?

Your any is not a method, it is just a generic function. This works:

trait Fred {
    fn any(self);
}

impl Fred for i64{
    fn any(self){
    }
}

fn main(){
    let b = Box::new(10i64);
    let c = &b;
    10i64.any();
    (*b).any();
    (**c).any();
    Box::new(10i64).any();

    b.any();
    c.any();
    (*c).any();
}

Other than that, it's unclear what your code wants to do. You defined any only for i64, but you're trying to call it with Boxes... expecting Deref to kick in and create references? If it did, &i64 doesn't implement Fred, so the call would be invalid.

Deref is used to create references from other things which act like references. Your Fred isn't implemented for any references, so Deref should never be invoked for the argument to any, as it only takes Freds.

If we fix that problem, we get something like the following:

fn any<T: Fred>(_t:&T) {
}

trait Fred {}
impl Fred for i64 {}

fn main() {
    let b = Box::new(10i64);
    any::<i64>(&b)
}

Note that if you try to call it like any(&b), we get a problem because it's not clear which possible version of any we should be deref coercing into. Just because a deref coercion would make the call valid, doesn't mean it should, because somebody could have made any take a boxed value by implementing Fred appropriately. By invoking the turbofish ::<>, we tell the compiler that there is only one any that should ever by invoked here, and so deref coercion can be employed without any guessing.

Tl;dr, there's two thing here:

  • deref coercions only work for values of type &T and &mut T, in order to obtain &U or &mut U. They will never coerce anything that isn't hidden behind a reference.
  • (if you try, you'll find it works for self.method() syntax. That's due to another feature often called "auto-ref")
  • dereference coercions never apply to a free function argument (i.e. an argument that isn't the method reciever) of generic type T. The argument type in the signature must be concrete enough for the compiler to precisely deduce the coercion that must occur without looking at trait impls (e.g. a &Vec<i32> can be given to an argument that needs &[T] for a generic parameter T, but the same is not true for an argument that needs &T.)

@ExpHP Yeah, of course, you are right. I reimplemented this as a method of Fred and it all works.