diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2016-11-25 19:30:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-25 19:30:43 +0100 |
commit | 690ba800ec04f05c0f5e5e369863ab5b9578d42f (patch) | |
tree | 9e2fe636a67e29b63ebec07bf4e00dc742389d92 /src/compiler/scala/tools/nsc/transform | |
parent | eb7d907f6283f897f6b248bae170bade57969519 (diff) | |
parent | 0fba8820d9773c9c718384d696032110d5c74b72 (diff) | |
download | scala-690ba800ec04f05c0f5e5e369863ab5b9578d42f.tar.gz scala-690ba800ec04f05c0f5e5e369863ab5b9578d42f.tar.bz2 scala-690ba800ec04f05c0f5e5e369863ab5b9578d42f.zip |
Merge pull request #5556 from dragos/ticket/10071
SI-10071 Separate compilation for varargs methods
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 95 |
2 files changed, 34 insertions, 62 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 25475515aa..92accaf9dd 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -1278,5 +1278,4 @@ abstract class Erasure extends InfoTransform } private class TypeRefAttachment(val tpe: TypeRef) - class TypeParamVarargsAttachment(val typeParamRef: Type) } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index d8fa7b58e8..ea3c7da014 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -27,6 +27,8 @@ import scala.reflect.internal.util.ListOfNil * - for every repeated Scala parameter `x: T*' --> x: Seq[T]. * - for every repeated Java parameter `x: T...' --> x: Array[T], except: * if T is an unbounded abstract type, replace --> x: Array[Object] + * - for every method defining repeated parameters annotated with @varargs, generate + * a synthetic Java-style vararg method * - for every argument list that corresponds to a repeated Scala parameter * (a_1, ..., a_n) => (Seq(a_1, ..., a_n)) * - for every argument list that corresponds to a repeated Java parameter @@ -44,6 +46,8 @@ import scala.reflect.internal.util.ListOfNil * def liftedTry$1 = try { x_i } catch { .. } * meth(x_1, .., liftedTry$1(), .. ) * } + * - remove calls to elidable methods and replace their bodies with NOPs when elide-below + * requires it */ /*</export> */ abstract class UnCurry extends InfoTransform @@ -577,7 +581,13 @@ abstract class UnCurry extends InfoTransform case None => literalRhsIfConst } ) - addJavaVarargsForwarders(dd, flatdd) + // Only class members can reasonably be called from Java due to name mangling. + // Additionally, the Uncurry info transformer only adds a forwarder symbol to class members, + // since the other symbols are not part of the ClassInfoType (see reflect.internal.transform.UnCurry) + if (dd.symbol.owner.isClass) + addJavaVarargsForwarders(dd, flatdd) + else + flatdd case tree: Try => if (tree.catches exists (cd => !treeInfo.isCatchCase(cd))) @@ -739,68 +749,32 @@ abstract class UnCurry extends InfoTransform if (!hasRepeated) reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.") } - /* Called during post transform, after the method argument lists have been flattened. - * It looks for the method in the `repeatedParams` map, and generates a Java-style + /** + * Called during post transform, after the method argument lists have been flattened. + * It looks for the forwarder symbol in the symbol attachments and generates a Java-style * varargs forwarder. + * + * @note The Java-style varargs method symbol is generated in the Uncurry info transformer. If the + * symbol can't be found this method reports a warning and carries on. + * @see [[scala.reflect.internal.transform.UnCurry]] */ private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = { if (!dd.symbol.hasAnnotation(VarargsClass) || !enteringUncurry(mexists(dd.symbol.paramss)(sym => definitions.isRepeatedParamType(sym.tpe)))) return flatdd - val forwSym = currentClass.newMethod(dd.name.toTermName, dd.pos, VARARGS | SYNTHETIC | flatdd.symbol.flags & ~DEFERRED) - - val isRepeated = enteringUncurry(dd.symbol.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe))) - - val oldPs = flatdd.symbol.paramss.head - - // see comment in method toArrayType below - val arrayTypesMappedToObject = mutable.Map.empty[Symbol, Type] - - val forwTpe = { - val (oldTps, tps) = dd.symbol.tpe match { - case PolyType(oldTps, _) => - val newTps = oldTps.map(_.cloneSymbol(forwSym)) - (oldTps, newTps) - - case _ => (Nil, Nil) - } - - def toArrayType(tp: Type, newParam: Symbol): Type = { - val arg = elementType(SeqClass, tp) - val elem = if (arg.typeSymbol.isTypeParameterOrSkolem && !(arg <:< AnyRefTpe)) { - // To prevent generation of an `Object` parameter from `Array[T]` parameter later - // as this would crash the Java compiler which expects an `Object[]` array for varargs - // e.g. def foo[T](a: Int, b: T*) - // becomes def foo[T](a: Int, b: Array[Object]) - // instead of def foo[T](a: Int, b: Array[T]) ===> def foo[T](a: Int, b: Object) - // - // In order for the forwarder method to type check we need to insert a cast: - // def foo'[T'](a: Int, b: Array[Object]) = foo[T'](a, wrapRefArray(b).asInstanceOf[Seq[T']]) - // The target element type for that cast (T') is stored in the `arrayTypesMappedToObject` map. - val originalArg = arg.substSym(oldTps, tps) - arrayTypesMappedToObject(newParam) = originalArg - // Store the type parameter that was replaced by Object to emit the correct generic signature - newParam.updateAttachment(new erasure.TypeParamVarargsAttachment(originalArg)) - ObjectTpe - } else - arg - arrayType(elem) + val forwSym: Symbol = { + currentClass.info // make sure the info is up to date, so the varargs forwarder symbol has been generated + flatdd.symbol.attachments.get[VarargsSymbolAttachment] match { + case Some(VarargsSymbolAttachment(sym)) => sym + case None => + reporter.warning(dd.pos, s"Could not generate Java varargs forwarder for ${flatdd.symbol}. Please file a bug.") + return flatdd } - - val ps = map2(oldPs, isRepeated)((oldParam, isRep) => { - val newParam = oldParam.cloneSymbol(forwSym) - val tp = if (isRep) toArrayType(oldParam.tpe, newParam) else oldParam.tpe - newParam.setInfo(tp) - }) - - val resTp = dd.symbol.tpe_*.finalResultType.substSym(oldPs, ps) - val mt = MethodType(ps, resTp) - val r = if (tps.isEmpty) mt else PolyType(tps, mt) - r.substSym(oldTps, tps) } - forwSym.setInfo(forwTpe) - val newPs = forwTpe.params + val newPs = forwSym.tpe.params + val isRepeated = enteringUncurry(dd.symbol.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe))) + val oldPs = flatdd.symbol.paramss.head val theTyper = typer.atOwner(dd, currentClass) val forwTree = theTyper.typedPos(dd.pos) { @@ -809,8 +783,8 @@ abstract class UnCurry extends InfoTransform else { val parTp = elementType(ArrayClass, param.tpe) val wrap = gen.mkWrapArray(Ident(param), parTp) - arrayTypesMappedToObject.get(param) match { - case Some(tp) => gen.mkCast(wrap, seqType(tp)) + param.attachments.get[TypeParamVarargsAttachment] match { + case Some(TypeParamVarargsAttachment(tp)) => gen.mkCast(wrap, seqType(tp)) case _ => wrap } } @@ -821,13 +795,12 @@ abstract class UnCurry extends InfoTransform } // check if the method with that name and those arguments already exists in the template - currentClass.info.member(forwSym.name).alternatives.find(s => s != forwSym && s.tpe.matches(forwSym.tpe)) match { - case Some(s) => reporter.error(dd.symbol.pos, - "A method with a varargs annotation produces a forwarder method with the same signature " - + s.tpe + " as an existing method.") + enteringUncurry(currentClass.info.member(forwSym.name).alternatives.find(s => s != forwSym && s.tpe.matches(forwSym.tpe))) match { + case Some(s) => + reporter.error(dd.symbol.pos, + s"A method with a varargs annotation produces a forwarder method with the same signature ${s.tpe} as an existing method.") case None => // enter symbol into scope - currentClass.info.decls enter forwSym addNewMember(forwTree) } |