Why does this Scala code fail to typecheck?
trait T { type A }
trait GenFoo[A0, S <: T { type A = A0 }]
trait Foo[S <: T] extends GenFoo[S#A, S]
I don't understand why "type arguments [S#A,S] do not conform to trait GenFoo's type parameter bounds [A0,S <: T{type A = A0}]". Is there a work-around?
Edit: As has been pointed out, the conformance error stems from the failure to verify S <: T{type A = S#A}
. Daniel Sobral pointed to -explaintypes
, which tells us:
S <: T{type A = S#A}?
S <: T?
true
S specializes type A?
this.A = this.A?
S = this.type?
false
false
false
false
I'm not sure how to interpret this.
Note that we get an illegal cyclic reference if we try to define,
trait Foo[S <: T { type A = S#A } ] extends GenFoo[S#A, S]
although the type refinement here doesn't seem to add any new information. (See also Why is this cyclic reference with a type projection illegal?)
My motivation is to create a trait Foo[S <: T]
that specializes on S#A
, as in: How to specialize on a type projection in Scala? To get this to work, I'm trying to surface S#A
as an explicit parameter A0
in the implementation trait GenFoo
, which can be specialized directly. I was hoping to apply the type refinement idea from Miles Sabin's answer to Why is this cyclic reference with a type projection illegal? but I run into this conformance error.
This seems to be the answer:
S specializes type A?
The question about specialize comes from here: T { type A = A0 }
. This is the type T
with type A
specialized -- meaning, it is more restricted than the original T
.
The answer to that question is no -- there's no constrains on S
that it be specialized.
In order to conform to the type constraints, S
would have to be a subtype of T { type A = A0 }
, but it is only a subtype of T
.
I'm not an expert on this topic, I just played around with your code and found out that the problem is not the S#A
part, but the S
part.
If you write the code like this:
trait T { type A }
trait GenFoo[A0, S <: T] // the { type A = A0 } part is not there anymore
trait Foo[S <: T] extends GenFoo[S#A, S]
then it compiles, because S
in Foo[S <: T]
conforms to the S
in GenFoo[A0, S <: T]
.
In your example the compiler knows that S
is a subtype of T
and therefore has the type A
defined, but it does not come to the point, where it can verify that the A
in S
is the S#A
.
来源:https://stackoverflow.com/questions/6795623/why-do-these-type-arguments-not-conform-to-a-type-refinement