Skip to content

Commit 7be0099

Browse files
committed
Packaging reorgs
- Finish typelevel -> compiletime by renaming internal symbols from TypeLevelX to CompiletimeX - Move some files that are in fact used at runtime from scala.compiletime to scala.reflect - Implement a new more efficient derivation scheme that is based on ordinals instead of repeated type tests.
1 parent dedae72 commit 7be0099

File tree

15 files changed

+594
-109
lines changed

15 files changed

+594
-109
lines changed

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,14 @@ class Definitions {
214214
lazy val Sys_errorR: TermRef = SysPackage.moduleClass.requiredMethodRef(nme.error)
215215
def Sys_error(implicit ctx: Context): Symbol = Sys_errorR.symbol
216216

217-
lazy val TypelevelPackageObjectRef: TermRef = ctx.requiredModuleRef("scala.compiletime.package")
218-
lazy val TypelevelPackageObject: Symbol = TypelevelPackageObjectRef.symbol.moduleClass
219-
lazy val Typelevel_errorR: TermRef = TypelevelPackageObjectRef.symbol.requiredMethodRef(nme.error)
220-
def Typelevel_error(implicit ctx: Context): Symbol = Typelevel_errorR.symbol
221-
lazy val Typelevel_constValueR: TermRef = TypelevelPackageObjectRef.symbol.requiredMethodRef("constValue")
222-
def Typelevel_constValue(implicit ctx: Context): Symbol = Typelevel_constValueR.symbol
223-
lazy val Typelevel_constValueOptR: TermRef = TypelevelPackageObjectRef.symbol.requiredMethodRef("constValueOpt")
224-
def Typelevel_constValueOpt(implicit ctx: Context): Symbol = Typelevel_constValueOptR.symbol
217+
lazy val CompiletimePackageObjectRef: TermRef = ctx.requiredModuleRef("scala.compiletime.package")
218+
lazy val CompiletimePackageObject: Symbol = CompiletimePackageObjectRef.symbol.moduleClass
219+
lazy val Compiletime_errorR: TermRef = CompiletimePackageObjectRef.symbol.requiredMethodRef(nme.error)
220+
def Compiletime_error(implicit ctx: Context): Symbol = Compiletime_errorR.symbol
221+
lazy val Compiletime_constValueR: TermRef = CompiletimePackageObjectRef.symbol.requiredMethodRef("constValue")
222+
def Compiletime_constValue(implicit ctx: Context): Symbol = Compiletime_constValueR.symbol
223+
lazy val Compiletime_constValueOptR: TermRef = CompiletimePackageObjectRef.symbol.requiredMethodRef("constValueOpt")
224+
def Compiletime_constValueOpt(implicit ctx: Context): Symbol = Compiletime_constValueOptR.symbol
225225

226226
/** The `scalaShadowing` package is used to safely modify classes and
227227
* objects in scala so that they can be used from dotty. They will
@@ -656,8 +656,8 @@ class Definitions {
656656
def ShapeCaseClass(implicit ctx: Context): ClassSymbol = ShapeCaseType.symbol.asClass
657657
lazy val ShapeCasesType: TypeRef = ctx.requiredClassRef("scala.compiletime.Shape.Cases")
658658
def ShapeCasesClass(implicit ctx: Context): ClassSymbol = ShapeCasesType.symbol.asClass
659-
lazy val MirrorType: TypeRef = ctx.requiredClassRef("scala.compiletime.Mirror")
660-
lazy val ReflectedClassType: TypeRef = ctx.requiredClassRef("scala.compiletime.ReflectedClass")
659+
lazy val MirrorType: TypeRef = ctx.requiredClassRef("scala.reflect.Mirror")
660+
lazy val ReflectedClassType: TypeRef = ctx.requiredClassRef("scala.reflect.ReflectedClass")
661661

662662
lazy val LanguageModuleRef: TermSymbol = ctx.requiredModule("scala.language")
663663
def LanguageModuleClass(implicit ctx: Context): ClassSymbol = LanguageModuleRef.moduleClass.asClass
@@ -909,8 +909,8 @@ class Definitions {
909909
}
910910
}
911911

912-
final def isTypelevel_S(sym: Symbol)(implicit ctx: Context): Boolean =
913-
sym.name == tpnme.S && sym.owner == TypelevelPackageObject
912+
final def isCompiletime_S(sym: Symbol)(implicit ctx: Context): Boolean =
913+
sym.name == tpnme.S && sym.owner == CompiletimePackageObject
914914

915915
// ----- Symbol sets ---------------------------------------------------
916916

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
845845
compareLower(bounds(param2), followSuperType = false)
846846
case tycon2: TypeRef =>
847847
isMatchingApply(tp1) ||
848-
defn.isTypelevel_S(tycon2.symbol) && compareS(tp2, tp1, fromBelow = true) || {
848+
defn.isCompiletime_S(tycon2.symbol) && compareS(tp2, tp1, fromBelow = true) || {
849849
tycon2.info match {
850850
case info2: TypeBounds =>
851851
val gbounds2 = ctx.gadt.bounds(tycon2.symbol)
@@ -886,7 +886,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
886886
case tycon1: TypeRef =>
887887
val sym = tycon1.symbol
888888
!sym.isClass && (
889-
defn.isTypelevel_S(sym) && compareS(tp1, tp2, fromBelow = false) || {
889+
defn.isCompiletime_S(sym) && compareS(tp1, tp2, fromBelow = false) || {
890890
val gbounds1 = ctx.gadt.bounds(tycon1.symbol)
891891
if (gbounds1 == null) recur(tp1.superType, tp2)
892892
else recur((gbounds1.hi & tycon1.info.bounds.hi).applyIfParameterized(args1), tp2)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3407,7 +3407,7 @@ object Types {
34073407
case _ =>
34083408
NoType
34093409
}
3410-
if (defn.isTypelevel_S(tycon.symbol) && args.length == 1) {
3410+
if (defn.isCompiletime_S(tycon.symbol) && args.length == 1) {
34113411
trace(i"normalize S $this", typr, show = true) {
34123412
args.head.normalized match {
34133413
case ConstantType(Constant(n: Int)) => ConstantType(Constant(n + 1))

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,9 @@ trait Deriving { this: Typer =>
271271

272272
/** The RHS of the `reflectedClass` value definition */
273273
private def reflectedClassRHS =
274-
New(defn.ReflectedClassType, Literal(Constant(labelString(shapeWithClassParams))) :: Nil)
274+
New(defn.ReflectedClassType,
275+
List(Literal(Constant(cls.typeRef)),
276+
Literal(Constant(labelString(shapeWithClassParams)))))
275277

276278
/** The RHS of the `derived$Shaped` typeclass instance.
277279
* Example: For the class definition

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,12 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
349349
def inlined(pt: Type): Tree = {
350350

351351
if (callTypeArgs.length == 1)
352-
if (inlinedMethod == defn.Typelevel_constValue) {
352+
if (inlinedMethod == defn.Compiletime_constValue) {
353353
val constVal = tryConstValue
354354
if (!constVal.isEmpty) return constVal
355355
ctx.error(i"not a constant type: ${callTypeArgs.head}; cannot take constValue", call.pos)
356356
}
357-
else if (inlinedMethod == defn.Typelevel_constValueOpt) {
357+
else if (inlinedMethod == defn.Compiletime_constValueOpt) {
358358
val constVal = tryConstValue
359359
return (
360360
if (constVal.isEmpty) ref(defn.NoneModuleRef)
@@ -464,7 +464,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
464464
// Drop unused bindings
465465
val (finalBindings, finalExpansion) = dropUnusedDefs(bindingsBuf.toList, expansion1)
466466

467-
if (inlinedMethod == defn.Typelevel_error) issueError()
467+
if (inlinedMethod == defn.Compiletime_error) issueError()
468468

469469
// Take care that only argument bindings go into `bindings`, since positions are
470470
// different for bindings from arguments and bindings from body.
@@ -909,7 +909,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
909909
| patterns : ${tree.cases.map(patStr).mkString("\n ")}"""
910910
else
911911
em"""cannot reduce inline match with
912-
| scrutinee: $sel : ${selType}
912+
| scrutinee: $sel : ${selType} : ${selType.underlyingIfProxy}
913913
| patterns : ${tree.cases.map(patStr).mkString("\n ")}"""
914914
errorTree(tree, msg)
915915
}

compiler/test/dotc/run-from-tasty.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ puzzle.scala
88
implicitMatch.scala
99
typeclass-derivation1.scala
1010
typeclass-derivation2.scala
11+
typeclass-derivation2a.scala
1112
typeclass-derivation3.scala
1213
deriving-interesting-prefixes.scala
1314

library/src-bootstrapped/scala/compiletime/Shaped.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ package scala.compiletime
33
/** Every generic derivation starts with a typeclass instance of this type.
44
* It informs that type `T` has shape `S` and also implements runtime reflection on `T`.
55
*/
6-
abstract class Shaped[T, S <: Shape] extends Reflected[T]
6+
abstract class Shaped[T, S <: Shape] extends scala.reflect.Reflected[T]

library/src-bootstrapped/scala/compiletime/Mirror.scala renamed to library/src/scala/reflect/Mirror.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package scala.compiletime
1+
package scala.reflect
22

33
/** A generic representation of a case in an ADT
44
* @param reflected The common class-speficic part of this mirror

library/src-bootstrapped/scala/compiletime/Reflected.scala renamed to library/src/scala/reflect/Reflected.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package scala.compiletime
1+
package scala.reflect
22

33
/** A class for mapping between an ADT value and
44
* the case mirror that represents the value.

library/src-bootstrapped/scala/compiletime/ReflectedClass.scala renamed to library/src/scala/reflect/ReflectedClass.scala

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1-
package scala.compiletime
1+
package scala.reflect
22
import annotation.tailrec
33
import collection.mutable.ArrayBuffer
44

5-
/** @param labelsStr: A string encoding all case and element labels according to the
5+
/** The part of `Reflected` instances that is common for all instances of a class.
6+
* @param labelsStr: A string encoding all case and element labels according to the
67
* following grammar:
78
*
89
* labelString ::= caseString { caseSeparator caseString }
910
* caseString ::= elemString { elemSeparator elemString }
10-
* caseSeparator ::= '\001'
11-
* elemSeparator ::= '\000'
12-
* elemString: "any sequence of characters not containing '\000` or `\001`"
11+
* caseSeparator ::= '\u0001'
12+
* elemSeparator ::= '\u0000'
13+
* elemString: "any sequence of characters not containing '\u0000` or `\u0001`"
1314
*/
14-
class ReflectedClass(labelsStr: String) {
15+
class ReflectedClass(val runtimeClass: Class[_], labelsStr: String) {
1516
import ReflectedClass._
1617

1718
/** A mirror of case with ordinal number `ordinal` and elements as given by `Product` */
1819
def mirror(ordinal: Int, product: Product): Mirror =
1920
new Mirror(this, ordinal, product)
2021

22+
/** A mirror of a case with no elements */
23+
def mirror(ordinal: Int): Mirror =
24+
mirror(ordinal, EmptyProduct)
25+
2126
/** A mirror with elements given as an array */
2227
def mirror(ordinal: Int, elems: Array[AnyRef]): Mirror =
2328
mirror(ordinal, new ArrayProduct(elems))
@@ -26,10 +31,9 @@ class ReflectedClass(labelsStr: String) {
2631
def mirror(ordinal: Int, numElems: Int): Mirror =
2732
mirror(ordinal, new Array[AnyRef](numElems))
2833

29-
/** A mirror of a case with no elements */
30-
def mirror(ordinal: Int): Mirror =
31-
mirror(ordinal, EmptyProduct)
32-
34+
/** Case and element labels as a two-dimensional array.
35+
* Each row of the array contains a case label, followed by the labels of the elements of that case.
36+
*/
3337
val label: Array[Array[String]] =
3438
initLabels(0, 0, new ArrayBuffer[String], new ArrayBuffer[Array[String]])
3539

@@ -50,8 +54,8 @@ class ReflectedClass(labelsStr: String) {
5054
}
5155

5256
object ReflectedClass {
53-
private final val elemSeparator = '\000'
54-
private final val caseSeparator = '\001'
57+
private final val elemSeparator = '\u0000'
58+
private final val caseSeparator = '\u0001'
5559

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

tests/pos-special/typeclass-scaling.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ object typeclasses {
215215
object Eq {
216216
import scala.compiletime.erasedValue
217217
import compiletime._
218+
import reflect._
218219

219220
inline def tryEql[T](x: T, y: T) = implicit match {
220221
case eq: Eq[T] => eq.eql(x, y)
@@ -270,6 +271,7 @@ object typeclasses {
270271
object Pickler {
271272
import scala.compiletime.{erasedValue, constValue}
272273
import compiletime._
274+
import reflect._
273275

274276
def nextInt(buf: mutable.ListBuffer[Int]): Int = try buf.head finally buf.trimStart(1)
275277

tests/run/typeclass-derivation2.scala

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ object Lst {
133133

134134
val NilMirror = mirror(1)
135135

136-
implicit def derived$Shape[T]: Shaped[Lst[T], Shape[T]] = new {
136+
implicit def derived$Shaped[T]: Shaped[Lst[T], Shape[T]] = new {
137137
def reflect(xs: Lst[T]): Mirror = xs match {
138138
case xs: Cons[T] => mirror(0, xs)
139-
case Nil => NilMirror
139+
case Nil => mirror(1)
140140
}
141141
def reify(c: Mirror): Lst[T] = c.ordinal match {
142142
case 0 => Cons[T](c(0).asInstanceOf, c(1).asInstanceOf)
@@ -171,7 +171,7 @@ object Pair {
171171
def common = reflectedClass
172172
}
173173

174-
// two clauses that could be generated from a `derives` clause
174+
// clauses that could be generated from a `derives` clause
175175
implicit def derived$Eq[T: Eq]: Eq[Pair[T]] = Eq.derived
176176
implicit def derived$Pickler[T: Pickler]: Pickler[Pair[T]] = Pickler.derived
177177
implicit def derived$Show[T: Show]: Show[Pair[T]] = Show.derived
@@ -222,40 +222,39 @@ object Eq {
222222
case eq: Eq[T] => eq.eql(x, y)
223223
}
224224

225-
inline def eqlElems[Elems <: Tuple](xs: Mirror, ys: Mirror, n: Int): Boolean =
225+
inline def eqlElems[Elems <: Tuple](xm: Mirror, ym: Mirror, n: Int): Boolean =
226226
inline erasedValue[Elems] match {
227227
case _: (elem *: elems1) =>
228-
tryEql[elem](xs(n).asInstanceOf, ys(n).asInstanceOf) &&
229-
eqlElems[elems1](xs, ys, n + 1)
228+
tryEql[elem](xm(n).asInstanceOf, ym(n).asInstanceOf) &&
229+
eqlElems[elems1](xm, ym, n + 1)
230230
case _: Unit =>
231231
true
232232
}
233233

234234
inline def eqlCase[T, Elems <: Tuple](r: Reflected[T], x: T, y: T) =
235235
eqlElems[Elems](r.reflect(x), r.reflect(y), 0)
236236

237-
inline def eqlCases[T, Alts <: Tuple](r: Reflected[T], x: T, y: T): Boolean =
237+
inline def eqlCases[T, Alts <: Tuple](xm: Mirror, ym: Mirror, ordinal: Int, n: Int): Boolean =
238238
inline erasedValue[Alts] match {
239239
case _: (Shape.Case[alt, elems] *: alts1) =>
240-
x match {
241-
case x: `alt` =>
242-
y match {
243-
case y: `alt` => eqlCase[T, elems](r, x, y)
244-
case _ => false
245-
}
246-
case _ => eqlCases[T, alts1](r, x, y)
247-
}
248-
case _: Unit =>
249-
false
250-
}
240+
if (n == ordinal) eqlElems[elems](xm, ym, 0)
241+
else eqlCases[T, alts1](xm, ym, ordinal, n + 1)
242+
case _: Unit =>
243+
false
244+
}
251245

252-
inline def derived[T, S <: Shape](implicit ev: Shaped[T, S]): Eq[T] = new {
253-
def eql(x: T, y: T): Boolean = inline erasedValue[S] match {
246+
inline def eqlMain[T, S <: Shape](xm: Mirror, ym: Mirror): Boolean =
247+
inline erasedValue[S] match {
254248
case _: Shape.Cases[alts] =>
255-
eqlCases[T, alts](ev, x, y)
249+
val ord = xm.ordinal
250+
ord == ym.ordinal &&
251+
eqlCases[T, alts](xm, ym, ord, 0)
256252
case _: Shape.Case[_, elems] =>
257-
eqlCase[T, elems](ev, x, y)
253+
eqlElems[elems](xm, ym, 0)
258254
}
255+
256+
inline def derived[T, S <: Shape](implicit ev: Shaped[T, S]): Eq[T] = new {
257+
def eql(x: T, y: T): Boolean = eqlMain[T, S](ev.reflect(x), ev.reflect(y))
259258
}
260259

261260
implicit object IntEq extends Eq[Int] {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ListBuffer(0, 11, 0, 22, 0, 33, 1)
2+
Cons(11,Cons(22,Cons(33,Nil)))
3+
ListBuffer(0, 0, 11, 0, 22, 0, 33, 1, 0, 0, 11, 0, 22, 1, 1)
4+
Cons(Cons(11,Cons(22,Cons(33,Nil))),Cons(Cons(11,Cons(22,Nil)),Nil))
5+
ListBuffer(1, 2)
6+
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()))

0 commit comments

Comments
 (0)