Skip to content

Commit 275a0a9

Browse files
oderskymilessabin
authored andcommitted
Generate sum mirrors for sealed traits that do not have a companion
1 parent be1a063 commit 275a0a9

File tree

5 files changed

+75
-29
lines changed

5 files changed

+75
-29
lines changed

compiler/src/dotty/tools/dotc/ast/DesugarEnums.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Symbols._, StdNames._, Trees._
88
import Decorators._
99
import util.{Property, SourceFile}
1010
import typer.ErrorReporting._
11+
import transform.SyntheticMembers.ExtendsSingletonMirror
1112

1213
import scala.annotation.internal.sharable
1314

@@ -22,9 +23,6 @@ object DesugarEnums {
2223
/** Attachment containing the number of enum cases and the smallest kind that was seen so far. */
2324
val EnumCaseCount: Property.Key[(Int, DesugarEnums.CaseKind.Value)] = new Property.Key
2425

25-
/** Attachment marking an anonymous class as a singleton case. */
26-
val SingletonCase: Property.StickyKey[Unit] = new Property.StickyKey
27-
2826
/** The enumeration class that belongs to an enum case. This works no matter
2927
* whether the case is still in the enum class or it has been transferred to the
3028
* companion object.
@@ -124,7 +122,7 @@ object DesugarEnums {
124122
derived = Nil,
125123
self = EmptyValDef,
126124
body = List(enumTagDef, toStringDef) ++ registerCall
127-
).withAttachment(SingletonCase, ()))
125+
).withAttachment(ExtendsSingletonMirror, ()))
128126
DefDef(nme.DOLLAR_NEW, Nil,
129127
List(List(param(nme.tag, defn.IntType), param(nme.name, defn.StringType))),
130128
TypeTree(), creator).withFlags(Private | Synthetic)
@@ -267,7 +265,7 @@ object DesugarEnums {
267265
.withFlags(Override)
268266
val (tagMeth, scaffolding) = enumTagMeth(CaseKind.Object)
269267
val impl1 = cpy.Template(impl)(body = List(tagMeth, toStringMeth) ++ registerCall)
270-
.withAttachment(SingletonCase, ())
268+
.withAttachment(ExtendsSingletonMirror, ())
271269
val vdef = ValDef(name, TypeTree(), New(impl1)).withMods(mods | Final)
272270
flatTree(scaffolding ::: vdef :: Nil).withSpan(span)
273271
}

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

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@ import NameOps._
1010
import Annotations.Annotation
1111
import typer.ProtoTypes.constrained
1212
import ast.untpd
13-
import ast.DesugarEnums.SingletonCase
1413
import ValueClasses.isDerivedValueClass
1514
import SymUtils._
15+
import util.Property
1616
import config.Printers.derive
1717

18+
object SyntheticMembers {
19+
20+
/** Attachment marking an anonymous class as a singleton case that will extend from Mirror.Singleton. */
21+
val ExtendsSingletonMirror: Property.StickyKey[Unit] = new Property.StickyKey
22+
23+
/** Attachment marking an anonymous class as a sum mirror that will extends from Mirror.Sum. */
24+
val ExtendsSumMirror: Property.StickyKey[Unit] = new Property.StickyKey
25+
}
26+
1827
/** Synthetic method implementations for case classes, case objects,
1928
* and value classes.
2029
*
@@ -38,6 +47,7 @@ import config.Printers.derive
3847
* def hashCode(): Int
3948
*/
4049
class SyntheticMembers(thisPhase: DenotTransformer) {
50+
import SyntheticMembers._
4151
import ast.tpd._
4252

4353
private[this] var myValueSymbols: List[Symbol] = Nil
@@ -381,7 +391,6 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
381391
*/
382392
def addMirrorSupport(impl: Template)(implicit ctx: Context): Template = {
383393
val clazz = ctx.owner.asClass
384-
val linked = clazz.linkedClass
385394

386395
var newBody = impl.body
387396
var newParents = impl.parents
@@ -392,40 +401,56 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
392401
classParents = oldClassInfo.classParents :+ parent)
393402
clazz.copySymDenotation(info = newClassInfo).installAfter(thisPhase)
394403
}
395-
def addMethod(name: TermName, info: Type, body: (Symbol, Tree, Context) => Tree): Unit = {
404+
def addMethod(name: TermName, info: Type, cls: Symbol, body: (Symbol, Tree, Context) => Tree): Unit = {
396405
val meth = ctx.newSymbol(clazz, name, Synthetic | Method, info, coord = clazz.coord)
397406
if (!existingDef(meth, clazz).exists) {
398407
meth.entered
399408
newBody = newBody :+
400-
synthesizeDef(meth, vrefss => ctx => body(linked, vrefss.head.head, ctx))
409+
synthesizeDef(meth, vrefss => ctx => body(cls, vrefss.head.head, ctx))
401410
}
402411
}
412+
val linked = clazz.linkedClass
403413
lazy val monoType = {
404-
val monoType =
405-
ctx.newSymbol(clazz, tpnme.MonoType, Synthetic, TypeAlias(linked.rawTypeRef), coord = clazz.coord)
406-
existingDef(monoType, clazz).orElse {
414+
val existing = clazz.info.member(tpnme.MonoType).symbol
415+
if (existing.exists && !existing.is(Deferred)) existing
416+
else {
417+
val monoType =
418+
ctx.newSymbol(clazz, tpnme.MonoType, Synthetic, TypeAlias(linked.rawTypeRef), coord = clazz.coord)
407419
newBody = newBody :+ TypeDef(monoType).withSpan(ctx.owner.span.focus)
408420
monoType.entered
409421
}
410422
}
423+
def makeSingletonMirror() =
424+
addParent(defn.Mirror_SingletonType)
425+
def makeProductMirror() = {
426+
addParent(defn.Mirror_ProductType)
427+
addMethod(
428+
nme.fromProduct,
429+
MethodType(defn.ProductType :: Nil, monoType.typeRef),
430+
linked,
431+
fromProductBody(_, _)(_).ensureConforms(monoType.typeRef)) // t4758.scala or i3381.scala are examples where a cast is needed
432+
}
433+
def makeSumMirror(cls: Symbol) = {
434+
addParent(defn.Mirror_SumType)
435+
addMethod(
436+
nme.ordinal,
437+
MethodType(monoType.typeRef :: Nil, defn.IntType),
438+
cls,
439+
ordinalBody(_, _)(_))
440+
}
441+
411442
if (clazz.is(Module)) {
412-
if (clazz.is(Case))
413-
addParent(defn.Mirror_SingletonType)
414-
else if (linked.isGenericProduct) {
415-
addParent(defn.Mirror_ProductType)
416-
addMethod(nme.fromProduct, MethodType(defn.ProductType :: Nil, monoType.typeRef),
417-
fromProductBody(_, _)(_).ensureConforms(monoType.typeRef)) // t4758.scala or i3381.scala are examples where a cast is needed
418-
}
419-
else if (linked.isGenericSum) {
420-
addParent(defn.Mirror_SumType)
421-
addMethod(nme.ordinal, MethodType(monoType.typeRef :: Nil, defn.IntType),
422-
ordinalBody(_, _)(_))
423-
}
443+
if (clazz.is(Case)) makeSingletonMirror()
444+
else if (linked.isGenericProduct) makeProductMirror()
445+
else if (linked.isGenericSum) makeSumMirror(linked)
424446
else if (linked.is(Sealed))
425447
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum}")
426448
}
427-
else if (impl.removeAttachment(SingletonCase).isDefined)
428-
addParent(defn.Mirror_SingletonType)
449+
else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
450+
makeSingletonMirror()
451+
else if (impl.removeAttachment(ExtendsSumMirror).isDefined)
452+
makeSumMirror(monoType.typeRef.dealias.classSymbol)
453+
429454
cpy.Template(impl)(parents = newParents, body = newBody)
430455
}
431456

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc
33
package typer
44

55
import core._
6-
import ast.{Trees, TreeTypeMap, untpd, tpd}
6+
import ast.{Trees, TreeTypeMap, untpd, tpd, DesugarEnums}
77
import util.Spans._
88
import util.Stats.{track, record, monitored}
99
import printing.{Showable, Printer}
@@ -29,6 +29,7 @@ import Inferencing.fullyDefinedType
2929
import Trees._
3030
import transform.SymUtils._
3131
import transform.TypeUtils._
32+
import transform.SyntheticMembers.ExtendsSumMirror
3233
import Hashable._
3334
import util.{Property, SourceFile, NoSource}
3435
import config.Config
@@ -925,8 +926,22 @@ trait Implicits { self: Typer =>
925926
.refinedWith(tpnme.MonoType, monoAlias)
926927
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
927928
var modul = cls.linkedClass.sourceModule
928-
if (!modul.exists) ???
929-
ref(modul).withSpan(span).cast(mirrorType)
929+
val mirrorRef =
930+
if (modul.exists) ref(modul).withSpan(span)
931+
else {
932+
// create an anonymous class `new Object { type MonoType = ... }`
933+
// and mark it so that it is made into a `Mirror.Sum` at PostTyper.
934+
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
935+
val newImpl = untpd.Template(
936+
constr = untpd.emptyConstructor,
937+
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
938+
derived = Nil,
939+
self = EmptyValDef,
940+
body = monoTypeDef :: Nil
941+
).withAttachment(ExtendsSumMirror, ())
942+
typed(untpd.New(newImpl).withSpan(span))
943+
}
944+
mirrorRef.cast(mirrorType)
930945
case _ =>
931946
EmptyTree
932947
}

tests/run/deriving.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ A(1,2)
22
A(1,2)
33
B
44
1
5+
0

tests/run/deriving.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ object T
44
case class A(x: Int, y: Int) extends T
55
case object B extends T
66

7+
sealed trait U
8+
case class C() extends U
9+
710
object Test extends App {
811
import deriving.{Mirror, EmptyProduct}
912

@@ -24,4 +27,8 @@ object Test extends App {
2427
case m: Mirror.SumOf[T] =>
2528
println(m.ordinal(B))
2629
}
30+
the[Mirror.Of[U]] match {
31+
case m: Mirror.SumOf[U] =>
32+
println(m.ordinal(C()))
33+
}
2734
}

0 commit comments

Comments
 (0)