Skip to content

Commit 5c2e1eb

Browse files
committed
Add MiniPhase to enter generated symbols from MacroAnnotations
1 parent e2b38f9 commit 5c2e1eb

File tree

5 files changed

+88
-1
lines changed

5 files changed

+88
-1
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import typer.{TyperPhase, RefChecks}
77
import parsing.Parser
88
import Phases.Phase
99
import transform._
10-
import dotty.tools.backend
1110
import backend.jvm.{CollectSuperCalls, GenBCode}
1211
import localopt.StringInterpolatorOpt
1312

@@ -49,6 +48,7 @@ class Compiler {
4948
protected def picklerPhases: List[List[Phase]] =
5049
List(new Pickler) :: // Generate TASTY info
5150
List(new Inlining) :: // Inline and execute macros
51+
List(new PostInlining2) :: // Add mirror support for inlined code
5252
List(new PostInlining) :: // Add mirror support for inlined code
5353
List(new CheckUnused.PostInlining) :: // Check for unused elements
5454
List(new Staging) :: // Check staging levels and heal staged types
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core.*
5+
import ast.tpd.*
6+
import Contexts.*
7+
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer
8+
9+
/**
10+
* ???
11+
* @author Hamza REMMAL ([email protected])
12+
*/
13+
class PostInlining2 extends MacroTransform, IdentityDenotTransformer:
14+
thisPhase =>
15+
16+
override def phaseName: String = PostInlining2.name
17+
18+
override def description: String = PostInlining2.description
19+
20+
override def changesMembers = true
21+
22+
def newTransformer(using Context): Transformer = new Transformer:
23+
override def transform(tree: Tree)(using Context): Tree =
24+
super.transform(tree) match
25+
// HR : Check if the owner of the added symbols is correct.
26+
// HR : if yes, and the symbol is not entered. enter it
27+
28+
/* HR : Questions :
29+
- What symbol are we allowed to change ? Check for now if the content of the tree is consistent
30+
- What happens if we enter a symbol twice ? I have a NamingError reported
31+
- What if we already have that symbol entered ? ignore it...
32+
- Can we merge it with the PostInlining phase ?
33+
- Is there an optimal way to check if a tree was generated by a macro annotation ?
34+
- Define a correct error message below
35+
*/
36+
37+
case t@TypeDef(_, template: Template) =>
38+
for tree <- template.constr :: template.body do
39+
if tree.symbol.owner == t.symbol then
40+
if !t.symbol.asClass.info.decls.exists(_ == tree.symbol) then
41+
tree.symbol.enteredAfter(thisPhase)
42+
else
43+
report.error("Macro added a definition with the wrong owner")
44+
t
45+
case t => t
46+
47+
48+
49+
object PostInlining2:
50+
val name: String = "postInlining2"
51+
val description: String = "check the result of the macro annotation extension"
52+

tests/neg/i18825.check

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
error overriding method toString in class Foo of type (): String;
2+
method toString of type (): String cannot override final member method toString in class Foo
3+
1 error found

tests/neg/i18825/Macro_1.scala

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import scala.annotation.experimental
2+
import scala.annotation.MacroAnnotation
3+
import scala.quoted.*
4+
5+
@experimental
6+
class toString 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 toStringSym = Symbol.requiredMethod("java.lang.Object.toString")
13+
val toStringOverrideSym = Symbol.newMethod(cls, "toString", toStringSym.info, Flags.Override, Symbol.noSymbol)
14+
val toStringDef = DefDef(toStringOverrideSym, _ => Some(Literal(StringConstant("Hello from macro"))))
15+
val newClassDef = ClassDef.copy(tree)(name, ctr, parents, self, toStringDef :: body)
16+
List(newClassDef)
17+
case _ =>
18+
report.error("@toString can only be annotated on class definitions")
19+
tree :: Nil

tests/neg/i18825/Test_2.scala

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import annotation.experimental
2+
3+
class Foo :
4+
final override def toString(): String = "Hello"
5+
6+
@experimental
7+
@toString
8+
class AFoo extends Foo //:
9+
//override def toString(): String = "Hello from macro"
10+
11+
@experimental
12+
@main def run =
13+
println(new AFoo().toString)

0 commit comments

Comments
 (0)