From 926585a3f36f35c9afc3f9ed9fe0ded72f6b7014 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 23 Jul 2014 09:56:24 +0200 Subject: SI-8743 Fix crasher with poly-methods annotated with @varargs The code that generated the Java varargs forwarder was basing things on the `ValDef-s` of the parameters of the source method. But, their types refer to a type parameter skolems of the enclosing method, which led to a type mismatch when typechecking the forwarder. Instead, I've reworked the code to simply use the `DefDef`-s symbol's info, which *doesn't* refer to skolems. This actually simplifies the surrounding code somewhat; rather than repeated symbols in a map we can just time travel the pre-uncurry method signatures to figure out which params are releated. --- .../scala/tools/nsc/transform/UnCurry.scala | 41 +++++++++------------- src/reflect/scala/reflect/internal/TreeInfo.scala | 7 ---- test/files/jvm/varargs.check | 3 +- test/files/jvm/varargs/JavaClass.java | 1 + test/files/jvm/varargs/VaClass.scala | 2 +- test/files/pos/t8743.scala | 15 ++++++++ 6 files changed, 35 insertions(+), 34 deletions(-) create mode 100644 test/files/pos/t8743.scala diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 2209aac00f..9b85f1b36a 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -69,7 +69,6 @@ abstract class UnCurry extends InfoTransform private val byNameArgs = mutable.HashSet[Tree]() private val noApply = mutable.HashSet[Tree]() private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]() - private val repeatedParams = mutable.Map[Symbol, List[ValDef]]() /** Add a new synthetic member for `currentOwner` */ private def addNewMember(t: Tree): Unit = @@ -428,7 +427,7 @@ abstract class UnCurry extends InfoTransform treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree) }) - if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd) + if (dd.symbol hasAnnotation VarargsClass) validateVarargs(dd) withNeedLift(needLift = false) { if (dd.symbol.isClassConstructor) { @@ -699,19 +698,12 @@ abstract class UnCurry extends InfoTransform } } - - /* Analyzes repeated params if method is annotated as `varargs`. - * If the repeated params exist, it saves them into the `repeatedParams` map, - * which is used later. - */ - private def saveRepeatedParams(dd: DefDef): Unit = + private def validateVarargs(dd: DefDef): Unit = if (dd.symbol.isConstructor) reporter.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.") - else treeInfo.repeatedParams(dd) match { - case Nil => - reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.") - case reps => - repeatedParams(dd.symbol) = reps + else { + val hasRepeated = mexists(dd.symbol.paramss)(sym => definitions.isRepeatedParamType(sym.tpe)) + 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. @@ -719,7 +711,7 @@ abstract class UnCurry extends InfoTransform * varargs forwarder. */ private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = { - if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol)) + if (!dd.symbol.hasAnnotation(VarargsClass) || !enteringUncurry(mexists(dd.symbol.paramss)(sym => definitions.isRepeatedParamType(sym.tpe)))) return flatdd def toArrayType(tp: Type): Type = { @@ -735,19 +727,18 @@ abstract class UnCurry extends InfoTransform ) } - val reps = repeatedParams(dd.symbol) - val rpsymbols = reps.map(_.symbol).toSet val theTyper = typer.atOwner(dd, currentClass) - val flatparams = flatdd.vparamss.head + val flatparams = flatdd.symbol.paramss.head + val isRepeated = enteringUncurry(dd.symbol.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe))) // create the type - val forwformals = flatparams map { - case p if rpsymbols(p.symbol) => toArrayType(p.symbol.tpe) - case p => p.symbol.tpe + val forwformals = map2(flatparams, isRepeated) { + case (p, true) => toArrayType(p.tpe) + case (p, false)=> p.tpe } val forwresult = dd.symbol.tpe_*.finalResultType val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) => - currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp) + currentClass.newValueParameter(oldparam.name.toTermName, oldparam.pos).setInfo(tp) ) def mono = MethodType(forwformsyms, forwresult) val forwtype = dd.symbol.tpe match { @@ -761,13 +752,13 @@ abstract class UnCurry extends InfoTransform // create the tree val forwtree = theTyper.typedPos(dd.pos) { - val locals = map2(forwParams, flatparams) { - case (_, fp) if !rpsymbols(fp.symbol) => null - case (argsym, fp) => + val locals = map3(forwParams, flatparams, isRepeated) { + case (_, fp, false) => null + case (argsym, fp, true) => Block(Nil, gen.mkCast( gen.mkWrapArray(Ident(argsym), elementType(ArrayClass, argsym.tpe)), - seqType(elementType(SeqClass, fp.symbol.tpe)) + seqType(elementType(SeqClass, fp.tpe)) ) ) } diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index b7d7d4df88..c521277f69 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -509,13 +509,6 @@ abstract class TreeInfo { case _ => false } - /** The parameter ValDefs of a method definition that have vararg types of the form T* - */ - def repeatedParams(tree: Tree): List[ValDef] = tree match { - case DefDef(_, _, _, vparamss, _, _) => vparamss.flatten filter (vd => isRepeatedParamType(vd.tpt)) - case _ => Nil - } - /** Is tpt a by-name parameter type of the form => T? */ def isByNameParamType(tpt: Tree) = tpt match { case TypeTree() => definitions.isByNameParamType(tpt.tpe) diff --git a/test/files/jvm/varargs.check b/test/files/jvm/varargs.check index 8379befe93..986f98896a 100644 --- a/test/files/jvm/varargs.check +++ b/test/files/jvm/varargs.check @@ -1,3 +1,4 @@ 7 10 -19 \ No newline at end of file +19 +a diff --git a/test/files/jvm/varargs/JavaClass.java b/test/files/jvm/varargs/JavaClass.java index 9851e1b78b..6928ee5adc 100644 --- a/test/files/jvm/varargs/JavaClass.java +++ b/test/files/jvm/varargs/JavaClass.java @@ -11,5 +11,6 @@ public class JavaClass { va.vi(1, 2, 3, 4); varargz(5, 1.0, 2.0, 3.0); va.vt(16, "", "", ""); + System.out.println(va.vt1(16, "a", "b", "c")); } } \ No newline at end of file diff --git a/test/files/jvm/varargs/VaClass.scala b/test/files/jvm/varargs/VaClass.scala index 6343f9c6f6..e94e8a625a 100644 --- a/test/files/jvm/varargs/VaClass.scala +++ b/test/files/jvm/varargs/VaClass.scala @@ -9,5 +9,5 @@ class VaClass { @varargs def vs(a: Int, b: String*) = println(a + b.length) @varargs def vi(a: Int, b: Int*) = println(a + b.sum) @varargs def vt[T](a: Int, b: T*) = println(a + b.length) - + @varargs def vt1[T](a: Int, b: T*): T = b.head } diff --git a/test/files/pos/t8743.scala b/test/files/pos/t8743.scala new file mode 100644 index 0000000000..03b0cd7044 --- /dev/null +++ b/test/files/pos/t8743.scala @@ -0,0 +1,15 @@ +import annotation.varargs + +object VarArgs { + @varargs + def foo[A](x: A, xs: String*): A = ??? + + @varargs + def bar[A](x: List[A], xs: String*): A = ??? + + @varargs + def baz[A](x: List[A], xs: String*): A = ??? + + @varargs + def boz[A](x: A, xs: String*): Nothing = ??? +} -- cgit v1.2.3