Skip to content

Commit

Permalink
Enter missing symbols in MacroAnnotations
Browse files Browse the repository at this point in the history
  • Loading branch information
hamzaremmal committed Nov 3, 2023
1 parent e2b38f9 commit 03a41a6
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 9 deletions.
1 change: 0 additions & 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
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/Inlining.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import dotty.tools.dotc.staging.StagingLevel
import scala.collection.mutable.ListBuffer

/** Inlines all calls to inline methods that are not in an inline method or a quote */
class Inlining extends MacroTransform {
class Inlining extends MacroTransform, IdentityDenotTransformer {
self =>

import tpd._

Expand Down Expand Up @@ -75,7 +76,7 @@ class Inlining extends MacroTransform {
&& StagingLevel.level == 0
&& MacroAnnotations.hasMacroAnnotation(tree.symbol)
then
val trees = (new MacroAnnotations).expandAnnotations(tree)
val trees = (new MacroAnnotations(self)).expandAnnotations(tree)
val trees1 = trees.map(super.transform)

// Find classes added to the top level from a package object
Expand Down
32 changes: 26 additions & 6 deletions compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import dotty.tools.dotc.config.Printers.{macroAnnot => debug}
import dotty.tools.dotc.core.Annotations.*
import dotty.tools.dotc.core.Contexts.*
import dotty.tools.dotc.core.Decorators.*
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer
import dotty.tools.dotc.core.Flags.*
import dotty.tools.dotc.core.MacroClassLoader
import dotty.tools.dotc.core.Symbols.*
Expand All @@ -23,7 +23,8 @@ import scala.util.control.NonFatal

import java.lang.reflect.InvocationTargetException

class MacroAnnotations:
class MacroAnnotations(phase: IdentityDenotTransformer):

import tpd.*
import MacroAnnotations.*

Expand Down Expand Up @@ -58,9 +59,14 @@ class MacroAnnotations:
case (prefixed, newTree :: suffixed) =>
allTrees ++= prefixed
insertedAfter = suffixed :: insertedAfter
prefixed.foreach(checkMacroDef(_, tree, annot))
suffixed.foreach(checkMacroDef(_, tree, annot))
transform.TreeChecker.checkMacroGeneratedTree(tree, newTree)
for prefixedTree <- prefixed do
checkMacroDef(prefixedTree, tree, annot)
enterMissingSymbols(prefixedTree)
for suffixedTree <- suffixed do
checkMacroDef(suffixedTree, tree, annot)
enterMissingSymbols(suffixedTree)
TreeChecker.checkMacroGeneratedTree(tree, newTree)
enterMissingSymbols(newTree)
newTree
case (Nil, Nil) =>
report.error(i"Unexpected `Nil` returned by `(${annot.tree}).transform(..)` during macro expansion", annot.tree.srcPos)
Expand Down Expand Up @@ -120,7 +126,7 @@ class MacroAnnotations:

/** Check that this tree can be added by the macro annotation */
private def checkMacroDef(newTree: DefTree, annotatedTree: Tree, annot: Annotation)(using Context) =
transform.TreeChecker.checkMacroGeneratedTree(annotatedTree, newTree)
TreeChecker.checkMacroGeneratedTree(annotatedTree, newTree)
val sym = newTree.symbol
val annotated = annotatedTree.symbol
if sym.isType && !sym.isClass then
Expand All @@ -130,6 +136,20 @@ class MacroAnnotations:
else if annotated.isClass && annotated.owner.is(Package) /*&& !sym.isClass*/ then
report.error(i"macro annotation can not add top-level ${sym.showKind}. $annot tried to add $sym.", annot.tree)

private def enterMissingSymbols(tree: MemberDef)(using Context) = new TreeTraverser {
def traverse(tree: tpd.Tree)(using Context): Unit = tree match
case tdef @ TypeDef(_, template: Template) =>
//for tree <- template.constr :: template.body do
val isSymbolInDecls = tdef.symbol.asClass.info.decls.toList.toSet
for tree <- template.body do
if tree.symbol.owner != tdef.symbol then
report.error(em"Macro added a definition with the wrong owner - ${tree.symbol.owner} - ${tdef.symbol} in ${tree.source}")
else if !isSymbolInDecls(tree.symbol) then
tree.symbol.enteredAfter(phase)
traverseChildren(tree) // Taverse before or after dealing with this class?
case _ => traverseChildren(tree)
}.traverse(tree)

object MacroAnnotations:

/** Is this an annotation that implements `scala.annation.MacroAnnotation` */
Expand Down
3 changes: 3 additions & 0 deletions tests/neg-macros/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
19 changes: 19 additions & 0 deletions tests/neg-macros/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
15 changes: 15 additions & 0 deletions tests/neg-macros/i18825/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// nopos-error

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 03a41a6

Please sign in to comment.