Reputation: 5210
I have a type class which I'd like to use to store a type of an object:
trait RetainType {
type A
}
object RetainType {
def apply[A0](): RetainType = new RetainType{
type A = A0
}
}
Given the following class:
trait Annotation
class Entity extends Annotation
I would like the compiler to prove that RetainType.A
extends Annotation
:
def hasAnnotation[A <: Annotation] = Unit
But using RetainType
the compiler does not seem to resolve this:
val retainType = RetainType[Entity]
hasAnnotation[RetainType.A] //throws an error: type arguments [retainType.A] do not conform to method hasAnnotation's type parameter bounds [A <: Annotation]
It works ok if the type is specified:
hasAnnotation[Entity] //works fine
Anyway the compiler can prove this relation?
Upvotes: 0
Views: 75
Reputation: 29148
You messed up the signature of RetainType.apply
:
def apply[A0](): RetainType
The return type does not mention A0
, so it is "forgotten". That is, in
val x = RetainType[Int]
x.A
is completely abstract; the compiler cannot prove that x.A = Int
because apply
's signature erased that information. Use a refinement type:
object RetainType {
def apply[A0](): RetainType { type A = A0 } = new RetainType { override type A = A0 }
}
You may want to use the Aux
pattern to make this nicer to work with:
object RetainType {
type Aux[A0] = RetainType { type A = A0 }
def apply[A0](): RetainType.Aux[A0] = new RetainType { override type A = A0 }
}
Upvotes: 5