Skip to content

Commit 5885e59

Browse files
committed
Deriving infrastructure in typelevel
1 parent 5039187 commit 5885e59

File tree

9 files changed

+216
-90
lines changed

9 files changed

+216
-90
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,16 @@ class Definitions {
647647
def Product_productElement(implicit ctx: Context): Symbol = Product_productElementR.symbol
648648
lazy val Product_productPrefixR: TermRef = ProductClass.requiredMethodRef(nme.productPrefix)
649649
def Product_productPrefix(implicit ctx: Context): Symbol = Product_productPrefixR.symbol
650+
651+
lazy val ShapedType: TypeRef = ctx.requiredClassRef("scala.typelevel.Shaped")
652+
def ShapedClass(implicit ctx: Context): ClassSymbol = ShapedType.symbol.asClass
653+
lazy val ShapeType: TypeRef = ctx.requiredClassRef("scala.typelevel.Shape")
654+
def ShapeClass(implicit ctx: Context): ClassSymbol = ShapeType.symbol.asClass
655+
lazy val ShapeCaseType: TypeRef = ctx.requiredClassRef("scala.typelevel.Shape.Case")
656+
def ShapeCaseClass(implicit ctx: Context): ClassSymbol = ShapeCaseType.symbol.asClass
657+
lazy val ShapeCasesType: TypeRef = ctx.requiredClassRef("scala.typelevel.Shape.Cases")
658+
def ShapeCasesClass(implicit ctx: Context): ClassSymbol = ShapeCasesType.symbol.asClass
659+
650660
lazy val LanguageModuleRef: TermSymbol = ctx.requiredModule("scala.language")
651661
def LanguageModuleClass(implicit ctx: Context): ClassSymbol = LanguageModuleRef.moduleClass.asClass
652662
lazy val NonLocalReturnControlType: TypeRef = ctx.requiredClassRef("scala.runtime.NonLocalReturnControl")

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ object StdNames {
346346
val RootClass: N = "RootClass"
347347
val Scala2: N = "Scala2"
348348
val Select: N = "Select"
349+
val Shape: N = "Shape"
349350
val StringContext: N = "StringContext"
350351
val This: N = "This"
351352
val ThisType: N = "ThisType"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package scala.typelevel
2+
3+
/** A generic representation of a case in an ADT
4+
* @param deriving The companion object of the ADT
5+
* @param ordinal The ordinal value of the case in the list of the ADT's cases
6+
* @param elems The elements of the case
7+
*/
8+
class Mirror(val reflected: ReflectedClass, val ordinal: Int, val elems: Product) {
9+
10+
/** The `n`'th element of this generic case */
11+
def apply(n: Int): Any = elems.productElement(n)
12+
13+
/** The name of the constructor of the case reflected by this mirror */
14+
def caseLabel: String = reflected.label(ordinal, 0)
15+
16+
/** The label of the `n`'th element of the case reflected by this mirror */
17+
def elementLabel(n: Int) = reflected.label(ordinal, n + 1)
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package scala.typelevel
2+
3+
/** A class for mapping between an ADT value and
4+
* the case mirror that represents the value.
5+
*/
6+
abstract class Reflected[T] {
7+
8+
/** The case mirror corresponding to ADT instance `x` */
9+
def reflect(x: T): Mirror
10+
11+
/** The ADT instance corresponding to given `mirror` */
12+
def reify(mirror: Mirror): T
13+
14+
/** The companion object of the ADT */
15+
def common: ReflectedClass
16+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package scala.typelevel
2+
import annotation.tailrec
3+
4+
/** @param caseLabels The case and element labels of the described ADT as encoded strings.
5+
*/
6+
class ReflectedClass(caseLabels: Array[String]) {
7+
import ReflectedClass._
8+
9+
/** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
10+
def mirror(ordinal: Int, product: Product): Mirror =
11+
new Mirror(this, ordinal, product)
12+
13+
/** A mirror with elements given as an array */
14+
def mirror(ordinal: Int, elems: Array[AnyRef]): Mirror =
15+
mirror(ordinal, new ArrayProduct(elems))
16+
17+
/** A mirror with an initial empty array of `numElems` elements, to be filled in. */
18+
def mirror(ordinal: Int, numElems: Int): Mirror =
19+
mirror(ordinal, new Array[AnyRef](numElems))
20+
21+
/** A mirror of a case with no elements */
22+
def mirror(ordinal: Int): Mirror =
23+
mirror(ordinal, EmptyProduct)
24+
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)
35+
}
36+
}
37+
38+
object ReflectedClass {
39+
40+
private final val separator = '\000'
41+
42+
/** Helper class to turn arrays into products */
43+
private class ArrayProduct(val elems: Array[AnyRef]) extends Product {
44+
def canEqual(that: Any): Boolean = true
45+
def productElement(n: Int) = elems(n)
46+
def productArity = elems.length
47+
override def productIterator: Iterator[Any] = elems.iterator
48+
def update(n: Int, x: Any) = elems(n) = x.asInstanceOf[AnyRef]
49+
}
50+
51+
/** Helper object */
52+
private object EmptyProduct extends Product {
53+
def canEqual(that: Any): Boolean = true
54+
def productElement(n: Int) = throw new IndexOutOfBoundsException
55+
def productArity = 0
56+
}
57+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package scala.typelevel
2+
3+
/** The shape of an ADT.
4+
* This is eithe a product (`Case`) or a sum (`Cases`) of products.
5+
*/
6+
sealed abstract class Shape
7+
8+
object Shape {
9+
10+
/** A sum with alternative types `Alts` */
11+
case class Cases[Alts <: Tuple] extends Shape
12+
13+
/** A product type `T` with element types `Elems` */
14+
case class Case[T, Elems <: Tuple] extends Shape
15+
}
16+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package scala.typelevel
2+
3+
/** Every generic derivation starts with a typeclass instance of this type.
4+
* It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
5+
*/
6+
abstract class Shaped[T, S <: Shape] extends Reflected[T]

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ package object typelevel {
44

55
erased def erasedValue[T]: T = ???
66

7-
case class Typed[T](val value: T) { type Type = T }
8-
97
inline def error(inline msg: String, objs: Any*): Nothing = ???
108

119
inline def constValueOpt[T]: Option[T] = ???

0 commit comments

Comments
 (0)