Skip to content

Commit d04f5ed

Browse files
committed
add support for arrays of value classes with underlying type that is value class
1 parent ddea7f3 commit d04f5ed

File tree

5 files changed

+66
-26
lines changed

5 files changed

+66
-26
lines changed

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import TypeErasure.ErasedValueType, ValueClasses._
1515
class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer {
1616

1717
import tpd._
18+
import ElimErasedValueType._
1819

1920
override def phaseName: String = "elimErasedValueType"
2021

@@ -40,17 +41,6 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer {
4041
elimEVT(tp)
4142
}
4243

43-
def elimEVT(tp: Type)(implicit ctx: Context): Type = tp match {
44-
case ErasedValueType(_, underlying) =>
45-
elimEVT(underlying)
46-
case tp: MethodType =>
47-
val paramTypes = tp.paramTypes.mapConserve(elimEVT)
48-
val retType = elimEVT(tp.resultType)
49-
tp.derivedMethodType(tp.paramNames, paramTypes, retType)
50-
case _ =>
51-
tp
52-
}
53-
5444
def transformTypeOfTree(tree: Tree)(implicit ctx: Context): Tree =
5545
tree.withType(elimEVT(tree.tpe))
5646

@@ -79,3 +69,16 @@ class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer {
7969
override def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo): Tree =
8070
transformTypeOfTree(tree)
8171
}
72+
73+
object ElimErasedValueType {
74+
def elimEVT(tp: Type)(implicit ctx: Context): Type = tp match {
75+
case ErasedValueType(_, underlying) =>
76+
elimEVT(underlying)
77+
case tp: MethodType =>
78+
val paramTypes = tp.paramTypes.mapConserve(elimEVT)
79+
val retType = elimEVT(tp.resultType)
80+
tp.derivedMethodType(tp.paramNames, paramTypes, retType)
81+
case _ =>
82+
tp
83+
}
84+
}

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Constants.Constant
88
import DenotTransformers._, TreeTransforms._, Phases.Phase
99
import TypeErasure.ErasedValueType, ValueClasses._
1010
import dotty.tools.dotc.core.SymDenotations.ClassDenotation
11+
import ElimErasedValueType.elimEVT
1112

1213
/** This phase erases arrays of value classes to their runtime representation.
1314
*
@@ -30,7 +31,7 @@ class VCArrays extends MiniPhaseTransform with InfoTransformer {
3031
tp match {
3132
case JavaArrayType(ErasedValueType(tr, eund)) =>
3233
val cls = tr.symbol.asClass
33-
defn.vcArrayOf(cls).typeRef
34+
defn.vcDeepArrayOf(cls).typeRef
3435
//case tp: MethodType =>
3536
//val paramTypes = tp.paramTypes.mapConserve(eraseVCArrays)
3637
//val retType = eraseVCArrays(tp.resultType)
@@ -59,8 +60,9 @@ class VCArrays extends MiniPhaseTransform with InfoTransformer {
5960
//box body implementation
6061
case _ if tree.name == nme.box && ValueClasses.isDerivedValueClass(tree.symbol.owner.companionClass) && !tree.symbol.is(Flags.Bridge) =>
6162
val List(List(param)) = tree.vparamss
62-
val newParam = ref(param.symbol).ensureConforms(ValueClasses.underlyingOfValueClass(vc.asClass))
63-
val newRhs = New(vc.typeRef, newParam :: Nil).ensureConforms(tree.tpt.tpe)
63+
val newParam = ref(param.symbol)
64+
val newRhs: Tree = if (param.tpt.symbol.isPrimitiveValueClass) newParam
65+
else New(vc.typeRef, newParam.ensureConforms(elimEVT(ValueClasses.deepUnderlyingOfValueClass(vc.asClass))) :: Nil)
6466
newRhs
6567
case _ => tree.rhs
6668
}
@@ -84,13 +86,14 @@ class VCArrays extends MiniPhaseTransform with InfoTransformer {
8486
tree.tpe match {
8587
// [arg1, arg2, ...] => new VCXArray([V.evt2u$(arg1), V.evt2u$(arg2), ...])
8688
case JavaArrayType(ErasedValueType(tr, tund)) =>
89+
val tund2 = elimEVT(tund)
8790
val cls = tr.symbol.asClass
8891
val evt2uMethod = ref(evt2u(cls))
8992
//[V.evt2u$(arg1), V.evt2u$(arg2), ...]
90-
val underlyingArray = JavaSeqLiteral(tree.elems.map(evt2uMethod.appliedTo(_)), TypeTree(tund))
93+
val underlyingArray = JavaSeqLiteral(tree.elems.map(evt2uMethod.appliedTo(_)), TypeTree(tund2))
9194
val mod = cls.companionModule
9295
//new VCXArray([V.evt2u$(arg1), V.evt2u$(arg2), ...], VCXCompanion)
93-
New(defn.vcArrayOf(cls).typeRef, List(underlyingArray, ref(mod)))
96+
New(defn.vcDeepArrayOf(cls).typeRef, List(underlyingArray, ref(mod)))
9497
case _ =>
9598
tree match {
9699
case SeqLiteral(elems, tptr) =>
@@ -130,10 +133,11 @@ class VCArrays extends MiniPhaseTransform with InfoTransformer {
130133
case jat@JavaArrayType(ErasedValueType(tr, underlying)) =>
131134
val cls = tr.symbol.asClass
132135
val mod = cls.companionModule
136+
val und2 = elimEVT(underlying)
133137
//TODO: und1 should be processed in case of EVT
134-
val und1 = eraseVCArrays(underlying)
138+
val und1 = eraseVCArrays(und2)
135139
val arTpe = jat.derivedJavaArrayType(und1)
136-
New(defn.vcArrayOf(cls).typeRef,
140+
New(defn.vcDeepArrayOf(cls).typeRef,
137141
List(newArray(und1, arTpe, tree.pos, dims.asInstanceOf[JavaSeqLiteral]).ensureConforms(arTpe),
138142
ref(mod)))
139143
case _: Type =>
@@ -144,7 +148,7 @@ class VCArrays extends MiniPhaseTransform with InfoTransformer {
144148
val mod = cls.companionModule
145149
val retTpt2 = eraseVCArrays(ins.asInstanceOf[Type])
146150
val Literal(Constant(compTptType)) = compTpt
147-
val compTpt2 = eraseVCArrays((compTptType.asInstanceOf[Type]))
151+
val compTpt2 = eraseVCArrays((elimEVT(compTptType.asInstanceOf[Type])))
148152
newArray(compTpt2, retTpt2, tree.pos, dims.asInstanceOf[JavaSeqLiteral])
149153
case _ =>
150154
transformTypeOfTree(tree)

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class VCParents extends MiniPhaseTransform with DenotTransformer {
3131
val cinfo = moduleClass.classInfo
3232
val decls1 = cinfo.decls.cloneScope
3333

34-
val underlying = underlyingOfValueClass(valueClass)
34+
val underlying = deepUnderlyingOfValueClass(valueClass)
3535
// TODO: what should we do if these symbols already exist (box and runtimeClassSym)?
3636
val boxParamTpe = if (underlying.classSymbol.isPrimitiveValueClass) underlying else defn.ObjectType
3737
val boxSymTpe = if (underlying.classSymbol.isPrimitiveValueClass) valueClass.typeRef else defn.ObjectType
@@ -42,7 +42,7 @@ class VCParents extends MiniPhaseTransform with DenotTransformer {
4242
decls1.enter(boxSym)
4343
decls1.enter(runtimeClassSym)
4444

45-
val superType = tpd.ref(defn.vcCompanionOf(valueClass))
45+
val superType = tpd.ref(defn.vcDeepCompanionOf(valueClass))
4646
.select(nme.CONSTRUCTOR)
4747
.appliedToType(valueClass.typeRef)
4848
.tpe
@@ -56,7 +56,7 @@ class VCParents extends MiniPhaseTransform with DenotTransformer {
5656
}
5757
case valueClass: ClassDenotation if isDerivedValueClass(valueClass) =>
5858
val cinfo = valueClass.classInfo
59-
val superType = defn.vcPrototypeOf(valueClass).typeRef
59+
val superType = defn.vcDeepPrototypeOf(valueClass).typeRef
6060

6161
val (p :: ps) = cinfo.classParents
6262
//TODO: remove assert to fix issue with i705-inner-value-class.scala
@@ -107,7 +107,7 @@ class VCParents extends MiniPhaseTransform with DenotTransformer {
107107
val rcDef = runtimeClassDefDef(valueClass)
108108
val boxDef = boxDefDef(valueClass)
109109

110-
val superCall = New(defn.vcCompanionOf(valueClass).typeRef)
110+
val superCall = New(defn.vcDeepCompanionOf(valueClass).typeRef)
111111
.select(nme.CONSTRUCTOR)
112112
.appliedToType(valueClass.typeRef)
113113
.appliedToNone
@@ -121,11 +121,22 @@ class VCParents extends MiniPhaseTransform with DenotTransformer {
121121
tree
122122
}
123123
case valueClass: ClassDenotation if isDerivedValueClass(valueClass) =>
124-
val prototype = defn.vcPrototypeOf(valueClass).typeRef
124+
val prototype = defn.vcDeepPrototypeOf(valueClass).typeRef
125125
val underlyingSym = valueClassUnbox(valueClass)
126126

127-
val superCallExpr = if (underlyingSym.info.classSymbol.isPrimitiveValueClass) ref(underlyingSym)
128-
else ref(underlyingSym).ensureConforms(defn.ObjectType) //ensureConforms is required in case of Any is underlying type (-Ycheck)
127+
def deepUndExpr(valueClass: Symbol): List[Symbol] = {
128+
val vcMethod = valueClassUnbox(valueClass.asClass)
129+
valueClass match {
130+
case _ if isDerivedValueClass(vcMethod.info.resultType.classSymbol) =>
131+
vcMethod :: deepUndExpr(vcMethod.info.resultType.classSymbol)
132+
case _ => List(vcMethod)
133+
}
134+
}
135+
val deepUnderlyingSyms = deepUndExpr(valueClass.symbol)
136+
//TODO: add null checkings
137+
val deepExpr = deepUnderlyingSyms.tail.foldLeft(ref(deepUnderlyingSyms.head))(_.select(_))
138+
val superCallExpr = if (deepUnderlyingSyms.last.info.classSymbol.isPrimitiveValueClass) deepExpr
139+
else deepExpr.ensureConforms(defn.ObjectType) //ensureConforms is required in case of Any is underlying type (-Ycheck)
129140
val superCall = New(prototype, List(superCallExpr))
130141
// TODO: manually do parameter forwarding: the prototype has a local field
131142
// so we don't need a field inside the value class
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
List(X@37, null)
2+
2
3+
List(X@0, X@0, X@0, X@0, X@0)
4+
List(X@37, X@4d)
5+
X@37
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class X(val y: Y) extends AnyVal
2+
class Y(val z: Z) extends AnyVal
3+
class Z(val x: Int) extends AnyVal
4+
object Test {
5+
def main(args: Array[String]) = {
6+
val arr = Array(new X(new Y(new Z(55))), null)
7+
println(arr.toList)
8+
val arr2 = Array.ofDim[X](2,3,4)
9+
println(arr2.toList.size)
10+
val arr3 = new Array[X](5)
11+
println(arr3.toList)
12+
arr(1) = new X(new Y(new Z(77)))
13+
println(arr.toList)
14+
val e = arr(0)
15+
println(e)
16+
}
17+
}

0 commit comments

Comments
 (0)