jamborta
jamborta

Reputation: 5210

Prove upper type bound for generic types

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

Answers (1)

HTNW
HTNW

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

Related Questions