Skip to content

Commit e15cfdb

Browse files
committed
Merge pull request #141 from dotty-staging/transform/repeated
Transform/repeated
2 parents 2f29892 + 36fd83b commit e15cfdb

File tree

15 files changed

+142
-42
lines changed

15 files changed

+142
-42
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ class Compiler {
1919
def phases: List[List[Phase]] =
2020
List(
2121
List(new FrontEnd),
22-
List(new Companions, new ElimRepeated /*, new ElimLocals*/),
22+
List(new Companions),
2323
List(new SuperAccessors),
24+
// pickling and refchecks goes here
25+
List(new ElimRepeated/*, new ElimLocals*/),
2426
List(new ExtensionMethods),
2527
List(new TailRec),
2628
List(new PatternMatcher,

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
175175
def isRepeatedParamType(tpt: Tree)(implicit ctx: Context) = tpt match {
176176
case tpt: TypeTree => tpt.typeOpt.isRepeatedParam
177177
case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS), _) => true
178-
case AppliedTypeTree(Select(_, tpnme.JAVA_REPEATED_PARAM_CLASS), _) => true
179178
case _ => false
180179
}
181180

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
256256
def ref(tp: NamedType)(implicit ctx: Context): NameTree =
257257
if (tp.symbol.isStatic || tp.prefix == NoPrefix) Ident(tp)
258258
else tp.prefix match {
259-
case pre: TermRef => ref(pre).select(tp)
259+
case pre: SingletonType => singleton(pre).select(tp)
260260
case pre => SelectFromTypeTree(TypeTree(pre), tp)
261261
} // no checks necessary
262262

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ class Definitions {
235235
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)
236236

237237
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType)
238-
lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS, Covariant, ArrayClass.typeRef)
239238

240239
// fundamental classes
241240
lazy val StringClass = ctx.requiredClass("java.lang.String")
@@ -327,7 +326,6 @@ class Definitions {
327326
def PairType: Type = PairClass.typeRef
328327
def StringType: Type = StringClass.typeRef
329328
def RepeatedParamType = RepeatedParamClass.typeRef
330-
def JavaRepeatedParamType = JavaRepeatedParamClass.typeRef
331329
def ThrowableType = ThrowableClass.typeRef
332330
def OptionType = OptionClass.typeRef
333331
def VolatileAnnotType = VolatileAnnot.typeRef
@@ -396,8 +394,6 @@ class Definitions {
396394
lazy val TupleClasses: Set[Symbol] = TupleClass.toSet
397395
lazy val ProductClasses: Set[Symbol] = ProductNClass.toSet
398396

399-
lazy val RepeatedParamClasses: Set[Symbol] = Set(RepeatedParamClass, JavaRepeatedParamClass)
400-
401397
/** `Modules whose members are in the default namespace and their module classes */
402398
lazy val UnqualifiedOwners = RootImports.toSet ++ RootImports.map(_.moduleClass)
403399

@@ -554,7 +550,6 @@ class Definitions {
554550
AnyClass,
555551
AnyRefAlias,
556552
RepeatedParamClass,
557-
JavaRepeatedParamClass,
558553
ByNameParamClass2x,
559554
AnyValClass,
560555
NullClass,

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ object StdNames {
160160

161161
final val BYNAME_PARAM_CLASS: N = "<byname>"
162162
final val EQUALS_PATTERN: N = "<equals>"
163-
final val JAVA_REPEATED_PARAM_CLASS: N = "<repeated...>"
164163
final val LOCAL_CHILD: N = "<local child>"
165164
final val REPEATED_PARAM_CLASS: N = "<repeated>"
166165
final val WILDCARD_STAR: N = "_*"

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,13 @@ class TypeApplications(val self: Type) extends AnyVal {
284284
to.typeRef
285285
else self
286286

287+
/** If this is repeated parameter type, its underlying Seq type,
288+
* or, if isJava is true, Array type, else the type itself.
289+
*/
290+
def underlyingIfRepeated(isJava: Boolean)(implicit ctx: Context): Type =
291+
if (self.isRepeatedParam) translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
292+
else self
293+
287294
/** If this is an encoding of a (partially) applied type, return its arguments,
288295
* otherwise return Nil.
289296
* Existential types in arguments are returned as TypeBounds instances.

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,16 @@ object Types {
156156

157157
/** Is this a type of a repeated parameter? */
158158
def isRepeatedParam(implicit ctx: Context): Boolean =
159-
defn.RepeatedParamClasses contains typeSymbol
159+
typeSymbol eq defn.RepeatedParamClass
160+
161+
/** Is this the type of a method that has a repeated parameter type as
162+
* last parameter type?
163+
*/
164+
def isVarArgsMethod(implicit ctx: Context): Boolean = this match {
165+
case tp: PolyType => tp.resultType.isVarArgsMethod
166+
case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam
167+
case _ => false
168+
}
160169

161170
/** Is this an alias TypeBounds? */
162171
def isAlias: Boolean = this match {
@@ -622,16 +631,6 @@ object Types {
622631
final def objToAny(implicit ctx: Context) =
623632
if ((this isRef defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this
624633

625-
/** If this is repeated parameter type, its underlying Seq type,
626-
* else the type itself.
627-
*/
628-
def underlyingIfRepeated(implicit ctx: Context): Type = this match {
629-
case rt @ RefinedType(tref: TypeRef, name) if defn.RepeatedParamClasses contains tref.symbol =>
630-
RefinedType(defn.SeqClass.typeRef, name, rt.refinedInfo)
631-
case _ =>
632-
this
633-
}
634-
635634
/** If this is a (possibly aliased, annotated, and/or parameterized) reference to
636635
* a class, the class type ref, otherwise NoType.
637636
*/
@@ -867,7 +866,7 @@ object Types {
867866
*/
868867
def toFunctionType(implicit ctx: Context): Type = this match {
869868
case mt @ MethodType(_, formals) if !mt.isDependent =>
870-
defn.FunctionType(formals mapConserve (_.underlyingIfRepeated), mt.resultType)
869+
defn.FunctionType(formals mapConserve (_.underlyingIfRepeated(mt.isJava)), mt.resultType)
871870
}
872871

873872
/** The signature of this type. This is by default NotAMethod,

src/dotty/tools/dotc/core/pickling/UnPickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ object UnPickler {
7070
}
7171

7272
/** Convert array parameters denoting a repeated parameter of a Java method
73-
* to `JavaRepeatedParamClass` types.
73+
* to `RepeatedParamClass` types.
7474
*/
7575
def arrayToRepeated(tp: Type)(implicit ctx: Context): Type = tp match {
7676
case tp @ MethodType(paramNames, paramTypes) =>
@@ -85,7 +85,7 @@ object UnPickler {
8585
}
8686
tp.derivedMethodType(
8787
paramNames,
88-
paramTypes.init :+ defn.JavaRepeatedParamType.appliedTo(elemtp),
88+
paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp),
8989
tp.resultType)
9090
case tp @ PolyType(paramNames) =>
9191
tp.derivedPolyType(paramNames, tp.paramBounds, arrayToRepeated(tp.resultType))

src/dotty/tools/dotc/core/transform/Erasure.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,12 @@ object Erasure {
4646

4747
def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)
4848
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)
49-
def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName =
50-
(if (isJava) javaSigFn else scalaSigFn).sigName(tp)
49+
def sigName(tp: Type, isJava: Boolean)(implicit ctx: Context): TypeName = {
50+
val normTp =
51+
if (tp.isRepeatedParam) tp.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
52+
else tp
53+
(if (isJava) javaSigFn else scalaSigFn).sigName(normTp)
54+
}
5155

5256
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
5357
*

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

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ class ElimRepeated extends TreeTransform with InfoTransformer { thisTransformer
3232
case tp @ MethodType(paramNames, paramTypes) =>
3333
val resultType1 = elimRepeated(tp.resultType)
3434
val paramTypes1 =
35-
if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) {
36-
paramTypes.init :+
37-
paramTypes.last.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
38-
}
35+
if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam)
36+
paramTypes.init :+ paramTypes.last.underlyingIfRepeated(tp.isJava)
3937
else paramTypes
4038
tp.derivedMethodType(paramNames, paramTypes1, resultType1)
4139
case tp: PolyType =>
@@ -58,4 +56,48 @@ class ElimRepeated extends TreeTransform with InfoTransformer { thisTransformer
5856

5957
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
6058
transformTypeOfTree(tree)
59+
60+
/** If method overrides a Java varargs method, add a varargs bridge.
61+
*/
62+
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
63+
assert(ctx.phase == thisTransformer)
64+
def overridesJava = tree.symbol.allOverriddenSymbols.exists(_ is JavaDefined)
65+
if (tree.symbol.info.isVarArgsMethod && overridesJava)
66+
addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next))
67+
else
68+
tree
69+
}
70+
71+
/** Add a Java varargs bridge
72+
* @param ddef the original method definition which is assumed to override
73+
* a Java varargs method JM up to this phase.
74+
* @return a thicket consisting of `ddef` and a varargs bridge method
75+
* which overrides the Java varargs method JM from this phase on
76+
* and forwards to `ddef`.
77+
*/
78+
private def addVarArgsBridge(ddef: DefDef)(implicit ctx: Context): Tree = {
79+
val original = ddef.symbol.asTerm
80+
val bridge = original.copy(
81+
flags = ddef.symbol.flags &~ Private | Artifact,
82+
info = toJavaVarArgs(ddef.symbol.info)).enteredAfter(thisTransformer).asTerm
83+
val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
84+
val (vrefs :+ varArgRef) :: vrefss1 = vrefss
85+
val elemtp = varArgRef.tpe.widen.argTypes.head
86+
ref(original.termRef)
87+
.appliedToTypes(trefs)
88+
.appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp))
89+
.appliedToArgss(vrefss1)
90+
})
91+
Thicket(ddef, bridgeDef)
92+
}
93+
94+
/** Convert type from Scala to Java varargs method */
95+
private def toJavaVarArgs(tp: Type)(implicit ctx: Context): Type = tp match {
96+
case tp: PolyType =>
97+
tp.derivedPolyType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType))
98+
case tp: MethodType =>
99+
val inits :+ last = tp.paramTypes
100+
val last1 = last.underlyingIfRepeated(isJava = true)
101+
tp.derivedMethodType(tp.paramNames, inits :+ last1, tp.resultType)
102+
}
61103
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import ast.Trees._
2323
import scala.collection.mutable.ListBuffer
2424
import dotty.tools.dotc.core.Flags
2525
import ValueClasses._
26+
import TypeUtils._
2627

2728
class Erasure extends Phase with DenotTransformer {
2829

@@ -83,7 +84,6 @@ object Erasure {
8384
}
8485

8586
def isErasedValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.isInstanceOf[ErasedValueType]
86-
def isPrimitiveValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.classSymbol.isPrimitiveValueClass
8787

8888
def constant(tree: Tree, const: Tree)(implicit ctx: Context) =
8989
if (isPureExpr(tree)) Block(tree :: Nil, const) else const
@@ -112,7 +112,7 @@ object Erasure {
112112
pt match {
113113
case ErasedValueType(clazz, underlying) =>
114114
val tree1 =
115-
if ((tree.tpe isRef defn.NullClass) && isPrimitiveValueType(underlying))
115+
if ((tree.tpe isRef defn.NullClass) && underlying.isPrimitiveValueType)
116116
// convert `null` directly to underlying type, as going
117117
// via the unboxed type would yield a NPE (see SI-5866)
118118
unbox(tree, underlying)
@@ -137,7 +137,7 @@ object Erasure {
137137
if (pt isRef defn.UnitClass) unbox(tree, pt)
138138
else (tree.tpe, pt) match {
139139
case (defn.ArrayType(treeElem), defn.ArrayType(ptElem))
140-
if isPrimitiveValueType(treeElem.widen) && !isPrimitiveValueType(ptElem) =>
140+
if treeElem.widen.isPrimitiveValueType && !ptElem.isPrimitiveValueType =>
141141
// See SI-2386 for one example of when this might be necessary.
142142
cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt)
143143
case _ =>
@@ -157,13 +157,13 @@ object Erasure {
157157
def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
158158
if (tree.tpe <:< pt)
159159
tree
160-
else if (isErasedValueType(tree.tpe.widen))
160+
else if (tree.tpe.widen.isErasedValueType)
161161
adaptToType(box(tree), pt)
162-
else if (isErasedValueType(pt))
162+
else if (pt.isErasedValueType)
163163
adaptToType(unbox(tree, pt), pt)
164-
else if (isPrimitiveValueType(tree.tpe.widen) && !isPrimitiveValueType(pt))
164+
else if (tree.tpe.widen.isPrimitiveValueType && !pt.isPrimitiveValueType)
165165
adaptToType(box(tree), pt)
166-
else if (isPrimitiveValueType(pt) && !isPrimitiveValueType(tree.tpe.widen))
166+
else if (pt.isPrimitiveValueType && !tree.tpe.widen.isPrimitiveValueType)
167167
adaptToType(unbox(tree, pt), pt)
168168
else
169169
cast(tree, pt)
@@ -211,11 +211,11 @@ object Erasure {
211211
else recur(cast(qual, erasedPre))
212212

213213
def recur(qual: Tree): Tree = {
214-
val qualIsPrimitive = isPrimitiveValueType(qual.tpe.widen)
214+
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
215215
val symIsPrimitive = sym.owner.isPrimitiveValueClass
216216
if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass))
217217
select(qual, defn.ObjectClass.info.decl(sym.name).symbol)
218-
else if (qualIsPrimitive && !symIsPrimitive || isErasedValueType(qual.tpe))
218+
else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.isErasedValueType)
219219
recur(box(qual))
220220
else if (!qualIsPrimitive && symIsPrimitive)
221221
recur(unbox(qual, sym.owner.typeRef))
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import Symbols._, Contexts._, Types._, Names._, StdNames._
6+
import ast._
7+
import Trees._
8+
import TypeUtils._
9+
10+
object TreeGen {
11+
12+
import tpd._
13+
14+
def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = {
15+
val elemCls = elemtp.classSymbol
16+
if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name)
17+
else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isPhantomClass) nme.wrapRefArray
18+
else nme.genericWrapArray
19+
}
20+
21+
def wrapArray(tree: Tree, elemtp: Type)(implicit ctx: Context): Tree =
22+
ref(defn.ScalaPredefModule)
23+
.select(wrapArrayMethodName(elemtp))
24+
.appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil)
25+
.appliedTo(tree)
26+
}
Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package dotty.tools.dotc
22
package transform
33

4-
import dotty.tools.dotc.core.Types._
5-
6-
import scala.language.implicitConversions
4+
import core._
5+
import core.transform.Erasure.ErasedValueType
6+
import Types._
7+
import Contexts._
8+
import Symbols._
9+
import Decorators._
10+
import StdNames.nme
11+
import NameOps._
12+
import language.implicitConversions
713

814
object TypeUtils {
915
implicit def decorateTypeUtils(tpe: Type): TypeUtils = new TypeUtils(tpe)
@@ -15,4 +21,10 @@ object TypeUtils {
1521
*/
1622
class TypeUtils(val self: Type) extends AnyVal {
1723

18-
}
24+
def isErasedValueType(implicit ctx: Context): Boolean =
25+
self.isInstanceOf[ErasedValueType]
26+
27+
def isPrimitiveValueType(implicit ctx: Context): Boolean =
28+
self.classSymbol.isPrimitiveValueClass
29+
30+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package test;
2+
public class A {
3+
4+
int foo(int... x) {
5+
return x.length;
6+
}
7+
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package test
2+
class B extends A {
3+
override def foo(x: Int*): Int = x.length + 1
4+
}
5+
object B extends App {
6+
println(new B().foo(1, 2, 3))
7+
}

0 commit comments

Comments
 (0)