@@ -20,8 +20,9 @@ object ElimRepeated {
2020 val name : String = " elimRepeated"
2121}
2222
23- /** A transformer that removes repeated parameters (T*) from all types, replacing
24- * them with Seq types.
23+ /** A transformer that eliminates repeated parameters (T*) from all types, replacing
24+ * them with Seq or Array types and adapting repeated arguments to conform to
25+ * the transformed type if needed.
2526 */
2627class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
2728 import ast .tpd ._
@@ -55,9 +56,28 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
5556 case tp @ MethodTpe (paramNames, paramTypes, resultType) =>
5657 val resultType1 = elimRepeated(resultType)
5758 val paramTypes1 =
58- if paramTypes.nonEmpty && paramTypes.last.isRepeatedParam then
59- val last = paramTypes.last.translateFromRepeated(toArray = tp.isJavaMethod)
60- paramTypes.init :+ last
59+ val lastIdx = paramTypes.length - 1
60+ if lastIdx >= 0 then
61+ val last = paramTypes(lastIdx)
62+ if last.isRepeatedParam then
63+ val isJava = tp.isJavaMethod
64+ // A generic Java varargs `T...` where `T` is unbounded is erased to
65+ // `Object[]` in bytecode, we directly translate such a type to
66+ // `Array[_ <: Object]` instead of `Array[_ <: T]` here. This allows
67+ // the tree transformer of this phase to emit the correct adaptation
68+ // for repeated arguments if needed (for example, an `Array[Int]` will
69+ // be copied into an `Array[Object]`, see `adaptToArray`).
70+ val last1 =
71+ if isJava && {
72+ val elemTp = last.elemType
73+ elemTp.isInstanceOf [TypeParamRef ] && elemTp.typeSymbol == defn.AnyClass
74+ }
75+ then
76+ defn.ArrayOf (TypeBounds .upper(defn.ObjectType ))
77+ else
78+ last.translateFromRepeated(toArray = isJava)
79+ paramTypes.updated(lastIdx, last1)
80+ else paramTypes
6181 else paramTypes
6282 tp.derivedLambdaType(paramNames, paramTypes1, resultType1)
6383 case tp : PolyType =>
@@ -82,9 +102,10 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
82102 case arg : Typed if isWildcardStarArg(arg) =>
83103 val isJavaDefined = tree.fun.symbol.is(JavaDefined )
84104 val tpe = arg.expr.tpe
85- if isJavaDefined && tpe.derivesFrom(defn.SeqClass ) then
86- seqToArray(arg.expr)
87- else if ! isJavaDefined && tpe.derivesFrom(defn.ArrayClass )
105+ if isJavaDefined then
106+ val pt = tree.fun.tpe.widen.firstParamTypes.last
107+ adaptToArray(arg.expr, pt.elemType.bounds.hi)
108+ else if tpe.derivesFrom(defn.ArrayClass ) then
88109 arrayToSeq(arg.expr)
89110 else
90111 arg.expr
@@ -107,7 +128,39 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
107128 .appliedToType(elemType)
108129 .appliedTo(tree, clsOf(elemClass.typeRef))
109130
110- /** Convert Java array argument to Scala Seq */
131+ /** Adapt a Seq or Array tree to be a subtype of `Array[_ <: $elemPt]`.
132+ *
133+ * @pre `elemPt` must either be a super type of the argument element type or `Object`.
134+ * The special handling of `Object` is required to deal with the translation
135+ * of generic Java varargs in `elimRepeated`.
136+ */
137+ private def adaptToArray (tree : Tree , elemPt : Type )(implicit ctx : Context ): Tree =
138+ val elemTp = tree.tpe.elemType
139+ val treeIsArray = tree.tpe.derivesFrom(defn.ArrayClass )
140+ if elemTp <:< elemPt then
141+ if treeIsArray then
142+ tree // no adaptation needed
143+ else
144+ tree match
145+ case SeqLiteral (elems, elemtpt) =>
146+ JavaSeqLiteral (elems, elemtpt).withSpan(tree.span)
147+ case _ =>
148+ // Convert a Seq[T] to an Array[$elemPt]
149+ ref(defn.DottyArraysModule )
150+ .select(nme.seqToArray)
151+ .appliedToType(elemPt)
152+ .appliedTo(tree, clsOf(elemPt))
153+ else if treeIsArray then
154+ // Convert an Array[T] to an Array[Object]
155+ ref(defn.ScalaRuntime_toObjectArray )
156+ .appliedTo(tree)
157+ else
158+ // Convert a Seq[T] to an Array[Object]
159+ ref(defn.ScalaRuntime_toArray )
160+ .appliedToType(elemTp)
161+ .appliedTo(tree)
162+
163+ /** Convert an Array into a scala.Seq */
111164 private def arrayToSeq (tree : Tree )(using Context ): Tree =
112165 tpd.wrapArray(tree, tree.tpe.elemType)
113166
0 commit comments