aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-03 17:06:29 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-03 17:06:29 +0200
commitb88b958bb7f25ba45a6c15c9f554df2d4c6746ed (patch)
tree59606a00437c471699f596eb12b2c74c3826b1a5
parent29e8f67ba19ab531932c98eba1411a63815cfa80 (diff)
downloaddotty-b88b958bb7f25ba45a6c15c9f554df2d4c6746ed.tar.gz
dotty-b88b958bb7f25ba45a6c15c9f554df2d4c6746ed.tar.bz2
dotty-b88b958bb7f25ba45a6c15c9f554df2d4c6746ed.zip
Add varargs bridge methods
Distinguish translations between Java and Scala varargs methods and add bridges where needed.
-rw-r--r--src/dotty/tools/dotc/Compiler.scala4
-rw-r--r--src/dotty/tools/dotc/core/Types.scala9
-rw-r--r--src/dotty/tools/dotc/transform/ElimRepeated.scala45
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala18
-rw-r--r--src/dotty/tools/dotc/transform/TreeGen.scala26
-rw-r--r--src/dotty/tools/dotc/transform/TypeUtils.scala20
6 files changed, 104 insertions, 18 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 95f74e290..28b340eb4 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -19,8 +19,10 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
- List(new Companions, new ElimRepeated /*, new ElimLocals*/),
+ List(new Companions),
List(new SuperAccessors),
+ // pickling and refchecks goes here
+ List(new ElimRepeated/*, new ElimLocals*/),
List(new ExtensionMethods),
List(new TailRec),
List(new PatternMatcher,
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index a37b872d2..84c799129 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -158,6 +158,15 @@ object Types {
def isRepeatedParam(implicit ctx: Context): Boolean =
typeSymbol eq defn.RepeatedParamClass
+ /** Is this the type of a method that has a repeated parameter type as
+ * last parameter type?
+ */
+ def isVarArgsMethod(implicit ctx: Context): Boolean = this match {
+ case tp: PolyType => tp.resultType.isVarArgsMethod
+ case MethodType(_, paramTypes) => paramTypes.nonEmpty && paramTypes.last.isRepeatedParam
+ case _ => false
+ }
+
/** Is this an alias TypeBounds? */
def isAlias: Boolean = this match {
case TypeBounds(lo, hi) => lo eq hi
diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala
index a362aee07..c78c012c3 100644
--- a/src/dotty/tools/dotc/transform/ElimRepeated.scala
+++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -32,10 +32,8 @@ class ElimRepeated extends TreeTransform with InfoTransformer { thisTransformer
case tp @ MethodType(paramNames, paramTypes) =>
val resultType1 = elimRepeated(tp.resultType)
val paramTypes1 =
- if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) {
- paramTypes.init :+
- paramTypes.last.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
- }
+ if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam)
+ paramTypes.init :+ paramTypes.last.underlyingIfRepeated(tp.isJava)
else paramTypes
tp.derivedMethodType(paramNames, paramTypes1, resultType1)
case tp: PolyType =>
@@ -58,4 +56,43 @@ class ElimRepeated extends TreeTransform with InfoTransformer { thisTransformer
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
transformTypeOfTree(tree)
+
+ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ assert(ctx.phase == thisTransformer)
+ def overridesJava = {
+ val overridden = tree.symbol.allOverriddenSymbols
+ overridden.hasNext && overridden.forall(_ is JavaDefined)
+ }
+ if (tree.symbol.info.isVarArgsMethod && overridesJava)
+ addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next))
+ else
+ tree
+ }
+
+ /** add varargs bridge method
+ */
+ private def addVarArgsBridge(ddef: DefDef)(implicit ctx: Context): Tree = {
+ val original = ddef.symbol.asTerm
+ val bridge = original.copy(
+ flags = ddef.symbol.flags &~ Private | Artifact,
+ info = toJavaVarArgs(ddef.symbol.info)).enteredAfter(thisTransformer).asTerm
+ val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
+ val (vrefs :+ varArgRef) :: vrefss1 = vrefss
+ val elemtp = varArgRef.tpe.widen.argTypes.head
+ ref(original.termRef)
+ .appliedToTypes(trefs)
+ .appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp))
+ .appliedToArgss(vrefss1)
+ })
+ Thicket(ddef, bridgeDef)
+ }
+
+ private def toJavaVarArgs(tp: Type)(implicit ctx: Context): Type = tp match {
+ case tp: PolyType =>
+ tp.derivedPolyType(tp.paramNames, tp.paramBounds, toJavaVarArgs(tp.resultType))
+ case tp: MethodType =>
+ val inits :+ last = tp.paramTypes
+ val last1 = last.underlyingIfRepeated(isJava = true)
+ tp.derivedMethodType(tp.paramNames, inits :+ last1, tp.resultType)
+ }
}
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 35742ac8c..1cc00bdee 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -23,6 +23,7 @@ import ast.Trees._
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Flags
import ValueClasses._
+import TypeUtils._
class Erasure extends Phase with DenotTransformer {
@@ -83,7 +84,6 @@ object Erasure {
}
def isErasedValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.isInstanceOf[ErasedValueType]
- def isPrimitiveValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.classSymbol.isPrimitiveValueClass
def constant(tree: Tree, const: Tree)(implicit ctx: Context) =
if (isPureExpr(tree)) Block(tree :: Nil, const) else const
@@ -112,7 +112,7 @@ object Erasure {
pt match {
case ErasedValueType(clazz, underlying) =>
val tree1 =
- if ((tree.tpe isRef defn.NullClass) && isPrimitiveValueType(underlying))
+ if ((tree.tpe isRef defn.NullClass) && underlying.isPrimitiveValueType)
// convert `null` directly to underlying type, as going
// via the unboxed type would yield a NPE (see SI-5866)
unbox(tree, underlying)
@@ -137,7 +137,7 @@ object Erasure {
if (pt isRef defn.UnitClass) unbox(tree, pt)
else (tree.tpe, pt) match {
case (defn.ArrayType(treeElem), defn.ArrayType(ptElem))
- if isPrimitiveValueType(treeElem.widen) && !isPrimitiveValueType(ptElem) =>
+ if treeElem.widen.isPrimitiveValueType && !ptElem.isPrimitiveValueType =>
// See SI-2386 for one example of when this might be necessary.
cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt)
case _ =>
@@ -157,13 +157,13 @@ object Erasure {
def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
if (tree.tpe <:< pt)
tree
- else if (isErasedValueType(tree.tpe.widen))
+ else if (tree.tpe.widen.isErasedValueType)
adaptToType(box(tree), pt)
- else if (isErasedValueType(pt))
+ else if (pt.isErasedValueType)
adaptToType(unbox(tree, pt), pt)
- else if (isPrimitiveValueType(tree.tpe.widen) && !isPrimitiveValueType(pt))
+ else if (tree.tpe.widen.isPrimitiveValueType && !pt.isPrimitiveValueType)
adaptToType(box(tree), pt)
- else if (isPrimitiveValueType(pt) && !isPrimitiveValueType(tree.tpe.widen))
+ else if (pt.isPrimitiveValueType && !tree.tpe.widen.isPrimitiveValueType)
adaptToType(unbox(tree, pt), pt)
else
cast(tree, pt)
@@ -211,11 +211,11 @@ object Erasure {
else recur(cast(qual, erasedPre))
def recur(qual: Tree): Tree = {
- val qualIsPrimitive = isPrimitiveValueType(qual.tpe.widen)
+ val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
val symIsPrimitive = sym.owner.isPrimitiveValueClass
if ((sym.owner eq defn.AnyClass) || (sym.owner eq defn.AnyValClass))
select(qual, defn.ObjectClass.info.decl(sym.name).symbol)
- else if (qualIsPrimitive && !symIsPrimitive || isErasedValueType(qual.tpe))
+ else if (qualIsPrimitive && !symIsPrimitive || qual.tpe.isErasedValueType)
recur(box(qual))
else if (!qualIsPrimitive && symIsPrimitive)
recur(unbox(qual, sym.owner.typeRef))
diff --git a/src/dotty/tools/dotc/transform/TreeGen.scala b/src/dotty/tools/dotc/transform/TreeGen.scala
new file mode 100644
index 000000000..7997aa308
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/TreeGen.scala
@@ -0,0 +1,26 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Symbols._, Contexts._, Types._, Names._, StdNames._
+import ast._
+import Trees._
+import TypeUtils._
+
+object TreeGen {
+
+ import tpd._
+
+ def wrapArrayMethodName(elemtp: Type)(implicit ctx: Context): TermName = {
+ val elemCls = elemtp.classSymbol
+ if (elemCls.isPrimitiveValueClass) nme.wrapXArray(elemCls.name)
+ else if (elemCls.derivesFrom(defn.ObjectClass) && !elemCls.isPhantomClass) nme.wrapRefArray
+ else nme.genericWrapArray
+ }
+
+ def wrapArray(tree: Tree, elemtp: Type)(implicit ctx: Context): Tree =
+ ref(defn.ScalaPredefModule)
+ .select(wrapArrayMethodName(elemtp))
+ .appliedToTypes(if (elemtp.isPrimitiveValueType) Nil else elemtp :: Nil)
+ .appliedTo(tree)
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/TypeUtils.scala b/src/dotty/tools/dotc/transform/TypeUtils.scala
index a26660092..d07930661 100644
--- a/src/dotty/tools/dotc/transform/TypeUtils.scala
+++ b/src/dotty/tools/dotc/transform/TypeUtils.scala
@@ -1,9 +1,15 @@
package dotty.tools.dotc
package transform
-import dotty.tools.dotc.core.Types._
-
-import scala.language.implicitConversions
+import core._
+import core.transform.Erasure.ErasedValueType
+import Types._
+import Contexts._
+import Symbols._
+import Decorators._
+import StdNames.nme
+import NameOps._
+import language.implicitConversions
object TypeUtils {
implicit def decorateTypeUtils(tpe: Type): TypeUtils = new TypeUtils(tpe)
@@ -15,4 +21,10 @@ object TypeUtils {
*/
class TypeUtils(val self: Type) extends AnyVal {
-} \ No newline at end of file
+ def isErasedValueType(implicit ctx: Context): Boolean =
+ self.isInstanceOf[ErasedValueType]
+
+ def isPrimitiveValueType(implicit ctx: Context): Boolean =
+ self.classSymbol.isPrimitiveValueClass
+
+ }