E0021 — dyn Trait object-safety violation
A trait used as dyn Trait declares a method that can’t be dispatched
through an erased trait-object receiver.
What triggers it
Two shapes are rejected:
- A method with no
selfreceiver — there’s no erased receiver value for adyn Traitcall to dispatch through. - A method that returns
Self— adyn Traitcaller has, by definition, erased the concrete type, so a method promising to hand back “the caller’s own concrete type” can’t be satisfied.
The check fires wherever dyn Trait appears — a fn parameter, fn
return type, let binding, or struct field — as soon as Trait names
a method with either shape, regardless of whether that specific method
is ever called through the trait object.
Minimal example
trait Factory {
fn make() -> int;
}
fn use_factory(dyn Factory f) -> int {
return 0;
}
Output:
scratch.rz:5:1: [E0021] `dyn Factory` is not object-safe: method `make` has no `self` receiver, so it cannot be dispatched through a `dyn Trait` value
trait Cloneable {
fn duplicate(self) -> Self;
}
fn use_cloneable(dyn Cloneable c) -> int {
return 0;
}
Output:
scratch.rz:5:1: [E0021] `dyn Cloneable` is not object-safe: method `duplicate` returns `Self`, which a `dyn Trait` caller cannot be given (the concrete type is erased)
Fix
Split the trait: keep the object-safe methods (those with a self
receiver and no Self-typed return) on the trait used as dyn Trait,
and move the non-object-safe methods to a separate trait or an inherent
method on the concrete type, called only where the concrete type is
statically known.
Source
Emitted from resilient/src/dyn_trait.rs’s object-safety pass, part of
the dyn Trait v2 work (issue #4095, increment 1). Vtable codegen,
dyn Trait in generic/container position, and flow-sensitive coercion
checking are tracked as follow-up increments on the same issue.