Skip to content

Commit c86c2be

Browse files
Fix #7212: Generate varargs bridge with the right flags on @VarArgs annotation
1 parent af344aa commit c86c2be

File tree

1 file changed

+22
-13
lines changed

1 file changed

+22
-13
lines changed

compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Denotations._, SymDenotations._
1515
import dotty.tools.dotc.ast.tpd
1616
import TypeErasure.erasure
1717
import DenotTransformers._
18+
import dotty.tools.backend.jvm.DottyBackendInterface.requiredClass
1819

1920
object ElimRepeated {
2021
val name: String = "elimRepeated"
@@ -47,6 +48,8 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
4748

4849
private def overridesJava(sym: Symbol)(implicit ctx: Context) = sym.allOverriddenSymbols.exists(_.is(JavaDefined))
4950

51+
private def hasVargsAnnotation(sym: Symbol)(using ctx: Context) = sym.hasAnnotation(requiredClass[scala.annotation.varargs])
52+
5053
private def elimRepeated(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match {
5154
case tp @ MethodTpe(paramNames, paramTypes, resultType) =>
5255
val resultType1 = elimRepeated(resultType)
@@ -109,35 +112,41 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
109112
override def transformTypeApply(tree: TypeApply)(implicit ctx: Context): Tree =
110113
transformTypeOfTree(tree)
111114

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.
114117
*/
115118
override def transformDefDef(tree: DefDef)(implicit ctx: Context): Tree =
116119
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)
119127
else
120128
tree
121129
}
122130

123131
/** 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`.
129139
*
130140
* A bridge is necessary because the following hold
131141
* - 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]`
134143
* The solution is to add a "bridge" method that converts its argument from `Array[? <: T]` to `Seq[T]` and
135144
* forwards it to `ddef`.
136145
*/
137-
private def addVarArgsBridge(ddef: DefDef)(implicit ctx: Context): Tree = {
146+
private def addVarArgsBridge(ddef: DefDef, addFlag: Flag)(implicit ctx: Context): Tree = {
138147
val original = ddef.symbol.asTerm
139148
val bridge = original.copy(
140-
flags = ddef.symbol.flags &~ Private | Artifact,
149+
flags = (ddef.symbol.flags | addFlag) &~ Private,
141150
info = toJavaVarArgs(ddef.symbol.info)).enteredAfter(thisPhase).asTerm
142151
val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
143152
val (vrefs :+ varArgRef) :: vrefss1 = vrefss

0 commit comments

Comments
 (0)