In this example, function f compiles, but g does not. To make g compiles it's necessary to repeat the C definition bound. For function f this is not necessary. This seems to be an inconsistency.
trait A {
fn a(&self);
}
trait B where Self: A {
fn b(&self);
}
trait C where for<'a> &'a Self: A {
fn c(&self);
}
fn f<T>(x: &T) where T: B {
x.b();
x.a();
}
fn g<T>(x: &T) where T: C, /*for<'a> &'a T: A*/ { // uncomment to work
x.c();
x.a();
}
fn main() {}
<anon>:19:7: 19:10 error: the trait `for<'a> A` is not implemented for the type `&'a T` [E0277]
<anon>:19 x.c();
^~~
<anon>:20:7: 20:10 error: no method named `a` found for type `&T` in the current scope
<anon>:20 x.a();
^~~
<anon>:20:7: 20:10 help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `a`, perhaps you need to implement it:
<anon>:20:7: 20:10 help: candidate #1: `A`
error: aborting due to 2 previous errors
This is how supertraits work. not a bug.
Could you give me some references to understanding this behavior?
Supertraits: from the reference:
Trait bounds on
Selfare considered "supertraits". These are
required to be acyclic. Supertraits are somewhat different from other
constraints in that they affect what methods are available in the
vtable when the trait is used as a trait object.
The issue (elaboration) - this is part of the trait-system and mostly documented by the code comments. The thing is that we don't want too many bounds to be implicitly available for functions, as this can lead to fragility with distant changes causing functions to stop compiling. There are basically 3 kinds of bounds available to a function:
T: B when you have that clause. This includes the "semi-explicit" Sized bound.trait B: A, the T: B bound adds a T: A bound).If your bound isn't in the list, you will have to add it explicitly if you want to use it. I guess this should be a FAQ entry.
While the description of how bounds are added to a function makes sense, and is very useful, I'm still left with the question "why?"
If I have some trait C: B where <Self as B>::A: A {}, it seems that for any case where T: C could possibly be true, the other bounds would have to be true as well. Could that proof be added to the trait bounds resolver?
Most helpful comment
While the description of how bounds are added to a function makes sense, and is very useful, I'm still left with the question "why?"
If I have some
trait C: B where <Self as B>::A: A {}, it seems that for any case whereT: Ccould possibly be true, the other bounds would have to be true as well. Could that proof be added to the trait bounds resolver?