Skip to content

Commit cc3c5d5

Browse files
authored
Add check for parents in Quotes (#19842) (#19870)
Fix #19842
2 parents 3694d95 + 1efe9ef commit cc3c5d5

File tree

8 files changed

+84
-27
lines changed

8 files changed

+84
-27
lines changed

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,17 @@ object TreeChecker {
198198
}
199199
}.apply(tp0)
200200

201+
def checkParents(sym: ClassSymbol, parents: List[tpd.Tree])(using Context): Unit =
202+
val symbolParents = sym.classInfo.parents.map(_.dealias.typeSymbol)
203+
val treeParents = parents.map(_.tpe.dealias.typeSymbol)
204+
assert(symbolParents == treeParents,
205+
i"""Parents of class symbol differs from the parents in the tree for $sym
206+
|
207+
|Parents in symbol: $symbolParents
208+
|Parents in tree: $treeParents
209+
|""".stripMargin)
210+
end checkParents
211+
201212
/** Run some additional checks on the nodes of the trees. Specifically:
202213
*
203214
* - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure
@@ -570,14 +581,7 @@ object TreeChecker {
570581
assert(ctx.owner.isClass)
571582
val sym = ctx.owner.asClass
572583
if !sym.isPrimitiveValueClass then
573-
val symbolParents = sym.classInfo.parents.map(_.dealias.typeSymbol)
574-
val treeParents = impl.parents.map(_.tpe.dealias.typeSymbol)
575-
assert(symbolParents == treeParents,
576-
i"""Parents of class symbol differs from the parents in the tree for $sym
577-
|
578-
|Parents in symbol: $symbolParents
579-
|Parents in tree: $treeParents
580-
|""".stripMargin)
584+
TreeChecker.checkParents(sym, impl.parents)
581585
}
582586

583587
override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import scala.quoted.runtime.impl.printers.*
2424

2525
import scala.reflect.TypeTest
2626
import dotty.tools.dotc.core.NameKinds.ExceptionBinderName
27+
import dotty.tools.dotc.transform.TreeChecker
2728

2829
object QuotesImpl {
2930

@@ -253,6 +254,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
253254
(cdef.name.toString, cdef.constructor, cdef.parents, cdef.self, rhs.body)
254255

255256
def module(module: Symbol, parents: List[Tree /* Term | TypeTree */], body: List[Statement]): (ValDef, ClassDef) = {
257+
if xCheckMacro then TreeChecker.checkParents(module.moduleClass.asClass, parents)
256258
val cls = module.moduleClass
257259
val clsDef = ClassDef(cls, parents, body)
258260
val newCls = Apply(Select(New(TypeIdent(cls)), cls.primaryConstructor), Nil)

tests/neg-macros/i19842.check renamed to tests/neg-macros/i19842-a.check

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,18 @@
1-
-- Error: tests/neg-macros/i19842/Test.scala:9:50 ----------------------------------------------------------------------
1+
-- Error: tests/neg-macros/i19842-a/Test.scala:9:50 --------------------------------------------------------------------
22
9 |@main def Test = summon[Serializer[ValidationCls]] // error
33
| ^
4-
|Malformed tree was found while expanding macro with -Xcheck-macros.
5-
|The tree does not conform to the compiler's tree invariants.
6-
|
7-
|Macro was:
8-
|scala.quoted.runtime.Expr.splice[Serializer[ValidationCls]](((contextual$2: scala.quoted.Quotes) ?=> Macros.makeSerializer[ValidationCls](scala.quoted.Type.of[ValidationCls](contextual$2), contextual$2)))
9-
|
10-
|The macro returned:
11-
|{
12-
| object objectSerializer$macro$1 extends Serializer[ValidationCls] { this: objectSerializer$macro$1.type =>
13-
|
14-
| }
15-
| objectSerializer$macro$1
16-
|}
17-
|
18-
|Error:
19-
|assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1
4+
|Exception occurred while executing macro expansion.
5+
|java.lang.AssertionError: assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1
206
|
217
|Parents in symbol: [class Object, trait Serializer]
228
|Parents in tree: [trait Serializer]
239
|
10+
| at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
11+
| at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:209)
12+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:257)
13+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:256)
14+
| at Macros$.makeSerializer(Macro.scala:25)
2415
|
25-
|stacktrace available when compiling with `-Ydebug`
2616
|---------------------------------------------------------------------------------------------------------------------
2717
|Inline stack trace
2818
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

tests/neg-macros/i19842/Macro.scala renamed to tests/neg-macros/i19842-a/Macro.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ object Macros {
1616
name,
1717
Flags.Implicit,
1818
Flags.EmptyFlags,
19-
// Without TypeRep.of[Object] it would fail with java.lang.AssertionError: assertion failed: First parent must be a class
2019
List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
2120
_ => Nil,
2221
Symbol.noSymbol

tests/neg-macros/i19842-b.check

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- Error: tests/neg-macros/i19842-b/Test.scala:9:50 --------------------------------------------------------------------
2+
9 |@main def Test = summon[Serializer[ValidationCls]] // error
3+
| ^
4+
|Exception occurred while executing macro expansion.
5+
|java.lang.AssertionError: assertion failed: Parents of class symbol differs from the parents in the tree for object objectSerializer$macro$1
6+
|
7+
|Parents in symbol: [class Object, trait Serializer]
8+
|Parents in tree: [class Object, trait Serializer, trait Foo]
9+
|
10+
| at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
11+
| at dotty.tools.dotc.transform.TreeChecker$.checkParents(TreeChecker.scala:209)
12+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:257)
13+
| at scala.quoted.runtime.impl.QuotesImpl$reflect$ClassDef$.module(QuotesImpl.scala:256)
14+
| at Macros$.makeSerializer(Macro.scala:27)
15+
|
16+
|---------------------------------------------------------------------------------------------------------------------
17+
|Inline stack trace
18+
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
19+
|This location contains code that was inlined from Test.scala:5
20+
5 | implicit inline def implicitMakeSerializer[T]: Serializer[T] = ${ Macros.makeSerializer[T] }
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
---------------------------------------------------------------------------------------------------------------------

tests/neg-macros/i19842-b/Macro.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//> using options -experimental -Yno-experimental
2+
3+
import scala.annotation.{experimental, targetName}
4+
import scala.quoted.*
5+
import scala.util.Try
6+
7+
trait Foo
8+
9+
object Macros {
10+
def makeSerializer[T: Type](using Quotes): Expr[Serializer[T]] = {
11+
import quotes.reflect.*
12+
13+
val tpe: TypeRepr = TypeRepr.of[T]
14+
val name: String = Symbol.freshName("objectSerializer")
15+
16+
val modSym: Symbol = Symbol.newModule(
17+
Symbol.spliceOwner,
18+
name,
19+
Flags.Implicit,
20+
Flags.EmptyFlags,
21+
List(TypeRepr.of[Object], TypeRepr.of[Serializer[T]]),
22+
_ => Nil,
23+
Symbol.noSymbol
24+
)
25+
26+
val (modValDef: ValDef, modClassDef: ClassDef) =
27+
ClassDef.module(modSym, List(TypeTree.of[Object], TypeTree.of[Serializer[T]], TypeTree.of[Foo]), Nil)
28+
29+
Block(List(modValDef, modClassDef), Ref(modSym)).asExprOf[Serializer[T]]
30+
}
31+
}

tests/neg-macros/i19842-b/Test.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
trait Serializer[@specialized T]
3+
4+
object Serializer:
5+
implicit inline def implicitMakeSerializer[T]: Serializer[T] = ${ Macros.makeSerializer[T] }
6+
7+
case class ValidationCls(string: String)
8+
9+
@main def Test = summon[Serializer[ValidationCls]] // error

0 commit comments

Comments
 (0)