@@ -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 ._
@@ -54,11 +55,22 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
5455 private def elimRepeated (tp : Type )(using Context ): Type = tp.stripTypeVar match
5556 case tp @ MethodTpe (paramNames, paramTypes, resultType) =>
5657 val resultType1 = elimRepeated(resultType)
57- val paramTypes1 =
58- if paramTypes.nonEmpty && paramTypes.last.isRepeatedParam then
59- val last = paramTypes.last.translateFromRepeated(toArray = tp.isJavaMethod)
60- paramTypes.init :+ last
61- else paramTypes
58+ val paramTypes1 = paramTypes match
59+ case init :+ last if last.isRepeatedParam =>
60+ val isJava = tp.isJavaMethod
61+ // A generic Java varargs `T...` is erased to `Object[]` in bytecode,
62+ // we directly translate such a type to `Array[_ <: Object]` instead
63+ // of `Array[_ <: T]` here. This allows the tree transformer of this phase
64+ // to emit the correct adaptation for repeated arguments without
65+ // relying on any cast (cf `adaptToArray`).
66+ val last1 =
67+ if isJava && last.elemType.isInstanceOf [TypeParamRef ] then
68+ defn.ArrayOf (TypeBounds .upper(defn.ObjectType ))
69+ else
70+ last.translateFromRepeated(toArray = isJava)
71+ init :+ last1
72+ case _ =>
73+ paramTypes
6274 tp.derivedLambdaType(paramNames, paramTypes1, resultType1)
6375 case tp : PolyType =>
6476 tp.derivedLambdaType(tp.paramNames, tp.paramInfos, elimRepeated(tp.resultType))
@@ -82,9 +94,10 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
8294 case arg : Typed if isWildcardStarArg(arg) =>
8395 val isJavaDefined = tree.fun.symbol.is(JavaDefined )
8496 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 )
97+ if isJavaDefined then
98+ val pt = tree.fun.tpe.widen.firstParamTypes.last
99+ adaptToArray(arg.expr, pt.elemType.bounds.hi)
100+ else if tpe.derivesFrom(defn.ArrayClass ) then
88101 arrayToSeq(arg.expr)
89102 else
90103 arg.expr
@@ -107,7 +120,39 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
107120 .appliedToType(elemType)
108121 .appliedTo(tree, clsOf(elemClass.typeRef))
109122
110- /** Convert Java array argument to Scala Seq */
123+ /** Adapt a Seq or Array tree to be a subtype of `Array[_ <: $elemPt]`.
124+ *
125+ * @pre `elemPt` must either be a super type of the argument element type or `Object`.
126+ * The special handling of `Object` is required to deal with the translation
127+ * of generic Java varargs in `elimRepeated`.
128+ */
129+ private def adaptToArray (tree : Tree , elemPt : Type )(implicit ctx : Context ): Tree =
130+ val elemTp = tree.tpe.elemType
131+ val treeIsArray = tree.tpe.derivesFrom(defn.ArrayClass )
132+ if elemTp <:< elemPt then
133+ if treeIsArray then
134+ tree // no adaptation needed
135+ else
136+ tree match
137+ case SeqLiteral (elems, elemtpt) =>
138+ JavaSeqLiteral (elems, elemtpt).withSpan(tree.span)
139+ case _ =>
140+ // Convert a Seq[T] to an Array[$elemPt]
141+ ref(defn.DottyArraysModule )
142+ .select(nme.seqToArray)
143+ .appliedToType(elemPt)
144+ .appliedTo(tree, clsOf(elemPt))
145+ else if treeIsArray then
146+ // Convert an Array[T] to an Array[Object]
147+ ref(defn.ScalaRuntime_toObjectArray )
148+ .appliedTo(tree)
149+ else
150+ // Convert a Seq[T] to an Array[Object]
151+ ref(defn.ScalaRuntime_toArray )
152+ .appliedToType(elemTp)
153+ .appliedTo(tree)
154+
155+ /** Convert an Array into a scala.Seq */
111156 private def arrayToSeq (tree : Tree )(using Context ): Tree =
112157 tpd.wrapArray(tree, tree.tpe.elemType)
113158
0 commit comments