@@ -54,9 +54,10 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
54
54
def caseSymbols (implicit ctx : Context ): List [Symbol ] = { initSymbols; myCaseSymbols }
55
55
def caseModuleSymbols (implicit ctx : Context ): List [Symbol ] = { initSymbols; myCaseModuleSymbols }
56
56
57
- private def alreadyDefined (sym : Symbol , clazz : ClassSymbol )(implicit ctx : Context ): Boolean = {
57
+ private def existingDef (sym : Symbol , clazz : ClassSymbol )(implicit ctx : Context ): Symbol = {
58
58
val existing = sym.matchingMember(clazz.thisType)
59
- existing.exists && ! (existing == sym || existing.is(Deferred ))
59
+ if (existing != sym && ! existing.is(Deferred )) existing
60
+ else NoSymbol
60
61
}
61
62
62
63
private def synthesizeDef (sym : TermSymbol , rhsFn : List [List [Tree ]] => Context => Tree )(implicit ctx : Context ): Tree =
@@ -80,7 +81,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
80
81
else Nil
81
82
82
83
def syntheticDefIfMissing (sym : Symbol ): List [Tree ] =
83
- if (alreadyDefined (sym, clazz)) Nil else syntheticDef(sym) :: Nil
84
+ if (existingDef (sym, clazz).exists ) Nil else syntheticDef(sym) :: Nil
84
85
85
86
def syntheticDef (sym : Symbol ): Tree = {
86
87
val synthetic = sym.copy(
@@ -344,42 +345,79 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
344
345
}
345
346
}
346
347
348
+ /** For an enum T:
349
+ *
350
+ * def ordinal(x: MonoType) = x.enumTag
351
+ *
352
+ * For sealed trait with children of normalized types C_1, ..., C_n:
353
+ *
354
+ * def ordinal(x: MonoType) = x match {
355
+ * case _: C_1 => 0
356
+ * ...
357
+ * case _: C_n => n - 1
358
+ *
359
+ * Here, the normalized type of a class C is C[_, ...., _] with
360
+ * a wildcard for each type parameter. The normalized type of an object
361
+ * O is O.type.
362
+ */
363
+ def ordinalBody (cls : Symbol , param : Tree )(implicit ctx : Context ): Tree =
364
+ if (cls.is(Enum )) param.select(nme.enumTag)
365
+ else {
366
+ val cases =
367
+ for ((child, idx) <- cls.children.zipWithIndex) yield {
368
+ val patType = if (child.isTerm) child.termRef else child.rawTypeRef
369
+ val pat = Typed (untpd.Ident (nme.WILDCARD ).withType(patType), TypeTree (patType))
370
+ CaseDef (pat, EmptyTree , Literal (Constant (idx)))
371
+ }
372
+ Match (param, cases)
373
+ }
374
+
375
+ /** - If `impl` is the companion of a generic sum, add `deriving.Mirror.Sum` parent
376
+ * and `MonoType` and `ordinal` members.
377
+ * - If `impl` is the companion of a generic product, add `deriving.Mirror.Product` parent
378
+ * and `MonoType` and `fromProduct` members.
379
+ */
347
380
def addMirrorSupport (impl : Template )(implicit ctx : Context ): Template = {
348
381
val clazz = ctx.owner.asClass
349
- var newBody = serializableObjectMethod(clazz) ::: caseAndValueMethods(clazz) ::: impl.body
382
+ val linked = clazz.linkedClass
383
+
384
+ var newBody = impl.body
350
385
var newParents = impl.parents
351
- def addParent (parent : Type ) = {
386
+ def addParent (parent : Type ): Unit = {
352
387
newParents = newParents :+ TypeTree (parent)
353
388
val oldClassInfo = clazz.classInfo
354
389
val newClassInfo = oldClassInfo.derivedClassInfo(
355
390
classParents = oldClassInfo.classParents :+ parent)
356
391
clazz.copySymDenotation(info = newClassInfo).installAfter(thisPhase)
357
392
}
393
+ def addMethod (name : TermName , info : Type , body : (Symbol , Tree , Context ) => Tree ): Unit = {
394
+ val meth = ctx.newSymbol(clazz, name, Synthetic | Method , info, coord = clazz.coord)
395
+ if (! existingDef(meth, clazz).exists) {
396
+ meth.entered
397
+ newBody = newBody :+
398
+ synthesizeDef(meth, vrefss => ctx => body(linked, vrefss.head.head, ctx))
399
+ }
400
+ }
401
+ lazy val monoType = {
402
+ val monoType =
403
+ ctx.newSymbol(clazz, tpnme.MonoType , Synthetic , TypeAlias (linked.rawTypeRef), coord = clazz.coord)
404
+ existingDef(monoType, clazz).orElse {
405
+ newBody = newBody :+ TypeDef (monoType).withSpan(ctx.owner.span.focus)
406
+ monoType.entered
407
+ }
408
+ }
358
409
if (clazz.is(Module )) {
359
- if (clazz.is(Case )) addParent(defn.Mirror_SingletonType )
360
- else {
361
- val linked = clazz.linkedClass
362
- if (linked.isGenericProduct) {
363
- addParent(defn.Mirror_ProductType )
364
- val rawClassType =
365
- linked.typeRef.appliedTo(linked.typeParams.map(_ => TypeBounds .empty))
366
- val monoType =
367
- ctx.newSymbol(clazz, tpnme.MonoType , Synthetic , TypeAlias (rawClassType), coord = clazz.coord)
368
- if (! alreadyDefined(monoType, clazz)) {
369
- monoType.entered
370
- newBody = newBody :+ TypeDef (monoType).withSpan(ctx.owner.span.focus)
371
- }
372
- val fromProduct =
373
- ctx.newSymbol(clazz, nme.fromProduct, Synthetic | Method ,
374
- info = MethodType (defn.ProductType :: Nil , monoType.typeRef), coord = clazz.coord)
375
- if (! alreadyDefined(fromProduct, clazz)) {
376
- fromProduct.entered
377
- newBody = newBody :+
378
- synthesizeDef(fromProduct, vrefss => ctx =>
379
- fromProductBody(linked, vrefss.head.head)(ctx)
380
- .ensureConforms(rawClassType)) // t4758.scala or i3381.scala are examples where a cast is needed
381
- }
382
- }
410
+ if (clazz.is(Case ))
411
+ addParent(defn.Mirror_SingletonType )
412
+ else if (linked.isGenericProduct) {
413
+ addParent(defn.Mirror_ProductType )
414
+ addMethod(nme.fromProduct, MethodType (defn.ProductType :: Nil , monoType.typeRef),
415
+ fromProductBody(_, _)(_).ensureConforms(monoType.typeRef)) // t4758.scala or i3381.scala are examples where a cast is needed
416
+ }
417
+ else if (linked.isGenericSum) {
418
+ addParent(defn.Mirror_SumType )
419
+ addMethod(nme.ordinal, MethodType (monoType.typeRef :: Nil , defn.IntType ),
420
+ ordinalBody(_, _)(_))
383
421
}
384
422
}
385
423
0 commit comments