Skip to content

Commit eda4232

Browse files
oderskymilessabin
authored andcommitted
Synthesize mirrors also for Scala 2 defined classes and objects
1 parent e50a032 commit eda4232

File tree

6 files changed

+175
-127
lines changed

6 files changed

+175
-127
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ class Definitions {
705705
lazy val Mirror_SingletonType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.Singleton")
706706
def Mirror_SingletonClass(implicit ctx: Context): ClassSymbol = Mirror_SingletonType.symbol.asClass
707707

708+
lazy val Mirror_SingletonProxyType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.SingletonProxy")
709+
def Mirror_SingletonProxyClass(implicit ctx: Context): ClassSymbol = Mirror_SingletonProxyType.symbol.asClass
710+
708711
lazy val GenericType: TypeRef = ctx.requiredClassRef("scala.reflect.Generic")
709712
def GenericClass(implicit ctx: Context): ClassSymbol = GenericType.symbol.asClass
710713
lazy val ShapeType: TypeRef = ctx.requiredClassRef("scala.compiletime.Shape")

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ import config.Printers.derive
1717

1818
object SyntheticMembers {
1919

20-
/** Attachment marking an anonymous class as a singleton case that will extend from Mirror.Singleton. */
20+
/** Attachment marking an anonymous class as a singleton case that will extend from Mirror.Singleton */
2121
val ExtendsSingletonMirror: Property.StickyKey[Unit] = new Property.StickyKey
2222

23-
/** Attachment marking an anonymous class as a sum mirror that will extends from Mirror.Sum. */
23+
/** Attachment recording that an anonymous class should extend Mirror.Product */
24+
val ExtendsProductMirror: Property.StickyKey[Unit] = new Property.StickyKey
25+
26+
/** Attachment recording that an anonymous class should extend Mirror.Sum */
2427
val ExtendsSumMirror: Property.StickyKey[Unit] = new Property.StickyKey
2528
}
2629

@@ -423,32 +426,28 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
423426
}
424427
def makeSingletonMirror() =
425428
addParent(defn.Mirror_SingletonType)
426-
def makeProductMirror() = {
429+
def makeProductMirror(cls: Symbol) = {
427430
addParent(defn.Mirror_ProductType)
428-
addMethod(
429-
nme.fromProduct,
430-
MethodType(defn.ProductType :: Nil, monoType.typeRef),
431-
linked,
431+
addMethod(nme.fromProduct, MethodType(defn.ProductType :: Nil, monoType.typeRef), cls,
432432
fromProductBody(_, _)(_).ensureConforms(monoType.typeRef)) // t4758.scala or i3381.scala are examples where a cast is needed
433433
}
434434
def makeSumMirror(cls: Symbol) = {
435435
addParent(defn.Mirror_SumType)
436-
addMethod(
437-
nme.ordinal,
438-
MethodType(monoType.typeRef :: Nil, defn.IntType),
439-
cls,
436+
addMethod(nme.ordinal, MethodType(monoType.typeRef :: Nil, defn.IntType), cls,
440437
ordinalBody(_, _)(_))
441438
}
442439

443440
if (clazz.is(Module)) {
444441
if (clazz.is(Case)) makeSingletonMirror()
445-
else if (linked.isGenericProduct) makeProductMirror()
442+
else if (linked.isGenericProduct) makeProductMirror(linked)
446443
else if (linked.isGenericSum) makeSumMirror(linked)
447444
else if (linked.is(Sealed))
448445
derive.println(i"$linked is not a sum because ${linked.whyNotGenericSum}")
449446
}
450447
else if (impl.removeAttachment(ExtendsSingletonMirror).isDefined)
451448
makeSingletonMirror()
449+
else if (impl.removeAttachment(ExtendsProductMirror).isDefined)
450+
makeProductMirror(monoType.typeRef.dealias.classSymbol)
452451
else if (impl.removeAttachment(ExtendsSumMirror).isDefined)
453452
makeSumMirror(monoType.typeRef.dealias.classSymbol)
454453

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

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import Inferencing.fullyDefinedType
2929
import Trees._
3030
import transform.SymUtils._
3131
import transform.TypeUtils._
32-
import transform.SyntheticMembers.ExtendsSumMirror
32+
import transform.SyntheticMembers._
3333
import Hashable._
3434
import util.{Property, SourceFile, NoSource}
3535
import config.Config
@@ -859,35 +859,69 @@ trait Implicits { self: Typer =>
859859
EmptyTree
860860
}
861861

862+
/** Create an anonymous class `new Object { type MonoType = ... }`
863+
* and mark it with given attachment so that it is made into a mirror at PostTyper.
864+
*/
865+
def anonymousMirror(monoType: Type, attachment: Property.StickyKey[Unit], span: Span)(implicit ctx: Context) = {
866+
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
867+
val newImpl = untpd.Template(
868+
constr = untpd.emptyConstructor,
869+
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
870+
derived = Nil,
871+
self = EmptyValDef,
872+
body = monoTypeDef :: Nil
873+
).withAttachment(attachment, ())
874+
typed(untpd.New(newImpl).withSpan(span))
875+
}
876+
862877
lazy val synthesizedProductMirror: SpecialHandler =
863878
(formal: Type, span: Span) => implicit (ctx: Context) => {
864-
formal.member(tpnme.MonoType).info match {
865-
case monoAlias @ TypeAlias(monoType) =>
879+
def mirrorFor(monoType: Type): Tree = monoType match {
880+
case AndType(tp1, tp2) =>
881+
mirrorFor(tp1).orElse(mirrorFor(tp2))
882+
case _ =>
866883
if (monoType.termSymbol.is(CaseVal)) {
867884
val modul = monoType.termSymbol
868885
val label = ConstantType(Constant(modul.name.toString))
869-
val mirrorType = defn.Mirror_SingletonType
870-
.refinedWith(tpnme.MonoType, monoAlias)
871-
.refinedWith(tpnme.Label, TypeAlias(label))
872-
ref(modul).withSpan(span).cast(mirrorType)
886+
if (modul.info.classSymbol.is(Scala2x)) {
887+
val mirrorType =
888+
defn.Mirror_SingletonProxyType
889+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
890+
.refinedWith(tpnme.Label, TypeAlias(label))
891+
val mirrorRef = New(defn.Mirror_SingletonProxyType, ref(modul).withSpan(span) :: Nil)
892+
mirrorRef.cast(mirrorType)
893+
}
894+
else {
895+
val mirrorType = defn.Mirror_SingletonType
896+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
897+
.refinedWith(tpnme.Label, TypeAlias(label))
898+
val mirrorRef = ref(modul).withSpan(span)
899+
mirrorRef.cast(mirrorType)
900+
}
873901
}
874902
else if (monoType.classSymbol.isGenericProduct) {
875903
val cls = monoType.classSymbol
876904
val accessors = cls.caseAccessors.filterNot(_.is(PrivateLocal))
877-
val elemTypes = accessors.map(monoType.memberInfo(_))
905+
val elemTypes = accessors.map(monoType.memberInfo(_).widenExpr)
878906
val label = ConstantType(Constant(cls.name.toString))
879907
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
880908
val mirrorType =
881909
defn.Mirror_ProductType
882-
.refinedWith(tpnme.MonoType, monoAlias)
910+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
883911
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
884912
.refinedWith(tpnme.Label, TypeAlias(label))
885913
.refinedWith(tpnme.ElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
886914
val modul = cls.linkedClass.sourceModule
887915
assert(modul.is(Module))
888-
ref(modul).withSpan(span).cast(mirrorType)
916+
val mirrorRef =
917+
if (cls.is(Scala2x)) anonymousMirror(monoType, ExtendsProductMirror, span)
918+
else ref(modul).withSpan(span)
919+
mirrorRef.cast(mirrorType)
889920
}
890921
else EmptyTree
922+
}
923+
formal.member(tpnme.MonoType).info match {
924+
case monoAlias @ TypeAlias(monoType) => mirrorFor(monoType)
891925
case _ => EmptyTree
892926
}
893927
}
@@ -907,9 +941,8 @@ trait Implicits { self: Typer =>
907941
case info: PolyType =>
908942
def instantiate(implicit ctx: Context) = {
909943
val poly = constrained(info, untpd.EmptyTree)._1
910-
val mono @ MethodType(_) = poly.resultType
911-
val resType = mono.finalResultType
912-
resType <:< cls.appliedRef
944+
val resType = poly.finalResultType
945+
resType <:< monoType
913946
val tparams = poly.paramRefs
914947
val variances = caseClass.typeParams.map(_.paramVariance)
915948
val instanceTypes = (tparams, variances).zipped.map((tparam, variance) =>
@@ -929,20 +962,8 @@ trait Implicits { self: Typer =>
929962
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
930963
var modul = cls.linkedClass.sourceModule
931964
val mirrorRef =
932-
if (modul.exists) ref(modul).withSpan(span)
933-
else {
934-
// create an anonymous class `new Object { type MonoType = ... }`
935-
// and mark it so that it is made into a `Mirror.Sum` at PostTyper.
936-
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
937-
val newImpl = untpd.Template(
938-
constr = untpd.emptyConstructor,
939-
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
940-
derived = Nil,
941-
self = EmptyValDef,
942-
body = monoTypeDef :: Nil
943-
).withAttachment(ExtendsSumMirror, ())
944-
typed(untpd.New(newImpl).withSpan(span))
945-
}
965+
if (modul.exists && !cls.is(Scala2x)) ref(modul).withSpan(span)
966+
else anonymousMirror(monoType, ExtendsSumMirror, span)
946967
mirrorRef.cast(mirrorType)
947968
case _ =>
948969
EmptyTree

library/src/scala/deriving.scala

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,15 @@ object deriving {
4242
type MonoType = this.type
4343
type ElemTypes = Unit
4444
type ElemLabels = Unit
45-
4645
def fromProduct(p: scala.Product) = this
46+
}
4747

48-
def productElement(n: Int): Any = throw new IndexOutOfBoundsException(n.toString)
49-
def productArity: Int = 0
48+
/** A proxy for Scala 2 singletons, which do not inherit `Singleton` directly */
49+
class SingletonProxy(val value: AnyRef) extends Product {
50+
type MonoType = value.type
51+
type ElemTypes = Unit
52+
type ElemLabels = Unit
53+
def fromProduct(p: scala.Product) = value
5054
}
5155

5256
type Of[T] = Mirror { type MonoType = T }

tests/run/typeclass-derivation3.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ ListBuffer(0, 0, 11, 0, 22, 0, 33, 1, 0, 0, 11, 0, 22, 1, 1)
44
Cons(Cons(11,Cons(22,Cons(33,Nil))),Cons(Cons(11,Cons(22,Nil)),Nil))
55
ListBuffer(1, 2)
66
Pair(1,2)
7-
Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil())))
8-
Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil()))), tl = Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Nil())), tl = Nil()))
9-
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil()))
10-
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil()))
7+
Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil)))
8+
Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Cons(hd = 33, tl = Nil))), tl = Cons(hd = Cons(hd = 11, tl = Cons(hd = 22, tl = Nil)), tl = Nil))
9+
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil))
10+
Cons(hd = Left(x = 1), tl = Cons(hd = Right(x = Pair(x = 2, y = 3)), tl = Nil))
1111
true
1212
::(head = 1, tl$access$1 = ::(head = 2, tl$access$1 = ::(head = 3, tl$access$1 = Nil())))
1313
::(head = ::(head = 1, tl$access$1 = Nil()), tl$access$1 = ::(head = ::(head = 2, tl$access$1 = ::(head = 3, tl$access$1 = Nil())), tl$access$1 = Nil()))

0 commit comments

Comments
 (0)