Skip to content

Commit 0bf30ce

Browse files
committed
Complete first version of derivation scheme
1 parent f1e2890 commit 0bf30ce

File tree

8 files changed

+312
-201
lines changed

8 files changed

+312
-201
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ object Config {
161161
final val showCompletions = false
162162

163163
/** If set, enables tracing */
164-
final val tracingEnabled = false
164+
final val tracingEnabled = true
165165

166166
/** Initial capacity of uniques HashMap.
167167
* Note: This MUST BE a power of two to work with util.HashSet

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ object StdNames {
483483
val null_ : N = "null"
484484
val ofDim: N = "ofDim"
485485
val opaque: N = "opaque"
486+
val ordinal: N = "ordinal"
486487
val origin: N = "origin"
487488
val prefix : N = "prefix"
488489
val productArity: N = "productArity"
@@ -491,7 +492,8 @@ object StdNames {
491492
val productPrefix: N = "productPrefix"
492493
val raw_ : N = "raw"
493494
val readResolve: N = "readResolve"
494-
val reflect : N = "reflect"
495+
val reflect: N = "reflect"
496+
val reflectedClass: N = "reflectedClass"
495497
val reflectiveSelectable: N = "reflectiveSelectable"
496498
val reify : N = "reify"
497499
val rootMirror : N = "rootMirror"

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

+259-87
Large diffs are not rendered by default.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,7 @@ class Namer { typer: Typer =>
990990
val derivingClass =
991991
if (original.removeAttachment(DerivingCompanion).isDefined) cls.companionClass.asClass
992992
else cls
993-
val deriver = new Deriver(derivingClass)(localCtx)
993+
val deriver = new Deriver(derivingClass, impl.pos.startPos)(localCtx)
994994
deriver.enterDerived(impl.derived)
995995
original.putAttachment(Deriver, deriver)
996996
}

library/src-scala3/scala/typelevel/Mirror.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class Mirror(val reflected: ReflectedClass, val ordinal: Int, val elems: Product
1111
def apply(n: Int): Any = elems.productElement(n)
1212

1313
/** The name of the constructor of the case reflected by this mirror */
14-
def caseLabel: String = reflected.label(ordinal, 0)
14+
def caseLabel: String = reflected.label(ordinal)(0)
1515

1616
/** The label of the `n`'th element of the case reflected by this mirror */
17-
def elementLabel(n: Int) = reflected.label(ordinal, n + 1)
17+
def elementLabel(n: Int) = reflected.label(ordinal)(n + 1)
1818
}

library/src-scala3/scala/typelevel/ReflectedClass.scala

+29-15
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package scala.typelevel
22
import annotation.tailrec
3+
import collection.mutable.ArrayBuffer
34

4-
/** @param caseLabels The case and element labels of the described ADT as encoded strings.
5-
*/
6-
class ReflectedClass(caseLabels: Array[String]) {
5+
/** @param labelsStr: A string encoding all case and element labels according to the
6+
* following grammar:
7+
*
8+
* labelString ::= caseString { caseSeparator caseString }
9+
* caseString ::= elemString { elemSeparator elemString }
10+
* caseSeparator ::= '\001'
11+
* elemSeparator ::= '\000'
12+
* elemString: "any sequence of characters not containing '\000` or `\001`"
13+
*/
14+
class ReflectedClass(labelsStr: String) {
715
import ReflectedClass._
816

917
/** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
@@ -22,22 +30,28 @@ class ReflectedClass(caseLabels: Array[String]) {
2230
def mirror(ordinal: Int): Mirror =
2331
mirror(ordinal, EmptyProduct)
2432

25-
private[typelevel] def label(ordinal: Int, idx: Int): String = {
26-
val labels = caseLabels(ordinal)
27-
@tailrec def separatorPos(from: Int): Int =
28-
if (from == labels.length || labels(from) == separator) from
29-
else separatorPos(from + 1)
30-
@tailrec def findLabel(count: Int, idx: Int): String =
31-
if (idx == labels.length) ""
32-
else if (count == 0) labels.substring(idx, separatorPos(idx))
33-
else findLabel(if (labels(idx) == separator) count - 1 else count, idx + 1)
34-
findLabel(idx, 0)
33+
val label: Array[Array[String]] =
34+
initLabels(0, 0, new ArrayBuffer[String], new ArrayBuffer[Array[String]])
35+
36+
private def initLabels(start: Int, cur: Int,
37+
elems: ArrayBuffer[String],
38+
cases: ArrayBuffer[Array[String]]): Array[Array[String]] = {
39+
def addElem = elems += labelsStr.substring(start, cur)
40+
def addCase = cases += addElem.toArray
41+
if (cur == labelsStr.length)
42+
addCase.toArray
43+
else if (labelsStr(cur) == caseSeparator)
44+
initLabels(cur + 1, cur + 1, new ArrayBuffer, addCase)
45+
else if (labelsStr(cur) == elemSeparator)
46+
initLabels(cur + 1, cur + 1, addElem, cases)
47+
else
48+
initLabels(start, cur + 1, elems, cases)
3549
}
3650
}
3751

3852
object ReflectedClass {
39-
40-
private final val separator = '\000'
53+
private final val elemSeparator = '\000'
54+
private final val caseSeparator = '\001'
4155

4256
/** Helper class to turn arrays into products */
4357
private class ArrayProduct(val elems: Array[AnyRef]) extends Product {

tests/run/typeclass-derivation2.scala

+14-14
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ object Lst {
133133

134134
val NilMirror = mirror(1)
135135

136-
implicit def lstShape[T]: Shaped[Lst[T], Shape[T]] = new {
136+
implicit def derived$Shape[T]: Shaped[Lst[T], Shape[T]] = new {
137137
def reflect(xs: Lst[T]): Mirror = xs match {
138138
case xs: Cons[T] => mirror(0, xs)
139139
case Nil => NilMirror
@@ -146,9 +146,9 @@ object Lst {
146146
}
147147

148148
// three clauses that could be generated from a `derives` clause
149-
implicit def LstEq[T: Eq]: Eq[Lst[T]] = Eq.derived
150-
implicit def LstPickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
151-
implicit def LstShow[T: Show]: Show[Lst[T]] = Show.derived
149+
implicit def derived$Eq[T: Eq]: Eq[Lst[T]] = Eq.derived
150+
implicit def derived$Pickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
151+
implicit def derived$Show[T: Show]: Show[Lst[T]] = Show.derived
152152
}
153153

154154
// A simple product type
@@ -163,7 +163,7 @@ object Pair {
163163
val reflectedClass = new ReflectedClass("Pair\000x\000y")
164164
import reflectedClass.mirror
165165

166-
implicit def pairShape[T]: Shaped[Pair[T], Shape[T]] = new {
166+
implicit def derived$Shape[T]: Shaped[Pair[T], Shape[T]] = new {
167167
def reflect(xy: Pair[T]) =
168168
mirror(0, xy)
169169
def reify(c: Mirror): Pair[T] =
@@ -172,9 +172,9 @@ object Pair {
172172
}
173173

174174
// two clauses that could be generated from a `derives` clause
175-
implicit def PairEq[T: Eq]: Eq[Pair[T]] = Eq.derived
176-
implicit def PairPickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
177-
implicit def PairShow[T: Show]: Show[Pair[T]] = Show.derived
175+
implicit def derived$Eq[T: Eq]: Eq[Pair[T]] = Eq.derived
176+
implicit def derived$Pickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
177+
implicit def derived$Show[T: Show]: Show[Pair[T]] = Show.derived
178178
}
179179

180180
sealed trait Either[+L, +R] extends Product // derives Eq, Pickler, Show
@@ -192,21 +192,21 @@ object Either {
192192
val reflectedClass = new ReflectedClass("Left\000x\001Right\000x")
193193
import reflectedClass.mirror
194194

195-
implicit def eitherShape[L, R]: Shaped[Either[L, R], Shape[L, R]] = new {
195+
implicit def derived$Shape[L, R]: Shaped[Either[L, R], Shape[L, R]] = new {
196196
def reflect(e: Either[L, R]): Mirror = e match {
197197
case e: Left[L] => mirror(0, e)
198198
case e: Right[R] => mirror(1, e)
199199
}
200200
def reify(c: Mirror): Either[L, R] = c.ordinal match {
201-
case 0 => Left[L](c(0).asInstanceOf)
202-
case 1 => Right[R](c(0).asInstanceOf)
201+
case 0 => Left(c(0).asInstanceOf)
202+
case 1 => Right(c(0).asInstanceOf)
203203
}
204204
def common = reflectedClass
205205
}
206206

207-
implicit def EitherEq[L: Eq, R: Eq]: Eq[Either[L, R]] = Eq.derived
208-
implicit def EitherPickler[L: Pickler, R: Pickler]: Pickler[Either[L, R]] = Pickler.derived
209-
implicit def EitherShow[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
207+
implicit def derived$Eq[L: Eq, R: Eq]: Eq[Either[L, R]] = Eq.derived
208+
implicit def derived$Pickler[L: Pickler, R: Pickler]: Pickler[Either[L, R]] = Pickler.derived
209+
implicit def derived$Show[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
210210
}
211211

212212
// A typeclass

tests/run/typeclass-derivation3.scala

+3-80
Original file line numberDiff line numberDiff line change
@@ -9,95 +9,18 @@ object datatypes {
99
case Nil
1010
}
1111

12-
object Lst {
13-
// common compiler-generated infrastructure
14-
import typelevel._
15-
/*
16-
type Shape[T] = Shape.Cases[(
17-
Shape.Case[Cons[T], (T, Lst[T])],
18-
Shape.Case[Nil.type, Unit]
19-
)]
20-
*/
21-
val reflectedClass = new ReflectedClass(Array("Cons\000hd\000tl", "Nil"))
22-
import reflectedClass.mirror
23-
24-
val NilMirror = mirror(1)
25-
26-
implicit def lstShape[T]: Shaped[Lst[T], Shape[T]] = new {
27-
def reflect(xs: Lst[T]): Mirror = xs match {
28-
case xs: Cons[T] => mirror(0, xs)
29-
case Nil => NilMirror
30-
}
31-
def reify(c: Mirror): Lst[T] = c.ordinal match {
32-
case 0 => Cons[T](c(0).asInstanceOf, c(1).asInstanceOf)
33-
case 1 => Nil
34-
}
35-
def common = reflectedClass
36-
}
37-
38-
// three clauses that could be generated from a `derives` clause
39-
//implicit def LstEq[T: Eq]: Eq[Lst[T]] = Eq.derived
40-
//implicit def LstPickler[T: Pickler]: Pickler[Lst[T]] = Pickler.derived
41-
//implicit def LstShow[T: Show]: Show[Lst[T]] = Show.derived
42-
}
12+
object Lst {}
4313

4414
// A simple product type
4515
case class Pair[T](x: T, y: T) derives Eq, Pickler, Show
16+
object Pair
4617

47-
object Pair {
48-
// common compiler-generated infrastructure
49-
import typelevel._
50-
51-
// type Shape[T] = Shape.Case[Pair[T], (T, T)]
52-
53-
val reflectedClass = new ReflectedClass(Array("Pair\000x\000y"))
54-
import reflectedClass.mirror
55-
56-
implicit def pairShape[T]: Shaped[Pair[T], Shape[T]] = new {
57-
def reflect(xy: Pair[T]) =
58-
mirror(0, xy)
59-
def reify(c: Mirror): Pair[T] =
60-
Pair(c(0).asInstanceOf, c(1).asInstanceOf)
61-
def common = reflectedClass
62-
}
63-
64-
// two clauses that could be generated from a `derives` clause
65-
//implicit def PairEq[T: Eq]: Eq[Pair[T]] = Eq.derived
66-
//implicit def PairPickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
67-
//implicit def PairShow[T: Show]: Show[Pair[T]] = Show.derived
68-
}
69-
18+
// another ADT
7019
sealed trait Either[+L, +R] extends Product derives Eq, Pickler, Show
7120
case class Left[L](x: L) extends Either[L, Nothing]
7221
case class Right[R](x: R) extends Either[Nothing, R]
7322

7423
object Either {
75-
import typelevel._
76-
77-
/*
78-
type Shape[L, R] = Shape.Cases[(
79-
Shape.Case[Left[L], L *: Unit],
80-
Shape.Case[Right[R], R *: Unit]
81-
)]
82-
*/
83-
val reflectedClass = new ReflectedClass(Array("Left\000x", "Right\000x"))
84-
import reflectedClass.mirror
85-
86-
implicit def eitherShape[L, R]: Shaped[Either[L, R], Shape[L, R]] = new {
87-
def reflect(e: Either[L, R]): Mirror = e match {
88-
case e: Left[L] => mirror(0, e)
89-
case e: Right[R] => mirror(1, e)
90-
}
91-
def reify(c: Mirror): Either[L, R] = c.ordinal match {
92-
case 0 => Left[L](c(0).asInstanceOf)
93-
case 1 => Right[R](c(0).asInstanceOf)
94-
}
95-
def common = reflectedClass
96-
}
97-
98-
//implicit def EitherEq[L: Eq, R: Eq]: Eq[Either[L, R]] = Eq.derived
99-
//implicit def EitherPickler[L: Pickler, R: Pickler]: Pickler[Either[L, R]] = Pickler.derived
100-
//implicit def EitherShow[L: Show, R: Show]: Show[Either[L, R]] = Show.derived
10124
}
10225
}
10326

0 commit comments

Comments
 (0)