@@ -68,6 +68,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
6868 def transformTypeOfTree (tree : Tree )(using Context ): Tree =
6969 tree.withType(elimRepeated(tree.tpe))
7070
71+ override def transformTypeApply (tree : TypeApply )(using Context ): Tree =
72+ transformTypeOfTree(tree)
73+
7174 override def transformIdent (tree : Ident )(using Context ): Tree =
7275 transformTypeOfTree(tree)
7376
@@ -108,25 +111,52 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
108111 private def arrayToSeq (tree : Tree )(using Context ): Tree =
109112 tpd.wrapArray(tree, tree.tpe.elemType)
110113
111- override def transformTypeApply (tree : TypeApply )(using Context ): Tree =
112- transformTypeOfTree(tree)
113-
114114 /** If method overrides a Java varargs method or is annotated with @varargs, add a varargs bridge.
115115 * Also transform trees inside method annotation.
116116 */
117117 override def transformDefDef (tree : DefDef )(using Context ): Tree =
118118 atPhase(thisPhase) {
119119 val sym = tree.symbol
120- val isOverride = overridesJava(sym)
121- val hasAnnotation = hasVarargsAnnotation(sym) || parentHasAnnotation(sym)
122- if tree.symbol.info.isVarArgsMethod && (isOverride || hasAnnotation) then
123- // non-overrides need the varargs bytecode flag and cannot be synthetic
124- // otherwise javac refuses to call them.
125- addVarArgsBridge(tree, isOverride)
120+ val hasAnnotation = hasVarargsAnnotation(sym)
121+ if hasRepeatedParams(sym) then
122+ val isOverride = overridesJava(sym)
123+ if isOverride || hasAnnotation || parentHasAnnotation(sym) then
124+ // java varargs are more restrictive than scala's
125+ // see https://github.com/scala/bug/issues/11714
126+ if ! isValidJavaVarArgs(sym.info) then
127+ ctx.error(""" To generate java-compatible varargs:
128+ | - there must be a single repeated parameter
129+ | - it must be the last argument in the last parameter list
130+ |""" .stripMargin,
131+ tree.sourcePos)
132+ tree
133+ else
134+ addVarArgsBridge(tree, isOverride)
135+ else
136+ tree
126137 else
138+ if hasAnnotation then
139+ ctx.error(" A method without repeated parameters cannot be annotated with @varargs" , tree.sourcePos)
127140 tree
128141 }
129142
143+ /** Is there a repeated parameter in some parameter list? */
144+ private def hasRepeatedParams (sym : Symbol )(using Context ): Boolean =
145+ sym.info.paramInfoss.flatten.exists(_.isRepeatedParam)
146+
147+ /** Is this the type of a method that has a repeated parameter type as
148+ * its last parameter in the last parameter list?
149+ */
150+ private def isValidJavaVarArgs (t : Type )(using Context ): Boolean = t match
151+ case mt : MethodType =>
152+ val initp :+ lastp = mt.paramInfoss
153+ initp.forall(_.forall(! _.isRepeatedParam)) &&
154+ lastp.nonEmpty &&
155+ lastp.init.forall(! _.isRepeatedParam) &&
156+ lastp.last.isRepeatedParam
157+ case _ => false
158+
159+
130160 /** Add a Java varargs bridge
131161 * @param ddef the original method definition
132162 * @param addFlag the flag to add to the method symbol
@@ -141,38 +171,52 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
141171 * The solution is to add a "bridge" method that converts its argument from `Array[? <: T]` to `Seq[T]` and
142172 * forwards it to `ddef`.
143173 */
144- private def addVarArgsBridge (ddef : DefDef , synthetic : Boolean )(using Context ): Tree =
174+ private def addVarArgsBridge (ddef : DefDef , javaOverride : Boolean )(using ctx : Context ): Tree =
145175 val original = ddef.symbol.asTerm
146176 // For simplicity we always set the varargs flag
147177 // although it's not strictly necessary for overrides
148- val flags = ddef.symbol.flags | JavaVarargs &~ Private
178+ // (but it is for non-overrides)
179+ val flags = ddef.symbol.flags | JavaVarargs
149180 val bridge = original.copy(
150- flags = if synthetic then flags | Artifact else flags,
181+ // non-overrides cannot be synthetic otherwise javac refuses to call them
182+ flags = if javaOverride then flags | Artifact else flags,
151183 info = toJavaVarArgs(ddef.symbol.info)
152184 ).enteredAfter(thisPhase).asTerm
153185
154186 val bridgeDef = polyDefDef(bridge, trefs => vrefss => {
155- val (vrefs :+ varArgRef) :: vrefss1 = vrefss
187+ val init :+ (last :+ vararg) = vrefss
156188 // Can't call `.argTypes` here because the underlying array type is of the
157189 // form `Array[? <: SomeType]`, so we need `.argInfos` to get the `TypeBounds`.
158- val elemtp = varArgRef .tpe.widen.argInfos.head
190+ val elemtp = vararg .tpe.widen.argInfos.head
159191 ref(original.termRef)
160192 .appliedToTypes(trefs)
161- .appliedToArgs(vrefs :+ tpd.wrapArray(varArgRef, elemtp) )
162- .appliedToArgss(vrefss1 )
193+ .appliedToArgss(init )
194+ .appliedToArgs(last :+ tpd.wrapArray(vararg, elemtp) )
163195 })
164196
165- Thicket (ddef, bridgeDef)
197+ val bridgeDenot = bridge.denot
198+ currentClass.info.member(bridge.name).alternatives.find { s =>
199+ s.matches(bridgeDenot) &&
200+ ! (s.asSymDenotation.is(JavaDefined ) && javaOverride)
201+ } match
202+ case Some (conflict) =>
203+ ctx.error(s " @varargs produces a forwarder method that conflicts with ${conflict.showDcl}" , ddef.sourcePos)
204+ EmptyTree
205+ case None =>
206+ Thicket (ddef, bridgeDef)
166207
167208 /** Convert type from Scala to Java varargs method */
168209 private def toJavaVarArgs (tp : Type )(using Context ): Type = tp match
169210 case tp : PolyType =>
170211 tp.derivedLambdaType(tp.paramNames, tp.paramInfos, toJavaVarArgs(tp.resultType))
171212 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)
213+ tp.resultType match
214+ case m : MethodType => // multiple param lists
215+ tp.derivedLambdaType(tp.paramNames, tp.paramInfos, toJavaVarArgs(m))
216+ case _ =>
217+ val init :+ last = tp.paramInfos
218+ val vararg = varargArrayType(last)
219+ tp.derivedLambdaType(tp.paramNames, init :+ vararg, tp.resultType)
176220
177221 /** Translate a repeated type T* to an `Array[? <: Upper]`
178222 * such that it is compatible with java varargs.
0 commit comments