diff options
author | ssankaran | 2014-03-12 04:46:47 +0000 |
---|---|---|
committer | ssankaran | 2014-03-12 05:13:08 +0000 |
commit | 2323f3f57de6c106bba7d022fda77960201afa72 (patch) | |
tree | 7335e460eb082b3c2093dd59d24342eeea432196 | |
parent | 9916f775bcfe4fab4e68ad17a0d64a5b39bb1037 (diff) | |
download | eclipse.jdt.core-2323f3f57de6c106bba7d022fda77960201afa72.tar.gz eclipse.jdt.core-2323f3f57de6c106bba7d022fda77960201afa72.tar.xz eclipse.jdt.core-2323f3f57de6c106bba7d022fda77960201afa72.zip |
Fixed Bug 430035 - [1.8][compiler][codegen] Bridge methods are not
generated for lambdas/method references
8 files changed, 523 insertions, 11 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR335ClassFileTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR335ClassFileTest.java index cf9791b098..80dd922ab4 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR335ClassFileTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/JSR335ClassFileTest.java @@ -2817,6 +2817,235 @@ public void test430015a() throws IOException, ClassFormatException { verifyClassFile(expectedOutput, "X.class", ClassFileBytesDisassembler.SYSTEM); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035() throws IOException, ClassFormatException { + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " void foo(String t, T u);\n" + + "}\n" + + "interface J<T> {\n" + + " void foo(T t, String u);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + " void foo(String t, String u);\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = (s, u) -> System.out.println(\"m(\"+ s + u + ')');\n" + + " k.foo(\"direct\", \" call\");\n" + + " J<String> j = k;\n" + + " j.foo(\"bridge\", \" method(j)\");\n" + + " I<String> i = k;\n" + + " i.foo(\"bridge\", \" method(i)\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method(j))\n" + + "m(bridge method(i))"); + + String expectedOutput = + "// Compiled from X.java (version 1.8 : 52.0, super bit)\n" + + "public class X {\n" + + " Constant pool:\n" + + " constant #1 class: #2 X\n" + + " constant #2 utf8: \"X\"\n" + + " constant #3 class: #4 java/lang/Object\n" + + " constant #4 utf8: \"java/lang/Object\"\n" + + " constant #5 utf8: \"<init>\"\n" + + " constant #6 utf8: \"()V\"\n" + + " constant #7 utf8: \"Code\"\n" + + " constant #8 method_ref: #3.#9 java/lang/Object.<init> ()V\n" + + " constant #9 name_and_type: #5.#6 <init> ()V\n" + + " constant #10 utf8: \"LineNumberTable\"\n" + + " constant #11 utf8: \"LocalVariableTable\"\n" + + " constant #12 utf8: \"this\"\n" + + " constant #13 utf8: \"LX;\"\n" + + " constant #14 utf8: \"main\"\n" + + " constant #15 utf8: \"([Ljava/lang/String;)V\"\n" + + " constant #16 name_and_type: #17.#18 foo ()LK;\n" + + " constant #17 utf8: \"foo\"\n" + + " constant #18 utf8: \"()LK;\"\n" + + " constant #19 invoke dynamic: #0 #16 foo ()LK;\n" + + " constant #20 string: #21 \"direct\"\n" + + " constant #21 utf8: \"direct\"\n" + + " constant #22 string: #23 \" call\"\n" + + " constant #23 utf8: \" call\"\n" + + " constant #24 interface_method_ref: #25.#27 K.foo (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #25 class: #26 K\n" + + " constant #26 utf8: \"K\"\n" + + " constant #27 name_and_type: #17.#28 foo (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #28 utf8: \"(Ljava/lang/String;Ljava/lang/String;)V\"\n" + + " constant #29 string: #30 \"bridge\"\n" + + " constant #30 utf8: \"bridge\"\n" + + " constant #31 string: #32 \" method(j)\"\n" + + " constant #32 utf8: \" method(j)\"\n" + + " constant #33 interface_method_ref: #34.#36 J.foo (Ljava/lang/Object;Ljava/lang/String;)V\n" + + " constant #34 class: #35 J\n" + + " constant #35 utf8: \"J\"\n" + + " constant #36 name_and_type: #17.#37 foo (Ljava/lang/Object;Ljava/lang/String;)V\n" + + " constant #37 utf8: \"(Ljava/lang/Object;Ljava/lang/String;)V\"\n" + + " constant #38 string: #39 \" method(i)\"\n" + + " constant #39 utf8: \" method(i)\"\n" + + " constant #40 interface_method_ref: #41.#43 I.foo (Ljava/lang/String;Ljava/lang/Object;)V\n" + + " constant #41 class: #42 I\n" + + " constant #42 utf8: \"I\"\n" + + " constant #43 name_and_type: #17.#44 foo (Ljava/lang/String;Ljava/lang/Object;)V\n" + + " constant #44 utf8: \"(Ljava/lang/String;Ljava/lang/Object;)V\"\n" + + " constant #45 utf8: \"x\"\n" + + " constant #46 utf8: \"[Ljava/lang/String;\"\n" + + " constant #47 utf8: \"k\"\n" + + " constant #48 utf8: \"LK;\"\n" + + " constant #49 utf8: \"j\"\n" + + " constant #50 utf8: \"LJ;\"\n" + + " constant #51 utf8: \"i\"\n" + + " constant #52 utf8: \"LI;\"\n" + + " constant #53 utf8: \"LocalVariableTypeTable\"\n" + + " constant #54 utf8: \"LJ<Ljava/lang/String;>;\"\n" + + " constant #55 utf8: \"LI<Ljava/lang/String;>;\"\n" + + " constant #56 utf8: \"lambda$0\"\n" + + " constant #57 field_ref: #58.#60 java/lang/System.out Ljava/io/PrintStream;\n" + + " constant #58 class: #59 java/lang/System\n" + + " constant #59 utf8: \"java/lang/System\"\n" + + " constant #60 name_and_type: #61.#62 out Ljava/io/PrintStream;\n" + + " constant #61 utf8: \"out\"\n" + + " constant #62 utf8: \"Ljava/io/PrintStream;\"\n" + + " constant #63 class: #64 java/lang/StringBuilder\n" + + " constant #64 utf8: \"java/lang/StringBuilder\"\n" + + " constant #65 string: #66 \"m(\"\n" + + " constant #66 utf8: \"m(\"\n" + + " constant #67 method_ref: #63.#68 java/lang/StringBuilder.<init> (Ljava/lang/String;)V\n" + + " constant #68 name_and_type: #5.#69 <init> (Ljava/lang/String;)V\n" + + " constant #69 utf8: \"(Ljava/lang/String;)V\"\n" + + " constant #70 method_ref: #63.#71 java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;\n" + + " constant #71 name_and_type: #72.#73 append (Ljava/lang/String;)Ljava/lang/StringBuilder;\n" + + " constant #72 utf8: \"append\"\n" + + " constant #73 utf8: \"(Ljava/lang/String;)Ljava/lang/StringBuilder;\"\n" + + " constant #74 method_ref: #63.#75 java/lang/StringBuilder.append (C)Ljava/lang/StringBuilder;\n" + + " constant #75 name_and_type: #72.#76 append (C)Ljava/lang/StringBuilder;\n" + + " constant #76 utf8: \"(C)Ljava/lang/StringBuilder;\"\n" + + " constant #77 method_ref: #63.#78 java/lang/StringBuilder.toString ()Ljava/lang/String;\n" + + " constant #78 name_and_type: #79.#80 toString ()Ljava/lang/String;\n" + + " constant #79 utf8: \"toString\"\n" + + " constant #80 utf8: \"()Ljava/lang/String;\"\n" + + " constant #81 method_ref: #82.#84 java/io/PrintStream.println (Ljava/lang/String;)V\n" + + " constant #82 class: #83 java/io/PrintStream\n" + + " constant #83 utf8: \"java/io/PrintStream\"\n" + + " constant #84 name_and_type: #85.#69 println (Ljava/lang/String;)V\n" + + " constant #85 utf8: \"println\"\n" + + " constant #86 utf8: \"s\"\n" + + " constant #87 utf8: \"Ljava/lang/String;\"\n" + + " constant #88 utf8: \"u\"\n" + + " constant #89 utf8: \"SourceFile\"\n" + + " constant #90 utf8: \"X.java\"\n" + + " constant #91 utf8: \"BootstrapMethods\"\n" + + " constant #92 method_ref: #93.#95 java/lang/invoke/LambdaMetafactory.altMetafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n" + + " constant #93 class: #94 java/lang/invoke/LambdaMetafactory\n" + + " constant #94 utf8: \"java/lang/invoke/LambdaMetafactory\"\n" + + " constant #95 name_and_type: #96.#97 altMetafactory (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\n" + + " constant #96 utf8: \"altMetafactory\"\n" + + " constant #97 utf8: \"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;\"\n" + + " constant #98 method handle: invokestatic (6) #92 \n" + + " constant #99 method type: #28 (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #100 method_ref: #1.#101 X.lambda$0 (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #101 name_and_type: #56.#28 lambda$0 (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #102 method handle: invokestatic (6) #100 \n" + + " constant #103 method type: #28 (Ljava/lang/String;Ljava/lang/String;)V\n" + + " constant #104 integer: 4\n" + // flag bridge + " constant #105 integer: 2\n" + // two bridges + " constant #106 method type: #44 (Ljava/lang/String;Ljava/lang/Object;)V\n" + // first bridge + " constant #107 method type: #37 (Ljava/lang/Object;Ljava/lang/String;)V\n" + // next bridge. + " constant #108 utf8: \"InnerClasses\"\n" + + " constant #109 class: #110 java/lang/invoke/MethodHandles$Lookup\n" + + " constant #110 utf8: \"java/lang/invoke/MethodHandles$Lookup\"\n" + + " constant #111 class: #112 java/lang/invoke/MethodHandles\n" + + " constant #112 utf8: \"java/lang/invoke/MethodHandles\"\n" + + " constant #113 utf8: \"Lookup\"\n" + + " \n" + + " // Method descriptor #6 ()V\n" + + " // Stack: 1, Locals: 1\n" + + " public X();\n" + + " 0 aload_0 [this]\n" + + " 1 invokespecial java.lang.Object() [8]\n" + + " 4 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 10]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 5] local: this index: 0 type: X\n" + + " \n" + + " // Method descriptor #15 ([Ljava/lang/String;)V\n" + + " // Stack: 3, Locals: 4\n" + + " public static void main(java.lang.String... x);\n" + + " 0 invokedynamic 0 foo() : K [19]\n" + + " 5 astore_1 [k]\n" + + " 6 aload_1 [k]\n" + + " 7 ldc <String \"direct\"> [20]\n" + + " 9 ldc <String \" call\"> [22]\n" + + " 11 invokeinterface K.foo(java.lang.String, java.lang.String) : void [24] [nargs: 3]\n" + + " 16 aload_1 [k]\n" + + " 17 astore_2 [j]\n" + + " 18 aload_2 [j]\n" + + " 19 ldc <String \"bridge\"> [29]\n" + + " 21 ldc <String \" method(j)\"> [31]\n" + + " 23 invokeinterface J.foo(java.lang.Object, java.lang.String) : void [33] [nargs: 3]\n" + + " 28 aload_1 [k]\n" + + " 29 astore_3 [i]\n" + + " 30 aload_3 [i]\n" + + " 31 ldc <String \"bridge\"> [29]\n" + + " 33 ldc <String \" method(i)\"> [38]\n" + + " 35 invokeinterface I.foo(java.lang.String, java.lang.Object) : void [40] [nargs: 3]\n" + + " 40 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 12]\n" + + " [pc: 6, line: 13]\n" + + " [pc: 16, line: 14]\n" + + " [pc: 18, line: 15]\n" + + " [pc: 28, line: 16]\n" + + " [pc: 30, line: 17]\n" + + " [pc: 40, line: 18]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 41] local: x index: 0 type: java.lang.String[]\n" + + " [pc: 6, pc: 41] local: k index: 1 type: K\n" + + " [pc: 18, pc: 41] local: j index: 2 type: J\n" + + " [pc: 30, pc: 41] local: i index: 3 type: I\n" + + " Local variable type table:\n" + + " [pc: 18, pc: 41] local: j index: 2 type: J<java.lang.String>\n" + + " [pc: 30, pc: 41] local: i index: 3 type: I<java.lang.String>\n" + + " \n" + + " // Method descriptor #28 (Ljava/lang/String;Ljava/lang/String;)V\n" + + " // Stack: 4, Locals: 2\n" + + " private static synthetic void lambda$0(java.lang.String s, java.lang.String u);\n" + + " 0 getstatic java.lang.System.out : java.io.PrintStream [57]\n" + + " 3 new java.lang.StringBuilder [63]\n" + + " 6 dup\n" + + " 7 ldc <String \"m(\"> [65]\n" + + " 9 invokespecial java.lang.StringBuilder(java.lang.String) [67]\n" + + " 12 aload_0 [s]\n" + + " 13 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [70]\n" + + " 16 aload_1 [u]\n" + + " 17 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [70]\n" + + " 20 bipush 41\n" + + " 22 invokevirtual java.lang.StringBuilder.append(char) : java.lang.StringBuilder [74]\n" + + " 25 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [77]\n" + + " 28 invokevirtual java.io.PrintStream.println(java.lang.String) : void [81]\n" + + " 31 return\n" + + " Line numbers:\n" + + " [pc: 0, line: 12]\n" + + " Local variable table:\n" + + " [pc: 0, pc: 32] local: s index: 0 type: java.lang.String\n" + + " [pc: 0, pc: 32] local: u index: 1 type: java.lang.String\n" + + "\n" + + " Inner classes:\n" + + " [inner class info: #109 java/lang/invoke/MethodHandles$Lookup, outer class info: #111 java/lang/invoke/MethodHandles\n" + + " inner name: #113 Lookup, accessflags: 25 public static final]\n" + + "Bootstrap methods:\n" + + " 0 : # 98 arguments: {#99,#102,#103,#104,#105,#106,#107}\n" + + "}"; + + verifyClassFile(expectedOutput, "X.class", ClassFileBytesDisassembler.SYSTEM); +} public static Class testClass() { return JSR335ClassFileTest.class; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java index b487b5d09c..e6e8ba306d 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java @@ -3811,6 +3811,191 @@ public void test430043() { }, "OK"); } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035() { + this.runConformTest( + new String[] { + "X.java", + "import java.util.function.Consumer;\n" + + "public class X {\n" + + " interface StringConsumer extends Consumer<String> {\n" + + " void accept(String t);\n" + + " }\n" + + " public static void main(String... x) {\n" + + " StringConsumer c = s->System.out.println(\"m(\"+s+')');\n" + + " c.accept(\"direct call\");\n" + + " Consumer<String> c4b=c;\n" + + " c4b.accept(\"bridge method\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method)"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035a() { // test reference expressions requiring bridges. + this.runConformTest( + new String[] { + "X.java", + "import java.util.function.Consumer;\n" + + "public class X {\n" + + " interface StringConsumer extends Consumer<String> {\n" + + " void accept(String t);\n" + + " }\n" + + " static void m(String s) { System.out.println(\"m(\"+s+\")\"); } \n" + + " public static void main(String... x) {\n" + + " StringConsumer c = X::m;\n" + + " c.accept(\"direct call\");\n" + + " Consumer<String> c4b=c;\n" + + " c4b.accept(\"bridge method\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method)"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035b() { + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " void foo(T t);\n" + + "}\n" + + "interface J<T> {\n" + + " void foo(T t);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = s -> System.out.println(\"m(\"+s+')');\n" + + " k.foo(\"direct call\");\n" + + " J<String> j = k;\n" + + " j.foo(\"bridge method\");\n" + + " I<String> i = k;\n" + + " i.foo(\"bridge method\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method)\n" + + "m(bridge method)"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035c() { + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " void foo(String t, T u);\n" + + "}\n" + + "interface J<T> {\n" + + " void foo(T t, String u);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + " void foo(String t, String u);\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = (s, u) -> System.out.println(\"m(\"+ s + u + ')');\n" + + " k.foo(\"direct\", \" call\");\n" + + " J<String> j = k;\n" + + " j.foo(\"bridge\", \" method(j)\");\n" + + " I<String> i = k;\n" + + " i.foo(\"bridge\", \" method(i)\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method(j))\n" + + "m(bridge method(i))"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035d() { // 8b131 complains of ambiguity. + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " void foo(String t, T u);\n" + + "}\n" + + "interface J<T> {\n" + + " void foo(T t, String u);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = (s, u) -> System.out.println(\"m(\"+ s + u + ')');\n" + + " k.foo(\"direct\", \" call\");\n" + + " J<String> j = k;\n" + + " j.foo(\"bridge\", \" method(j)\");\n" + + " I<String> i = k;\n" + + " i.foo(\"bridge\", \" method(i)\");\n" + + " }\n" + + "}\n" + }, + "m(direct call)\n" + + "m(bridge method(j))\n" + + "m(bridge method(i))"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035e() { // 8b131 complains of ambiguity in call. + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " Object foo(String t, T u);\n" + + "}\n" + + "interface J<T> {\n" + + " String foo(T t, String u);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = (s, u) -> s + u;\n" + + " System.out.println(k.foo(\"direct\", \" call\"));\n" + + " J<String> j = k;\n" + + " System.out.println(j.foo(\"bridge\", \" method(j)\"));\n" + + " I<String> i = k;\n" + + " System.out.println(i.foo(\"bridge\", \" method(i)\"));\n" + + " }\n" + + "}\n" + }, + "direct call\n" + + "bridge method(j)\n" + + "bridge method(i)"); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430035, [1.8][compiler][codegen] Bridge methods are not generated for lambdas/method references +public void test430035f() { // ensure co-variant return emits a bridge request. + this.runConformTest( + new String[] { + "X.java", + "interface I<T> {\n" + + " Object foo(String t, String u);\n" + + "}\n" + + "interface J<T> {\n" + + " String foo(String t, String u);\n" + + "}\n" + + "interface K extends I<String>, J<String> {\n" + + "}\n" + + "public class X {\n" + + " public static void main(String... x) {\n" + + " K k = (s, u) -> s + u;\n" + + " System.out.println(k.foo(\"direct\", \" call\"));\n" + + " J<String> j = k;\n" + + " System.out.println(j.foo(\"bridge\", \" method(j)\"));\n" + + " I<String> i = k;\n" + + " System.out.println(i.foo(\"bridge\", \" method(i)\"));\n" + + " }\n" + + "}\n" + }, + "direct call\n" + + "bridge method(j)\n" + + "bridge method(i)"); +} + public static Class testClass() { return LambdaExpressionsTest.class; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java index 7e70e425f2..3727dbc456 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java @@ -1699,7 +1699,7 @@ public void test044() { "5. ERROR in X.java (at line 11)\n" + " D d = (p) -> { return null;};\n" + " ^^^^^^\n" + - "Illegal lambda expression: Method foo of type A is generic \n" + + "Illegal lambda expression: Method foo of type B is generic \n" + "----------\n" + "6. ERROR in X.java (at line 12)\n" + " E e = (p) -> { return null;};\n" + diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java index bf7e30ce4c..f2046bd943 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java @@ -2880,11 +2880,12 @@ public class ClassFile implements TypeConstants, TypeIds { this.contents[localContentsOffset++] = (byte) numberOfBootstraps; for (int i = 0; i < numberOfBootstraps; i++) { FunctionalExpression functional = (FunctionalExpression) functionalExpressionList.get(i); - + MethodBinding [] bridges = functional.getRequiredBridges(); TypeBinding[] markerInterfaces = null; if (functional instanceof LambdaExpression && (((markerInterfaces=((LambdaExpression)functional).getMarkerInterfaces()) != null) || - ((LambdaExpression)functional).isSerializable)) { + ((LambdaExpression)functional).isSerializable) || + bridges != null) { LambdaExpression lambdaEx = (LambdaExpression)functional; // may need even more space @@ -2893,6 +2894,10 @@ public class ClassFile implements TypeConstants, TypeIds { // 2 for the marker interface list size then 2 per marker interface index extraSpace += (2 + 2 * markerInterfaces.length); } + if (bridges != null) { + // 2 for bridge count then 2 per bridge method type. + extraSpace += (2 + 2 * bridges.length); + } if (extraSpace + localContentsOffset >= this.contents.length) { resizeContents(extraSpace); } @@ -2907,7 +2912,8 @@ public class ClassFile implements TypeConstants, TypeIds { // u2 num_bootstrap_arguments this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) (4+(markerInterfaces==null?0:1+markerInterfaces.length)); + this.contents[localContentsOffset++] = (byte) (4 + (markerInterfaces==null?0:1+markerInterfaces.length) + + (bridges == null ? 0 : 1 + bridges.length)); int functionalDescriptorIndex = this.constantPool.literalIndexForMethodType(functional.descriptor.original().signature()); this.contents[localContentsOffset++] = (byte) (functionalDescriptorIndex >> 8); @@ -2922,7 +2928,6 @@ public class ClassFile implements TypeConstants, TypeIds { this.contents[localContentsOffset++] = (byte) (methodTypeIndex >> 8); this.contents[localContentsOffset++] = (byte) methodTypeIndex; - // Does this block have to deal with FLAG_BRIDGE? When is it needed? int bitflags = 0; if (lambdaEx.isSerializable) { bitflags |= ClassFileConstants.FLAG_SERIALIZABLE; @@ -2930,6 +2935,9 @@ public class ClassFile implements TypeConstants, TypeIds { if (markerInterfaces!=null) { bitflags |= ClassFileConstants.FLAG_MARKERS; } + if (bridges != null) { + bitflags |= ClassFileConstants.FLAG_BRIDGES; + } int indexForBitflags = this.constantPool.literalIndex(bitflags); this.contents[localContentsOffset++] = (byte)(indexForBitflags>>8); @@ -2945,6 +2953,17 @@ public class ClassFile implements TypeConstants, TypeIds { this.contents[localContentsOffset++] = (byte)(classTypeIndex); } } + if (bridges != null) { + int bridgeCountIndex = this.constantPool.literalIndex(bridges.length); + this.contents[localContentsOffset++] = (byte) (bridgeCountIndex >> 8); + this.contents[localContentsOffset++] = (byte) (bridgeCountIndex); + for (int m = 0, maxm = bridges.length; m < maxm; m++) { + char [] bridgeSignature = bridges[m].signature(); + int bridgeMethodTypeIndex = this.constantPool.literalIndexForMethodType(bridgeSignature); + this.contents[localContentsOffset++] = (byte) (bridgeMethodTypeIndex >> 8); + this.contents[localContentsOffset++] = (byte) bridgeMethodTypeIndex; + } + } } else { if (indexForMetaFactory == 0) { indexForMetaFactory = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangInvokeLambdaMetafactory, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java index df3300c655..39f06b440b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java @@ -39,8 +39,11 @@ import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.IntersectionCastTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; @@ -168,6 +171,7 @@ public abstract class FunctionalExpression extends Expression { public TypeBinding resolveType(BlockScope blockScope) { this.constant = Constant.NotAConstant; + this.enclosingScope = blockScope; MethodBinding sam = this.expectedType == null ? null : this.expectedType.getSingleAbstractMethod(blockScope, argumentsTypeElided()); if (sam == null) { blockScope.problemReporter().targetTypeIsNotAFunctionalInterface(this); @@ -282,4 +286,76 @@ public abstract class FunctionalExpression extends Expression { public int diagnosticsSourceEnd() { return this.sourceEnd; } -} + + public MethodBinding[] getRequiredBridges() { + + class BridgeCollector { + + MethodBinding [] bridges; + MethodBinding method; + char [] selector; + LookupEnvironment environment; + Scope scope; + + BridgeCollector(ReferenceBinding functionalType, MethodBinding method) { + this.method = method; + this.selector = method.selector; + this.environment = FunctionalExpression.this.enclosingScope.environment(); + this.scope = FunctionalExpression.this.enclosingScope; + collectBridges(functionalType.superInterfaces()); + } + + void collectBridges(ReferenceBinding[] interfaces) { + int length = interfaces == null ? 0 : interfaces.length; + for (int i = 0; i < length; i++) { + ReferenceBinding superInterface = interfaces[i]; + if (superInterface == null) + continue; + MethodBinding [] methods = superInterface.getMethods(this.selector); + for (int j = 0, count = methods == null ? 0 : methods.length; j < count; j++) { + MethodBinding inheritedMethod = methods[j]; + if (inheritedMethod == null || this.method == inheritedMethod) // descriptor declaring class may not be same functional interface target type. + continue; + if (inheritedMethod.isStatic() || inheritedMethod.isDefaultMethod() || inheritedMethod.redeclaresPublicObjectMethod(this.scope)) + continue; + inheritedMethod = MethodVerifier.computeSubstituteMethod(inheritedMethod, this.method, this.environment); + if (inheritedMethod == null || !MethodVerifier.isSubstituteParameterSubsignature(this.method, inheritedMethod, this.environment) || + !MethodVerifier.areReturnTypesCompatible(this.method, inheritedMethod, this.environment)) + continue; + final MethodBinding originalInherited = inheritedMethod.original(); + if (!this.method.areParameterErasuresEqual(originalInherited) || TypeBinding.notEquals(this.method.returnType, originalInherited.returnType)) + add(originalInherited); + } + collectBridges(superInterface.superInterfaces()); + } + } + void add(MethodBinding inheritedMethod) { + if (this.bridges == null) { + this.bridges = new MethodBinding[] { inheritedMethod }; + return; + } + int length = this.bridges.length; + for (int i = 0; i < length; i++) { + if (this.bridges[i].areParameterErasuresEqual(inheritedMethod) && TypeBinding.equalsEquals(this.bridges[i].returnType, inheritedMethod.returnType)) + return; + } + System.arraycopy(this.bridges, 0, this.bridges = new MethodBinding[length + 1], 0, length); + this.bridges[length] = inheritedMethod; + } + MethodBinding [] getBridges () { + return this.bridges; + } + } + + ReferenceBinding functionalType; + if (this.expectedType instanceof IntersectionCastTypeBinding) { + functionalType = (ReferenceBinding) ((IntersectionCastTypeBinding)this.expectedType).getSAMType(this.enclosingScope); + } else { + functionalType = (ReferenceBinding) this.expectedType; + } + return new BridgeCollector(functionalType, this.descriptor).getBridges(); + } + boolean requiresBridges() { + return getRequiredBridges() != null; + } +}
\ No newline at end of file diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java index 53265a6684..f45230b105 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java @@ -184,7 +184,9 @@ public class ReferenceExpression extends FunctionalExpression implements Invocat return (this.binding.isVarargs() || (isConstructorReference() && this.receiverType.syntheticOuterLocalVariables() != null && currentScope.methodScope().isStatic) || this.expectedType instanceof IntersectionCastTypeBinding || // marker interfaces require alternate meta factory. - this.expectedType.findSuperTypeOriginatingFrom(currentScope.getJavaIoSerializable()) != null); // serialization support. + this.expectedType.findSuperTypeOriginatingFrom(currentScope.getJavaIoSerializable()) != null || // serialization support. + this.requiresBridges()); // bridges. + // To fix: We should opt for direct code generation wherever possible. } public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java index 05162f39d3..86e7b30728 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java @@ -83,7 +83,7 @@ static boolean areMethodsCompatible(MethodBinding one, MethodBinding two, Lookup boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) { return areReturnTypesCompatible(one, two, this.type.scope.environment()); } -static boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two, LookupEnvironment environment) { +public static boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two, LookupEnvironment environment) { if (TypeBinding.equalsEquals(one.returnType, two.returnType)) return true; if (environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_5) { // short is compatible with int, but as far as covariance is concerned, its not @@ -667,7 +667,7 @@ MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBindi return computeSubstituteMethod(inheritedMethod, currentMethod, this.environment); } -static MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod, LookupEnvironment environment) { +public static MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod, LookupEnvironment environment) { if (inheritedMethod == null) return null; if (currentMethod.parameters.length != inheritedMethod.parameters.length) return null; // no match @@ -857,7 +857,7 @@ boolean isSubstituteParameterSubsignature(MethodBinding method, MethodBinding su return isSubstituteParameterSubsignature(method, substituteMethod, this.environment); } -static boolean isSubstituteParameterSubsignature(MethodBinding method, MethodBinding substituteMethod, LookupEnvironment environment) { +public static boolean isSubstituteParameterSubsignature(MethodBinding method, MethodBinding substituteMethod, LookupEnvironment environment) { if (!areParametersEqual(method, substituteMethod)) { // method can still override substituteMethod in cases like : // <U extends Number> void c(U u) {} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java index 39137a2442..75933ff21e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -1960,7 +1960,8 @@ public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcar final LookupEnvironment environment = scope.environment(); boolean genericMethodSeen = false; - next:for (int i = 0, length = methods.length; i < length; i++) { + int length = methods.length; + next:for (int i = length - 1; i >= 0; --i) { MethodBinding method = methods[i], otherMethod = null; if (method.typeVariables != Binding.NO_TYPE_VARIABLES) genericMethodSeen = true; |