From 62be0dec5fa244f5d7d3afd30fe5540bc1884a41 Mon Sep 17 00:00:00 2001 From: Hamza Remmal <56235032+hamzaremmal@users.noreply.github.com> Date: Fri, 3 Nov 2023 11:04:06 +0100 Subject: [PATCH] Enter missing symbols in MacroAnnotations --- compiler/src/dotty/tools/dotc/Compiler.scala | 1 - .../dotty/tools/dotc/transform/Inlining.scala | 5 +- .../dotc/transform/MacroAnnotations.scala | 32 +++++++++--- .../tools/dotc/transform/PostInlining2.scala | 52 ------------------- tests/{neg => neg-macros}/i18825.check | 2 +- .../{neg => neg-macros}/i18825/Macro_1.scala | 0 tests/{neg => neg-macros}/i18825/Test_2.scala | 2 + 7 files changed, 32 insertions(+), 62 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/transform/PostInlining2.scala rename tests/{neg => neg-macros}/i18825.check (92%) rename tests/{neg => neg-macros}/i18825/Macro_1.scala (100%) rename tests/{neg => neg-macros}/i18825/Test_2.scala (94%) diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 8e40e23be66a..3972ef654b72 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -48,7 +48,6 @@ 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 diff --git a/compiler/src/dotty/tools/dotc/transform/Inlining.scala b/compiler/src/dotty/tools/dotc/transform/Inlining.scala index 10f73fa94e08..e36061a79820 100644 --- a/compiler/src/dotty/tools/dotc/transform/Inlining.scala +++ b/compiler/src/dotty/tools/dotc/transform/Inlining.scala @@ -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._ @@ -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 diff --git a/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala b/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala index 7878b5795703..464f73fc486c 100644 --- a/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala +++ b/compiler/src/dotty/tools/dotc/transform/MacroAnnotations.scala @@ -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.* @@ -23,7 +23,8 @@ import scala.util.control.NonFatal import java.lang.reflect.InvocationTargetException -class MacroAnnotations: +class MacroAnnotations(phase: IdentityDenotTransformer): + import tpd.* import MacroAnnotations.* @@ -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) @@ -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 @@ -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` */ diff --git a/compiler/src/dotty/tools/dotc/transform/PostInlining2.scala b/compiler/src/dotty/tools/dotc/transform/PostInlining2.scala deleted file mode 100644 index ff65469f4e50..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/PostInlining2.scala +++ /dev/null @@ -1,52 +0,0 @@ -package dotty.tools.dotc -package transform - -import core.* -import ast.tpd.* -import Contexts.* -import dotty.tools.dotc.core.DenotTransformers.IdentityDenotTransformer - -/** - * ??? - * @author Hamza REMMAL (hamza.remmal@epfl.ch) - */ -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" - diff --git a/tests/neg/i18825.check b/tests/neg-macros/i18825.check similarity index 92% rename from tests/neg/i18825.check rename to tests/neg-macros/i18825.check index 341b5596fbc9..0269f9880828 100644 --- a/tests/neg/i18825.check +++ b/tests/neg-macros/i18825.check @@ -1,3 +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 \ No newline at end of file diff --git a/tests/neg/i18825/Macro_1.scala b/tests/neg-macros/i18825/Macro_1.scala similarity index 100% rename from tests/neg/i18825/Macro_1.scala rename to tests/neg-macros/i18825/Macro_1.scala diff --git a/tests/neg/i18825/Test_2.scala b/tests/neg-macros/i18825/Test_2.scala similarity index 94% rename from tests/neg/i18825/Test_2.scala rename to tests/neg-macros/i18825/Test_2.scala index 84be37e04533..0d784b4bf93e 100644 --- a/tests/neg/i18825/Test_2.scala +++ b/tests/neg-macros/i18825/Test_2.scala @@ -1,3 +1,5 @@ +// nopos-error + import annotation.experimental class Foo :