diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index d0736564957b..4a7548f40f43 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -198,6 +198,17 @@ object TreeChecker { } }.apply(tp0) + def checkParents(sym: ClassSymbol, parents: List[tpd.Tree])(using Context): Unit = + val symbolParents = sym.classInfo.parents.map(_.dealias.typeSymbol) + val treeParents = parents.map(_.tpe.dealias.typeSymbol) + assert(symbolParents == treeParents, + i"""Parents of class symbol differs from the parents in the tree for $sym + | + |Parents in symbol: $symbolParents + |Parents in tree: $treeParents + |""".stripMargin) + end checkParents + /** Run some additional checks on the nodes of the trees. Specifically: * * - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure @@ -570,14 +581,7 @@ object TreeChecker { assert(ctx.owner.isClass) val sym = ctx.owner.asClass if !sym.isPrimitiveValueClass then - val symbolParents = sym.classInfo.parents.map(_.dealias.typeSymbol) - val treeParents = impl.parents.map(_.tpe.dealias.typeSymbol) - assert(symbolParents == treeParents, - i"""Parents of class symbol differs from the parents in the tree for $sym - | - |Parents in symbol: $symbolParents - |Parents in tree: $treeParents - |""".stripMargin) + TreeChecker.checkParents(sym, impl.parents) } override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = { diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index c802d2a9201d..6dfa00dde59f 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -24,6 +24,7 @@ import scala.quoted.runtime.impl.printers.* import scala.reflect.TypeTest import dotty.tools.dotc.core.NameKinds.ExceptionBinderName +import dotty.tools.dotc.transform.TreeChecker object QuotesImpl { @@ -253,6 +254,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler (cdef.name.toString, cdef.constructor, cdef.parents, cdef.self, rhs.body) def module(module: Symbol, parents: List[Tree /* Term | TypeTree */], body: List[Statement]): (ValDef, ClassDef) = { + if xCheckMacro then TreeChecker.checkParents(module.moduleClass.asClass, parents) val cls = module.moduleClass val clsDef = ClassDef(cls, parents, body) val newCls = Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil) diff --git a/tests/neg-macros/i19842.check b/tests/neg-macros/i19842-a.check similarity index 53% rename from tests/neg-macros/i19842.check rename to tests/neg-macros/i19842-a.check index b22efc51a94a..af5dbc604f93 100644 --- a/tests/neg-macros/i19842.check +++ b/tests/neg-macros/i19842-a.check @@ -1,28 +1,18 @@ --- Error: tests/neg-macros/i19842/Test.scala:9:50 ---------------------------------------------------------------------- +-- Error: tests/neg-macros/i19842-a/Test.scala:9:50 -------------------------------------------------------------------- 9 |@main def Test = summon[Serializer[ValidationCls]] // error | ^ - |Malformed tree was found while expanding macro with -Xcheck-macros. - |The tree does not conform to the compiler's tree invariants. - | - |Macro was: - |scala.quoted.runtime.Expr.splice[Serializer[ValidationCls]](((contextual$2: scala.quoted.Quotes) ?=> Macros.makeSerializer[ValidationCls](scala.quoted.Type.of[ValidationCls](contextual$2), contextual$2))) - | - |The macro returned: - |{ - | object objectSerializer$macro$1 extends Serializer[ValidationCls] { this: objectSerializer$macro$1.type => - | - | } - | objectSerializer$macro$1 - |} - | - |Error: - |assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1 + |Exception occurred while executing macro expansion. + |java.lang.AssertionError: assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1 | |Parents in symbol: [class Object, trait Serializer] |Parents in tree: [trait Serializer] | + | at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8) + | at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:209) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:257) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:256) + | at Macros$.makeSerializer(Macro.scala:25) | - |stacktrace available when compiling with `-Ydebug` |--------------------------------------------------------------------------------------------------------------------- |Inline stack trace |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/neg-macros/i19842/Macro.scala b/tests/neg-macros/i19842-a/Macro.scala similarity index 86% rename from tests/neg-macros/i19842/Macro.scala rename to tests/neg-macros/i19842-a/Macro.scala index 78b1f576f1b4..936e08b02592 100644 --- a/tests/neg-macros/i19842/Macro.scala +++ b/tests/neg-macros/i19842-a/Macro.scala @@ -16,7 +16,6 @@ object Macros { name, Flags.Implicit, Flags.EmptyFlags, - // Without TypeRep.of[Object] it would fail with java.lang.AssertionError: assertion failed: First parent must be a class List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]), _ => Nil, Symbol.noSymbol diff --git a/tests/neg-macros/i19842/Test.scala b/tests/neg-macros/i19842-a/Test.scala similarity index 100% rename from tests/neg-macros/i19842/Test.scala rename to tests/neg-macros/i19842-a/Test.scala diff --git a/tests/neg-macros/i19842-b.check b/tests/neg-macros/i19842-b.check new file mode 100644 index 000000000000..95a71fb9f98d --- /dev/null +++ b/tests/neg-macros/i19842-b.check @@ -0,0 +1,22 @@ +-- Error: tests/neg-macros/i19842-b/Test.scala:9:50 -------------------------------------------------------------------- +9 |@main def Test = summon[Serializer[ValidationCls]] // error + | ^ + |Exception occurred while executing macro expansion. + |java.lang.AssertionError: assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1 + | + |Parents in symbol: [class Object, trait Serializer] + |Parents in tree: [class Object, trait Serializer, trait Foo] + | + | at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8) + | at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:209) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:257) + | at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:256) + | at Macros$.makeSerializer(Macro.scala:27) + | + |--------------------------------------------------------------------------------------------------------------------- + |Inline stack trace + |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + |This location contains code that was inlined from Test.scala:5 +5 | implicit inline def implicitMakeSerializer[T]: Serializer[T] = ${ Macros.makeSerializer[T] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --------------------------------------------------------------------------------------------------------------------- diff --git a/tests/neg-macros/i19842-b/Macro.scala b/tests/neg-macros/i19842-b/Macro.scala new file mode 100644 index 000000000000..d46ff758342b --- /dev/null +++ b/tests/neg-macros/i19842-b/Macro.scala @@ -0,0 +1,31 @@ +//> using options -experimental -Yno-experimental + +import scala.annotation.{experimental, targetName} +import scala.quoted.* +import scala.util.Try + +trait Foo + +object Macros { + def makeSerializer[T: Type](using Quotes): Expr[Serializer[T]] = { + import quotes.reflect.* + + val tpe: TypeRepr = TypeRepr.of[T] + val name: String = Symbol.freshName("objectSerializer") + + val modSym: Symbol = Symbol.newModule( + Symbol.spliceOwner, + name, + Flags.Implicit, + Flags.EmptyFlags, + List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]), + _ => Nil, + Symbol.noSymbol + ) + + val (modValDef: ValDef, modClassDef: ClassDef) = + ClassDef.module(modSym, List(TypeTree.of[Object], TypeTree.of[Serializer[T]], TypeTree.of[Foo]), Nil) + + Block(List(modValDef, modClassDef), Ref(modSym)).asExprOf[Serializer[T]] + } +} \ No newline at end of file diff --git a/tests/neg-macros/i19842-b/Test.scala b/tests/neg-macros/i19842-b/Test.scala new file mode 100644 index 000000000000..ba1611d97696 --- /dev/null +++ b/tests/neg-macros/i19842-b/Test.scala @@ -0,0 +1,9 @@ + +trait Serializer[@specialized T] + +object Serializer: + implicit inline def implicitMakeSerializer[T]: Serializer[T] = ${ Macros.makeSerializer[T] } + +case class ValidationCls(string: String) + +@main def Test = summon[Serializer[ValidationCls]] // error \ No newline at end of file