Open CAD97 opened 2 years ago
The only trait bounds that are implied ("elaborated" in rustc terminology) are supertrait bounds or Self: Trait
bounds, so I'm not sure if this is right to be considered a bug.
I agree that this veers close to being a new feature rather than a bug. However, since where Self: Trait
bounds are implied/elaborated, I personally think the same should be true of all where
bounds on the trait itself.
And as I just found out, nightly trait aliases do provide elaborated bounds for non-Self
bounds in their where
:
#![feature(trait_alias)]
pub trait Trait {}
pub trait WithAssoc {
type Assoc;
}
pub trait WithBoundAssoc = WithAssoc where <Self as WithAssoc>::Assoc: Trait;
// pub trait WithBoundAssoc: WithAssoc where Self::Assoc: Trait {}
pub struct S<T: WithBoundAssoc>(T::Assoc);
Obviously I think the trait alias behavior is more intuitive.
This might unfortunately be technically a breaking change to the language, though, since because the where
is not elaborated currently, it's technically not a breaking library change to remove a (non-Self
) where
bound from a trait
declaration.
@rustbot label +C-feature-request
I wonder if that trait alias example is a bug, lol. Or, at least, I'm not exactly sure if we should be treating where clauses on trait aliases as supertraits :thinking:
IIUC, where
clauses are deliberately elaborated for trait aliases, because IIRC the intent is that writing <T: TraitAlias>
should be equivalent to inlining the trait alias (i.e. writing the supertrait and where
bounds out explicitly).
Makes sense.
I believe this basically is a subset of the more general idea of implied bounds. Adding a bit more context,
I don't know what the proper thing is to do with this issue at this point.
After some search I found this issue is actually aged, which can be traced back to 2015.
This is how supertraits work. not a bug. 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.
However, the issue author is not convinced. His comment has received 8 👍🏼s including me.
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
::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?
There is a related question on Stack Overflow. Eric Langlois gives a workaround using a helper trait.
On the other hand, this issue spawned https://github.com/rust-lang/reference/issues/504 for documenting this behavior. But until now no one has actually written the doc.
Unfortunately where clauses are not, in general, implied like this. Only bounds that concern the trait's Self type are implied.
While it's possible to satisfy some user's requirements using trait alias, I agree with @CAD97 that it is a subset of implied bounds, and should be implied without explicitly writing where <T as WithAssoc>::Assoc: Trait
in the end.
I think this is actually a duplicate of #20671 as well; that thread mentions the same workaround too.
I just ran into this, unfortunately with GATs this time. Unfortunately the workaround doesn't seem to work with GATs for some reason (Playground):
pub trait Trait {}
pub trait WithAssoc {
type Assoc<'a>;
}
pub trait WithBoundAssoc: for<'a> WithAssoc<Assoc<'a> = Self::__Assoc<'a>> {
type __Assoc<'a>: Trait;
}
impl<T: WithAssoc> WithBoundAssoc for T
where
for<'a> Self::Assoc<'a>: Trait,
{
type __Assoc<'a> = Self::Assoc<'a>;
}
error[E0275]: overflow evaluating the requirement `Self: WithBoundAssoc`
--> src/lib.rs:7:1
|
7 | pub trait WithBoundAssoc: for<'a> WithAssoc<Assoc<'a> = Self::__Assoc<'a>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`playground`)
note: required for `Self` to implement `WithBoundAssoc`
--> src/lib.rs:11:20
|
11 | impl<T: WithAssoc> WithBoundAssoc for T
| ^^^^^^^^^^^^^^ ^
12 | where
13 | for<'a> Self::Assoc<'a>: Trait,
| ----- unsatisfied trait bound introduced here
= note: 63 redundant requirements hidden
= note: required for `Self` to implement `WithBoundAssoc`
For more information about this error, try `rustc --explain E0275`.
error: could not compile `playground` (lib) due to 1 previous error
It does compile successfully with trait aliases (Playground):
#![feature(trait_alias)]
pub trait Trait {}
pub trait WithAssoc {
type Assoc<'a>;
}
pub trait WithBoundAssoc = WithAssoc where for<'a> <Self as WithAssoc>::Assoc<'a>: Trait;
It seems like there's no real way to get elaborated bounds for GATs in stable Rust, which is super unfortunate. :/ Does anyone know if this is possible? Is the "overflow evaluating the requirement" error a bug?
I tried this code: [playground]
I expected this to compile. Instead, it gives the following error:
Meta
playground 1.66.0-nightly (2022-10-21 5c8bff74bc1c52bef0c7)