Dyn Compatible
(Jin Qing’s Column, April., 2025)
A dyn-compatible trait can be the base trait of a trait object.
A trait is dyn compatible if it has the following qualities (see reference):
- All supertraits must also be dyn compatible.
- Sized must not be a supertrait. In other words, it must not require Self: Sized.
- It must not have any associated constants.
- It must not have any associated types with generics.
- All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable.
- The AsyncFn, AsyncFnMut, and AsyncFnOnce traits are not dyn-compatible.
These ways of violation are defined in enum DynCompatibilityViolation:
pub enum DynCompatibilityViolation {
/// `Self: Sized` declared on the trait.
SizedSelf(SmallVec<[Span; 1]>),
/// Supertrait reference references `Self` an in illegal location
/// (e.g., `trait Foo : Bar<Self>`).
SupertraitSelf(SmallVec<[Span; 1]>),
// Supertrait has a non-lifetime `for<T>` binder.
SupertraitNonLifetimeBinder(SmallVec<[Span; 1]>),
/// Method has something illegal.
Method(Symbol, MethodViolationCode, Span),
/// Associated const.
AssocConst(Symbol, Span),
/// GAT
GAT(Symbol, Span),
}
MethodViolationCode is:
/// Reasons a method might not be dyn-compatible.
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum MethodViolationCode {
/// e.g., `fn foo()`
StaticMethod(Option<(/* add &self */ (String, Span), /* add Self: Sized */ (String, Span))>),
/// e.g., `fn foo(&self, x: Self)`
ReferencesSelfInput(Option<Span>),
/// e.g., `fn foo(&self) -> Self`
ReferencesSelfOutput,
/// e.g., `fn foo(&self) -> impl Sized`
ReferencesImplTraitInTrait(Span),
/// e.g., `async fn foo(&self)`
AsyncFn,
/// e.g., `fn foo(&self) where Self: Clone`
WhereClauseReferencesSelf,
/// e.g., `fn foo<A>()`
Generic,
/// the method's receiver (`self` argument) can't be dispatched on
UndispatchableReceiver(Option<Span>),
}