@@ -46,7 +46,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
46
46
47
47
private def overridesJava (sym : Symbol )(using Context ) = sym.allOverriddenSymbols.exists(_.is(JavaDefined ))
48
48
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)
50
52
51
53
/** Eliminate repeated parameters from method types. */
52
54
private def elimRepeated (tp : Type )(using Context ): Type = tp.stripTypeVar match
@@ -114,8 +116,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
114
116
*/
115
117
override def transformDefDef (tree : DefDef )(using ctx : Context ): Tree =
116
118
ctx.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)
119
122
if tree.symbol.info.isVarArgsMethod && (isOverride || hasAnnotation) then
120
123
// non-overrides need the varargs bytecode flag and cannot be synthetic
121
124
// otherwise javac refuses to call them.
@@ -125,7 +128,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
125
128
}
126
129
127
130
/** Add a Java varargs bridge
128
- * @param ddef the original method definition
131
+ * @param ddef the original method definition
129
132
* @param addFlag the flag to add to the method symbol
130
133
131
134
* @return a thicket consisting of `ddef` and a varargs bridge method
@@ -141,6 +144,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
141
144
private def addVarArgsBridge (ddef : DefDef , synthetic : Boolean )(using Context ): Tree =
142
145
val original = ddef.symbol.asTerm
143
146
// For simplicity we always set the varargs flag
147
+ // although it's not strictly necessary for overrides
144
148
val flags = ddef.symbol.flags | JavaVarargs &~ Private
145
149
val bridge = original.copy(
146
150
flags = if synthetic then flags | Artifact else flags,
@@ -162,11 +166,26 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
162
166
163
167
/** Convert type from Scala to Java varargs method */
164
168
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 is it 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 )))
171
190
172
191
}
0 commit comments