diff options
author | Stephan Herrmann | 2014-01-30 16:09:05 +0000 |
---|---|---|
committer | Stephan Herrmann | 2014-01-30 23:03:20 +0000 |
commit | 3efbae02af9125c723d4c2de65767b20d72aaa7a (patch) | |
tree | 7d848698dccc36f230ebcca34b4b7be1ecd4b25e | |
parent | 995521865cfd6e568bdd12bfb7d4a59fc50611ab (diff) | |
download | eclipse.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"
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) { |