Skip to content

Commit

Permalink
Add MiniPhase to enter generated symbols from MacroAnnotations
Browse files Browse the repository at this point in the history
  • Loading branch information
hamzaremmal committed Nov 2, 2023
1 parent e2b38f9 commit 5c2e1eb
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 1 deletion.
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import typer.{TyperPhase, RefChecks}
import parsing.Parser
import Phases.Phase
import transform._
import dotty.tools.backend
import backend.jvm.{CollectSuperCalls, GenBCode}
import localopt.StringInterpolatorOpt

Expand Down Expand Up @@ -49,6 +48,7 @@ class Compiler {
protected def picklerPhases: List[List[Phase]] =
List(new Pickler) :: // Generate TASTY info
List(new Inlining) :: // Inline and execute macros
List(new PostInlining2) :: // Add mirror support for inlined code
List(new PostInlining) :: // Add mirror support for inlined code
List(new CheckUnused.PostInlining) :: // Check for unused elements
List(new Staging) :: // Check staging levels and heal staged types
Expand Down
52 changes: 52 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/PostInlining2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package dotty.tools.dotc
package transform

import core.*
import ast.tpd.*
import Contexts.*
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer

/**
* ???
* @author Hamza REMMAL ([email protected])
*/
class PostInlining2 extends MacroTransform, IdentityDenotTransformer:
thisPhase =>

override def phaseName: String = PostInlining2.name

override def description: String = PostInlining2.description

override def changesMembers = true

def newTransformer(using Context): Transformer = new Transformer:
override def transform(tree: Tree)(using Context): Tree =
super.transform(tree) match
// HR : Check if the owner of the added symbols is correct.
// HR : if yes, and the symbol is not entered. enter it

/* HR : Questions :
- What symbol are we allowed to change ? Check for now if the content of the tree is consistent
- What happens if we enter a symbol twice ? I have a NamingError reported
- What if we already have that symbol entered ? ignore it...
- Can we merge it with the PostInlining phase ?
- Is there an optimal way to check if a tree was generated by a macro annotation ?
- Define a correct error message below
*/

case t@TypeDef(_, template: Template) =>
for tree <- template.constr :: template.body do
if tree.symbol.owner == t.symbol then
if !t.symbol.asClass.info.decls.exists(_ == tree.symbol) then
tree.symbol.enteredAfter(thisPhase)
else
report.error("Macro added a definition with the wrong owner")
t
case t => t



object PostInlining2:
val name: String = "postInlining2"
val description: String = "check the result of the macro annotation extension"

3 changes: 3 additions & 0 deletions tests/neg/i18825.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
error overriding method toString in class Foo of type (): String;
method toString of type (): String cannot override final member method toString in class Foo
1 error found
19 changes: 19 additions & 0 deletions tests/neg/i18825/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import scala.annotation.experimental
import scala.annotation.MacroAnnotation
import scala.quoted.*

@experimental
class toString extends MacroAnnotation :
def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
import quotes.reflect.*
tree match
case ClassDef(name, ctr, parents, self, body) =>
val cls = tree.symbol
val toStringSym = Symbol.requiredMethod("java.lang.Object.toString")
val toStringOverrideSym = Symbol.newMethod(cls, "toString", toStringSym.info, Flags.Override, Symbol.noSymbol)
val toStringDef = DefDef(toStringOverrideSym, _ => Some(Literal(StringConstant("Hello from macro"))))
val newClassDef = ClassDef.copy(tree)(name, ctr, parents, self, toStringDef :: body)
List(newClassDef)
case _ =>
report.error("@toString can only be annotated on class definitions")
tree :: Nil
13 changes: 13 additions & 0 deletions tests/neg/i18825/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import annotation.experimental

class Foo :
final override def toString(): String = "Hello"

@experimental
@toString
class AFoo extends Foo //:
//override def toString(): String = "Hello from macro"

@experimental
@main def run =
println(new AFoo().toString)

0 comments on commit 5c2e1eb

Please sign in to comment.