Skip to content

Commit ac222a8

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

File tree

5 files changed

+75
-0
lines changed

5 files changed

+75
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.quoted.*
2+
3+
object Macro:
4+
inline def myMacro[T](): Unit =
5+
${ myMacroImpl[T]() }
6+
7+
def myMacroImpl[T: Type]()(using Quotes): Expr[Unit] =
8+
import quotes.reflect.*
9+
val myTypeRepr = MyTypeRepr(TypeRepr.of[T])
10+
11+
println(myTypeRepr.optionalAnnotationValue[caseName])
12+
println(myTypeRepr.requiredAnnotationValue[caseName])
13+
14+
'{()}
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/pos-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+
Macro.myMacro[SealedTrait3.B[Any]]()
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
import quotes.reflect.*
10+
val typeSymbol = TypeRepr.of[caseName].typeSymbol
11+
x.asTerm match {
12+
case Apply(Select(New(clazz), _), List(nameArg)) if clazz.symbol == typeSymbol =>
13+
Some(caseName(nameArg.asExprOf[String].valueOrAbort))
14+
case _ =>
15+
None
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)