-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Description
pub trait Marker<'a> {}
pub trait Trait where for<'a> &'a Self: Marker<'a> {
fn usable(&self) {}
}
impl<'a> Marker<'a> for &'a () {}
impl Trait for () {}
pub fn f() {
// `(): Trait`
let u = ();
u.usable();
// `dyn Trait` exists and `()` can coerce to it...
let _t: &dyn Trait = &();
// But `dyn Trait: !Trait`
// _t.usable();
// error[E0277]: the trait bound `for<'a> &'a T: Marker<'a>` is not satisfied
}I expected to see this happen: The unsized coercion is denied (but see discussion below).
Instead, this happened: The unsized coercion happened and we end up with a dyn Trait which does not implement Trait.
Meta
This works on any stable version of Rust.
Notes
The failure to meet the trait bound is caught when you actually try to use the dyn Trait, at least trivially. I haven't found a way to weaponize this, but I haven't put any effort into doing so either.
dyn Trait implements Trait if you impl<'a> Marker<'a> for &'a (dyn Trait + 'static) {} in the example. However, the non-super-trait bound need not be a marker trait (it can have non-defaulted methods).
Related: Implied Bounds, #20671
Discussion
I'm filing this as a bug because the assertion that dyn Trait: Trait always holds has been expressed as a belief by Rust team members, e.g.
There are some possibilities in line with this assertion:
- Unsized coercion checks the bounds and is denied in this case
- Bounds that aren't super-traits make a trait object unsafe generally
- Bounds that aren't super-traits don't apply to
dyn Trait
However, another possibility is to generalize RFC 2027 and just accept the current behavior:
dyn Traitis always a valid type, as per RFC 2027- Unsized coercion is still dependent on all methods being either object safe or not applicable (
where Self: Sized)- Though this could be relaxed too (if you're not object safe,
dyn Traitjust doesn't implementTrait)
- Though this could be relaxed too (if you're not object safe,
- If unsized coercion is possible, you can instantiate a
dyn Trait, even if it doesn't implementTrait - Naturally, you can't use the
Traitmethods if it doesn't implementTrait
I'm sure there are a lot of subtleties and backwards-compatibility concerns in any of the possible approaches.