What is the relation between auto-dereferencing and deref coercion?

The parallels between the two cases are rather superficial.

In a method call expression, the compiler first needs to determine which method to call. This decision is based on the type of the receiver. The compiler builds a list of candidate receiver types, which include all types obtained by repeatedly derefencing the receiver, but also &T and &mut T for all types T encountered. This is the reason why you can call a method receiving &mut self directly as x.foo() instead of having to write (&mut x).foo(). For each type in the candidate list, the compiler then looks up inherent methods and methods on visible traits. See the language reference for further details.

A deref coercion is rather different. It only occurs at a coercion site where the compiler exactly knows what type to expect. If the actual type encountered is different from the expected type, the compiler can use any coercion, including a deref coercion, to convert the actual type to the expected type. The list of possible coercions includes unsized coercions, pointer weakening and deref coercions. See the the chapter on coercions in the Nomicon for further details.

So these are really two quite different mechanisms – one for finding the right method, and one for converting types when it is already known what type exactly to expect. The first mechanism also automatically references the receiver, which can never happen in a coercion.

I thought that a dereference does not always involve deref coercion, but I’m not sure: does dereferencing always use some Deref::deref trait implementation?

Not every dereferencing is a deref coercion. If you write *x, you explicitly dereference x. A deref coercion in contrast is performed implicitly by the compiler, and only in places where the compiler knows the expected type.

The semantics of dereferencing depend on whether the type of x is a pointer type, i.e. a reference or a raw pointer, or not. For pointer types, *x denotes the object x points to, while for other types *x is equivalent to *Deref::deref(&x) (or the mutable anlogue of this).

If so, is the implementor of T: Deref<Target = U> where T: &U built into the compiler?

I’m not quite sure what your syntax is supposed to mean – it’s certainly not valid Rust syntax – but I guess you are asking whether derefencing an instance of &T to T is built into the compiler. As mentioned above, dereferencing of pointer types, including references, is built into the compiler, but there is also a blanket implementation of Deref for &T in the standard library. This blanket implementation is useful for generic code – the trait bound T: Deref<Target = U> otherwise wouldn’t allow for T = &U.

Leave a Comment