Skip to content
Permalink
Browse files

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.
  • Loading branch information
retronym committed May 20, 2012
1 parent 1f5584f commit 076b1c4235293d4b306913aee485c49ec4736af9
@@ -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,18 +688,19 @@ 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:
* - synthetic Java varargs forwarders for repeated parameters
*/
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
@@ -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)
@@ -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)
}
@@ -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)
@@ -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])
}

0 comments on commit 076b1c4

Please sign in to comment.
You can’t perform that action at this time.