Open
Description
Compiler version
3.6.3
Minimized code
final case class caseName(name: String) extends scala.annotation.Annotation
object caseName {
given FromExpr[caseName] =
new FromExpr[caseName] {
override def unapply(x: Expr[caseName])(using Quotes): Option[caseName] =
x match {
case '{ caseName(${ Expr(name) }) } => caseName(name).some
// with/without the following line...
case '{ new caseName(${ Expr(name) }) } => caseName(name).some
case _ => println(x.show); None
}
}
}
sealed trait SealedTrait3[+A, +B] derives Show
object SealedTrait3 {
final case class AB1[+B, +A](a: B, b: A) extends SealedTrait3[B, A]
final case class AB2[+C, +D](a: C, b: D) extends SealedTrait3[D, C]
final case class A[+A](a: A) extends SealedTrait3[A, Nothing]
@caseName("_B_") final case class B[+B](b: B) extends SealedTrait3[Nothing, B]
case object Neither extends SealedTrait3[Nothing, Nothing]
}
def optionalAnnotation[Annot: Type]: Option[Expr[Annot]] = {
val annotTpe = TypeRepr.of[Annot]
val annotFlags = annotTpe.typeSymbol.flags
if (annotFlags.is(Flags.Abstract) || annotFlags.is(Flags.Trait))
report.errorAndAbort(s"Bad annotation type ${annotTpe.show} is abstract")
this.getAnnotation(annotTpe.typeSymbol) match
case Some(tree) if tree.tpe <:< annotTpe => tree.asExprOf[Annot].some
case _ => None
}
def requiredAnnotation[Annot: Type]: Expr[Annot] =
optionalAnnotation[Annot].getOrElse(report.errorAndAbort(s"Missing required annotation `${TypeRepr.of[Annot].show}` for `$this`"))
def optionalAnnotationValue[Annot: {Type, FromExpr}]: Option[Annot] =
optionalAnnotation[Annot].map { expr =>
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
}
def requiredAnnotationValue[Annot: {Type, FromExpr}]: Annot = {
val expr = requiredAnnotation[Annot]
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
}
Output
[error] |Found annotation `oxygen.meta.example.caseName` for `oxygen.meta.example.SealedTrait3.B[B]`, but are unable to extract Expr.value
[error] |new oxygen.meta.example.caseName("_B_")
then add a case for that in the FromExpr
, and...
[error] 28 | case '{ new caseName(${ Expr(name) }) } => caseName(name).some
[error] | ^^^^^^^^
[error] | caseName does not have a constructor
Expectation
That either:
case '{ caseName(${ Expr(name) }) } => caseName(name).some
matchescase '{ new caseName(${ Expr(name) }) } => caseName(name).some
is allowed, and matches
Quite difficult to handle when you see "we found this, but cant match on it", and then when you try to match on the exact expr.show
, it says that expr is not valid?