Skip to content

Commit 51c7a41

Browse files
committed
Macro annotations class modifications (part 2)
Enable modification of classes with `MacroAnnotation`: * Can annotate `class` to transform it * Can annotate `object` to transform the companion class Supported class modifications: * Modify the implementations of `def`, `val`, `var`, `lazy val`, `class`, `object` in the class * Add new `def`, `val`, `var`, `lazy val`, `class`, `object` members to the class * Add a new override for a `def`, `val`, `var`, `lazy val` members in the class Restrictions: * An annotation on a top-level class cannot return a top-level `def`, `val`, `var`, `lazy val`
1 parent 07e395d commit 51c7a41

File tree

33 files changed

+556
-135
lines changed

33 files changed

+556
-135
lines changed

compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala

+8-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import dotty.tools.dotc.config.Printers.{macroAnnot => debug}
99
import dotty.tools.dotc.core.Annotations.*
1010
import dotty.tools.dotc.core.Contexts.*
1111
import dotty.tools.dotc.core.Decorators.*
12+
import dotty.tools.dotc.core.Decorators.*
1213
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
1314
import dotty.tools.dotc.core.Flags.*
1415
import dotty.tools.dotc.core.MacroClassLoader
@@ -29,14 +30,10 @@ class MacroAnnotations(thisPhase: DenotTransformer):
2930
def expandAnnotations(tree: MemberDef)(using Context): List[DefTree] =
3031
if !hasMacroAnnotation(tree.symbol) then
3132
List(tree)
32-
else if tree.symbol.is(Module) then
33-
if tree.symbol.isClass then // error only reported on module class
34-
report.error("macro annotations are not supported on object", tree)
35-
List(tree)
36-
else if tree.symbol.isClass then
37-
report.error("macro annotations are not supported on class", tree)
33+
else if tree.symbol.is(Module) && !tree.symbol.isClass then
34+
// only class is transformed
3835
List(tree)
39-
else if tree.symbol.isType then
36+
else if tree.symbol.isType && !tree.symbol.isClass then
4037
report.error("macro annotations are not supported on type", tree)
4138
List(tree)
4239
else
@@ -70,7 +67,6 @@ class MacroAnnotations(thisPhase: DenotTransformer):
7067
else
7168
tree
7269
}
73-
7470
allTrees += transformedTree
7571
insertedAfter.foreach(allTrees.++=)
7672

@@ -98,11 +94,13 @@ class MacroAnnotations(thisPhase: DenotTransformer):
9894
private def checkAndEnter(newTree: Tree, annotated: Symbol, annot: Annotation)(using Context) =
9995
val sym = newTree.symbol
10096
if sym.isClass then
101-
report.error("Generating classes is not supported", annot.tree)
97+
report.error(i"macro annotation returning a `class` is not yet supported. $annot tried to add $sym", annot.tree)
10298
else if sym.isType then
103-
report.error("Generating type is not supported", annot.tree)
99+
report.error(i"macro annotation cannot return a `type`. $annot tried to add $sym", annot.tree)
104100
else if sym.owner != annotated.owner then
105101
report.error(i"macro annotation $annot added $sym with an inconsistent owner. Expected it to be owned by ${annotated.owner} but was owned by ${sym.owner}.", annot.tree)
102+
else if annotated.isClass && annotated.owner.is(Package) /*&& !sym.isClass*/ then
103+
report.error(i"macro annotation can not add top-level ${sym.showKind}. $annot tried to add $sym.", annot.tree)
106104
else
107105
sym.enteredAfter(thisPhase)
108106

+78-48
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,98 @@
11

2-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:18:6 ---------------------------------------------------------
3-
17 | @error
4-
18 | val vMember: Int = 1 // error
2+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:17:6 ---------------------------------------------------------
3+
16 |@error
4+
17 |class cGlobal // error
5+
|^
6+
|MACRO ERROR
7+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:20:7 ---------------------------------------------------------
8+
19 |@error
9+
20 |object oGlobal // error
10+
|^
11+
|MACRO ERROR
12+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:24:6 ---------------------------------------------------------
13+
23 | @error
14+
24 | val vMember: Int = 1 // error
515
| ^
616
| MACRO ERROR
7-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:20:11 --------------------------------------------------------
8-
19 | @error
9-
20 | lazy val lvMember: Int = 1 // error
17+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:26:11 --------------------------------------------------------
18+
25 | @error
19+
26 | lazy val lvMember: Int = 1 // error
1020
| ^
1121
| MACRO ERROR
12-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:22:6 ---------------------------------------------------------
13-
21 | @error
14-
22 | def dMember: Int = 1 // error
22+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:28:6 ---------------------------------------------------------
23+
27 | @error
24+
28 | def dMember: Int = 1 // error
1525
| ^
1626
| MACRO ERROR
17-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:24:8 ---------------------------------------------------------
18-
23 | @error
19-
24 | given gMember: Int = 1 // error
27+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:30:8 ---------------------------------------------------------
28+
29 | @error
29+
30 | given gMember: Int = 1 // error
2030
| ^
2131
| MACRO ERROR
22-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:26:8 ---------------------------------------------------------
23-
25 | @error
24-
26 | given gMember2: Num[Int] with // error: object not supported (TODO support)
32+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:32:8 ---------------------------------------------------------
33+
31 | @error
34+
32 | given gMember2: Num[Int] with // error
35+
| ^
36+
| MACRO ERROR
37+
33 | def zero = 0
38+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:35:8 ---------------------------------------------------------
39+
34 | @error
40+
35 | given gMember3(using DummyImplicit): Num[Int] with // error
41+
| ^
42+
| MACRO ERROR
43+
36 | def zero = 0
44+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:39:8 ---------------------------------------------------------
45+
38 | @error
46+
39 | class cMember // error
2547
| ^
26-
| macro annotations are not supported on object
27-
27 | def zero = 0
28-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:29:8 ---------------------------------------------------------
29-
28 | @error
30-
29 | given gMember3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
48+
| MACRO ERROR
49+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:42:9 ---------------------------------------------------------
50+
41 | @error
51+
42 | object oMember // error
3152
| ^
32-
| macro annotations are not supported on class
33-
30 | def zero = 0
34-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:34:8 ---------------------------------------------------------
35-
33 | @error
36-
34 | val vLocal: Int = 1 // error
53+
| MACRO ERROR
54+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:46:8 ---------------------------------------------------------
55+
45 | @error
56+
46 | val vLocal: Int = 1 // error
3757
| ^
3858
| MACRO ERROR
39-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:36:13 --------------------------------------------------------
40-
35 | @error
41-
36 | lazy val lvLocal: Int = 1 // error
59+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:48:13 --------------------------------------------------------
60+
47 | @error
61+
48 | lazy val lvLocal: Int = 1 // error
4262
| ^
4363
| MACRO ERROR
44-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:38:8 ---------------------------------------------------------
45-
37 | @error
46-
38 | def dLocal: Int = 1 // error
64+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:50:8 ---------------------------------------------------------
65+
49 | @error
66+
50 | def dLocal: Int = 1 // error
4767
| ^
4868
| MACRO ERROR
49-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:40:10 --------------------------------------------------------
50-
39 | @error
51-
40 | given gLocal: Int = 1 // error
69+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:52:10 --------------------------------------------------------
70+
51 | @error
71+
52 | given gLocal: Int = 1 // error
5272
| ^
5373
| MACRO ERROR
54-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:42:10 --------------------------------------------------------
55-
41 | @error
56-
42 | given gLocal2: Num[Int] with // error: object not supported (TODO support)
74+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:54:10 --------------------------------------------------------
75+
53 | @error
76+
54 | given gLocal2: Num[Int] with // error
5777
| ^
58-
| macro annotations are not supported on object
59-
43 | def zero = 0
60-
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:45:10 --------------------------------------------------------
61-
44 | @error
62-
45 | given gLocal3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
78+
| MACRO ERROR
79+
55 | def zero = 0
80+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:57:10 --------------------------------------------------------
81+
56 | @error
82+
57 | given gLocal3(using DummyImplicit): Num[Int] with // error
6383
| ^
64-
| macro annotations are not supported on class
65-
46 | def zero = 0
84+
| MACRO ERROR
85+
58 | def zero = 0
86+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:61:10 --------------------------------------------------------
87+
60 | @error
88+
61 | class cLocal // error
89+
| ^
90+
| MACRO ERROR
91+
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:63:11 --------------------------------------------------------
92+
62 | @error
93+
63 | object oLocal // error
94+
| ^
95+
| MACRO ERROR
6696
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:2:4 ----------------------------------------------------------
6797
1 |@error
6898
2 |val vGlobal: Int = 1 // error
@@ -85,13 +115,13 @@
85115
|MACRO ERROR
86116
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:10:6 ---------------------------------------------------------
87117
9 |@error
88-
10 |given gGlobal2: Num[Int] with // error: object not supported (TODO support)
118+
10 |given gGlobal2: Num[Int] with // error
89119
|^
90-
|macro annotations are not supported on object
120+
|MACRO ERROR
91121
11 | def zero = 0
92122
-- Error: tests/neg-macros/annot-error-annot/Test_2.scala:13:6 ---------------------------------------------------------
93123
12 |@error
94-
13 |given gGlobal3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
124+
13 |given gGlobal3(using DummyImplicit): Num[Int] with // error
95125
|^
96-
|macro annotations are not supported on class
126+
|MACRO ERROR
97127
14 | def zero = 0

tests/neg-macros/annot-error-annot/Test_2.scala

+23-6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ def dGlobal: Int = 1 // error
77
@error
88
given gGlobal: Int = 1 // error
99
@error
10-
given gGlobal2: Num[Int] with // error: object not supported (TODO support)
10+
given gGlobal2: Num[Int] with // error
1111
def zero = 0
1212
@error
13-
given gGlobal3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
13+
given gGlobal3(using DummyImplicit): Num[Int] with // error
1414
def zero = 0
1515

16+
@error
17+
class cGlobal // error
18+
19+
@error
20+
object oGlobal // error
21+
1622
class B:
1723
@error
1824
val vMember: Int = 1 // error
@@ -23,12 +29,18 @@ class B:
2329
@error
2430
given gMember: Int = 1 // error
2531
@error
26-
given gMember2: Num[Int] with // error: object not supported (TODO support)
32+
given gMember2: Num[Int] with // error
2733
def zero = 0
2834
@error
29-
given gMember3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
35+
given gMember3(using DummyImplicit): Num[Int] with // error
3036
def zero = 0
3137

38+
@error
39+
class cMember // error
40+
41+
@error
42+
object oMember // error
43+
3244
def locals: Unit =
3345
@error
3446
val vLocal: Int = 1 // error
@@ -39,11 +51,16 @@ class B:
3951
@error
4052
given gLocal: Int = 1 // error
4153
@error
42-
given gLocal2: Num[Int] with // error: object not supported (TODO support)
54+
given gLocal2: Num[Int] with // error
4355
def zero = 0
4456
@error
45-
given gLocal3(using DummyImplicit): Num[Int] with // error: class not supported (TODO support)
57+
given gLocal3(using DummyImplicit): Num[Int] with // error
4658
def zero = 0
59+
60+
@error
61+
class cLocal // error
62+
@error
63+
object oLocal // error
4764
()
4865

4966
trait Num[T]:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
-- Error: tests/neg-macros/annot-mod-class-add-top-method/Test_2.scala:1:0 ---------------------------------------------
3+
1 |@addTopLevelMethod // error
4+
|^^^^^^^^^^^^^^^^^^
5+
|macro annotation can not add top-level method. @addTopLevelMethod tried to add method toLevelMethod$1.
6+
-- Error: tests/neg-macros/annot-mod-class-add-top-method/Test_2.scala:4:0 ---------------------------------------------
7+
4 |@addTopLevelMethod // error
8+
|^^^^^^^^^^^^^^^^^^
9+
|macro annotation can not add top-level method. @addTopLevelMethod tried to add method toLevelMethod$2.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.annotation.{experimental, MacroAnnotation}
2+
import scala.quoted._
3+
import scala.collection.mutable
4+
5+
@experimental
6+
class addTopLevelMethod extends MacroAnnotation:
7+
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
8+
import quotes.reflect._
9+
tree match
10+
case ClassDef(name, ctr, parents, self, body) =>
11+
val cls = tree.symbol
12+
val methType = MethodType(Nil)(_ => Nil, _ => TypeRepr.of[Int])
13+
val methSym = Symbol.newUniqueMethod(cls.owner, "toLevelMethod", methType, Flags.EmptyFlags, Symbol.noSymbol)
14+
val methDef = DefDef(methSym, _ => Some(Literal(IntConstant(1))))
15+
List(methDef, tree)
16+
case _ =>
17+
report.error("Annotation only supports `class`")
18+
List(tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@addTopLevelMethod // error
2+
class Foo
3+
4+
@addTopLevelMethod // error
5+
object Foo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
-- Error: tests/neg-macros/annot-mod-class-add-top-val/Test_2.scala:1:0 ------------------------------------------------
3+
1 |@addTopLevelVal // error
4+
|^^^^^^^^^^^^^^^
5+
|macro annotation can not add top-level value. @addTopLevelVal tried to add value toLevelvalod$1.
6+
-- Error: tests/neg-macros/annot-mod-class-add-top-val/Test_2.scala:4:0 ------------------------------------------------
7+
4 |@addTopLevelVal // error
8+
|^^^^^^^^^^^^^^^
9+
|macro annotation can not add top-level value. @addTopLevelVal tried to add value toLevelvalod$2.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.annotation.{experimental, MacroAnnotation}
2+
import scala.quoted._
3+
import scala.collection.mutable
4+
5+
@experimental
6+
class addTopLevelVal extends MacroAnnotation:
7+
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
8+
import quotes.reflect._
9+
tree match
10+
case ClassDef(name, ctr, parents, self, body) =>
11+
val cls = tree.symbol
12+
val valSym = Symbol.newUniqueVal(cls.owner, "toLevelvalod", TypeRepr.of[Int], Flags.EmptyFlags, Symbol.noSymbol)
13+
val valDef = DefDef(valSym, _ => Some(Literal(IntConstant(1))))
14+
List(valDef, tree)
15+
case _ =>
16+
report.error("Annotation only supports `class`")
17+
List(tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@addTopLevelVal // error
2+
class Foo
3+
4+
@addTopLevelVal // error
5+
object Foo

tests/neg-macros/annot-on-class.check

-17
This file was deleted.

tests/neg-macros/annot-on-class/Macro_1.scala

-8
This file was deleted.

tests/neg-macros/annot-on-class/Test_2.scala

-11
This file was deleted.

tests/neg-macros/annot-on-object.check

-16
This file was deleted.

0 commit comments

Comments
 (0)