Auto-generate crate-agnostic anonoymous sub-traits for `dyn Foo + ...`

Then this is not a problem that we're introducing (which I was scared would set this back), it is actually a known issue. I don't know if this is viable, but I propose having inside rustc a thread-safe data structure (like dashmap) that allows us to register generated vtables and save their addresses; before generating a vtable we just have to lookup it to see if it's already generated, elsewhere we mark an atomic flag to indicate that it's being generated and then we just store the address of the generated trait.

Iā€™m confused by the simultaneous high and low level of detail in this proposal discussion. Iā€™m not even sure yet whether or not dyn Foo + Bar is supposed to be the same as dyn Bar + Foo, yet the discussion dives deep into specifics of vtables across crates.

Yes, it is supposed to be the same, the compiler has to deal with it so that it is always the same, even across crates; I thought that was implied when we were talking about codegen determinism.

Okay, two follow-up questions:

  • dyn Foo + Foo vs dyn Foo?

  • Support for upcasting of dyn A + B + C + D + E + F to something like dyn A + C + E (and all the other ā‰ˆ2n combinations)?

My understanding is that this is impossible in general, IIRC things like shared libraries on Windows specifically cause issues. But it doesn't really matter, there's no ODR requirement so whether they're duplicated or not they work fine.

There's no issue that needs fixing, this is just a known limitation of Rust vtables, you can't directly compare two &dyn X for equality because their vtables may or may not have been merged.

The thing that needs to be deterministic is things like the order the supertraits are stored in the combined vtable. This doesn't seem like it would be hard to me either, there are things stored in the metadata that I assume can be used to sort dyn ::a::A + ::b::B and dyn ::b::B + ::a::A into the same order even if they're being used in different crates.

In my mind the most logical thing is to remove duplicated trait bounds. We could also issue a warning or even an error.

I've said multiple times that I am not 100% sure about this one, but because the type is unknown at compile-time, it is not possible to generate another vtable for the target traits and just overwrite the pointers. Thus, I don't think that upcasting is possible.

Thanks for the answers :slight_smile:

Sorry if I have missed an existing point of discussion about the latter question; maybe I missed it when skipping over the side-discussion of super fat pointers. My goal is just to get a better understanding of what kind of feature you have in mind.


With rules like dyn Foo + Bar being the same as dyn Bar + Foo, this does feel relatively similar to union types in many ways; I havenā€™t thought about those in a while, but some issues might transfer from those. E.g. Iā€™m specifically considering the case dyn Foo<'a> + Foo<'b> now, and thinking it would probably need to be able with only a single vtable and representation identical to dyn Foo<'c>. Especially as soon as dyn Foo<'a> + Foo<'b> must be the same as dyn Foo<'b> + Foo<'a> and/or dyn Foo<'c> + Foo<'c> the same as dyn Foo<'c>.

(Iā€™ve also tested how the compiler currently handles a trait FooFoo<'a, 'b>: Foo<'a> + Foo<'b> and ā€¦ well ā€¦ itā€™s ā€œfunā€ as soon as you start calling methods (looks like it loves falling back to the second one of the two? [I havenā€™t saved the playgroundā€¦]))

1 Like

I appreciate it, thanks. The goal of this is to create a way to interface dyn types with multiple traits between crates transparenty, because if every create has their own sub-trait, it can become a mess very quickly.

The lifetimes mess is so cursed lol... What would you do moving forward?

Apt description. Anywaysā€¦ my point was that, at least for the concrete case dyn Foo<'a> + Foo<'b>, as lifetimes donā€™t influence program behavior, having only a single vtable should be viable ā€“ i.e. the Foo<'a> and Foo<'b> implementation (would come from the same impl and) would have identical vtables to begin with. I.e. it might just about work.

Iā€™ll probably re-think about union types another day (itā€™s quite late on my end) and if any issues that also apply to this feature come to mind, Iā€™ll make sure to comment them here, too :slight_smile:

Thank you. As you were saying, lifetimes are an illusion, so at codegen time we can get away merging all same traits with different lifetimes.

Have a good night, I'm also going offline.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.