@@ -15,6 +15,7 @@ import Denotations._, SymDenotations._
15
15
import dotty .tools .dotc .ast .tpd
16
16
import TypeErasure .erasure
17
17
import DenotTransformers ._
18
+ import dotty .tools .backend .jvm .DottyBackendInterface .requiredClass
18
19
19
20
object ElimRepeated {
20
21
val name : String = " elimRepeated"
@@ -47,6 +48,8 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
47
48
48
49
private def overridesJava (sym : Symbol )(implicit ctx : Context ) = sym.allOverriddenSymbols.exists(_.is(JavaDefined ))
49
50
51
+ private def hasVargsAnnotation (sym : Symbol )(using ctx : Context ) = sym.hasAnnotation(requiredClass[scala.annotation.varargs])
52
+
50
53
private def elimRepeated (tp : Type )(implicit ctx : Context ): Type = tp.stripTypeVar match {
51
54
case tp @ MethodTpe (paramNames, paramTypes, resultType) =>
52
55
val resultType1 = elimRepeated(resultType)
@@ -109,35 +112,41 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
109
112
override def transformTypeApply (tree : TypeApply )(implicit ctx : Context ): Tree =
110
113
transformTypeOfTree(tree)
111
114
112
- /** If method overrides a Java varargs method, add a varargs bridge.
113
- * Also transform trees inside method annotation
115
+ /** If method overrides a Java varargs method or is annotated with @varargs , add a varargs bridge.
116
+ * Also transform trees inside method annotation.
114
117
*/
115
118
override def transformDefDef (tree : DefDef )(implicit ctx : Context ): Tree =
116
119
ctx.atPhase(thisPhase) {
117
- if (tree.symbol.info.isVarArgsMethod && overridesJava(tree.symbol))
118
- addVarArgsBridge(tree)
120
+ val isOverride = overridesJava(tree.symbol)
121
+ val hasAnnotation = hasVargsAnnotation(tree.symbol)
122
+ if tree.symbol.info.isVarArgsMethod && (isOverride || hasAnnotation) then
123
+ // java varargs can be overriden by synthetic methods with an Array param,
124
+ // but non-overrides need the varargs bytecode flag and cannot be synthetic
125
+ // otherwise javac refuses to call them.
126
+ addVarArgsBridge(tree, if hasAnnotation then JavaVarargs else Artifact )
119
127
else
120
128
tree
121
129
}
122
130
123
131
/** Add a Java varargs bridge
124
- * @param ddef the original method definition which is assumed to override
125
- * a Java varargs method JM up to this phase.
126
- * @return a thicket consisting of `ddef` and a varargs bridge method
127
- * which overrides the Java varargs method JM from this phase on
128
- * and forwards to `ddef`.
132
+ * @param ddef the original method definition which is assumed to override
133
+ * a Java varargs method JM up to this phase.
134
+ * @param addFlag the flag to add to the method definition
135
+
136
+ * @return a thicket consisting of `ddef` and a varargs bridge method
137
+ * which forwards java varargs to `ddef`. It retains all the
138
+ * flags of `ddef` except `Private`.
129
139
*
130
140
* A bridge is necessary because the following hold
131
141
* - the varargs in `ddef` will change from `RepeatedParam[T]` to `Seq[T]` after this phase
132
- * - _but_ the callers of `ddef` expect its varargs to be changed to `Array[? <: T]`, since it overrides
133
- * a Java varargs
142
+ * - _but_ the callers of `ddef` expect its varargs to be changed to `Array[? <: T]`
134
143
* The solution is to add a "bridge" method that converts its argument from `Array[? <: T]` to `Seq[T]` and
135
144
* forwards it to `ddef`.
136
145
*/
137
- private def addVarArgsBridge (ddef : DefDef )(implicit ctx : Context ): Tree = {
146
+ private def addVarArgsBridge (ddef : DefDef , addFlag : Flag )(implicit ctx : Context ): Tree = {
138
147
val original = ddef.symbol.asTerm
139
148
val bridge = original.copy(
140
- flags = ddef.symbol.flags &~ Private | Artifact ,
149
+ flags = ( ddef.symbol.flags | addFlag) &~ Private ,
141
150
info = toJavaVarArgs(ddef.symbol.info)).enteredAfter(thisPhase).asTerm
142
151
val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
143
152
val (vrefs :+ varArgRef) :: vrefss1 = vrefss
0 commit comments