Skip to content

Commit c5b83bd

Browse files
committed
Add workaround for #22616
1 parent e9808a9 commit c5b83bd

File tree

6 files changed

+69
-0
lines changed

6 files changed

+69
-0
lines changed

tests/run-macros/i22616c.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_B_
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted.*
2+
3+
object Macro:
4+
inline def myMacro[T](): String =
5+
${ myMacroImpl[T]() }
6+
7+
def myMacroImpl[T: Type]()(using Quotes): Expr[String] =
8+
import quotes.reflect.*
9+
val myTypeRepr = MyTypeRepr(TypeRepr.of[T])
10+
val `caseName`(name) = myTypeRepr.requiredAnnotationValue[caseName]
11+
Expr(name)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import scala.quoted.*
2+
3+
final class MyTypeRepr(using val quotes: Quotes)(val unwrap: quotes.reflect.TypeRepr) {
4+
import quotes.reflect.*
5+
6+
def getAnnotation(annotTpe: quotes.reflect.Symbol): Option[quotes.reflect.Term] =
7+
unwrap.typeSymbol.getAnnotation(annotTpe)
8+
9+
def optionalAnnotation[Annot: Type]: Option[Expr[Annot]] = {
10+
val annotTpe = TypeRepr.of[Annot]
11+
val annotFlags = annotTpe.typeSymbol.flags
12+
13+
if (annotFlags.is(Flags.Abstract) || annotFlags.is(Flags.Trait))
14+
report.errorAndAbort(s"Bad annotation type ${annotTpe.show} is abstract")
15+
16+
this.getAnnotation(annotTpe.typeSymbol) match
17+
case Some(tree) if tree.tpe <:< annotTpe => Some(tree.asExprOf[Annot])
18+
case _ => None
19+
}
20+
21+
def requiredAnnotation[Annot: Type]: Expr[Annot] =
22+
optionalAnnotation[Annot].getOrElse(report.errorAndAbort(s"Missing required annotation `${TypeRepr.of[Annot].show}` for `$this`"))
23+
24+
def optionalAnnotationValue[Annot: {Type, FromExpr}]: Option[Annot] =
25+
optionalAnnotation[Annot].map { expr =>
26+
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
27+
}
28+
29+
def requiredAnnotationValue[Annot: {Type, FromExpr}]: Annot = {
30+
val expr = requiredAnnotation[Annot]
31+
expr.value.getOrElse(report.errorAndAbort(s"Found annotation `${TypeRepr.of[Annot].show}` for `$this`, but are unable to extract Expr.value\n${expr.show}"))
32+
}
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
sealed trait SealedTrait3[+A, +B]
2+
object SealedTrait3 {
3+
final case class AB1[+B, +A](a: B, b: A) extends SealedTrait3[B, A]
4+
final case class AB2[+C, +D](a: C, b: D) extends SealedTrait3[D, C]
5+
final case class A[+T](a: T) extends SealedTrait3[T, Nothing]
6+
@caseName("_B_") final case class B[+T](b: T) extends SealedTrait3[Nothing, T]
7+
case object Neither extends SealedTrait3[Nothing, Nothing]
8+
}

tests/run-macros/i22616c/Test_5.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@main def Test =
2+
println(Macro.myMacro[SealedTrait3.B[Any]]())
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted.*
2+
3+
final case class caseName(name: String) extends scala.annotation.Annotation
4+
object caseName {
5+
// This demonstrates a workaround for issue #22616.
6+
given FromExpr[caseName] =
7+
new FromExpr[caseName] {
8+
override def unapply(x: Expr[caseName])(using Quotes): Option[caseName] =
9+
x match {
10+
case '{ new `caseName`(${ Expr(name) }) } => Some(caseName(name))
11+
case _ => println(x.show); None
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)