Skip to content

Commit 8018590

Browse files
committed
Enter missing symbols in MacroAnnotations
1 parent f91e5d8 commit 8018590

File tree

6 files changed

+65
-9
lines changed

6 files changed

+65
-9
lines changed

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import dotty.tools.dotc.staging.StagingLevel
1717
import scala.collection.mutable.ListBuffer
1818

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

2223
import tpd.*
2324

@@ -75,7 +76,7 @@ class Inlining extends MacroTransform {
7576
&& StagingLevel.level == 0
7677
&& MacroAnnotations.hasMacroAnnotation(tree.symbol)
7778
then
78-
val trees = (new MacroAnnotations).expandAnnotations(tree)
79+
val trees = (new MacroAnnotations(self)).expandAnnotations(tree)
7980
val trees1 = trees.map(super.transform)
8081

8182
// Find classes added to the top level from a package object

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

+24-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +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.DenotTransformers.DenotTransformer
12+
import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer
1313
import dotty.tools.dotc.core.Flags.*
1414
import dotty.tools.dotc.core.MacroClassLoader
1515
import dotty.tools.dotc.core.Symbols.*
@@ -23,7 +23,8 @@ import scala.util.control.NonFatal
2323

2424
import java.lang.reflect.InvocationTargetException
2525

26-
class MacroAnnotations:
26+
class MacroAnnotations(phase: IdentityDenotTransformer):
27+
2728
import tpd.*
2829
import MacroAnnotations.*
2930

@@ -58,9 +59,11 @@ class MacroAnnotations:
5859
case (prefixed, newTree :: suffixed) =>
5960
allTrees ++= prefixed
6061
insertedAfter = suffixed :: insertedAfter
61-
prefixed.foreach(checkMacroDef(_, tree, annot))
62-
suffixed.foreach(checkMacroDef(_, tree, annot))
63-
transform.TreeChecker.checkMacroGeneratedTree(tree, newTree)
62+
for prefixedTree <- prefixed do
63+
checkMacroDef(prefixedTree, tree, annot)
64+
for suffixedTree <- suffixed do
65+
checkMacroDef(suffixedTree, tree, annot)
66+
TreeChecker.checkMacroGeneratedTree(tree, newTree)
6467
newTree
6568
case (Nil, Nil) =>
6669
report.error(i"Unexpected `Nil` returned by `(${annot.tree}).transform(..)` during macro expansion", annot.tree.srcPos)
@@ -76,6 +79,7 @@ class MacroAnnotations:
7679
insertedAfter.foreach(allTrees.++=)
7780

7881
val result = allTrees.result()
82+
for tree <- result do enterMissingSymbols(tree)
7983
debug.println(result.map(_.show).mkString("expanded to:\n", "\n", ""))
8084
result
8185

@@ -120,7 +124,7 @@ class MacroAnnotations:
120124

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

137+
private def enterMissingSymbols(tree: DefTree)(using Context) = new TreeTraverser {
138+
def traverse(tree: tpd.Tree)(using Context): Unit = tree match
139+
case tdef @ TypeDef(_, template: Template) =>
140+
//for tree <- template.constr :: template.body do
141+
val isSymbolInDecls = tdef.symbol.asClass.info.decls.toList.toSet
142+
for tree <- template.body do
143+
if tree.symbol.owner != tdef.symbol then
144+
report.error(em"Macro added a definition with the wrong owner - ${tree.symbol.owner} - ${tdef.symbol} in ${tree.source}")
145+
else if !isSymbolInDecls(tree.symbol) then
146+
tree.symbol.enteredAfter(phase)
147+
traverseChildren(tree) // Taverse before or after dealing with this class?
148+
case _ => traverseChildren(tree)
149+
}.traverse(tree)
150+
133151
object MacroAnnotations:
134152

135153
/** Is this an annotation that implements `scala.annation.MacroAnnotation` */

tests/neg-macros/i18825.check

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

tests/neg-macros/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-macros/i18825/Test_2.scala

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

tests/run/quotes-add-erased/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class erasedParamsMethod extends MacroAnnotation:
1515
assert(methType.hasErasedParams)
1616
assert(methType.erasedParams == List(true, false))
1717

18-
val methSym = Symbol.newMethod(tree.symbol, "takesErased", methType, Flags.EmptyFlags, Symbol.noSymbol)
18+
val methSym = Symbol.newMethod(tree.symbol, "takesErased", methType, Flags.Override, Symbol.noSymbol)
1919
val methDef = DefDef(methSym, _ => Some(Literal(IntConstant(1))))
2020

2121
val clsDef = ClassDef.copy(tree)(name, ctr, parents, self, methDef :: body)

0 commit comments

Comments
 (0)