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.