Skip to content

Commit 8ad55f8

Browse files
retronymadriaanm
authored andcommitted
Simplify creation of varargs forwarder symbol
Cloning the original symbol in its entirety, rather than cloning its type/value parameters individually. `cloneSymbol` takes care of all the tricky substitutions for us!
1 parent c603449 commit 8ad55f8

File tree

1 file changed

+26
-42
lines changed

1 file changed

+26
-42
lines changed

src/reflect/scala/reflect/internal/transform/UnCurry.scala

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -103,57 +103,41 @@ trait UnCurry {
103103
}
104104

105105
private def varargForwarderSym(currentClass: Symbol, origSym: Symbol, newInfo: Type): Symbol = {
106-
val forwSym = currentClass.newMethod(origSym.name.toTermName, origSym.pos, VARARGS | SYNTHETIC | origSym.flags & ~DEFERRED)
106+
val forwSym = origSym.cloneSymbol(currentClass, VARARGS | SYNTHETIC | origSym.flags & ~DEFERRED, origSym.name.toTermName).withoutAnnotations
107107

108108
// we are using `origSym.info`, which contains the type *before* the transformation
109109
// so we still see repeated parameter types (uncurry replaces them with Seq)
110110
val isRepeated = origSym.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe))
111111
val oldPs = newInfo.paramss.head
112+
def toArrayType(tp: Type, newParam: Symbol): Type = {
113+
val arg = elementType(SeqClass, tp)
114+
val elem = if (arg.typeSymbol.isTypeParameterOrSkolem && !(arg <:< AnyRefTpe)) {
115+
// To prevent generation of an `Object` parameter from `Array[T]` parameter later
116+
// as this would crash the Java compiler which expects an `Object[]` array for varargs
117+
// e.g. def foo[T](a: Int, b: T*)
118+
// becomes def foo[T](a: Int, b: Array[Object])
119+
// instead of def foo[T](a: Int, b: Array[T]) ===> def foo[T](a: Int, b: Object)
120+
//
121+
// In order for the forwarder method to type check we need to insert a cast:
122+
// def foo'[T'](a: Int, b: Array[Object]) = foo[T'](a, wrapRefArray(b).asInstanceOf[Seq[T']])
123+
// The target element type for that cast (T') is stored in the TypeParamVarargsAttachment
124+
// val originalArg = arg.substSym(oldTps, tps)
125+
// Store the type parameter that was replaced by Object to emit the correct generic signature
126+
newParam.updateAttachment(new TypeParamVarargsAttachment(arg))
127+
ObjectTpe
128+
} else
129+
arg
130+
arrayType(elem)
131+
}
112132

113-
val forwTpe = {
114-
val (oldTps, tps) = newInfo match {
115-
case PolyType(oldTps, _) =>
116-
val newTps = oldTps.map(_.cloneSymbol(forwSym))
117-
(oldTps, newTps)
118-
119-
case _ => (Nil, Nil)
120-
}
121-
122-
def toArrayType(tp: Type, newParam: Symbol): Type = {
123-
val arg = elementType(SeqClass, tp)
124-
val elem = if (arg.typeSymbol.isTypeParameterOrSkolem && !(arg <:< AnyRefTpe)) {
125-
// To prevent generation of an `Object` parameter from `Array[T]` parameter later
126-
// as this would crash the Java compiler which expects an `Object[]` array for varargs
127-
// e.g. def foo[T](a: Int, b: T*)
128-
// becomes def foo[T](a: Int, b: Array[Object])
129-
// instead of def foo[T](a: Int, b: Array[T]) ===> def foo[T](a: Int, b: Object)
130-
//
131-
// In order for the forwarder method to type check we need to insert a cast:
132-
// def foo'[T'](a: Int, b: Array[Object]) = foo[T'](a, wrapRefArray(b).asInstanceOf[Seq[T']])
133-
// The target element type for that cast (T') is stored in the TypeParamVarargsAttachment
134-
val originalArg = arg.substSym(oldTps, tps)
135-
// Store the type parameter that was replaced by Object to emit the correct generic signature
136-
newParam.updateAttachment(new TypeParamVarargsAttachment(originalArg))
137-
ObjectTpe
138-
} else
139-
arg
140-
arrayType(elem)
133+
foreach2(forwSym.paramss.flatten, isRepeated)((p, isRep) =>
134+
if (isRep) {
135+
p.setInfo(toArrayType(p.info, p))
141136
}
142-
143-
val ps = map2(oldPs, isRepeated)((oldParam, isRep) => {
144-
val newParam = oldParam.cloneSymbol(forwSym)
145-
val tp = if (isRep) toArrayType(oldParam.tpe, newParam) else oldParam.tpe
146-
newParam.setInfo(tp)
147-
})
148-
149-
val resTp = newInfo.finalResultType.substSym(oldPs, ps)
150-
val mt = MethodType(ps, resTp)
151-
val r = if (tps.isEmpty) mt else PolyType(tps, mt)
152-
r.substSym(oldTps, tps)
153-
}
137+
)
154138

155139
origSym.updateAttachment(VarargsSymbolAttachment(forwSym))
156-
forwSym.setInfo(forwTpe)
140+
forwSym
157141
}
158142

159143
/** - return symbol's transformed type,

0 commit comments

Comments
 (0)