Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2014-01-30 16:09:05 +0000
committerStephan Herrmann2014-01-30 23:03:20 +0000
commit3efbae02af9125c723d4c2de65767b20d72aaa7a (patch)
tree7d848698dccc36f230ebcca34b4b7be1ecd4b25e
parent995521865cfd6e568bdd12bfb7d4a59fc50611ab (diff)
downloadeclipse.jdt.core-3efbae02af9125c723d4c2de65767b20d72aaa7a.tar.gz
eclipse.jdt.core-3efbae02af9125c723d4c2de65767b20d72aaa7a.tar.xz
eclipse.jdt.core-3efbae02af9125c723d4c2de65767b20d72aaa7a.zip
Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java171
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java130
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java18
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java167
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java5
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java231
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java3
9 files changed, 582 insertions, 156 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
index 6b4a3c57a4..84f0c1d551 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java
@@ -16,6 +16,7 @@
* bug 399567 - [1.8] Different error message from the reference compiler
* bug 401796 - [1.8][compiler] don't treat default methods as overriding an independent inherited abstract method
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -1148,6 +1149,7 @@ X.java:4: warning: [unchecked] unchecked method invocation: method pickOne in cl
" }\n" +
"}\n"
},
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"----------\n" +
"1. WARNING in Y.java (at line 4)\n" +
" H hraw = null;\n" +
@@ -1213,7 +1215,44 @@ X.java:4: warning: [unchecked] unchecked method invocation: method pickOne in cl
" new X().a6(hraw);\n" +
" ^^\n" +
"The method a6(H) is ambiguous for the type X\n" +
- "----------\n",
+ "----------\n"
+ : // in 1.8 fewer of the calls are ambiguous
+ "----------\n" +
+ "1. WARNING in Y.java (at line 4)\n" +
+ " H hraw = null;\n" +
+ " ^\n" +
+ "H is a raw type. References to generic type H<T3> should be parameterized\n" +
+ "----------\n" +
+ "2. ERROR in Y.java (at line 5)\n" +
+ " new X().a(h);\n" +
+ " ^\n" +
+ "The method a(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "3. ERROR in Y.java (at line 6)\n" +
+ " new X().a(hraw);\n" +
+ " ^\n" +
+ "The method a(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "4. ERROR in Y.java (at line 7)\n" +
+ " new X().a2(h);\n" +
+ " ^^\n" +
+ "The method a2(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "5. ERROR in Y.java (at line 8)\n" +
+ " new X().a2(hraw);\n" +
+ " ^^\n" +
+ "The method a2(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "6. ERROR in Y.java (at line 13)\n" +
+ " new X().a5(h);\n" +
+ " ^^\n" +
+ "The method a5(H<C>) is ambiguous for the type X\n" +
+ "----------\n" +
+ "7. ERROR in Y.java (at line 14)\n" +
+ " new X().a5(hraw);\n" +
+ " ^^\n" +
+ "The method a5(H) is ambiguous for the type X\n" +
+ "----------\n"),
null,
false
);
@@ -1436,6 +1475,7 @@ X.java:4: warning: [unchecked] unchecked method invocation: method pickOne in cl
" ^\n" +
"H is a raw type. References to generic type H<T3> should be parameterized\n" +
"----------\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"23. ERROR in X.java (at line 52)\n" +
" x.a(h);\n" +
" ^\n" +
@@ -1526,7 +1566,50 @@ X.java:4: warning: [unchecked] unchecked method invocation: method pickOne in cl
" ^^\n" +
"The method g2(H) is ambiguous for the type X\n" +
"----------\n" +
- "41. WARNING in X.java (at line 98)\n" +
+ "41. WARNING in X.java (at line 98)\n"
+ : // fewer ambiguities in 1.8
+ "23. ERROR in X.java (at line 61)\n" +
+ " x.d(h);\n" +
+ " ^\n" +
+ "The method d(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "24. ERROR in X.java (at line 62)\n" +
+ " x.d(hraw);\n" +
+ " ^\n" +
+ "The method d(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "25. ERROR in X.java (at line 64)\n" +
+ " x.e(h);\n" +
+ " ^\n" +
+ "The method e(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "26. ERROR in X.java (at line 65)\n" +
+ " x.e(hraw);\n" +
+ " ^\n" +
+ "The method e(G) is ambiguous for the type X\n" +
+ "----------\n" +
+ "27. ERROR in X.java (at line 82)\n" +
+ " x.d2(h);\n" +
+ " ^^\n" +
+ "The method d2(H<C>) is ambiguous for the type X\n" +
+ "----------\n" +
+ "28. ERROR in X.java (at line 83)\n" +
+ " x.d2(hraw);\n" +
+ " ^^\n" +
+ "The method d2(H) is ambiguous for the type X\n" +
+ "----------\n" +
+ "29. ERROR in X.java (at line 85)\n" +
+ " x.e2(h);\n" +
+ " ^^\n" +
+ "The method e2(H<C>) is ambiguous for the type X\n" +
+ "----------\n" +
+ "30. ERROR in X.java (at line 86)\n" +
+ " x.e2(hraw);\n" +
+ " ^^\n" +
+ "The method e2(H) is ambiguous for the type X\n" +
+ "----------\n" +
+ "31. WARNING in X.java (at line 98)\n"
+ ) +
" class C extends B implements I {}\n" +
" ^\n" +
"I is a raw type. References to generic type I<T> should be parameterized\n" +
@@ -2648,6 +2731,7 @@ public void test051() {
" }\n" +
"}\n"
},
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"----------\n" +
"1. ERROR in X.java (at line 9)\n" +
" bar(new Z());\n" +
@@ -2658,7 +2742,19 @@ public void test051() {
" private static final class Z implements I {\n" +
" ^\n" +
"I is a raw type. References to generic type I<T> should be parameterized\n" +
- "----------\n");
+ "----------\n"
+ : // in 1.8 bar(Z) is recognized as being more specific than bar(I<#RAW>)
+ "----------\n" +
+ "1. WARNING in X.java (at line 9)\n" +
+ " bar(new Z());\n" +
+ " ^^^^^^^\n" +
+ "Access to enclosing constructor X.Z() is emulated by a synthetic accessor method\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 13)\n" +
+ " private static final class Z implements I {\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n"));
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=166355
// variant
@@ -2706,6 +2802,7 @@ public void test053() {
" }\n" +
"}\n"
},
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"----------\n" +
"1. ERROR in X.java (at line 9)\n" +
" bar(new Z(){});\n" +
@@ -2716,7 +2813,19 @@ public void test053() {
" private static class Z implements I {\n" +
" ^\n" +
"I is a raw type. References to generic type I<T> should be parameterized\n" +
- "----------\n");
+ "----------\n"
+ : // in 1.8 bar(Z) is recognized as being more specific than bar(I<#RAW>)
+ "----------\n" +
+ "1. WARNING in X.java (at line 9)\n" +
+ " bar(new Z(){});\n" +
+ " ^^^\n" +
+ "Access to enclosing constructor X.Z() is emulated by a synthetic accessor method\n" +
+ "----------\n" +
+ "2. WARNING in X.java (at line 13)\n" +
+ " private static class Z implements I {\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n"));
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=166355
// variant
@@ -3435,8 +3544,10 @@ public void test074() {
" d(new C2());\n" +
" d(new D2());\n" +
" }\n" +
- "}"
+ "}\n" +
+ "public class Y {}\n"
},
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"----------\n" +
"1. WARNING in Y.java (at line 3)\n" +
" void a(I x) {}\n" +
@@ -3493,6 +3604,33 @@ public void test074() {
" ^\n" +
"I is a raw type. References to generic type I<T> should be parameterized\n" +
"----------\n"
+ : // no ambiguities in 1.8
+ "----------\n" +
+ "1. WARNING in Y.java (at line 3)\n" +
+ " void a(I x) {}\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n" +
+ "2. WARNING in Y.java (at line 9)\n" +
+ " class C extends B implements I {\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n" +
+ "3. WARNING in Y.java (at line 28)\n" +
+ " void a(I x) {}\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n" +
+ "4. WARNING in Y.java (at line 33)\n" +
+ " class B2 extends A2 {}\n" +
+ " ^^\n" +
+ "A2 is a raw type. References to generic type A2<T> should be parameterized\n" +
+ "----------\n" +
+ "5. WARNING in Y.java (at line 34)\n" +
+ " class C2 extends B2 implements I {\n" +
+ " ^\n" +
+ "I is a raw type. References to generic type I<T> should be parameterized\n" +
+ "----------\n")
);
}
@@ -4314,4 +4452,27 @@ public void test089() {
"----------\n"
);
}
+public void testBug426521() {
+ runNegativeTest(
+ new String[] {
+ "Test.java",
+ "import java.util.List;\n" +
+ "\n" +
+ "class Test {\n" +
+ " <U> void m(List<U> l, U v) { }\n" +
+ "\n" +
+ " <V> void m(List<V> l1, List<V> l2) { }\n" +
+ "\n" +
+ " void test(List<Object> l) {\n" +
+ " m(l, l); //JDK 6/7 give ambiguity here - EJC compiles ok\n" +
+ " }\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 9)\n" +
+ " m(l, l); //JDK 6/7 give ambiguity here - EJC compiles ok\n" +
+ " ^\n" +
+ "The method m(List<Object>, Object) is ambiguous for the type Test\n" +
+ "----------\n");
+}
}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 7ccf381c97..4c6ccfe26d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -22,6 +22,7 @@
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Bug 424286 - [1.8] Update type inference to spec version 0.9.1
* Bug 426676 - [1.8][compiler] Wrong generic method type inferred from lambda expression
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -46,7 +47,7 @@ public class GenericTypeTest extends AbstractComparableTest {
// Static initializer to specify tests subset using TESTS_* static variables
// All specified tests which does not belong to the class are skipped...
static {
-// TESTS_NAMES = new String[] { "test1031" };
+// TESTS_NAMES = new String[] { "test1277" };
// TESTS_NUMBERS = new int[] { 470, 627 };
// TESTS_RANGE = new int[] { 1097, -1 };
}
@@ -33018,11 +33019,14 @@ public void test0992() {
" ^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type safety: The method add(Object) belongs to the raw type Collection. References to generic type Collection<E> should be parameterized\n" +
"----------\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"4. WARNING in X.java (at line 6)\n" +
" this.add(null);\n" +
" ^^^^^^^^^^^^^^\n" +
"Type safety: The method add(Object) belongs to the raw type Collection. References to generic type Collection<E> should be parameterized\n" +
- "----------\n");
+ "----------\n"
+ : // 1.8 picks the non-raw version as being more specific(?)
+ ""));
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=142897
@@ -43176,6 +43180,7 @@ public void test1234() {
" ^\n" +
"H is a raw type. References to generic type H<T3> should be parameterized\n" +
"----------\n" +
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"3. ERROR in X.java (at line 8)\n" +
" new X().a3(hx);\n" +
" ^^\n" +
@@ -43185,7 +43190,9 @@ public void test1234() {
" new X().a3(hraw);\n" +
" ^^\n" +
"The method a3(G) is ambiguous for the type X\n" +
- "----------\n");
+ "----------\n"
+ : // not ambiguous in 1.8
+ ""));
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=215843 - variation
public void test1235() {
@@ -44289,43 +44296,58 @@ public void test1272() {
"#3##CLASSCAST#");
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
-// FIXME javac8 rejects
public void test1273() {
- this.runConformTest(
+ String sourceX =
+ "public class X {\n" +
+ " // some functor and functor instances definitions\n" +
+ " static interface OO<T, E> { \n" +
+ " public T eval(E x);\n" +
+ " }\n" +
+ " static interface TO<T> extends OO<String, T> {\n" +
+ " public String eval(T x);\n" +
+ " }\n" +
+ " static interface TT extends TO<String> {\n" +
+ " public String eval(String x);\n" +
+ " }\n" +
+ " static final TO<Object> FUNC1 = null;\n" +
+ " static final TT FUNC2 = null;\n" +
+ "\n" +
+ " // some functor combinators\n" +
+ " static <E> TO<E> combine(final TT x, final TO<? super E> y) { // # 1\n" +
+ " System.out.println(\"#1#\");\n" +
+ " return new TO<E>() { public String eval(E o) { return x.eval(y.eval(o)); } }; \n" +
+ " }\n" +
+ " static <E, T> TO<T> combine(final TO<? super E> x, final OO<E, T> y) { // # 2\n" +
+ " System.out.println(\"#2#\");\n" +
+ " return new TO<T>() { public String eval(T o) { return x.eval(y.eval(o)); } }; \n" +
+ " }\n" +
+ " // body of the test\n" +
+ " static <E> void put(Class<E> type, TO<? super E> func) {\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " put(Integer.class, combine(FUNC2, FUNC1));\n" +
+ " }\n" +
+ "}\n";
+ if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+ this.runConformTest(
new String[] {
- "X.java",
- "public class X {\n" +
- " // some functor and functor instances definitions\n" +
- " static interface OO<T, E> { \n" +
- " public T eval(E x);\n" +
- " }\n" +
- " static interface TO<T> extends OO<String, T> {\n" +
- " public String eval(T x);\n" +
- " }\n" +
- " static interface TT extends TO<String> {\n" +
- " public String eval(String x);\n" +
- " }\n" +
- " static final TO<Object> FUNC1 = null;\n" +
- " static final TT FUNC2 = null;\n" +
- "\n" +
- " // some functor combinators\n" +
- " static <E> TO<E> combine(final TT x, final TO<? super E> y) { // # 1\n" +
- " System.out.println(\"#1#\");\n" +
- " return new TO<E>() { public String eval(E o) { return x.eval(y.eval(o)); } }; \n" +
- " }\n" +
- " static <E, T> TO<T> combine(final TO<? super E> x, final OO<E, T> y) { // # 2\n" +
- " System.out.println(\"#2#\");\n" +
- " return new TO<T>() { public String eval(T o) { return x.eval(y.eval(o)); } }; \n" +
- " }\n" +
- " // body of the test\n" +
- " static <E> void put(Class<E> type, TO<? super E> func) {\n" +
- " }\n" +
- " public static void main(String[] args) {\n" +
- " put(Integer.class, combine(FUNC2, FUNC1));\n" +
- " }\n" +
- "}\n", // =================
+ "X.java",
+ sourceX,
},
"#1#");
+ } else {
+ runNegativeTest(
+ new String[] {
+ "X.java",
+ sourceX
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 28)\n" +
+ " put(Integer.class, combine(FUNC2, FUNC1));\n" +
+ " ^^^^^^^\n" +
+ "The method combine(X.TT, X.TO<? super Object>) is ambiguous for the type X\n" +
+ "----------\n" );
+ }
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
public void test1274() {
@@ -44366,9 +44388,8 @@ public void test1274() {
"#1#");
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
-//FIXME javac8 rejects
public void test1275() {
- this.runConformTest(
+ String[] input =
new String[] {
"X.java",
"public class X {\n" +
@@ -44401,8 +44422,21 @@ public void test1275() {
" put(Integer.class, combine(FUNC2, FUNC1));\n" +
" }\n" +
"}\n", // =================
- },
+ };
+ if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+ runConformTest(
+ input,
"#1#");
+ } else {
+ runNegativeTest(
+ input,
+ "----------\n" +
+ "1. ERROR in X.java (at line 28)\n" +
+ " put(Integer.class, combine(FUNC2, FUNC1));\n" +
+ " ^^^^^^^\n" +
+ "The method combine(X.TT, X.TO<? super Object>) is ambiguous for the type X\n" +
+ "----------\n");
+ }
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
public void test1276() {
@@ -44481,9 +44515,8 @@ public void test1277() {
"#2#");
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
-//FIXME javac8 rejects
public void test1278() {
- this.runConformTest(
+ String[] input =
new String[] {
"X.java",
"public class X {\n" +
@@ -44520,8 +44553,21 @@ public void test1278() {
" put(Integer.class, combine(FUNC2, FUNC1));\n" +
" }\n" +
"}\n", // =================
- },
+ };
+ if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+ runConformTest(
+ input,
"#1#");
+ } else {
+ runNegativeTest(
+ input,
+ "----------\n" +
+ "1. ERROR in X.java (at line 32)\n" +
+ " put(Integer.class, combine(FUNC2, FUNC1));\n" +
+ " ^^^^^^^\n" +
+ "The method combine(X.TT, X.TO<? super Object>) is ambiguous for the type X\n" +
+ "----------\n");
+ }
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=216686 - variation
public void test1279() {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java
index 3219940854..fe5a2a79f7 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/VarargsTest.java
@@ -11,6 +11,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -1500,6 +1502,7 @@ public class VarargsTest extends AbstractComparableTest {
" void foo3(String s, V v, String r, Object o, Object... obs) {System.out.print(2);}\n" +
"}\n",
},
+ (this.complianceLevel < ClassFileConstants.JDK1_8 ?
"----------\n" +
"1. ERROR in V.java (at line 4)\r\n" +
" v.foo2(null, \"\");\r\n" +
@@ -1515,7 +1518,20 @@ public class VarargsTest extends AbstractComparableTest {
" v.foo3(\"\", v, null, \"\");\r\n" +
" ^^^^\n" +
"The method foo3(String, V, String[]) is ambiguous for the type V\n" +
- "----------\n");
+ "----------\n"
+ : // one fewer ambiguity in 1.8:
+ "----------\n" +
+ "1. ERROR in V.java (at line 4)\n" +
+ " v.foo2(null, \"\");\n" +
+ " ^^^^\n" +
+ "The method foo2(String, Object[]) is ambiguous for the type V\n" +
+ "----------\n" +
+ "2. ERROR in V.java (at line 5)\n" +
+ " v.foo2(null, \"\", \"\");\n" +
+ " ^^^^\n" +
+ "The method foo2(String, Object[]) is ambiguous for the type V\n" +
+ "----------\n")
+ );
}
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=105801
public void test038() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 90826e9ee7..7f59b1b9e9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -24,6 +24,7 @@
* Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Bug 426792 - [1.8][inference][impl] generify new type inference engine
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -1163,6 +1164,8 @@ public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t) {
TypeBinding expressionType = this.resolvedType;
if (expressionType == null || !expressionType.isValidBinding()) // Shouldn't get here, just to play it safe
return false; // trigger ambiguity.
+ if (s.isBaseType() && t.isBaseType())
+ return s.isCompatibleWith(t);
return s.findSuperTypeOriginatingFrom(t) != null;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 0d924862a5..b1bd69c201 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -25,13 +25,14 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.ExpressionContext;
import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression;
import org.eclipse.jdt.internal.compiler.ast.Invocation;
+import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
+import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
/**
@@ -89,7 +90,7 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard;
* As long as a target type is still unavailable this phase keeps getting deferred.</br>
* Different wrappers exist for the convenience of different callers.</dd>
* <dt>18.5.3 Functional Interface Parameterization Inference</dt>
- * <dd>Controlled from {@link LambdaExpression#resolveTypeBinding()}.</dd>
+ * <dd>Controlled from {@link LambdaExpression#resolveType(BlockScope)}.</dd>
* <dt>18.5.4 More Specific Method Inference</dt>
* <dd><em>Not Yet Implemented</em></dd>
* </dl>
@@ -570,6 +571,168 @@ public class InferenceContext18 {
return true;
}
+ /**
+ * 18.5.4 More Specific Method Inference
+ */
+ public boolean isMoreSpecificThan(Invocation invocation, MethodBinding m1, MethodBinding m2, boolean isVarArgs, boolean isVarArgs2) {
+ // TODO: we don't yet distinguish vararg-with-passthrough from vararg-with-exactly-one-vararg-arg
+ if (isVarArgs != isVarArgs2) {
+ return isVarArgs2;
+ }
+ Expression[] arguments = invocation.arguments();
+ int numInvocArgs = arguments == null ? 0 : arguments.length;
+ TypeVariableBinding[] p = m2.typeVariables();
+ TypeBinding[] s = m1.parameters;
+ TypeBinding[] t = new TypeBinding[m2.parameters.length];
+ createInitialBoundSet(p);
+ for (int i = 0; i < t.length; i++)
+ t[i] = substitute(m2.parameters[i]);
+
+ try {
+ for (int i = 0; i < numInvocArgs; i++) {
+ TypeBinding si = getParameter(s, i, isVarArgs);
+ TypeBinding ti = getParameter(t, i, isVarArgs);
+ Boolean result = moreSpecificMain(si, ti, this.invocationArguments[i]);
+ if (result == Boolean.FALSE)
+ return false;
+ if (result == null)
+ if (!reduceAndIncorporate(new ConstraintTypeFormula(si, ti, ReductionResult.SUBTYPE)))
+ return false;
+ }
+ if (t.length == numInvocArgs + 1) {
+ TypeBinding skplus1 = getParameter(s, numInvocArgs, true);
+ TypeBinding tkplus1 = getParameter(t, numInvocArgs, true);
+ if (!reduceAndIncorporate(new ConstraintTypeFormula(skplus1, tkplus1, ReductionResult.SUBTYPE)))
+ return false;
+ }
+ return solve() != null;
+ } catch (InferenceFailureException e) {
+ return false;
+ }
+ }
+
+ // FALSE: inference fails
+ // TRUE: constraints have been incorporated
+ // null: need the otherwise branch
+ private Boolean moreSpecificMain(TypeBinding si, TypeBinding ti, Expression expri) throws InferenceFailureException {
+ if (si.isProperType(true) && ti.isProperType(true)) {
+ return expri.sIsMoreSpecific(si, ti) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ if (si.isFunctionalInterface(this.scope)) {
+ TypeBinding funcI = ti.original();
+ if (funcI.isFunctionalInterface(this.scope)) {
+ // "... none of the following is true:"
+ if (siSuperI(si, funcI) || siSubI(si, funcI))
+ return null;
+ if (si instanceof IntersectionCastTypeBinding) {
+ TypeBinding[] elements = ((IntersectionCastTypeBinding)si).intersectingTypes;
+ checkSuper: {
+ for (int i = 0; i < elements.length; i++)
+ if (!siSuperI(elements[i], funcI))
+ break checkSuper;
+ return null; // each element of the intersection is a superinterface of I, or a parameterization of a superinterface of I.
+ }
+ for (int i = 0; i < elements.length; i++)
+ if (siSubI(elements[i], funcI))
+ return null; // some element of the intersection is a subinterface of I, or a parameterization of a subinterface of I.
+ }
+ // all passed, time to do some work:
+ TypeBinding siCapture = si.capture(this.scope, this.captureId++);
+ MethodBinding sam = siCapture.getSingleAbstractMethod(this.scope, false); // no wildcards should be left needing replacement
+ TypeBinding[] u = sam.parameters;
+ TypeBinding r1 = sam.isConstructor() ? sam.declaringClass : sam.returnType;
+ sam = ti.getSingleAbstractMethod(this.scope, true); // TODO
+ TypeBinding[] v = sam.parameters;
+ TypeBinding r2 = sam.isConstructor() ? sam.declaringClass : sam.returnType;
+ return Boolean.valueOf(checkExpression(expri, u, r1, v, r2));
+ }
+ }
+ return null;
+ }
+
+ private boolean checkExpression(Expression expri, TypeBinding[] u, TypeBinding r1, TypeBinding[] v, TypeBinding r2)
+ throws InferenceFailureException {
+ if (expri instanceof LambdaExpression && !((LambdaExpression)expri).argumentsTypeElided()) {
+ if (r2.id == TypeIds.T_void)
+ return true;
+ LambdaExpression lambda = (LambdaExpression) expri;
+ Expression[] results = lambda.resultExpressions();
+ if (r1.isFunctionalInterface(this.scope) && r2.isFunctionalInterface(this.scope)
+ && !(r1.isCompatibleWith(r2) || r2.isCompatibleWith(r1))) {
+ // "these rules are applied recursively to R1 and R2, for each result expression in expi."
+ // (what does "applied .. to R1 and R2" mean? Why mention R1/R2 and not U/V?)
+ for (int i = 0; i < results.length; i++) {
+ if (!checkExpression(results[i], u, r1, v, r2))
+ return false;
+ }
+ return true;
+ }
+ checkPrimitive1: if (r1.isBaseType() && !r2.isBaseType()) {
+ // check: each result expression is a standalone expression of a primitive type
+ for (int i = 0; i < results.length; i++) {
+ if (results[i].isPolyExpression() || (results[i].resolvedType != null && !results[i].resolvedType.isBaseType()))
+ break checkPrimitive1;
+ }
+ return true;
+ }
+ checkPrimitive2: if (r2.isBaseType() && !r1.isBaseType()) {
+ for (int i = 0; i < results.length; i++) {
+ // for all expressions (not for any expression not)
+ if (!(
+ (!results[i].isPolyExpression() && (results[i].resolvedType != null && !results[i].resolvedType.isBaseType())) // standalone of a referencetype
+ || results[i].isPolyExpression())) // or a poly
+ break checkPrimitive2;
+ }
+ return true;
+ }
+ return reduceAndIncorporate(new ConstraintTypeFormula(r1, r2, ReductionResult.SUBTYPE));
+ } else if (expri instanceof ReferenceExpression && ((ReferenceExpression)expri).isExactMethodReference()) {
+ for (int i = 0; i < u.length; i++) {
+ ReferenceExpression reference = (ReferenceExpression) expri;
+ if (!reduceAndIncorporate(new ConstraintTypeFormula(u[i], v[i], ReductionResult.SAME)))
+ return false;
+ if (r2.id == TypeIds.T_void)
+ return true;
+ MethodBinding method = reference.findCompileTimeMethodTargeting(null, this.scope); // TODO directly access exactMethodBinding!
+ TypeBinding returnType = method.isConstructor() ? method.declaringClass : method.returnType;
+ if (r1.isBaseType() && !r2.isBaseType() && returnType.isBaseType())
+ return true;
+ if (r2.isBaseType() && !r1.isBaseType() && !returnType.isBaseType())
+ return true;
+ }
+ return reduceAndIncorporate(new ConstraintTypeFormula(r1, r2, ReductionResult.SUBTYPE));
+ } else if (expri instanceof ConditionalExpression) {
+ ConditionalExpression cond = (ConditionalExpression) expri;
+ return checkExpression(cond.valueIfTrue, u, r1, v, r2) && checkExpression(cond.valueIfFalse, u, r1, v, r2);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean siSuperI(TypeBinding si, TypeBinding funcI) {
+ if (TypeBinding.equalsEquals(si, funcI) || TypeBinding.equalsEquals(si.original(), funcI))
+ return true;
+ TypeBinding[] superIfcs = funcI.superInterfaces();
+ if (superIfcs == null) return false;
+ for (int i = 0; i < superIfcs.length; i++) {
+ if (siSuperI(si, superIfcs[i]))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean siSubI(TypeBinding si, TypeBinding funcI) {
+ if (TypeBinding.equalsEquals(si, funcI) || TypeBinding.equalsEquals(si.original(), funcI))
+ return true;
+ TypeBinding[] superIfcs = si.superInterfaces();
+ if (superIfcs == null) return false;
+ for (int i = 0; i < superIfcs.length; i++) {
+ if (siSubI(superIfcs[i], funcI))
+ return true;
+ }
+ return false;
+ }
+
// ========== Below this point: implementation of the generic algorithm: ==========
/**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index 09b2ed4b91..4c2d4d815c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -22,6 +22,7 @@
* Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Bug 425152 - [1.8] [compiler] Lambda Expression not resolved but flow analyzed leading to NPE.
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
* Jesper Steen Moller - Contributions for
* Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing
*******************************************************************************/
@@ -898,6 +899,10 @@ public MethodBinding shallowOriginal() {
return original();
}
+public MethodBinding genericMethod() {
+ return this;
+}
+
public char[] readableName() /* foo(int, Thread) */ {
StringBuffer buffer = new StringBuffer(this.parameters.length + 1 * 20);
if (isConstructor())
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 75978a4d39..9bc3adf494 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,6 +18,7 @@
* bug 413958 - Function override returning inherited Generic Type
* Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
* Bug 424710 - [1.8][compiler] CCE in SingleNameReference.localVariableBinding
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -744,4 +745,11 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
this.tiebreakMethod = this.originalMethod.asRawMethod(this.environment);
return this.tiebreakMethod;
}
+
+ @Override
+ public MethodBinding genericMethod() {
+ if (this.isRaw) // mostSpecificMethodBinding() would need inference, but that doesn't work well for raw methods
+ return this; // -> prefer traditional comparison using the substituted method
+ return this.originalMethod;
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 2ff993e5ec..ef19cce147 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -32,7 +32,8 @@
* Bug 426589 - [1.8][compiler] Compiler error with generic method/constructor invocation as vargs argument
* Bug 426590 - [1.8][compiler] Compiler error with tenary operator
* Bug 426764 - [1.8] Presence of conditional expression as method argument confuses compiler
- * Bug 426998 - [1.8][compiler] method(java.lang.Class, java.lang.String) not applicable for the arguments (java.lang.Class, java.lang.String)
+ * Bug 426998 - [1.8][compiler] method(java.lang.Class, java.lang.String) not applicable for the arguments (java.lang.Class, java.lang.String)
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
* Jesper S Moller - Contributions for
* Bug 378674 - "The method can be declared as static" is wrong
* Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
@@ -4322,43 +4323,8 @@ public abstract class Scope {
protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize, TypeBinding[] argumentTypes, final InvocationSite invocationSite, ReferenceBinding receiverType) {
boolean isJdk18 = compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8;
- if (isJdk18) {
- // Apply one level of filtering per poly expression more specific rules.
- MethodBinding[] moreSpecific = new MethodBinding[visibleSize];
- int count = 0;
- nextJ: for (int j = 0; j < visibleSize; j++) {
- MethodBinding mbj = visible[j].original();
- final TypeBinding[] mbjParameters = mbj.parameters;
- final int mbjParametersLength = mbjParameters.length;
- for (int k = 0; k < visibleSize; k++) {
- if (j == k) continue;
- MethodBinding mbk = visible[k].original();
- final TypeBinding[] mbkParameters = mbk.parameters;
- final int mbkParametersLength = mbkParameters.length;
- for (int i = 0, length = argumentTypes.length; i < length; i++) {
- TypeBinding argumentType = argumentTypes[i];
- if (argumentType.kind() != Binding.POLY_TYPE)
- continue;
- TypeBinding s = i < mbjParametersLength ? mbjParameters[i] : mbjParameters[mbjParametersLength - 1];
- TypeBinding t = i < mbkParametersLength ? mbkParameters[i] : mbkParameters[mbkParametersLength - 1];
- if (TypeBinding.equalsEquals(s, t))
- continue;
- if (!argumentType.sIsMoreSpecific(s,t)) {
- continue nextJ;
- }
- }
- }
- moreSpecific[count++] = visible[j];
- }
- if (count != 0) {
- visible = moreSpecific;
- visibleSize = count;
- }
- }
-
- // JLS7 implementation
-
+ // common part for all compliance levels:
int[] compatibilityLevels = new int[visibleSize];
for (int i = 0; i < visibleSize; i++) {
TypeBinding[] argTypes = argumentTypes;
@@ -4369,81 +4335,139 @@ public abstract class Scope {
}
compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argTypes);
}
-
- InvocationSite tieBreakInvocationSite = new InvocationSite() {
- public TypeBinding[] genericTypeArguments() { return null; } // ignore genericTypeArgs
- public boolean isSuperAccess() { return invocationSite.isSuperAccess(); }
- public boolean isTypeAccess() { return invocationSite.isTypeAccess(); }
- public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */}
- public void setDepth(int depth) { /* ignore */}
- public void setFieldIndex(int depth) { /* ignore */}
- public int sourceStart() { return invocationSite.sourceStart(); }
- public int sourceEnd() { return invocationSite.sourceStart(); }
- public TypeBinding invocationTargetType() { return invocationSite.invocationTargetType(); }
- public boolean receiverIsImplicitThis() { return invocationSite.receiverIsImplicitThis();}
- public InferenceContext18 freshInferenceContext(Scope scope) { return null; /* no inference when ignoring genericTypeArgs */ }
- public ExpressionContext getExpressionContext() { return ExpressionContext.VANILLA_CONTEXT; }
- };
MethodBinding[] moreSpecific = new MethodBinding[visibleSize];
- int count = 0;
- for (int level = 0, max = VARARGS_COMPATIBLE; level <= max; level++) {
- nextVisible : for (int i = 0; i < visibleSize; i++) {
- if (compatibilityLevels[i] != level) continue nextVisible;
- max = level; // do not examine further categories, will either return mostSpecific or report ambiguous case
- MethodBinding current = visible[i];
- MethodBinding original = current.original();
- MethodBinding tiebreakMethod = current.tiebreakMethod();
- for (int j = 0; j < visibleSize; j++) {
- if (i == j || compatibilityLevels[j] != level) continue;
- MethodBinding next = visible[j];
- if (original == next.original()) {
- // parameterized superclasses & interfaces may be walked twice from different paths so skip next from now on
- compatibilityLevels[j] = -1;
- continue;
+
+ if (isJdk18) {
+ // 15.12.2.5 Choosing the Most Specific Method
+ int count = 0;
+
+ nextJ: for (int j = 0; j < visibleSize; j++) {
+ MethodBinding mbj = visible[j].genericMethod();
+ final TypeBinding[] mbjParameters = mbj.parameters;
+ int levelj = compatibilityLevels[j];
+ nextK: for (int k = 0; k < visibleSize; k++) {
+ if (j == k) continue;
+ // TODO do we want to check existing inference contexts whether they can tell us better about the used inferenceKind?
+ int levelk = compatibilityLevels[k];
+ if (levelj > -1 && levelk > -1 && levelj != levelk) {
+ if (levelj < levelk)
+ continue nextK; // j is more specific than this k
+ else
+ continue nextJ; // j cannot be more specific
+ }
+ MethodBinding mbk = visible[k].genericMethod();
+ final TypeBinding[] mbkParameters = mbk.parameters;
+ // TODO: should the following line also find diamond-typeVariables?
+ if ((invocationSite instanceof Invocation) && mbk.typeVariables() != Binding.NO_TYPE_VARIABLES) {
+ // 18.5.4 More Specific Method Inference
+ Invocation invocation = (Invocation)invocationSite;
+ InferenceContext18 ic18 = new InferenceContext18(this, invocation.arguments(), invocation);
+ if (!ic18.isMoreSpecificThan(invocation, mbj, mbk, levelj == VARARGS_COMPATIBLE, levelk == VARARGS_COMPATIBLE)) {
+ continue nextJ;
+ }
+ } else {
+ for (int i = 0, length = argumentTypes.length; i < length; i++) {
+ TypeBinding argumentType = argumentTypes[i];
+ TypeBinding s = InferenceContext18.getParameter(mbjParameters, i, levelj == VARARGS_COMPATIBLE);
+ TypeBinding t = InferenceContext18.getParameter(mbkParameters, i, levelk == VARARGS_COMPATIBLE);
+ if (TypeBinding.equalsEquals(s, t))
+ continue;
+ if (!argumentType.sIsMoreSpecific(s,t)) {
+ continue nextJ;
+ }
+ }
}
+ }
+ moreSpecific[count++] = visible[j];
+ }
+ if (count == 0) {
+ return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters, ProblemReasons.Ambiguous);
+ } else if (count == 1) {
+ MethodBinding candidate = inferInvocationType(invocationSite, moreSpecific[0], argumentTypes);
+ compilationUnitScope().recordTypeReferences(candidate.thrownExceptions);
+ return candidate;
+ } else {
+ visibleSize = count;
+ // we proceed with pre 1.8 code below, which checks for overriding
+ }
+ } else {
- MethodBinding methodToTest = next;
- if (next instanceof ParameterizedGenericMethodBinding) {
- ParameterizedGenericMethodBinding pNext = (ParameterizedGenericMethodBinding) next;
- if (pNext.isRaw && !pNext.isStatic()) {
- // hold onto the raw substituted method
- } else {
- methodToTest = pNext.originalMethod;
+ // JLS7 implementation
+
+ InvocationSite tieBreakInvocationSite = new InvocationSite() {
+ public TypeBinding[] genericTypeArguments() { return null; } // ignore genericTypeArgs
+ public boolean isSuperAccess() { return invocationSite.isSuperAccess(); }
+ public boolean isTypeAccess() { return invocationSite.isTypeAccess(); }
+ public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */}
+ public void setDepth(int depth) { /* ignore */}
+ public void setFieldIndex(int depth) { /* ignore */}
+ public int sourceStart() { return invocationSite.sourceStart(); }
+ public int sourceEnd() { return invocationSite.sourceStart(); }
+ public TypeBinding invocationTargetType() { return invocationSite.invocationTargetType(); }
+ public boolean receiverIsImplicitThis() { return invocationSite.receiverIsImplicitThis();}
+ public InferenceContext18 freshInferenceContext(Scope scope) { return null; /* no inference when ignoring genericTypeArgs */ }
+ public ExpressionContext getExpressionContext() { return ExpressionContext.VANILLA_CONTEXT; }
+ };
+ int count = 0;
+ for (int level = 0, max = VARARGS_COMPATIBLE; level <= max; level++) {
+ nextVisible : for (int i = 0; i < visibleSize; i++) {
+ if (compatibilityLevels[i] != level) continue nextVisible;
+ max = level; // do not examine further categories, will either return mostSpecific or report ambiguous case
+ MethodBinding current = visible[i];
+ MethodBinding original = current.original();
+ MethodBinding tiebreakMethod = current.tiebreakMethod();
+ for (int j = 0; j < visibleSize; j++) {
+ if (i == j || compatibilityLevels[j] != level) continue;
+ MethodBinding next = visible[j];
+ if (original == next.original()) {
+ // parameterized superclasses & interfaces may be walked twice from different paths so skip next from now on
+ compatibilityLevels[j] = -1;
+ continue;
}
+
+ MethodBinding methodToTest = next;
+ if (next instanceof ParameterizedGenericMethodBinding) {
+ ParameterizedGenericMethodBinding pNext = (ParameterizedGenericMethodBinding) next;
+ if (pNext.isRaw && !pNext.isStatic()) {
+ // hold onto the raw substituted method
+ } else {
+ methodToTest = pNext.originalMethod;
+ }
+ }
+ MethodBinding acceptable = computeCompatibleMethod(methodToTest, tiebreakMethod.parameters,
+ tieBreakInvocationSite, INVOCATION_TYPE, level == VARARGS_COMPATIBLE);
+ /* There are 4 choices to consider with current & next :
+ foo(B) & foo(A) where B extends A
+ 1. the 2 methods are equal (both accept each others parameters) -> want to continue
+ 2. current has more specific parameters than next (so acceptable is a valid method) -> want to continue
+ 3. current has less specific parameters than next (so acceptable is null) -> go on to next
+ 4. current and next are not compatible with each other (so acceptable is null) -> go on to next
+ */
+ if (acceptable == null || !acceptable.isValidBinding())
+ continue nextVisible;
+ if (!isAcceptableMethod(tiebreakMethod, acceptable))
+ continue nextVisible;
+ // pick a concrete method over a bridge method when parameters are equal since the return type of the concrete method is more specific
+ if (current.isBridge() && !next.isBridge())
+ if (tiebreakMethod.areParametersEqual(acceptable))
+ continue nextVisible; // skip current so acceptable wins over this bridge method
}
- MethodBinding acceptable = computeCompatibleMethod(methodToTest, tiebreakMethod.parameters,
- tieBreakInvocationSite, INVOCATION_TYPE, level == VARARGS_COMPATIBLE);
- /* There are 4 choices to consider with current & next :
- foo(B) & foo(A) where B extends A
- 1. the 2 methods are equal (both accept each others parameters) -> want to continue
- 2. current has more specific parameters than next (so acceptable is a valid method) -> want to continue
- 3. current has less specific parameters than next (so acceptable is null) -> go on to next
- 4. current and next are not compatible with each other (so acceptable is null) -> go on to next
- */
- if (acceptable == null || !acceptable.isValidBinding())
- continue nextVisible;
- if (!isAcceptableMethod(tiebreakMethod, acceptable))
- continue nextVisible;
- // pick a concrete method over a bridge method when parameters are equal since the return type of the concrete method is more specific
- if (current.isBridge() && !next.isBridge())
- if (tiebreakMethod.areParametersEqual(acceptable))
- continue nextVisible; // skip current so acceptable wins over this bridge method
+ moreSpecific[i] = current;
+ count++;
}
- moreSpecific[i] = current;
- count++;
}
- }
- if (count == 1) {
- for (int i = 0; i < visibleSize; i++) {
- if (moreSpecific[i] != null) {
- // 1.8: Give inference a chance to perform outstanding tasks (18.5.2):
- MethodBinding candidate = inferInvocationType(invocationSite, visible[i], argumentTypes);
- compilationUnitScope().recordTypeReferences(candidate.thrownExceptions);
- return candidate;
+ if (count == 1) {
+ for (int i = 0; i < visibleSize; i++) {
+ if (moreSpecific[i] != null) {
+ // 1.8: Give inference a chance to perform outstanding tasks (18.5.2):
+ MethodBinding candidate = inferInvocationType(invocationSite, visible[i], argumentTypes);
+ compilationUnitScope().recordTypeReferences(candidate.thrownExceptions);
+ return candidate;
+ }
}
+ } else if (count == 0) {
+ return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters, ProblemReasons.Ambiguous);
}
- } else if (count == 0) {
- return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters, ProblemReasons.Ambiguous);
}
// found several methods that are mutually acceptable -> must be equal
@@ -4561,7 +4585,6 @@ public abstract class Scope {
}
}
- // if all moreSpecific methods are equal then see if duplicates exist because of substitution
return new ProblemMethodBinding(visible[0], visible[0].selector, visible[0].parameters, ProblemReasons.Ambiguous);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index 23597e8a1d..9daeb7f5ce 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -24,6 +24,7 @@
* Bug 424712 - [1.8][compiler] NPE in TypeBinding.isProvablyDistinctTypeArgument
* Bug 426792 - [1.8][inference][impl] generify new type inference engine
* Bug 426764 - [1.8] Presence of conditional expression as method argument confuses compiler
+ * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference"
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
*******************************************************************************/
@@ -1520,7 +1521,7 @@ public boolean hasTypeBit(int bit) {
}
public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t) {
- return s.isCompatibleWith(t);
+ return s.isCompatibleWith(t) && !s.needsUncheckedConversion(t);
}
public MethodBinding[] getMethods(char[] selector) {

Back to the top