@@ -34,34 +34,34 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
34
34
elimRepeated(tp)
35
35
36
36
override def transform (ref : SingleDenotation )(using Context ): SingleDenotation =
37
- super .transform(ref) match {
37
+ super .transform(ref) match
38
38
case ref1 : SymDenotation if (ref1 ne ref) && overridesJava(ref1.symbol) =>
39
39
// This method won't override the corresponding Java method at the end of this phase,
40
40
// only the bridge added by `addVarArgsBridge` will.
41
41
ref1.copySymDenotation(initFlags = ref1.flags &~ Override )
42
42
case ref1 =>
43
43
ref1
44
- }
45
44
46
45
override def mayChange (sym : Symbol )(using Context ): Boolean = sym.is(Method )
47
46
48
47
private def overridesJava (sym : Symbol )(using Context ) = sym.allOverriddenSymbols.exists(_.is(JavaDefined ))
49
48
50
- private def elimRepeated (tp : Type )(using Context ): Type = tp.stripTypeVar match {
49
+ private def hasVargsAnnotation (sym : Symbol )(using ctx : Context ) = sym.hasAnnotation(defn.VarargsAnnot )
50
+
51
+ /** Eliminate repeated parameters from method types. */
52
+ private def elimRepeated (tp : Type )(using Context ): Type = tp.stripTypeVar match
51
53
case tp @ MethodTpe (paramNames, paramTypes, resultType) =>
52
54
val resultType1 = elimRepeated(resultType)
53
55
val paramTypes1 =
54
- if ( paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) {
56
+ if paramTypes.nonEmpty && paramTypes.last.isRepeatedParam then
55
57
val last = paramTypes.last.translateFromRepeated(toArray = tp.isJavaMethod)
56
58
paramTypes.init :+ last
57
- }
58
59
else paramTypes
59
60
tp.derivedLambdaType(paramNames, paramTypes1, resultType1)
60
61
case tp : PolyType =>
61
62
tp.derivedLambdaType(tp.paramNames, tp.paramInfos, elimRepeated(tp.resultType))
62
63
case tp =>
63
64
tp
64
- }
65
65
66
66
def transformTypeOfTree (tree : Tree )(using Context ): Tree =
67
67
tree.withType(elimRepeated(tree.tpe))
@@ -72,35 +72,35 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
72
72
override def transformSelect (tree : Select )(using Context ): Tree =
73
73
transformTypeOfTree(tree)
74
74
75
- override def transformApply (tree : Apply )(using Context ): Tree = {
75
+ override def transformApply (tree : Apply )(using Context ): Tree =
76
76
val args = tree.args.mapConserve {
77
77
case arg : Typed if isWildcardStarArg(arg) =>
78
78
val isJavaDefined = tree.fun.symbol.is(JavaDefined )
79
79
val tpe = arg.expr.tpe
80
- if ( isJavaDefined && tpe.derivesFrom(defn.SeqClass ))
80
+ if isJavaDefined && tpe.derivesFrom(defn.SeqClass ) then
81
81
seqToArray(arg.expr)
82
- else if ( ! isJavaDefined && tpe.derivesFrom(defn.ArrayClass ) )
82
+ else if ! isJavaDefined && tpe.derivesFrom(defn.ArrayClass )
83
83
arrayToSeq(arg.expr)
84
84
else
85
85
arg.expr
86
86
case arg => arg
87
87
}
88
88
transformTypeOfTree(cpy.Apply (tree)(tree.fun, args))
89
- }
90
89
91
90
/** Convert sequence argument to Java array */
92
- private def seqToArray (tree : Tree )(using Context ): Tree = tree match {
91
+ private def seqToArray (tree : Tree )(using Context ): Tree = tree match
93
92
case SeqLiteral (elems, elemtpt) =>
94
93
JavaSeqLiteral (elems, elemtpt)
95
94
case _ =>
96
95
val elemType = tree.tpe.elemType
97
96
var elemClass = erasure(elemType).classSymbol
98
- if (defn.NotRuntimeClasses .contains(elemClass)) elemClass = defn.ObjectClass
97
+ if defn.NotRuntimeClasses .contains(elemClass) then
98
+ elemClass = defn.ObjectClass
99
+ end if
99
100
ref(defn.DottyArraysModule )
100
101
.select(nme.seqToArray)
101
102
.appliedToType(elemType)
102
103
.appliedTo(tree, clsOf(elemClass.typeRef))
103
- }
104
104
105
105
/** Convert Java array argument to Scala Seq */
106
106
private def arrayToSeq (tree : Tree )(using Context ): Tree =
@@ -109,36 +109,44 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
109
109
override def transformTypeApply (tree : TypeApply )(using Context ): Tree =
110
110
transformTypeOfTree(tree)
111
111
112
- /** If method overrides a Java varargs method, add a varargs bridge.
113
- * Also transform trees inside method annotation
112
+ /** If method overrides a Java varargs method or is annotated with @varargs , add a varargs bridge.
113
+ * Also transform trees inside method annotation.
114
114
*/
115
115
override def transformDefDef (tree : DefDef )(using Context ): Tree =
116
116
atPhase(thisPhase) {
117
- if (tree.symbol.info.isVarArgsMethod && overridesJava(tree.symbol))
118
- addVarArgsBridge(tree)
117
+ val isOverride = overridesJava(tree.symbol)
118
+ val hasAnnotation = hasVargsAnnotation(tree.symbol)
119
+ if tree.symbol.info.isVarArgsMethod && (isOverride || hasAnnotation) then
120
+ // non-overrides need the varargs bytecode flag and cannot be synthetic
121
+ // otherwise javac refuses to call them.
122
+ addVarArgsBridge(tree, isOverride)
119
123
else
120
124
tree
121
125
}
122
126
123
127
/** 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`.
128
+ * @param ddef the original method definition
129
+ * @param addFlag the flag to add to the method symbol
130
+
131
+ * @return a thicket consisting of `ddef` and a varargs bridge method
132
+ * which forwards java varargs to `ddef`. It retains all the
133
+ * flags of `ddef` except `Private`.
129
134
*
130
- * A bridge is necessary because the following hold
135
+ * A bridge is necessary because the following hold:
131
136
* - 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
137
+ * - _but_ the callers of `ddef` expect its varargs to be changed to `Array[? <: T]`
134
138
* The solution is to add a "bridge" method that converts its argument from `Array[? <: T]` to `Seq[T]` and
135
139
* forwards it to `ddef`.
136
140
*/
137
- private def addVarArgsBridge (ddef : DefDef )(using Context ): Tree = {
141
+ private def addVarArgsBridge (ddef : DefDef , synthetic : Boolean )(using Context ): Tree =
138
142
val original = ddef.symbol.asTerm
143
+ // For simplicity we always set the varargs flag
144
+ val flags = ddef.symbol.flags | JavaVarargs &~ Private
139
145
val bridge = original.copy(
140
- flags = ddef.symbol.flags &~ Private | Artifact ,
141
- info = toJavaVarArgs(ddef.symbol.info)).enteredAfter(thisPhase).asTerm
146
+ flags = if synthetic then flags | Artifact else flags,
147
+ info = toJavaVarArgs(ddef.symbol.info)
148
+ ).enteredAfter(thisPhase).asTerm
149
+
142
150
val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
143
151
val (vrefs :+ varArgRef) :: vrefss1 = vrefss
144
152
// Can't call `.argTypes` here because the underlying array type is of the
@@ -151,15 +159,14 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
151
159
})
152
160
153
161
Thicket (ddef, bridgeDef)
154
- }
155
162
156
163
/** Convert type from Scala to Java varargs method */
157
- private def toJavaVarArgs (tp : Type )(using Context ): Type = tp match {
164
+ private def toJavaVarArgs (tp : Type )(using Context ): Type = tp match
158
165
case tp : PolyType =>
159
166
tp.derivedLambdaType(tp.paramNames, tp.paramInfos, toJavaVarArgs(tp.resultType))
160
167
case tp : MethodType =>
161
168
val inits :+ last = tp.paramInfos
162
169
val last1 = last.translateFromRepeated(toArray = true )
163
170
tp.derivedLambdaType(tp.paramNames, inits :+ last1, tp.resultType)
164
- }
171
+
165
172
}
0 commit comments