Skip to content

Commit d32c023

Browse files
committed
super constructor implicitly materialized self-annotations
1 parent 07d17d9 commit d32c023

File tree

4 files changed

+98
-17
lines changed

4 files changed

+98
-17
lines changed

commons-core/src/main/scala/com/avsystem/commons/misc/AnnotationOf.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,26 @@ case class AnnotationsOf[A, T](annots: List[A]) extends AnyVal
1515
object AnnotationsOf {
1616
implicit def materialize[A, T]: AnnotationsOf[A, T] = macro macros.misc.MiscMacros.annotationsOf[A, T]
1717
}
18+
19+
final class HasAnnotation[A, T]
20+
object HasAnnotation {
21+
private[this] val reusable = new HasAnnotation
22+
def create[A, T]: HasAnnotation[A, T] = reusable.asInstanceOf
23+
24+
implicit def materialize[A, T]: AnnotationsOf[A, T] = macro macros.misc.MiscMacros.hasAnnotation[A, T]
25+
}
26+
27+
case class SelfAnnotation[A](annot: A) extends AnyVal
28+
object SelfAnnotation {
29+
implicit def materialize[A]: SelfAnnotation[A] = macro macros.misc.MiscMacros.selfAnnotation[A]
30+
}
31+
32+
case class SelfOptAnnotation[A](annotOpt: Opt[A])
33+
object SelfOptAnnotationOf {
34+
implicit def materialize[A]: SelfOptAnnotation[A] = macro macros.misc.MiscMacros.selfOptAnnotation[A]
35+
}
36+
37+
case class SelfAnnotations[A](annots: List[A]) extends AnyVal
38+
object SelfAnnotations {
39+
implicit def materialize[A]: SelfAnnotations[A] = macro macros.misc.MiscMacros.selfAnnotations[A]
40+
}

commons-core/src/test/scala/com/avsystem/commons/misc/AnnotationOfTest.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@ import org.scalatest.FunSuite
66

77
import scala.annotation.StaticAnnotation
88

9-
class genann[T](val value: T) extends StaticAnnotation
10-
class genagg[T](value: T) extends AnnotationAggregate {
9+
case class genann[T](value: T) extends StaticAnnotation
10+
case class genagg[T](value: T) extends AnnotationAggregate {
1111
@genann(value) type Implied
1212
}
1313

1414
@genagg(42)
1515
class Subject
1616

17+
abstract class SelfAnnots(implicit val annots: SelfAnnotations[genann[_]])
18+
@genagg(42) @genann("fuu") class Klass extends SelfAnnots
19+
@genagg(42) @genann("fuu") object Objekt extends SelfAnnots
20+
1721
class AnnotationOfTest extends FunSuite {
1822
test("aggregate with generic") {
1923
assert(AnnotationOf.materialize[genann[Int], Subject].annot.value == 42)
2024
}
25+
26+
test("self annotations") {
27+
assert(new Klass().annots.annots == List(genann(42), genann("fuu")))
28+
assert(Objekt.annots.annots == List(genann(42), genann("fuu")))
29+
}
2130
}

commons-macros/src/main/scala/com/avsystem/commons/macros/MacroCommons.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ trait MacroCommons { bundle =>
346346

347347
def mkMacroGenerated(companionTpe: Type, tpe: Type, baseMaterialize: Tree): Tree = {
348348
def fail() =
349-
abort(s"invocation of this macro is allowed only to be passed as super constructor parameter of an object")
349+
abort(s"${c.macroApplication.symbol} can only be used in super constructor argument of an object")
350350

351351
val ownerConstr = c.internal.enclosingOwner
352352
if (!ownerConstr.isConstructor) {

commons-macros/src/main/scala/com/avsystem/commons/macros/misc/MiscMacros.scala

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,11 @@ class MiscMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
482482
"""
483483
}
484484

485-
def assertLocal(tpe: Type): Type = {
486-
if (tpe.typeSymbol.pos.source != c.enclosingPosition.source) {
487-
abort(s"Macro inspection of $tpe can only be done in the same source file where that type is defined")
485+
def assertLocal(sym: Symbol): Symbol = {
486+
if (sym.pos.source != c.enclosingPosition.source) {
487+
abort(s"Macro inspection of $sym can only be done in the same source file where it is defined")
488488
}
489-
tpe
489+
sym
490490
}
491491

492492
def safeAnnotTree(annot: Annot): Tree = {
@@ -496,28 +496,77 @@ class MiscMacros(ctx: blackbox.Context) extends AbstractMacroCommons(ctx) {
496496
c.untypecheck(annot.tree)
497497
}
498498

499+
def classSymbol(sym: Symbol): ClassSymbol = {
500+
if (sym.isClass) sym.asClass
501+
else abort(s"$sym is not a class")
502+
}
503+
499504
def annotationOf[A: WeakTypeTag, T: WeakTypeTag]: Tree = instrument {
500-
val atpe = weakTypeOf[A].dealias
501-
val tpe = assertLocal(weakTypeOf[T].dealias)
502-
val annot = findAnnotation(tpe.typeSymbol, atpe)
503-
.getOrElse(abort(s"No annotation of type $atpe found on $tpe"))
505+
val atpe = weakTypeOf[A]
506+
val tpe = weakTypeOf[T]
507+
val sym = assertLocal(classSymbol(tpe.dealias.typeSymbol))
508+
val annot = findAnnotation(sym, atpe)
509+
.getOrElse(abort(s"No annotation of type $atpe found on $sym"))
504510
q"$MiscPkg.AnnotationOf(${safeAnnotTree(annot)})"
505511
}
506512

507513
def optAnnotationOf[A: WeakTypeTag, T: WeakTypeTag]: Tree = instrument {
508-
val atpe = weakTypeOf[A].dealias
509-
val tpe = assertLocal(weakTypeOf[T].dealias)
510-
val annotTree = findAnnotation(tpe.typeSymbol, atpe)
514+
val atpe = weakTypeOf[A]
515+
val tpe = weakTypeOf[T]
516+
val sym = assertLocal(classSymbol(tpe.dealias.typeSymbol))
517+
val annotTree = findAnnotation(sym, atpe)
511518
.fold[Tree](q"$MiscPkg.Opt.Empty")(a => q"$MiscPkg.Opt(${safeAnnotTree(a)})")
512519
q"$MiscPkg.OptAnnotationOf($annotTree)"
513520
}
514521

515522
def annotationsOf[A: WeakTypeTag, T: WeakTypeTag]: Tree = instrument {
516-
val atpe = weakTypeOf[A].dealias
517-
val tpe = assertLocal(weakTypeOf[T].dealias)
518-
val annots = allAnnotations(tpe.typeSymbol, atpe).map(safeAnnotTree)
523+
val atpe = weakTypeOf[A]
524+
val tpe = weakTypeOf[T]
525+
val sym = assertLocal(classSymbol(tpe.dealias.typeSymbol))
526+
val annots = allAnnotations(sym, atpe).map(safeAnnotTree)
519527
q"$MiscPkg.AnnotationsOf($ListObj(..$annots))"
520528
}
529+
530+
def hasAnnotation[A: WeakTypeTag, T: WeakTypeTag]: Tree = instrument {
531+
val atpe = weakTypeOf[A]
532+
val tpe = weakTypeOf[T]
533+
val sym = assertLocal(classSymbol(tpe.dealias.typeSymbol))
534+
if (findAnnotation(sym, atpe).nonEmpty)
535+
q"$MiscPkg.HasAnnotation.create[$atpe, $tpe]"
536+
else
537+
abort(s"No annotation of type $atpe found on $sym")
538+
}
539+
540+
def classBeingConstructed: Symbol = {
541+
val ownerConstr = c.internal.enclosingOwner
542+
if (!ownerConstr.isConstructor) {
543+
abort(s"${c.macroApplication.symbol} can only be used as super constructor argument")
544+
}
545+
classSymbol(ownerConstr.owner)
546+
}
547+
548+
def selfAnnotation[A: WeakTypeTag]: Tree = instrument {
549+
val atpe = weakTypeOf[A]
550+
val sym = classBeingConstructed
551+
val annot = findAnnotation(sym, atpe)
552+
.getOrElse(abort(s"No annotation of type $atpe found on $sym"))
553+
q"$MiscPkg.SelfAnnotation(${safeAnnotTree(annot)})"
554+
}
555+
556+
def selfOptAnnotation[A: WeakTypeTag]: Tree = instrument {
557+
val atpe = weakTypeOf[A]
558+
val sym = classBeingConstructed
559+
val annotTree = findAnnotation(sym, atpe)
560+
.fold[Tree](q"$MiscPkg.Opt.Empty")(a => q"$MiscPkg.Opt(${safeAnnotTree(a)})")
561+
q"$MiscPkg.SelfOptAnnotation($annotTree)"
562+
}
563+
564+
def selfAnnotations[A: WeakTypeTag]: Tree = instrument {
565+
val atpe = weakTypeOf[A]
566+
val sym = classBeingConstructed
567+
val annots = allAnnotations(sym, atpe).map(safeAnnotTree)
568+
q"$MiscPkg.SelfAnnotations($ListObj(..$annots))"
569+
}
521570
}
522571

523572
class WhiteMiscMacros(ctx: whitebox.Context) extends AbstractMacroCommons(ctx) {

0 commit comments

Comments
 (0)