+/// 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`"
+/// (substitution 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 object safe, creating a cycle (until object_safe_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>>>`
+//
+// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
+// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
+// `self: Wrapper<Self>`.
+#[allow(dead_code)]
+fn receiver_is_dispatchable<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ method: &ty::AssocItem,
+ receiver_ty: Ty<'tcx>,
+) -> bool {
+ debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
+
+ let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
+ let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
+ (u, cu)
+ } else {
+ debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+ return false;
+ };
+
+ // the type `U` in the query
+ // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
+ // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
+ // replace this with `dyn Trait`
+ let unsized_self_ty: Ty<'tcx> =
+ tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome"));
+
+ // `Receiver[Self => U]`
+ let unsized_receiver_ty =
+ receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
+
+ // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
+ // `U: ?Sized` is already implied here
+ let param_env = {
+ let mut param_env = tcx.param_env(method.def_id);
+
+ // Self: Unsize<U>
+ let unsize_predicate = ty::TraitRef {
+ def_id: unsize_did,
+ substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
+ }
+ .to_predicate();
+
+ // U: Trait<Arg1, ..., ArgN>
+ let trait_predicate = {
+ let substs =
+ InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+ if param.index == 0 {
+ unsized_self_ty.into()
+ } else {
+ tcx.mk_param_from_def(param)
+ }
+ });