Skip to content

Commit 01da2ff

Browse files
committed
Synthesize mirrors also for Scala 2 defined classes and objects
1 parent 68a3fa3 commit 01da2ff

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
@@ -703,6 +703,9 @@ class Definitions {
703703
lazy val Mirror_SingletonType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.Singleton")
704704
def Mirror_SingletonClass(implicit ctx: Context): ClassSymbol = Mirror_SingletonType.symbol.asClass
705705

706+
lazy val Mirror_SingletonProxyType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.SingletonProxy")
707+
def Mirror_SingletonProxyClass(implicit ctx: Context): ClassSymbol = Mirror_SingletonProxyType.symbol.asClass
708+
706709
lazy val GenericType: TypeRef = ctx.requiredClassRef("scala.reflect.Generic")
707710
def GenericClass(implicit ctx: Context): ClassSymbol = GenericType.symbol.asClass
708711
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
@@ -815,35 +815,69 @@ trait Implicits { self: Typer =>
815815
EmptyTree
816816
}
817817

818+
/** Create an anonymous class `new Object { type MonoType = ... }`
819+
* and mark it with given attachment so that it is made into a mirror at PostTyper.
820+
*/
821+
def anonymousMirror(monoType: Type, attachment: Property.StickyKey[Unit], span: Span)(implicit ctx: Context) = {
822+
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
823+
val newImpl = untpd.Template(
824+
constr = untpd.emptyConstructor,
825+
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
826+
derived = Nil,
827+
self = EmptyValDef,
828+
body = monoTypeDef :: Nil
829+
).withAttachment(attachment, ())
830+
typed(untpd.New(newImpl).withSpan(span))
831+
}
832+
818833
lazy val synthesizedProductMirror: SpecialHandler =
819834
(formal: Type, span: Span) => implicit (ctx: Context) => {
820-
formal.member(tpnme.MonoType).info match {
821-
case monoAlias @ TypeAlias(monoType) =>
835+
def mirrorFor(monoType: Type): Tree = monoType match {
836+
case AndType(tp1, tp2) =>
837+
mirrorFor(tp1).orElse(mirrorFor(tp2))
838+
case _ =>
822839
if (monoType.termSymbol.is(CaseVal)) {
823840
val modul = monoType.termSymbol
824841
val label = ConstantType(Constant(modul.name.toString))
825-
val mirrorType = defn.Mirror_SingletonType
826-
.refinedWith(tpnme.MonoType, monoAlias)
827-
.refinedWith(tpnme.Label, TypeAlias(label))
828-
ref(modul).withSpan(span).cast(mirrorType)
842+
if (modul.info.classSymbol.is(Scala2x)) {
843+
val mirrorType =
844+
defn.Mirror_SingletonProxyType
845+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
846+
.refinedWith(tpnme.Label, TypeAlias(label))
847+
val mirrorRef = New(defn.Mirror_SingletonProxyType, ref(modul).withSpan(span) :: Nil)
848+
mirrorRef.cast(mirrorType)
849+
}
850+
else {
851+
val mirrorType = defn.Mirror_SingletonType
852+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
853+
.refinedWith(tpnme.Label, TypeAlias(label))
854+
val mirrorRef = ref(modul).withSpan(span)
855+
mirrorRef.cast(mirrorType)
856+
}
829857
}
830858
else if (monoType.classSymbol.isGenericProduct) {
831859
val cls = monoType.classSymbol
832860
val accessors = cls.caseAccessors.filterNot(_.is(PrivateLocal))
833-
val elemTypes = accessors.map(monoType.memberInfo(_))
861+
val elemTypes = accessors.map(monoType.memberInfo(_).widenExpr)
834862
val label = ConstantType(Constant(cls.name.toString))
835863
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
836864
val mirrorType =
837865
defn.Mirror_ProductType
838-
.refinedWith(tpnme.MonoType, monoAlias)
866+
.refinedWith(tpnme.MonoType, TypeAlias(monoType))
839867
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
840868
.refinedWith(tpnme.Label, TypeAlias(label))
841869
.refinedWith(tpnme.ElemLabels, TypeAlias(TypeOps.nestedPairs(elemLabels)))
842870
val modul = cls.linkedClass.sourceModule
843871
assert(modul.is(Module))
844-
ref(modul).withSpan(span).cast(mirrorType)
872+
val mirrorRef =
873+
if (cls.is(Scala2x)) anonymousMirror(monoType, ExtendsProductMirror, span)
874+
else ref(modul).withSpan(span)
875+
mirrorRef.cast(mirrorType)
845876
}
846877
else EmptyTree
878+
}
879+
formal.member(tpnme.MonoType).info match {
880+
case monoAlias @ TypeAlias(monoType) => mirrorFor(monoType)
847881
case _ => EmptyTree
848882
}
849883
}
@@ -863,9 +897,8 @@ trait Implicits { self: Typer =>
863897
case info: PolyType =>
864898
def instantiate(implicit ctx: Context) = {
865899
val poly = constrained(info, untpd.EmptyTree)._1
866-
val mono @ MethodType(_) = poly.resultType
867-
val resType = mono.finalResultType
868-
resType <:< cls.appliedRef
900+
val resType = poly.finalResultType
901+
resType <:< monoType
869902
val tparams = poly.paramRefs
870903
val variances = caseClass.typeParams.map(_.paramVariance)
871904
val instanceTypes = (tparams, variances).zipped.map((tparam, variance) =>
@@ -885,20 +918,8 @@ trait Implicits { self: Typer =>
885918
.refinedWith(tpnme.ElemTypes, TypeAlias(TypeOps.nestedPairs(elemTypes)))
886919
var modul = cls.linkedClass.sourceModule
887920
val mirrorRef =
888-
if (modul.exists) ref(modul).withSpan(span)
889-
else {
890-
// create an anonymous class `new Object { type MonoType = ... }`
891-
// and mark it so that it is made into a `Mirror.Sum` at PostTyper.
892-
val monoTypeDef = untpd.TypeDef(tpnme.MonoType, untpd.TypeTree(monoType))
893-
val newImpl = untpd.Template(
894-
constr = untpd.emptyConstructor,
895-
parents = untpd.TypeTree(defn.ObjectType) :: Nil,
896-
derived = Nil,
897-
self = EmptyValDef,
898-
body = monoTypeDef :: Nil
899-
).withAttachment(ExtendsSumMirror, ())
900-
typed(untpd.New(newImpl).withSpan(span))
901-
}
921+
if (modul.exists && !cls.is(Scala2x)) ref(modul).withSpan(span)
922+
else anonymousMirror(monoType, ExtendsSumMirror, span)
902923
mirrorRef.cast(mirrorType)
903924
case _ =>
904925
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)