diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-05-20 13:59:00 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-05-20 13:59:00 +0200 |
commit | 076b1c4235293d4b306913aee485c49ec4736af9 (patch) | |
tree | 62b0efe65c503da1857d3a185021b00301b8910b | |
parent | 1f5584fbe183041d4af269278f0125e2f0b94a44 (diff) | |
download | scala-076b1c4235293d4b306913aee485c49ec4736af9.tar.gz scala-076b1c4235293d4b306913aee485c49ec4736af9.tar.bz2 scala-076b1c4235293d4b306913aee485c49ec4736af9.zip |
Fix @varargs forwarder generation in the presence of nested templates.
Makes `newMembers` a Map[Symbol, Buffer[Tree]] to ensure we add the forwarders to the right template.
Closes SI-5125.
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 28 | ||||
-rw-r--r-- | test/files/run/t5125.check | 4 | ||||
-rw-r--r-- | test/files/run/t5125.scala | 24 | ||||
-rw-r--r-- | test/files/run/t5125b.check | 7 | ||||
-rw-r--r-- | test/files/run/t5125b.scala | 37 |
5 files changed, 90 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f01cbade18..8af12f3f10 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -77,9 +77,17 @@ abstract class UnCurry extends InfoTransform private var inConstructorFlag = 0L private val byNameArgs = mutable.HashSet[Tree]() private val noApply = mutable.HashSet[Tree]() - private val newMembers = mutable.ArrayBuffer[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 = + newMembers.getOrElseUpdate(currentOwner, mutable.Buffer()) += t + + /** Process synthetic members for `owner`. They are removed form the `newMembers` as a side-effect. */ + @inline private def useNewMembers[T](owner: Symbol)(f: List[Tree] => T): T = + f(newMembers.remove(owner).getOrElse(Nil).toList) + @inline private def withInPattern[T](value: Boolean)(body: => T): T = { inPattern = value try body @@ -573,7 +581,7 @@ abstract class UnCurry extends InfoTransform val vparamssNoRhs = dd.vparamss mapConserve (_ mapConserve {p => treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree) }) - + if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd) withNeedLift(false) { @@ -680,9 +688,8 @@ abstract class UnCurry extends InfoTransform tree match { /* Some uncurry post transformations add members to templates. - * When inside a template, the following sequence is available: - * - newMembers - * Any entry in this sequence will be added into the template + * + * Members registered by `addMembers` for the current template are added * once the template transformation has finished. * * In particular, this case will add: @@ -690,8 +697,10 @@ abstract class UnCurry extends InfoTransform */ case Template(_, _, _) => localTyper = typer.atOwner(tree, currentClass) - try deriveTemplate(tree)(transformTrees(newMembers.toList) ::: _) - finally newMembers.clear() + useNewMembers(currentClass) { + newMembers => + deriveTemplate(tree)(transformTrees(newMembers) ::: _) + } case dd @ DefDef(_, _, _, vparamss0, _, rhs0) => val flatdd = copyDefDef(dd)( @@ -763,7 +772,7 @@ abstract class UnCurry extends InfoTransform /* 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 - * varargs forwarder. It then adds the forwarder to the `newMembers` sequence. + * varargs forwarder. */ private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = { if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol)) @@ -840,8 +849,7 @@ abstract class UnCurry extends InfoTransform case None => // enter symbol into scope currentClass.info.decls enter forwsym - // add the method to `newMembers` - newMembers += forwtree + addNewMember(forwtree) } flatdd diff --git a/test/files/run/t5125.check b/test/files/run/t5125.check new file mode 100644 index 0000000000..d8a0565005 --- /dev/null +++ b/test/files/run/t5125.check @@ -0,0 +1,4 @@ +public void O1$.f(java.lang.String[]) +public void O1$.f(scala.collection.Seq) +public void O2$.f(java.lang.String[]) +public void O2$.f(scala.collection.Seq) diff --git a/test/files/run/t5125.scala b/test/files/run/t5125.scala new file mode 100644 index 0000000000..7ec2b929d9 --- /dev/null +++ b/test/files/run/t5125.scala @@ -0,0 +1,24 @@ +object O1 { + def instance = this + @scala.annotation.varargs + def f(values:String*) = println("Calling O1.f(): " + values) +} + +object O2 { + def instance = this + @scala.annotation.varargs + def f(values:String*) = println("Calling O2.f(): " + values) + // uncommenting g() results in errors in A.java + def g(): String => Int = s => s.hashCode +} + +object Test extends App { + def check(c: Class[_]) { + val methodName = "f" + val methods = c.getDeclaredMethods.filter(_.getName == methodName) + println(methods.map(_.toString).sorted.mkString("\n")) + } + + check(O1.getClass) + check(O2.getClass) +}
\ No newline at end of file diff --git a/test/files/run/t5125b.check b/test/files/run/t5125b.check new file mode 100644 index 0000000000..ddbf908f04 --- /dev/null +++ b/test/files/run/t5125b.check @@ -0,0 +1,7 @@ +public void C1.f(java.lang.String[]) +public void C1.f(scala.collection.Seq) +public void C2.f(java.lang.String[]) +public void C2.f(scala.collection.Seq) +public void C2$C3.f(java.lang.String[]) +public void C2$C3.f(scala.collection.Seq) +public void C4.f(scala.collection.Seq) diff --git a/test/files/run/t5125b.scala b/test/files/run/t5125b.scala new file mode 100644 index 0000000000..3b3596d8bf --- /dev/null +++ b/test/files/run/t5125b.scala @@ -0,0 +1,37 @@ +class C1 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C1.f(): " + values) +} + +class C2 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C2.f(): " + values) + // def g(): String => Int = s => s.hashCode + + class C3 { + @scala.annotation.varargs + def f(values:String*) = println("Calling C3.f(): " + values) + } +} + +class C4 { + def f(values: String*) = println("Calling C4.f(): " + values) + + locally { + @scala.annotation.varargs + def f(values: String*) = println("Calling C4.<locally>.f(): " + values) + } +} + +object Test extends App { + def check(c: Class[_]) { + val methodName = "f" + val methods = c.getDeclaredMethods.filter(_.getName == methodName) + println(methods.map(_.toString).sorted.mkString("\n")) + } + + check(classOf[C1]) + check(classOf[C2]) + check(classOf[C2#C3]) + check(classOf[C4]) +} |