# the most `dyn` of traits
{%preview https://github.com/rust-lang/rust/issues/57893 %}
https://github.com/rust-lang/rust/issues/57893#issuecomment-2860064425
core constraints
- need to choose builtin candidate for methods, support `dyn Any`
- need to choose assoc types from impl, due to `<T as Trait>::Assoc` norm
doesn't matter what we do, need to detect overlap.
this must not care about trait object args:
- can't handle higher rankeds
- also, auto traits?
## what to do if there's overlap
- completely disable builtin impl if there's overlap and the trait has an assoc type/const
- ???? whatever,
## how to detct overlap
`fn overlap_with_builtin(dyn_trait_def_id, goal_trait_def_id, [auto_traits?]) -> bool`
- must be consistent between crates, all crates in the crate graph must agree whether the builtin impl is disabled
- it's otherwise always allowed to return "does overlap"
- if `dyn Trait` does not impl super trait via a builtin impl, it must also not impl `Trait` via builtin
- https://github.com/rust-lang/rust/pull/132289#issuecomment-2564492153
doing it outside the trait solver feels horrible :>
### how would we impl it via coherence
#### naive way
take `dyn Trait` with infer args check for overlap with user written impls
- what if there are quiery cycles when checking `overlap_with_builtin`
- does not handle cases where there is only overlap for `dyn for<'a> Trait<&'a ()>`. we need to detect overlap for that
####
```rust
// check for overlap of `dyn Trait` via this dummy impl
impl<T: !Sized> Trait for T {}
// this may overlap with the following :< but must not
// be considered to do so as there is no blanket impl
impl<T: NotImplemented + ?Sized> Trait for T {}
```
#### via typing mode
```rust
// check for overlap of `dyn Trait` via this dummy impl
impl<T: !Sized> Trait for dyn Trait<idk> {}
// this may overlap with the following :< but must not
// be considered to do so as there is no blanket impl
impl<T: NotImplemented + ?Sized> Trait for T {}
```
when assembling builtin candidates for a trait object, always bail with ambiguity
issue: explicit impls for trait objects can also be higher ranked. when looking at candidates which references a dyn?, always say MAYBE
ALWAYS DISABLE LEAK CHECK WITH THIS TYPING MODE, instead of using `trait_has_impl_which_may_shadow_dyn`, fail with ambiguity
- different auto traits
- arity of projections :>
alternative: change type relations + matches on `ty::Dyn` to not look at args iwth that typing mode
- keep leak check :>
### outside of coherence
{%preview https://github.com/rust-lang/rust/pull/132289 %}
`fn trait_has_impl_which_may_shadow_dyn`
when proving where-bounds of the blanket impl, we need to copy the is_knowable coherence check https://github.com/rust-lang/rust/pull/132289#issuecomment-2564587796
pretty much: if any where-bound of blanket impls has an unconstrained (or inside fundamental) arg, err
Alternative: just always error impls with object types as self-type as foreign
#### 3rd repro: https://github.com/rust-lang/rust/pull/132289#issuecomment-2564599221
Adding a downstream impl with a normalizeable alias as the self type, must not disable the upstream builtin impl
### rarw uwu design proposal
> alternative: change type relations + matches on `ty::Dyn` to not look at args iwth that typing mode
> - keep leak check :>
do we always want to disable all impls, or maybe allow super trait but disable sub trait.
IMPORTANT: force encode cross crate. Coherence may return "may overlap" in downstream but not root.
## SO FUCKING UWU
actually, prefering methods over user impls is certainly unsound https://github.com/rust-lang/rust/issues/57893#issuecomment-2860064425
So, we've got a good reason to just entirely forbid this
### how to continue supporting `dyn Any`
add intrinsic
```rust
fn vtable_ref<T, R>(this: &T, f: F, fallback: impl FnOnce(&T) -> R) -> R;
fn vtable_mut<T, R>(this: &mut T, f: F, fallback: impl FnOnce(&mut T) -> R) -> R;
```
```rust
trait Any: 'static {}
impl<T: ?Sized + 'static> Any for T {
fn type_id(&self) -> TypeId {
vtable_ref(self, <dyn Any as Any>::type_id, |_| {
TypeId::of::<T>()
})
}
}
```
```rust
trait Trait<T> {}
// downstream
struct Local;
impl Trait<Local> for dyn Trait<Local> {}
```
### how to deal with breakage
- future compat lint traits with blanket impls which overlap. We can lint on the overlapping impl
---
- silently preferring user impl seems very ass for `Any`. Very surprising and hard to lint at usage site.
- can we hard error on overlap? probably not, affects too many impls, e.g. `ToString`, `TryFuture`, and much more
Given an attribute to crate authors to explicitly opt out of emitting a builtin impl. The attribute replaces the check
Without the attribute:
- edition curr, future compat warn deps
- edition next, hard error on trait definition