From deaec4b9bff2e44fa75281a40ed710f13c848552 Mon Sep 17 00:00:00 2001 From: Hamza REMMAL Date: Mon, 4 Mar 2024 16:31:13 +0100 Subject: [PATCH] Add check for parents in Quotes (#i19842) --- .../quoted/runtime/impl/QuotesImpl.scala | 6 ++++ .../{i19842.check => i19842-a.check} | 24 ++------------- .../{i19842 => i19842-a}/Macro.scala | 1 - .../{i19842 => i19842-a}/Test.scala | 0 tests/neg-macros/i19842-b.check | 14 +++++++++ tests/neg-macros/i19842-b/Macro.scala | 30 +++++++++++++++++++ tests/neg-macros/i19842-b/Test.scala | 9 ++++++ 7 files changed, 62 insertions(+), 22 deletions(-) rename tests/neg-macros/{i19842.check => i19842-a.check} (51%) rename tests/neg-macros/{i19842 => i19842-a}/Macro.scala (85%) rename tests/neg-macros/{i19842 => i19842-a}/Test.scala (100%) create mode 100644 tests/neg-macros/i19842-b.check create mode 100644 tests/neg-macros/i19842-b/Macro.scala create mode 100644 tests/neg-macros/i19842-b/Test.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 04d8d7bc51a0..0b137a4ce548 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -253,6 +253,12 @@ 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) = { + xCheckMacroAssert(parents.nonEmpty && !parents.head.tpe.dealias.classSymbol.is(dotc.core.Flags.Trait), "First parent must be a class") + xCheckMacroAssert( + module.moduleClass.asClass.classInfo.parents.map(_.dealias.typeSymbol) + == + parents.map(_.tpe.dealias.typeSymbol), + "Parents in the symbol are not compatible with the provided 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 51% rename from tests/neg-macros/i19842.check rename to tests/neg-macros/i19842-a.check index b22efc51a94a..84f22f7bd0f2 100644 --- a/tests/neg-macros/i19842.check +++ b/tests/neg-macros/i19842-a.check @@ -1,28 +1,10 @@ -- Error: tests/neg-macros/i19842/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. + | Exception occurred while executing macro expansion. + | java.lang.AssertionError: First parent must be a class + | at Macros$.makeSerializer(Macro.scala:24) | - |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 - | - |Parents in symbol: [class Object, trait Serializer] - |Parents in tree: [trait Serializer] - | - | - |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 85% rename from tests/neg-macros/i19842/Macro.scala rename to tests/neg-macros/i19842-a/Macro.scala index 481c0b2468b0..e14786de236d 100644 --- a/tests/neg-macros/i19842/Macro.scala +++ b/tests/neg-macros/i19842-a/Macro.scala @@ -15,7 +15,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..a8bcf75c41b8 --- /dev/null +++ b/tests/neg-macros/i19842-b.check @@ -0,0 +1,14 @@ +-- 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: Parents in the symbol are not compatible with the provided parents + | at Macros$.makeSerializer(Macro.scala:26) + | + |--------------------------------------------------------------------------------------------------------------------- + |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..b00f71ab26be --- /dev/null +++ b/tests/neg-macros/i19842-b/Macro.scala @@ -0,0 +1,30 @@ + +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