Skip to content

Commit 2051769

Browse files
committed
New phase VCParents: add parents to value classes and their companions
Note that this mean that the following does not pass Ycheck after VCParents: def foo[T <: AnyVal](...) foo[Meter](...) Ycheck will complain that Meter does not conform to the upper bound AnyVal, which is true. I'm not sure what the best way to deal with this is.
1 parent b1fa658 commit 2051769

File tree

4 files changed

+113
-18
lines changed

4 files changed

+113
-18
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Compiler {
4646
new ElimRepeated,
4747
new NormalizeFlags,
4848
new ExtensionMethods,
49+
new VCParents,
4950
new ExpandSAMs,
5051
new TailRec,
5152
new ClassOf),

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package core
44

55
import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._
66
import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._
7+
import transform.ValueClasses
78
import unpickleScala2.Scala2Unpickler.ensureConstructor
89
import scala.annotation.{ switch, meta }
910
import scala.collection.{ mutable, immutable }
@@ -599,6 +600,31 @@ class Definitions {
599600
lazy val volatileRefClass: Map[Symbol, Symbol] =
600601
refClasses.map(rc => rc -> ctx.requiredClass(s"scala.runtime.Volatile${rc.name}Ref")).toMap
601602

603+
lazy val vcPrototype: Map[Symbol, Symbol] =
604+
refClasses.map(vc => vc -> ctx.requiredClass(s"dotty.runtime.vc.VC${vc.name}Prototype")).toMap
605+
lazy val vcCompanion: Map[Symbol, Symbol] =
606+
refClasses.map(vc => vc -> ctx.requiredClass(s"dotty.runtime.vc.VC${vc.name}Companion")).toMap
607+
lazy val vcArray: Map[Symbol, Symbol] =
608+
refClasses.map(vc => vc -> ctx.requiredClass(s"dotty.runtime.vc.VC${vc.name}Array")).toMap
609+
610+
lazy val VCArrayPrototypeClass = ctx.requiredClass(s"dotty.runtime.vc.VCArrayPrototype")
611+
def VCArrayPrototypeType = VCArrayPrototypeClass.typeRef
612+
613+
def vcPrototypeOf(vc: ClassDenotation) = {
614+
val underlying = ValueClasses.valueClassUnbox(vc).info.classSymbol
615+
vcPrototype.getOrElse(underlying, vcPrototype(defn.ObjectClass))
616+
}
617+
def vcCompanionOf(vc: ClassDenotation) = {
618+
val underlying = ValueClasses.valueClassUnbox(vc).info.classSymbol
619+
vcCompanion.getOrElse(underlying, vcCompanion(defn.ObjectClass))
620+
}
621+
def vcArrayOf(vc: ClassDenotation) = {
622+
val underlying = ValueClasses.valueClassUnbox(vc).info.classSymbol
623+
vcArray.getOrElse(underlying, vcArray(defn.ObjectClass))
624+
}
625+
626+
627+
602628
def wrapArrayMethodName(elemtp: Type): TermName = {
603629
val cls = elemtp.classSymbol
604630
if (cls.isPrimitiveValueClass) nme.wrapXArray(cls.name)

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,12 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
7272
val evt2uSym = ctx.newSymbol(moduleSym, nme.EVT2U, Synthetic | Method,
7373
MethodType(List(nme.x_0), List(evt), underlying))
7474

75-
val defn = ctx.definitions
76-
77-
val underlyingCls = underlying.classSymbol
78-
val underlyingClsName =
79-
if (defn.ScalaNumericValueClasses.contains(underlyingCls) ||
80-
underlyingCls == defn.BooleanClass) underlyingCls.name else nme.Object
81-
82-
83-
val syp = ctx.requiredClass(s"dotty.runtime.vc.VC${underlyingClsName}Companion").asClass
84-
85-
newSuperClass = tpd.ref(syp).select(nme.CONSTRUCTOR).appliedToType(valueClass.typeRef).tpe.resultType
86-
8775
decls1.enter(u2evtSym)
8876
decls1.enter(evt2uSym)
8977
}
9078

91-
// Add the extension methods, the cast methods u2evt$ and evt2u$, and a VC*Companion superclass
92-
moduleClassSym.copySymDenotation(info =
93-
cinfo.derivedClassInfo(
94-
// FIXME: use of VC*Companion superclasses is disabled until the conflicts with SyntheticMethods are solved.
95-
//classParents = ctx.normalizeToClassRefs(List(newSuperClass), moduleSym, decls1),
96-
decls = decls1))
79+
// Add the extension methods, the cast methods u2evt$ and evt2u$
80+
moduleClassSym.copySymDenotation(info = cinfo.derivedClassInfo(decls = decls1))
9781
case _ =>
9882
moduleClassSym
9983
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import ast.{Trees, tpd}
5+
import core._, core.Decorators._
6+
import Contexts._, Flags._, Trees._, Types._, StdNames._, Symbols._
7+
import Denotations._, SymDenotations._
8+
import DenotTransformers._, TreeTransforms._, Phases.Phase
9+
import ValueClasses._
10+
11+
/** This phase makes value classes extend VCXPrototype and make their companions extend VCXCompanion.
12+
*
13+
* For a value class class V whose erased underlying type is U, X is "U" if U is a primitive
14+
* type and is "Object" otherwise.
15+
*
16+
*/
17+
class VCParents extends MiniPhaseTransform with DenotTransformer {
18+
import tpd._
19+
20+
override def phaseName: String = "vcParents"
21+
22+
override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
23+
case moduleClass: ClassDenotation if moduleClass.is(ModuleClass) =>
24+
moduleClass.linkedClass match {
25+
case valueClass: ClassSymbol if isDerivedValueClass(valueClass) =>
26+
val moduleSym = moduleClass.symbol.asClass
27+
val cinfo = moduleClass.classInfo
28+
29+
val superType = tpd.ref(defn.vcCompanionOf(valueClass))
30+
.select(nme.CONSTRUCTOR)
31+
.appliedToType(valueClass.typeRef)
32+
.tpe
33+
.resultType
34+
35+
moduleClass.copySymDenotation(info =
36+
cinfo.derivedClassInfo(classParents =
37+
ctx.normalizeToClassRefs(List(superType), moduleSym, cinfo.decls)))
38+
case _ =>
39+
moduleClass
40+
}
41+
case valueClass: ClassDenotation if isDerivedValueClass(valueClass) =>
42+
val cinfo = valueClass.classInfo
43+
val superType = defn.vcPrototypeOf(valueClass).typeRef
44+
45+
val (p :: ps) = cinfo.classParents
46+
assert(p.isRef(defn.AnyValClass))
47+
val parents = superType :: ps
48+
valueClass.copySymDenotation(info = cinfo.derivedClassInfo(classParents = parents))
49+
case _ =>
50+
ref
51+
}
52+
53+
override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
54+
ctx.owner.denot match {
55+
case moduleClass: ClassDenotation if moduleClass.is(ModuleClass) =>
56+
moduleClass.linkedClass match {
57+
case valueClass: ClassSymbol if isDerivedValueClass(valueClass) =>
58+
val superCall = New(defn.vcCompanionOf(valueClass).typeRef)
59+
.select(nme.CONSTRUCTOR)
60+
.appliedToType(valueClass.typeRef)
61+
.appliedToNone
62+
63+
val (p :: ps) = tree.parents
64+
// TODO: We shouldn't disallow extending companion objects of value classes
65+
// with classes other than AnyRef
66+
assert(p.tpe.isRef(defn.ObjectClass))
67+
cpy.Template(tree)(parents = superCall :: ps)
68+
case _ =>
69+
tree
70+
}
71+
case valueClass: ClassDenotation if isDerivedValueClass(valueClass) =>
72+
val prototype = defn.vcPrototypeOf(valueClass).typeRef
73+
val underlyingSym = valueClassUnbox(valueClass)
74+
val superCall = New(prototype, List(ref(underlyingSym)))
75+
// TODO: manually do parameter forwarding: the prototype has a local field
76+
// so we don't need a field inside the value class
77+
78+
val (p :: ps) = tree.parents
79+
assert(p.tpe.isRef(defn.AnyValClass))
80+
cpy.Template(tree)(parents = superCall :: ps)
81+
case _ =>
82+
tree
83+
}
84+
}

0 commit comments

Comments
 (0)