Why does Rust not automatically dereference arguments when calling methods with fully qualified syntax?

Why does Rust not automatically dereference arguments when calling methods with fully qualified syntax?

trait H {
    fn hello(&self) {}
}

impl H for i32 {
    fn hello(&self) {}
    
}


fn foo(a: &i32) {}

fn main() {
    let num: i32 = 20;

    foo(&&num);       
    H::hello(&&num);     // fail

    foo(&num);          
    H::hello(&num);      
    
}

See the coercion RFC:

These coercions occur when matching the type of the receiver of a method call with the self type (i.e., the type of e in e.m(...)) or in field access. These coercions can be thought of as a feature of the . operator, they do not apply when using the UFCS form with the self argument in argument position. Only an expression before the dot is coerced as a receiver. When using the UFCS form of method call, arguments are only coerced according to the expression coercion rules. This matches the rules for dispatch - dynamic dispatch only happens using the . operator, not the UFCS form.

4 Likes

Note that it will also fail when called explicitly with an i32 argument:

A::hello(num); // the trait bound `&i32: A` is not satisfied

This is because you are calling &self in the trait definition.

thanks

That's not fully qualified syntax. This is and this works:

<i32 as H>::hello(&&num);

As do these:

<i32>::hello(&&num);
i32::hello(&&num);

They work because it knows the implementing type, so it knows the implementation to look at, so it knows what the expected receiver is -- and can coerce to it if the rules allow it.

When you only use the trait in the path, it doesn't try to coerce the receiver type.

8 Likes