Skip to content

Commit 3617cba

Browse files
oderskymilessabin
authored andcommitted
Add deriving.Mirror infrastructure
1 parent c30af3c commit 3617cba

File tree

6 files changed

+112
-31
lines changed

6 files changed

+112
-31
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,16 @@ class Definitions {
690690
lazy val ModuleSerializationProxyConstructor: TermSymbol =
691691
ModuleSerializationProxyClass.requiredMethod(nme.CONSTRUCTOR, List(ClassType(TypeBounds.empty)))
692692

693+
//lazy val MirrorType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror")
694+
lazy val Mirror_ProductType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.Product")
695+
def Mirror_ProductClass(implicit ctx: Context): ClassSymbol = Mirror_ProductType.symbol.asClass
696+
697+
lazy val Mirror_Product_fromProductR: TermRef = Mirror_ProductClass.requiredMethodRef(nme.fromProduct)
698+
def Mirror_Product_fromProduct(implicit ctx: Context): Symbol = Mirror_Product_fromProductR.symbol
699+
700+
lazy val Mirror_SingletonType: TypeRef = ctx.requiredClassRef("scala.deriving.Mirror.Singleton")
701+
def Mirror_SingletonClass(implicit ctx: Context): ClassSymbol = Mirror_SingletonType.symbol.asClass
702+
693703
lazy val GenericType: TypeRef = ctx.requiredClassRef("scala.reflect.Generic")
694704
def GenericClass(implicit ctx: Context): ClassSymbol = GenericType.symbol.asClass
695705
lazy val ShapeType: TypeRef = ctx.requiredClassRef("scala.compiletime.Shape")

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ object StdNames {
340340
val longHash: N = "longHash"
341341
val MatchCase: N = "MatchCase"
342342
val Modifiers: N = "Modifiers"
343+
val MonoType: N = "MonoType"
343344
val NestedAnnotArg: N = "NestedAnnotArg"
344345
val NoFlags: N = "NoFlags"
345346
val NoPrefix: N = "NoPrefix"
@@ -432,6 +433,7 @@ object StdNames {
432433
val flagsFromBits : N = "flagsFromBits"
433434
val flatMap: N = "flatMap"
434435
val foreach: N = "foreach"
436+
val fromProduct: N = "fromProduct"
435437
val genericArrayOps: N = "genericArrayOps"
436438
val genericClass: N = "genericClass"
437439
val get: N = "get"

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ class Namer { typer: Typer =>
447447
case _ => tree
448448
}
449449

450-
/** For all class definitions `stat` in `xstats`: If the companion class if
450+
/** For all class definitions `stat` in `xstats`: If the companion class is
451451
* not also defined in `xstats`, invalidate it by setting its info to
452452
* NoType.
453453
*/
@@ -702,7 +702,7 @@ class Namer { typer: Typer =>
702702
// If a top-level object or class has no companion in the current run, we
703703
// enter a dummy companion (`denot.isAbsent` returns true) in scope. This
704704
// ensures that we never use a companion from a previous run or from the
705-
// classpath. See tests/pos/false-companion for an example where this
705+
// class path. See tests/pos/false-companion for an example where this
706706
// matters.
707707
if (ctx.owner.is(PackageClass)) {
708708
for (cdef @ TypeDef(moduleName, _) <- moduleDef.values) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,9 @@ trait TypeAssigner {
160160
private def toRepeated(tree: Tree, from: ClassSymbol)(implicit ctx: Context): Tree =
161161
Typed(tree, TypeTree(tree.tpe.widen.translateParameterized(from, defn.RepeatedParamClass)))
162162

163-
def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.SeqClass)
163+
def seqToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.SeqClass)
164164

165-
def arrayToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.ArrayClass)
165+
def arrayToRepeated(tree: Tree)(implicit ctx: Context): Tree = toRepeated(tree, defn.ArrayClass)
166166

167167
/** A denotation exists really if it exists and does not point to a stale symbol. */
168168
final def reallyExists(denot: Denotation)(implicit ctx: Context): Boolean = try

library/src/scala/deriving.scala

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package scala
2+
3+
object deriving {
4+
5+
/** Mirrors allows typelevel access to enums, case classes and objects, and their sealed parents.
6+
*/
7+
sealed trait Mirror {
8+
9+
/** The mirrored *-type */
10+
type MonoType
11+
}
12+
13+
object Mirror {
14+
15+
/** The Mirror for a sum type */
16+
trait Sum extends Mirror { self =>
17+
18+
type ElemTypes <: Tuple
19+
20+
/** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
21+
def ordinal(x: MonoType): Int
22+
}
23+
24+
/** The Mirror for a product type */
25+
trait Product extends Mirror {
26+
27+
/** The types of the elements */
28+
type ElemTypes <: Tuple
29+
30+
/** The name of the whole product type */
31+
type CaseLabel <: String
32+
33+
/** The names of the product elements */
34+
type ElemLabels <: Tuple
35+
36+
/** Create a new instance of type `T` with elements taken from product `p`. */
37+
def fromProduct(p: scala.Product): MonoType
38+
}
39+
40+
trait Singleton extends Product with scala.Product {
41+
type MonoType = this.type
42+
def fromProduct(p: scala.Product) = this
43+
44+
def productElement(n: Int): Any = throw new IndexOutOfBoundsException(n.toString)
45+
def productArity: Int = 0
46+
}
47+
}
48+
49+
type MirrorOf[T] = Mirror { type MonoType = T }
50+
type ProductMirrorOf[T] = Mirror.Product { type MonoType = T }
51+
type SumMirrorOf[T] = Mirror.Sum { type MonoType = T }
52+
53+
/** Helper class to turn arrays into products */
54+
class ArrayProduct(val elems: Array[AnyRef]) extends Product {
55+
def this(size: Int) = this(new Array[AnyRef](size))
56+
def canEqual(that: Any): Boolean = true
57+
def productElement(n: Int) = elems(n)
58+
def productArity = elems.length
59+
override def productIterator: Iterator[Any] = elems.iterator
60+
def update(n: Int, x: Any) = elems(n) = x.asInstanceOf[AnyRef]
61+
}
62+
63+
/** The empty product */
64+
object EmptyProduct extends ArrayProduct(Array[AnyRef]())
65+
66+
/** Helper method to select a product element */
67+
def productElement[T](x: Any, idx: Int) =
68+
x.asInstanceOf[Product].productElement(idx).asInstanceOf[T]
69+
}

tests/run/typeclass-derivation2d.scala

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ object Deriving {
1414
sealed abstract class Mirror {
1515

1616
/** The mirrored *-type */
17-
type MonoType
17+
type _MonoType
1818
}
19-
type MirrorOf[T] = Mirror { type MonoType = T }
20-
type ProductMirrorOf[T] = Mirror.Product { type MonoType = T }
21-
type SumMirrorOf[T] = Mirror.Sum { type MonoType = T }
19+
type MirrorOf[T] = Mirror { type _MonoType = T }
20+
type ProductMirrorOf[T] = Mirror.Product { type _MonoType = T }
21+
type SumMirrorOf[T] = Mirror.Sum { type _MonoType = T }
2222

2323
object Mirror {
2424

@@ -28,7 +28,7 @@ object Deriving {
2828
type ElemTypes <: Tuple
2929

3030
/** The ordinal number of the case class of `x`. For enums, `ordinal(x) == x.ordinal` */
31-
def ordinal(x: MonoType): Int
31+
def ordinal(x: _MonoType): Int
3232
}
3333

3434
/** The Mirror for a product type */
@@ -44,12 +44,12 @@ object Deriving {
4444
type ElemLabels <: Tuple
4545

4646
/** Create a new instance of type `T` with elements taken from product `p`. */
47-
def fromProduct(p: scala.Product): MonoType
47+
def _fromProduct(p: scala.Product): _MonoType
4848
}
4949

5050
trait Singleton extends Product {
51-
type MonoType = this.type
52-
def fromProduct(p: scala.Product) = this
51+
type _MonoType = this.type
52+
def _fromProduct(p: scala.Product) = this
5353
}
5454
}
5555

@@ -74,30 +74,30 @@ import Deriving._
7474
sealed trait Lst[+T] // derives Eq, Pickler, Show
7575

7676
object Lst extends Mirror.Sum {
77-
type MonoType = Lst[_]
77+
type _MonoType = Lst[_]
7878

7979
def ordinal(x: Lst[_]) = x match {
8080
case x: Cons[_] => 0
8181
case Nil => 1
8282
}
8383

8484
implicit def mirror[T]: Mirror.Sum {
85-
type MonoType = Lst[T]
85+
type _MonoType = Lst[T]
8686
type ElemTypes = (Cons[T], Nil.type)
8787
} = this.asInstanceOf
8888

8989
case class Cons[T](hd: T, tl: Lst[T]) extends Lst[T]
9090

9191
object Cons extends Mirror.Product {
92-
type MonoType = Lst[_]
92+
type _MonoType = Lst[_]
9393

9494
def apply[T](x: T, xs: Lst[T]): Lst[T] = new Cons(x, xs)
9595

96-
def fromProduct(p: Product): Cons[_] =
96+
def _fromProduct(p: Product): Cons[_] =
9797
new Cons(productElement[Any](p, 0), productElement[Lst[Any]](p, 1))
9898

9999
implicit def mirror[T]: Mirror.Product {
100-
type MonoType = Cons[T]
100+
type _MonoType = Cons[T]
101101
type ElemTypes = (T, Lst[T])
102102
type CaseLabel = "Cons"
103103
type ElemLabels = ("hd", "tl")
@@ -107,7 +107,7 @@ object Lst extends Mirror.Sum {
107107
case object Nil extends Lst[Nothing] with Mirror.Singleton {
108108

109109
implicit def mirror: Mirror.Singleton {
110-
type MonoType = Nil.type
110+
type _MonoType = Nil.type
111111
type ElemTypes = Unit
112112
type CaseLabel = "Nil"
113113
type ElemLabels = Unit
@@ -125,13 +125,13 @@ object Lst extends Mirror.Sum {
125125
case class Pair[T](x: T, y: T) // derives Eq, Pickler, Show
126126

127127
object Pair extends Mirror.Product {
128-
type MonoType = Pair[_]
128+
type _MonoType = Pair[_]
129129

130-
def fromProduct(p: Product): Pair[_] =
130+
def _fromProduct(p: Product): Pair[_] =
131131
Pair(productElement[Any](p, 0), productElement[Any](p, 1))
132132

133133
implicit def mirror[T]: Mirror.Product {
134-
type MonoType = Pair[T]
134+
type _MonoType = Pair[T]
135135
type ElemTypes = (T, T)
136136
type CaseLabel = "Pair"
137137
type ElemLabels = ("x", "y")
@@ -148,15 +148,15 @@ object Pair extends Mirror.Product {
148148
sealed trait Either[+L, +R] extends Product with Serializable // derives Eq, Pickler, Show
149149

150150
object Either extends Mirror.Sum {
151-
type MonoType = Either[_, _]
151+
type _MonoType = Either[_, _]
152152

153153
def ordinal(x: Either[_, _]) = x match {
154154
case x: Left[_] => 0
155155
case x: Right[_] => 1
156156
}
157157

158158
implicit def mirror[L, R]: Mirror.Sum {
159-
type MonoType = Either[L, R]
159+
type _MonoType = Either[L, R]
160160
type ElemTypes = (Left[L], Right[R])
161161
} = this.asInstanceOf
162162

@@ -169,21 +169,21 @@ case class Left[L](elem: L) extends Either[L, Nothing]
169169
case class Right[R](elem: R) extends Either[Nothing, R]
170170

171171
object Left extends Mirror.Product {
172-
type MonoType = Left[_]
173-
def fromProduct(p: Product): Left[_] = Left(productElement[Any](p, 0))
172+
type _MonoType = Left[_]
173+
def _fromProduct(p: Product): Left[_] = Left(productElement[Any](p, 0))
174174
implicit def mirror[L]: Mirror.Product {
175-
type MonoType = Left[L]
175+
type _MonoType = Left[L]
176176
type ElemTypes = L *: Unit
177177
type CaseLabel = "Left"
178178
type ElemLabels = "x" *: Unit
179179
} = this.asInstanceOf
180180
}
181181

182182
object Right extends Mirror.Product {
183-
type MonoType = Right[_]
184-
def fromProduct(p: Product): Right[_] = Right(productElement[Any](p, 0))
183+
type _MonoType = Right[_]
184+
def _fromProduct(p: Product): Right[_] = Right(productElement[Any](p, 0))
185185
implicit def mirror[R]: Mirror.Product {
186-
type MonoType = Right[R]
186+
type _MonoType = Right[R]
187187
type ElemTypes = R *: Unit
188188
type CaseLabel = "Right"
189189
type ElemLabels = "x" *: Unit
@@ -293,11 +293,11 @@ object Pickler {
293293
inline def unpickleCase[T, Elems <: Tuple](buf: mutable.ListBuffer[Int], m: ProductMirrorOf[T]): T = {
294294
inline val size = constValue[Tuple.Size[Elems]]
295295
inline if (size == 0)
296-
m.fromProduct(EmptyProduct)
296+
m._fromProduct(EmptyProduct)
297297
else {
298298
val elems = new ArrayProduct(size)
299299
unpickleElems[Elems](0)(buf, elems)
300-
m.fromProduct(elems)
300+
m._fromProduct(elems)
301301
}
302302
}
303303

0 commit comments

Comments
 (0)