Head up: This is me walking myself through it. I don't think it's documented for GATs anywhere (but would love to be proven wrong).
Let's look at the definition of "constrained", and apply it to each case.
impl<T, M> ToCalc for T
where
T: ForCalc<A = M>,
-
T
: Is constrained as T
appears in the Self
type
-
M
: Is constrained as
-
<T as ForCalc>::A == M
is a clause
-
T as ForCalc
is not this impl
-
T
is constrained
The idea here is that at some invocation site where T
and the trait ToCalc
is known, we can determine all the other parameters. We know T
, so we can find T
's impl of ForCalc
(as it too must be findable), and that impl
must have exactly one value for the associated type A
, and from that we can find M
.
Next case:
impl<'a, T, M> ToCalc for T
where
T: ForCalc<A<'a> = M>,
{}
-
T
: Is constrained as T
appears in the Self
type
-
'a
: Is not contrained (see below)
-
M
: Is not constrained as
- While
<T as ForCalc>::A<'a> == M
is a clause
- And
<T as ForCalc>
is not this impl
- And
T
is constrained,
-
'a
is not constrained
- So we can't figure out what
M
is
That RFC predates GATs, but the lifetime being unconstrained is mentioned in this issue.
Here's me spitballing: 'a
isn't an output of the implementation of ForCalc
. So we can still find impl ForCalc for T
from T
, but we still don't know what lifetime we're talking about. So we can't figure out M
either. Maybe ForCalc
looks like this for example:
trait ForCalc {
type A<'a>;
fn uses_the_gat(&self, a: A<'_>) -> &'a str;
fn does_not_use_the_gat(&self);
}
If we're somewhere else in code and have:
t.does_not_use_the_gat();
Then if method resolution is unambiguous, we have found
t: T
- And the method is
ForCalc::does_not_use_the_gat
But there is no way to decide what 'a
might be, so there is no way to find what M
might be, so we can't figure out which exact implementation (with all generic parameters resolved) to use.
Or in short, for a lifetime to be constrained it has to be part of the implementor, part of the trait, or part of a non-generic associated type... so just being the input to a GAT is not enough.
Make sense?
The linked issue says:
the general gist is to be able to do something like for<'b> T: AsRef2<Output<'b> = &'b [U]>
, we need some sort of implied bounds or additional reasoning.
In other words, sort of like your last thread, you need some way to formulate a rule that always applies. That way you don't need to find the 'a
, you can use any 'a
.
If you have an actual failing use-case you'd like to try and fix, feel free to supply it. Presumably your actual implementation cares about M
in some way.