summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-07-05 14:22:00 +0200
committerAdriaan Moors <adriaan@lightbend.com>2017-01-09 15:34:26 -0800
commitde361dfe4fab67a01750bccf960788ef10321e4d (patch)
tree7a53bd46e157055c4f99fca884643d1b41f9a48a /test
parentf841dab6c2eb8d9002c286d57ea80df637a0d4bc (diff)
downloadscala-de361dfe4fab67a01750bccf960788ef10321e4d.tar.gz
scala-de361dfe4fab67a01750bccf960788ef10321e4d.tar.bz2
scala-de361dfe4fab67a01750bccf960788ef10321e4d.zip
SI-8786 fix generic signature for @varargs forwarder methods
When generating a varargs forwarder for def foo[T](a: T*) the parameter type of the forwarder needs to be Array[Object]. If we generate Array[T] in UnCurry, that would be erased to plain Object, and the method would not be a valid varargs. Unfortunately, setting the parameter type to Array[Object] lead to an invalid generic signature - the generic signature should reflect the real signature. This change adds an attachment to the parameter symbol in the varargs forwarder method and special-cases signature generation. Also cleans up the code to produce the varargs forwarder. For example, type parameter and parameter symbols in the forwarder's method type were not clones, but the same symbols from the original method were re-used. Backported from 0d2760dce189cdcb363e54868381175af4b2646f, with a small tweak (checkVarargs) to make the test work on Java 6, as well as later versions.
Diffstat (limited to 'test')
-rw-r--r--test/files/jvm/t8786-sig.scala126
-rw-r--r--test/files/jvm/t8786/A_1.scala3
-rw-r--r--test/files/jvm/t8786/B_2.java22
-rw-r--r--test/files/jvm/t8786/Test_2.scala3
-rw-r--r--test/files/jvm/varargs/JavaClass.java26
-rw-r--r--test/files/jvm/varargs/VaClass.scala9
-rw-r--r--test/files/jvm/varargs/varargs.scala16
7 files changed, 166 insertions, 39 deletions
diff --git a/test/files/jvm/t8786-sig.scala b/test/files/jvm/t8786-sig.scala
new file mode 100644
index 0000000000..f22e400528
--- /dev/null
+++ b/test/files/jvm/t8786-sig.scala
@@ -0,0 +1,126 @@
+class A[U] {
+ @annotation.varargs def m1[T] (a: T*): T = a.head
+ @annotation.varargs def m2[T <: AnyRef](a: T*): T = a.head
+ @annotation.varargs def m3[T <: AnyVal](a: T*): T = a.head
+ @annotation.varargs def m4[T <: Int] (a: T*): T = a.head
+ @annotation.varargs def m5[T <: String](a: T*): T = a.head
+ @annotation.varargs def m6 (a: String*): String = a.head
+ @annotation.varargs def m7 (a: Int*): Int = a.head
+ @annotation.varargs def m8 (a: U*): U = a.head
+
+ def n1[T] (a: Array[T]): T = a(0)
+ def n2[T <: AnyRef](a: Array[T]): T = a(0)
+ def n3[T <: AnyVal](a: Array[T]): T = a(0)
+ def n4[T <: Int] (a: Array[T]): T = a(0)
+ def n5[T <: String](a: Array[T]): T = a(0)
+ def n6 (a: Array[String]): String = a(0)
+ def n7 (a: Array[Int]): Int = a(0)
+ def n8 (a: Array[U]): U = a(0)
+}
+
+object Test extends App {
+ val a = classOf[A[_]]
+
+ def sig (method: String, tp: Class[_]) = a.getDeclaredMethod(method, tp).toString
+ def genSig(method: String, tp: Class[_]) = a.getDeclaredMethod(method, tp).toGenericString
+ def isVarArgs(method: String, tp: Class[_]) = a.getDeclaredMethod(method, tp).isVarArgs
+ def bound (method: String, tp: Class[_]) = {
+ val m = a.getDeclaredMethod(method, tp)
+ m.getGenericParameterTypes.apply(0) match {
+ case _: Class[_] => ""
+ case gat: java.lang.reflect.GenericArrayType =>
+ val compTp = gat.getGenericComponentType.asInstanceOf[java.lang.reflect.TypeVariable[_]]
+ compTp.getBounds.apply(0).toString
+ }
+ }
+
+ def check(found: String, expected: String): Unit =
+ assert(found == expected, s"found: $found\nexpected: $expected")
+
+ def checkVarArgs(method: String, tp: Class[_])(expected: String): Unit = {
+ assert(isVarArgs(method, tp), s"expected varargs for $method")
+ val found = genSig(method, tp)
+
+ def varArgsToBraces(sig: String) = sig.replaceAll("""\.\.\.""","[]")
+ // Normalize sigs so that the tests works on Java 6 (where varargs are printed as [])
+ // and above (where vargs are pretty printed using ...)
+ assert(varArgsToBraces(found) == varArgsToBraces(expected), s"found: $found\nexpected: $expected (modulo `...` or `[]` as varargs suffix)")
+ }
+
+ val sq = classOf[Seq[_]]
+ val ob = classOf[Object]
+ val ao = classOf[Array[Object]]
+ val as = classOf[Array[String]]
+ val ai = classOf[Array[Int]]
+
+ check(sig("m1", sq) , "public java.lang.Object A.m1(scala.collection.Seq)")
+ check(sig("m2", sq) , "public java.lang.Object A.m2(scala.collection.Seq)")
+ check(sig("m3", sq) , "public java.lang.Object A.m3(scala.collection.Seq)")
+ check(sig("m4", sq) , "public int A.m4(scala.collection.Seq)")
+ check(sig("m5", sq) , "public java.lang.String A.m5(scala.collection.Seq)")
+ check(sig("m6", sq) , "public java.lang.String A.m6(scala.collection.Seq)")
+ check(sig("m7", sq) , "public int A.m7(scala.collection.Seq)")
+ check(sig("m8", sq) , "public java.lang.Object A.m8(scala.collection.Seq)")
+
+ check(genSig("m1", sq), "public <T> T A.m1(scala.collection.Seq<T>)")
+ check(genSig("m2", sq), "public <T> T A.m2(scala.collection.Seq<T>)")
+ check(genSig("m3", sq), "public <T> T A.m3(scala.collection.Seq<T>)")
+ // TODO: the signature for is wrong for T <: Int, SI-9846. The signature should be
+ // `public int A.m4(scala.collection.Seq<java.lang.Object>)`. This is testing the status quo.
+ check(genSig("m4", sq), "public <T> T A.m4(scala.collection.Seq<T>)")
+ check(genSig("m5", sq), "public <T> T A.m5(scala.collection.Seq<T>)")
+ check(genSig("m6", sq), "public java.lang.String A.m6(scala.collection.Seq<java.lang.String>)")
+ check(genSig("m7", sq), "public int A.m7(scala.collection.Seq<java.lang.Object>)")
+ check(genSig("m8", sq), "public U A.m8(scala.collection.Seq<U>)")
+
+
+ // varargs forwarder
+
+ check(sig("m1", ao) , "public java.lang.Object A.m1(java.lang.Object[])")
+ check(sig("m2", ao) , "public java.lang.Object A.m2(java.lang.Object[])")
+ check(sig("m3", ao) , "public java.lang.Object A.m3(java.lang.Object[])")
+ check(sig("m4", ao) , "public int A.m4(java.lang.Object[])")
+ check(sig("m5", as) , "public java.lang.String A.m5(java.lang.String[])")
+ check(sig("m6", as) , "public java.lang.String A.m6(java.lang.String[])")
+ check(sig("m7", ai) , "public int A.m7(int[])")
+ check(sig("m8", ao) , "public java.lang.Object A.m8(java.lang.Object[])")
+
+ checkVarArgs("m1", ao)("public <T> T A.m1(T...)")
+ checkVarArgs("m2", ao)("public <T> T A.m2(T...)")
+ checkVarArgs("m3", ao)("public <T> T A.m3(T...)")
+ // testing status quo: signature is wrong for T <: Int, SI-9846
+ checkVarArgs("m4", ao)("public <T> T A.m4(T...)")
+ checkVarArgs("m5", as)("public <T> T A.m5(T...)")
+ checkVarArgs("m6", as)("public java.lang.String A.m6(java.lang.String...)")
+ checkVarArgs("m7", ai)("public int A.m7(int...)")
+ checkVarArgs("m8", ao)("public U A.m8(U...)")
+
+ check(bound("m1", ao) , "class java.lang.Object")
+ check(bound("m2", ao) , "class java.lang.Object")
+ check(bound("m3", ao) , "class java.lang.Object")
+ check(bound("m4", ao) , "class java.lang.Object")
+ check(bound("m5", as) , "class java.lang.String")
+ check(bound("m6", as) , "")
+ check(bound("m7", ai) , "")
+ check(bound("m8", ao) , "class java.lang.Object")
+
+
+ check(sig("n1", ob) , "public java.lang.Object A.n1(java.lang.Object)")
+ check(sig("n2", ao) , "public java.lang.Object A.n2(java.lang.Object[])")
+ check(sig("n3", ob) , "public java.lang.Object A.n3(java.lang.Object)")
+ check(sig("n4", ob) , "public int A.n4(java.lang.Object)")
+ check(sig("n5", as) , "public java.lang.String A.n5(java.lang.String[])")
+ check(sig("n6", as) , "public java.lang.String A.n6(java.lang.String[])")
+ check(sig("n7", ai) , "public int A.n7(int[])")
+ check(sig("n8", ob) , "public java.lang.Object A.n8(java.lang.Object)")
+
+ check(genSig("n1", ob), "public <T> T A.n1(java.lang.Object)")
+ check(genSig("n2", ao), "public <T> T A.n2(T[])")
+ check(genSig("n3", ob), "public <T> T A.n3(java.lang.Object)")
+ // testing status quo: signature is wrong for T <: Int, SI-9846
+ check(genSig("n4", ob), "public <T> T A.n4(java.lang.Object)")
+ check(genSig("n5", as), "public <T> T A.n5(T[])")
+ check(genSig("n6", as), "public java.lang.String A.n6(java.lang.String[])")
+ check(genSig("n7", ai), "public int A.n7(int[])")
+ check(genSig("n8", ob), "public U A.n8(java.lang.Object)")
+}
diff --git a/test/files/jvm/t8786/A_1.scala b/test/files/jvm/t8786/A_1.scala
new file mode 100644
index 0000000000..13c0ad191d
--- /dev/null
+++ b/test/files/jvm/t8786/A_1.scala
@@ -0,0 +1,3 @@
+class A {
+ @annotation.varargs def foo[T](a: Int, b: T*): T = b.head
+}
diff --git a/test/files/jvm/t8786/B_2.java b/test/files/jvm/t8786/B_2.java
new file mode 100644
index 0000000000..dc155a290f
--- /dev/null
+++ b/test/files/jvm/t8786/B_2.java
@@ -0,0 +1,22 @@
+public class B_2 {
+ private static int res = 0;
+
+ public static void m(char a[]) { res += 10; }
+ public static void m(String a) { res += 100; }
+ public static void m(Object a) { res += 1000; }
+
+ public static <T> T foo(int a, T... b) { return b[0]; }
+
+ public static <T> T bar(T b[]) { return b[0]; }
+
+ public static void main(String[] args) {
+ m(foo(15, "a", "b", "c"));
+ if (res != 100)
+ throw new Error("bad: "+ res);
+
+ A a = new A();
+ m(a.foo(16, "a", "b", "c"));
+ if (res != 200)
+ throw new Error("bad: " + res);
+ }
+}
diff --git a/test/files/jvm/t8786/Test_2.scala b/test/files/jvm/t8786/Test_2.scala
new file mode 100644
index 0000000000..76ccb4c3ed
--- /dev/null
+++ b/test/files/jvm/t8786/Test_2.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ B_2.main(null)
+}
diff --git a/test/files/jvm/varargs/JavaClass.java b/test/files/jvm/varargs/JavaClass.java
index 6928ee5adc..0cc3587c5e 100644
--- a/test/files/jvm/varargs/JavaClass.java
+++ b/test/files/jvm/varargs/JavaClass.java
@@ -1,16 +1,12 @@
-
-
-
public class JavaClass {
- public static <T> void varargz(int i, T... v) {
- }
-
- public static void callSomeAnnotations() {
- VaClass va = new VaClass();
- va.vs(4, "", "", "");
- 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
+ public static <T> void varargz(int i, T... v) { }
+
+ public static void callSomeAnnotations() {
+ VaClass va = new VaClass();
+ va.vs(4, "", "", "");
+ 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"));
+ }
+}
diff --git a/test/files/jvm/varargs/VaClass.scala b/test/files/jvm/varargs/VaClass.scala
index d83e63ace1..ee8c288a16 100644
--- a/test/files/jvm/varargs/VaClass.scala
+++ b/test/files/jvm/varargs/VaClass.scala
@@ -1,15 +1,8 @@
-
-
import annotation.varargs
-
-
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)
-
- // TODO remove type bound after fixing SI-8786, see also https://github.com/scala/scala/pull/3961
- @varargs def vt1[T <: String](a: Int, b: T*): T = b.head
+ @varargs def vt1[T](a: Int, b: T*): T = b.head
}
diff --git a/test/files/jvm/varargs/varargs.scala b/test/files/jvm/varargs/varargs.scala
index 6d2e707bdf..b09818f46f 100644
--- a/test/files/jvm/varargs/varargs.scala
+++ b/test/files/jvm/varargs/varargs.scala
@@ -1,21 +1,5 @@
-
-
-
-
-
-
object Test {
def main(args: Array[String]) {
JavaClass.callSomeAnnotations
}
}
-
-
-
-
-
-
-
-
-
-