rustc_trait_selection::traits::dyn_compatibility

Function receiver_is_dispatchable

source
fn receiver_is_dispatchable<'tcx>(
    tcx: TyCtxt<'tcx>,
    method: AssocItem,
    receiver_ty: Ty<'tcx>,
) -> bool
Expand description

Checks the method’s receiver (the self argument) can be dispatched on when Self is a trait object. We require that DispatchableFromDyn be implemented for the receiver type in the following way:

  • let Receiver be the type of the self argument, i.e Self, &Self, Rc<Self>,

  • require the following bound:

    Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>

    where Foo[X => Y] means “the same type as Foo, but with X replaced with Y” (instantiation notation).

Some examples of receiver types and their required obligation:

  • &'a mut self requires &'a mut Self: DispatchFromDyn<&'a mut dyn Trait>,
  • self: Rc<Self> requires Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>,
  • self: Pin<Box<Self>> requires Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>.

The only case where the receiver is not dispatchable, but is still a valid receiver type (just not object-safe), is when there is more than one level of pointer indirection. E.g., self: &&Self, self: &Rc<Self>, self: Box<Box<Self>>. In these cases, there is no way, or at least no inexpensive way, to coerce the receiver from the version where Self = dyn Trait to the version where Self = T, where T is the unknown erased type contained by the trait object, because the object that needs to be coerced is behind a pointer.

In practice, we cannot use dyn Trait explicitly in the obligation because it would result in a new check that Trait is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). Instead, we fudge a little by introducing a new type parameter U such that Self: Unsize<U> and U: Trait + ?Sized, and use U in place of dyn Trait. Written as a chalk-style query:

forall (U: Trait + ?Sized) {
    if (Self: Unsize<U>) {
        Receiver: DispatchFromDyn<Receiver[Self => U]>
    }
}

for self: &'a mut Self, this means &'a mut Self: DispatchFromDyn<&'a mut U> for self: Rc<Self>, this means Rc<Self>: DispatchFromDyn<Rc<U>> for self: Pin<Box<Self>>, this means Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>