# 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