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 theself
argument, i.eSelf
,&Self
,Rc<Self>
, -
require the following bound:
ⓘReceiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
where
Foo[X => Y]
means “the same type asFoo
, but withX
replaced withY
” (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>
requiresRc<Self>: DispatchFromDyn<Rc<dyn Trait>>
,self: Pin<Box<Self>>
requiresPin<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>>>