@@ -46,7 +46,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
4646
4747 private def overridesJava (sym : Symbol )(using Context ) = sym.allOverriddenSymbols.exists(_.is(JavaDefined ))
4848
49- private def hasVargsAnnotation (sym : Symbol )(using ctx : Context ) = sym.hasAnnotation(defn.VarargsAnnot )
49+ private def hasVarargsAnnotation (sym : Symbol )(using Context ) = sym.hasAnnotation(defn.VarargsAnnot )
50+
51+ private def parentHasAnnotation (sym : Symbol )(using Context ) = sym.allOverriddenSymbols.exists(hasVarargsAnnotation)
5052
5153 /** Eliminate repeated parameters from method types. */
5254 private def elimRepeated (tp : Type )(using Context ): Type = tp.stripTypeVar match
@@ -114,8 +116,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
114116 */
115117 override def transformDefDef (tree : DefDef )(using Context ): Tree =
116118 atPhase(thisPhase) {
117- val isOverride = overridesJava(tree.symbol)
118- val hasAnnotation = hasVargsAnnotation(tree.symbol)
119+ val sym = tree.symbol
120+ val isOverride = overridesJava(sym)
121+ val hasAnnotation = hasVarargsAnnotation(sym) || parentHasAnnotation(sym)
119122 if tree.symbol.info.isVarArgsMethod && (isOverride || hasAnnotation) then
120123 // non-overrides need the varargs bytecode flag and cannot be synthetic
121124 // otherwise javac refuses to call them.
@@ -125,7 +128,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
125128 }
126129
127130 /** Add a Java varargs bridge
128- * @param ddef the original method definition
131+ * @param ddef the original method definition
129132 * @param addFlag the flag to add to the method symbol
130133
131134 * @return a thicket consisting of `ddef` and a varargs bridge method
@@ -141,6 +144,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
141144 private def addVarArgsBridge (ddef : DefDef , synthetic : Boolean )(using Context ): Tree =
142145 val original = ddef.symbol.asTerm
143146 // For simplicity we always set the varargs flag
147+ // although it's not strictly necessary for overrides
144148 val flags = ddef.symbol.flags | JavaVarargs &~ Private
145149 val bridge = original.copy(
146150 flags = if synthetic then flags | Artifact else flags,
@@ -162,11 +166,26 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
162166
163167 /** Convert type from Scala to Java varargs method */
164168 private def toJavaVarArgs (tp : Type )(using Context ): Type = tp match
165- case tp : PolyType =>
166- tp.derivedLambdaType(tp.paramNames, tp.paramInfos, toJavaVarArgs(tp.resultType))
167- case tp : MethodType =>
168- val inits :+ last = tp.paramInfos
169- val last1 = last.translateFromRepeated(toArray = true )
170- tp.derivedLambdaType(tp.paramNames, inits :+ last1, tp.resultType)
169+ case tp : PolyType =>
170+ tp.derivedLambdaType(tp.paramNames, tp.paramInfos, toJavaVarArgs(tp.resultType))
171+ case tp : MethodType =>
172+ val inits :+ last = tp.paramInfos
173+ val vararg = varargArrayType(last)
174+ val params = inits :+ vararg
175+ tp.derivedLambdaType(tp.paramNames, params, tp.resultType)
176+
177+ /** Translate a repeated type T* to an `Array[? <: Upper]`
178+ * such that it is compatible with java varargs.
179+ *
180+ * If T is not a primitive type, we set `Upper = T & AnyRef`
181+ * to prevent the erasure of `Array[? <: Upper]` to Object,
182+ * which would break the varargs from Java.
183+ */
184+ private def varargArrayType (tp : Type )(using Context ): Type =
185+ val array = tp.translateFromRepeated(toArray = true )
186+ val element = array.elemType.typeSymbol
187+
188+ if element.isPrimitiveValueClass then array
189+ else defn.ArrayOf (TypeBounds .upper(AndType (element.typeRef, defn.AnyRefType )))
171190
172191}
0 commit comments