Skip to content

Commit 03a41a6

Browse files
committed
Enter missing symbols in MacroAnnotations
1 parent e2b38f9 commit 03a41a6

File tree

6 files changed

+66
-9
lines changed

6 files changed

+66
-9
lines changed

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

-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

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

+26-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,14 @@ 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+
enterMissingSymbols(prefixedTree)
65+
for suffixedTree <- suffixed do
66+
checkMacroDef(suffixedTree, tree, annot)
67+
enterMissingSymbols(suffixedTree)
68+
TreeChecker.checkMacroGeneratedTree(tree, newTree)
69+
enterMissingSymbols(newTree)
6470
newTree
6571
case (Nil, Nil) =>
6672
report.error(i"Unexpected `Nil` returned by `(${annot.tree}).transform(..)` during macro expansion", annot.tree.srcPos)
@@ -120,7 +126,7 @@ class MacroAnnotations:
120126

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

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

135155
/** 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)

0 commit comments

Comments
 (0)