-
Notifications
You must be signed in to change notification settings - Fork 12
Description
Hi there 👋
When reading the Readme, I got excited at the idea that maybe Quotidian would help solve the problem of reading the value of static annotations at compile time. Reduced to a simple form, the problem is essentially this :
given this static annotation:
case class Check(value: Int) extends StaticAnnotation derives FromExpr
I want to write a macro inline def check[T] : Unit to fail compilation if a type T is annotated with a Check that holds a value lower than zero.
So I've tried the following :
//> using lib "io.github.kitlangton::quotidian:0.0.14"
import scala.quoted.*
import quotidian.*
import scala.compiletime.*
import scala.annotation.StaticAnnotation
case class Check(x: Int) extends StaticAnnotation derives ToExpr, FromExpr
inline def check[T]: Unit = ${ checkMacro[T] }
private def checkMacro[T: Type](using Quotes): Expr[Unit] = {
import quotes.reflect.*
val sym = TypeRepr.of[T].typeSymbol
val constraintType = TypeRepr.of[Check]
sym.annotations.find(_.tpe =:= constraintType) match {
case None => '{ error("couldn't find Check annotation") }
case Some(term) =>
term.asExprOf[Check].valueOrAbort match
case value =>
if (value.x < 0) '{ error("Check should be positive") }
else '{ () }
}
}and when attempting to call the macro, it appears that the FromExpr is not able to derive the value from the annotation :
@Check(1)
case class Bar()
def test() = {
check[Bar]
}fails with :
Compiling project (Scala 3.3.0, JVM)
[error] ./test.scala:5:3
[error] Expected a known value.
[error]
[error] The value of: new Check(1)
[error] could not be extracted using Check$$anon$2@16b5188f
[error] check[Bar]
[error] ^^^^^^^^^^So I take it the derived FromExpr is probably not able to "parse" the new T expression, and returns None as a result.
Now I'm only novice when it comes to Scala 3 macros, but a quick read through the internals of quotidian makes me think that maybe the macro is looking at the generated apply invocations for case-classes, and omits the new invocations ? Am I even remotely correct ? Is the support of new could potentially be supported by the library ?
Collateral question : I've also noticed that trying to invoke the FromExpr derivation from Scala 3.3.3 fails with : Illegal reference to scala.quoted.runtime.Expr, which may explain why the FromExpr/ToExpr` round-trip tests are commented in this repo. Have some recent changes in the compiler made this library prematurely obsolete ? 😕
Thank you in advance for reading