简体   繁体   中英

Explicit type conversion in Scala 3 macros

I defined the following trait in Scala 3:

trait A[T <: Tuple]

Using Scala 3 macros, I then create objects of this trait performing further checks on the actual types of the tuple T ; in particular, I want to check that all the types ( T_1 , …, T_n ) of the tuple T are subtypes of another given type, B :

trait B
private def allSubtypesOfB[T <: Tuple: Type](using quotes: Quotes): Boolean = {
    import quotes.reflect.*
    case '[Nothing] => false // I don't want nothing to be in T
    case '[head *: tail] if TypeRepr.of[head] <:< TypeRepr.of[B] => allSubtypesOfB[tail]
    case '[EmptyTuple] => true
    case _ => false
}

inline def createA[T <: Tuple] = ${ createAImpl[T] }
private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
    import quotes.reflect.*
    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
    // ... create instance of A
}

The problem is that later I need to call, for each type in the tuple type T , a method that has the following signature:

def doSomethingWithBSubtype[T <: B] = ??? // Do something with type T

So, the code would look something like this:

private def createAImpl[T <: Tuple: Type](using quotes: Quotes): Expr[A[T]] = {
    import quotes.reflect.*
    if !allSubtypesOfB[T] then report.error("All types in T must be subtypes of B")
    Type.of[T] match {
        case '[head *: tail] => doSomethingWithBSubtype[head]
        case '[EmptyTuple] => ???
    }
    // ... create instance of A
}

This code won't compile as the compiler says that head must be a subtype of B to be used in the method doSomethingWithBSubtype . However, with the if preceding the match case, I already ensured that all types inside T are subtypes of B . Is there a way to force the compiler to recognise head as a subtype of B ?

There are compile time and runtime of macros. There are compile time and runtime of main code (using the macros). The runtime of macros is the compile time of main code.

Inside createAImpl the line if.allSubtypesOfB[T]... ensures that all types of T are subtypes of B at the runtime of createAImpl . But when you call doSomethingWithBSubtype[head] you need to know that head is a subtype of B at the compile time of createAImpl so you don't have information from the runtime of createAImpl yet ( if.allSubtypesOfB[T]... ).

You could do

case '[head *: tail] => doSomethingWithBSubtype[head & B]

What Scala 3 syntax can match on a Type and its Type parameters in the context of a macro?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM