Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

Commit 4b01e1f

Browse files
author
Adriaan Moors
committed
Merge pull request scala#587 from retronym/ticket/5125
Fix @VarArgs forwarder generation in the presence of nested templates.
2 parents 08334b0 + dbee14f commit 4b01e1f

File tree

5 files changed

+90
-10
lines changed

5 files changed

+90
-10
lines changed

src/compiler/scala/tools/nsc/transform/UnCurry.scala

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,17 @@ abstract class UnCurry extends InfoTransform
7777
private var inConstructorFlag = 0L
7878
private val byNameArgs = mutable.HashSet[Tree]()
7979
private val noApply = mutable.HashSet[Tree]()
80-
private val newMembers = mutable.ArrayBuffer[Tree]()
80+
private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]()
8181
private val repeatedParams = mutable.Map[Symbol, List[ValDef]]()
8282

83+
/** Add a new synthetic member for `currentOwner` */
84+
private def addNewMember(t: Tree): Unit =
85+
newMembers.getOrElseUpdate(currentOwner, mutable.Buffer()) += t
86+
87+
/** Process synthetic members for `owner`. They are removed form the `newMembers` as a side-effect. */
88+
@inline private def useNewMembers[T](owner: Symbol)(f: List[Tree] => T): T =
89+
f(newMembers.remove(owner).getOrElse(Nil).toList)
90+
8391
@inline private def withInPattern[T](value: Boolean)(body: => T): T = {
8492
inPattern = value
8593
try body
@@ -573,7 +581,7 @@ abstract class UnCurry extends InfoTransform
573581
val vparamssNoRhs = dd.vparamss mapConserve (_ mapConserve {p =>
574582
treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree)
575583
})
576-
584+
577585
if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd)
578586

579587
withNeedLift(false) {
@@ -680,18 +688,19 @@ abstract class UnCurry extends InfoTransform
680688

681689
tree match {
682690
/* Some uncurry post transformations add members to templates.
683-
* When inside a template, the following sequence is available:
684-
* - newMembers
685-
* Any entry in this sequence will be added into the template
691+
*
692+
* Members registered by `addMembers` for the current template are added
686693
* once the template transformation has finished.
687694
*
688695
* In particular, this case will add:
689696
* - synthetic Java varargs forwarders for repeated parameters
690697
*/
691698
case Template(_, _, _) =>
692699
localTyper = typer.atOwner(tree, currentClass)
693-
try deriveTemplate(tree)(transformTrees(newMembers.toList) ::: _)
694-
finally newMembers.clear()
700+
useNewMembers(currentClass) {
701+
newMembers =>
702+
deriveTemplate(tree)(transformTrees(newMembers) ::: _)
703+
}
695704

696705
case dd @ DefDef(_, _, _, vparamss0, _, rhs0) =>
697706
val flatdd = copyDefDef(dd)(
@@ -763,7 +772,7 @@ abstract class UnCurry extends InfoTransform
763772

764773
/* Called during post transform, after the method argument lists have been flattened.
765774
* It looks for the method in the `repeatedParams` map, and generates a Java-style
766-
* varargs forwarder. It then adds the forwarder to the `newMembers` sequence.
775+
* varargs forwarder.
767776
*/
768777
private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = {
769778
if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol))
@@ -840,8 +849,7 @@ abstract class UnCurry extends InfoTransform
840849
case None =>
841850
// enter symbol into scope
842851
currentClass.info.decls enter forwsym
843-
// add the method to `newMembers`
844-
newMembers += forwtree
852+
addNewMember(forwtree)
845853
}
846854

847855
flatdd

test/files/run/t5125.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public void O1$.f(java.lang.String[])
2+
public void O1$.f(scala.collection.Seq)
3+
public void O2$.f(java.lang.String[])
4+
public void O2$.f(scala.collection.Seq)

test/files/run/t5125.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
object O1 {
2+
def instance = this
3+
@scala.annotation.varargs
4+
def f(values:String*) = println("Calling O1.f(): " + values)
5+
}
6+
7+
object O2 {
8+
def instance = this
9+
@scala.annotation.varargs
10+
def f(values:String*) = println("Calling O2.f(): " + values)
11+
// uncommenting g() results in errors in A.java
12+
def g(): String => Int = s => s.hashCode
13+
}
14+
15+
object Test extends App {
16+
def check(c: Class[_]) {
17+
val methodName = "f"
18+
val methods = c.getDeclaredMethods.filter(_.getName == methodName)
19+
println(methods.map(_.toString).sorted.mkString("\n"))
20+
}
21+
22+
check(O1.getClass)
23+
check(O2.getClass)
24+
}

test/files/run/t5125b.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public void C1.f(java.lang.String[])
2+
public void C1.f(scala.collection.Seq)
3+
public void C2.f(java.lang.String[])
4+
public void C2.f(scala.collection.Seq)
5+
public void C2$C3.f(java.lang.String[])
6+
public void C2$C3.f(scala.collection.Seq)
7+
public void C4.f(scala.collection.Seq)

test/files/run/t5125b.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class C1 {
2+
@scala.annotation.varargs
3+
def f(values:String*) = println("Calling C1.f(): " + values)
4+
}
5+
6+
class C2 {
7+
@scala.annotation.varargs
8+
def f(values:String*) = println("Calling C2.f(): " + values)
9+
def g(): String => Int = s => s.hashCode
10+
11+
class C3 {
12+
@scala.annotation.varargs
13+
def f(values:String*) = println("Calling C3.f(): " + values)
14+
}
15+
}
16+
17+
class C4 {
18+
def f(values: String*) = println("Calling C4.f(): " + values)
19+
20+
locally {
21+
@scala.annotation.varargs
22+
def f(values: String*) = println("Calling C4.<locally>.f(): " + values)
23+
}
24+
}
25+
26+
object Test extends App {
27+
def check(c: Class[_]) {
28+
val methodName = "f"
29+
val methods = c.getDeclaredMethods.filter(_.getName == methodName)
30+
println(methods.map(_.toString).sorted.mkString("\n"))
31+
}
32+
33+
check(classOf[C1])
34+
check(classOf[C2])
35+
check(classOf[C2#C3])
36+
check(classOf[C4])
37+
}

0 commit comments

Comments
 (0)