-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trait inheritance for bounded type parameters #4070
Conversation
Does this work? If not, is it planned to work eventually?
|
@bstrie No, it does not work - each trait must have it's own impl. I think it should work, but with different syntax to make it clear that you are implementing multiple traits. Maybe something like this:
|
I'd like to hold off on the proposed implement-multiple-traits-at-a-time syntax; it adds complexity and I'm not sure we need it (Haskell does not have it, for example). |
From the traits paper I was under the impression that implementing a given trait made it your responsibility to implement all methods of that trait (sans defaulted methods), regardless of whether those methods belonged directly to the trait or whether they were inherited from supertraits. Is this incorrect, or is Rust just going with a different design? |
In fact my example managed to accidentally reproduce this test case exactly: https://github.com/mozilla/rust/blob/master/src/test/run-pass/trait-inheritance-simple.rs |
Or perhaps not exactly reproduce, since the bound is on the parent trait rather than the child trait. |
@bstrie: That test case is rewritten in this patch to use multiple impls |
So I haven't read the traits paper, but what we have is probably different, since our traits are type classes. /me reading now |
r=me |
Inheritance will be implemented differently, hopefully simpler
Automatic Rustup
r? @pcwalton
This makes trait inheritance work for lots of test cases involving bounded type parameters, type substitutions and static methods.
Here's one with type substitutions: https://github.com/brson/rust/blob/39dbf4fe74925b1c238c8bc82911e85fd91c3d0b/src/test/run-pass/trait-inheritance-overloading.rs
And one with static methods: https://github.com/brson/rust/blob/39dbf4fe74925b1c238c8bc82911e85fd91c3d0b/src/test/run-pass/trait-inheritance-static2.rs
The basic strategy it uses is to expand bound lists to include their supertraits, in
<T: B>
is treated in the internal vtable calculations as<T: B A>
. This is made easier and more obvious by the limitation that each impl implements a single trait, not that trait and its supertraits.This limitation makes the implementation straightforword and has no new implications for coherence.
trait B: A
just means that to instantiate B there must also be an impl of A. The trait inheritance list has strong parallels to the bounded typaram list.I still don't understand type substitutions and why
lookup_vtables
andpush_inherent_candidates_for_param
do their substitutions differently. You can see thatpush_inherent_candidates_for_param
is the only code that does the trait hierarchy traversal that doesn't use the newiter_bound_traits_and_supertraits
code because it needs to thread substitutions through. I could keep going and try to abstractiter_bound_traits_and_supertraits
into a generic fold but I figure now is the time to get review and see if this is looking ok.Future work:
impl S: B { }
there should also be animpl S: A { }
somewhere. This isn't required for soundness since the lack of A will be detected when somebody tries to actually useS
asA
, but it makes sense to enforce.