diff options
author | Stephan Herrmann | 2018-08-16 18:55:45 +0000 |
---|---|---|
committer | Stephan Herrmann | 2019-05-19 13:56:21 +0000 |
commit | c3bca83c3ba740ea3abc5cd2e334d9ab35a56b82 (patch) | |
tree | 244fe08313f6da2b0a30cb806507cec53227f62d | |
parent | 5147f38abb400d33a4aa49de5af5318835c60b88 (diff) | |
download | eclipse.jdt.core-c3bca83c3ba740ea3abc5cd2e334d9ab35a56b82.tar.gz eclipse.jdt.core-c3bca83c3ba740ea3abc5cd2e334d9ab35a56b82.tar.xz eclipse.jdt.core-c3bca83c3ba740ea3abc5cd2e334d9ab35a56b82.zip |
Bug 525822 - [1.8] ECJ compiles ambiguous lambda method invocation
without warning, breaking builds with javac.
Change-Id: Iaad08af8fe399311ed05252129037b7377f4fa72
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
19 files changed, 206 insertions, 51 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java index 671b104925..07f04a67ea 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java @@ -808,6 +808,7 @@ public void test011_problem_categories() { expectedProblemAttributes.put("MissingTypeInLambda", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("MissingTypeInMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("MissingValueForAnnotationMember", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); + expectedProblemAttributes.put("MissingValueFromLambda", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL)); expectedProblemAttributes.put("MultiCatchNotBelow17", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("MultipleFunctionalInterfaces", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("StaticInterfaceMethodNotBelow18", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); @@ -1755,6 +1756,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("MissingTypeInLambda", SKIP); expectedProblemAttributes.put("MissingTypeInMethod", SKIP); expectedProblemAttributes.put("MissingValueForAnnotationMember", SKIP); + expectedProblemAttributes.put("MissingValueFromLambda", SKIP); expectedProblemAttributes.put("MultiCatchNotBelow17", SKIP); expectedProblemAttributes.put("MultipleFunctionalInterfaces", SKIP); expectedProblemAttributes.put("StaticInterfaceMethodNotBelow18", SKIP); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java index 18ae2dd83b..5d1bf7e8e5 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java @@ -9855,4 +9855,29 @@ public void testBug508834_comment0() { "}\n" }); } + public void testBug525822() { + runNegativeTest( + new String[] { + "ECJTest.java", + "import java.util.*;\n" + + "import java.util.function.*;\n" + + "\n" + + "public class ECJTest {\n" + + "\n" + + " static {\n" + + " final List<String> list = new ArrayList<>();\n" + + " accept(list::add);\n" + + " }\n" + + "\n" + + " static void accept(Consumer<String> yay) {};\n" + + " static void accept(BiConsumer<String, String> nooo) {};\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in ECJTest.java (at line 8)\n" + + " accept(list::add);\n" + + " ^^^^^^\n" + + "The method accept(Consumer<String>) is ambiguous for the type ECJTest\n" + + "----------\n"); + } } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java index d23366f1f8..5be3c39bc7 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java @@ -4671,9 +4671,7 @@ public void test441929() { } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=437781, [1.8][compiler] Eclipse accepts code rejected by javac because of ambiguous method reference public void test437781() { - this.runConformTest( - false, - EclipseHasABug.EclipseBug510528, + this.runNegativeTest( new String[] { "X.java", "import java.util.function.Consumer;\n" + @@ -4691,7 +4689,17 @@ public void test437781() { " } \n" + "}\n" }, - "Consumer"); + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " new X().visit( System.out::println );\n" + + " ^^^^^\n" + + "The method visit(Function<Integer,Boolean>) is ambiguous for the type X\n" + + "----------\n" + + "2. ERROR in X.java (at line 5)\n" + + " new X().visit( System.out::println );\n" + + " ^^^^^^^^^^^^^^^^^^^\n" + + "The type of println(Object) from the type PrintStream is void, this is incompatible with the descriptor\'s return type: Boolean\n" + + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=443889, [1.8][compiler] Lambdas get compiled to duplicate methods public void test443889() { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java index a7309d52ef..7f9e4e28e4 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java @@ -571,8 +571,8 @@ public void test016() { "----------\n" + "1. ERROR in X.java (at line 8)\n" + " goo((x) -> {while (FALSE) throw new Exception();});\n" + - " ^^^\n" + - "The method goo(I) in the type X is not applicable for the arguments ((<no type> x) -> {})\n" + + " ^^^^^^\n" + + "This lambda expression must return a result of type String\n" + "----------\n"); } public void test017() { @@ -977,8 +977,8 @@ public void test029() { "----------\n" + "1. ERROR in X.java (at line 8)\n" + " goo((x) -> {\n" + - " ^^^\n" + - "The method goo(I) in the type X is not applicable for the arguments ((<no type> x) -> {})\n" + + " ^^^^^^\n" + + "This lambda expression must return a result of type String\n" + "----------\n"); } public void test030() { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java index 99e4545791..4cf5e61f5e 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2018 IBM Corporation and others. + * Copyright (c) 2011, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -5193,6 +5193,11 @@ this.runNegativeTest( "----------\n" + "3. ERROR in X.java (at line 7)\n" + " new X().foo(()->{});\n" + + " ^^^\n" + + "The method foo(I<Object>) in the type X is not applicable for the arguments (() -> {})\n" + + "----------\n" + + "4. ERROR in X.java (at line 7)\n" + + " new X().foo(()->{});\n" + " ^^^^\n" + "The target type of this expression is not a well formed parameterized type due to bound(s) mismatch\n" + "----------\n"); @@ -5827,13 +5832,13 @@ public void test401939b() { "----------\n" + "1. ERROR in X.java (at line 14)\n" + " goo((x) -> { while (FALSE) throw new Exception(); });\n" + - " ^^^\n" + - "The method goo(I) in the type X is not applicable for the arguments ((<no type> x) -> {})\n" + + " ^^^^^^\n" + + "This lambda expression must return a result of type String\n" + "----------\n" + "2. ERROR in X.java (at line 17)\n" + " goo((x) -> { while (POI) throw new Exception(); });\n" + - " ^^^\n" + - "The method goo(I) in the type X is not applicable for the arguments ((<no type> x) -> {})\n" + + " ^^^^^^\n" + + "This lambda expression must return a result of type String\n" + "----------\n" + "3. ERROR in X.java (at line 19)\n" + " goo((x) -> { if (TRUE) throw new Exception(); });\n" + @@ -5842,8 +5847,8 @@ public void test401939b() { "----------\n" + "4. ERROR in X.java (at line 22)\n" + " goo((x) -> { while (BLANK) throw new Exception(); });\n" + - " ^^^\n" + - "The method goo(I) in the type X is not applicable for the arguments ((<no type> x) -> {})\n" + + " ^^^^^^\n" + + "This lambda expression must return a result of type String\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=401939, [1.8][compiler] Incorrect shape analysis leads to method resolution failure . @@ -7814,7 +7819,7 @@ public void test423129() { "}\n" }, "----------\n" + - "1. ERROR in X.java (at line 1)\n" + + "1. ERROR in X.java (at line 12)\n" + " return xyz.\n" + " ^^^\n" + "Type mismatch: cannot convert from Integer to String\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/OverloadResolutionTest8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/OverloadResolutionTest8.java index a3ef6e4fcf..d7a307d6c4 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/OverloadResolutionTest8.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/OverloadResolutionTest8.java @@ -1584,8 +1584,9 @@ public void test4008712p() { "X is a raw type. References to generic type X<T> should be parameterized\n" + "----------\n"); } -public void test4008712q() { - this.runConformTest( +public void test4008712q_raw() { + Runner runner = new Runner(); + runner.testFiles = new String[] { "X.java", "interface I {\n" + @@ -1610,11 +1611,59 @@ public void test4008712q() { " goo(new X()::foo);\n" + " }\n" + "}\n", + }; + runner.expectedCompilerLog = + "----------\n" + + "1. ERROR in X.java (at line 20)\n" + + " goo(new X()::foo);\n" + + " ^^^\n" + + "The method goo(I) is ambiguous for the type X<T>\n" + + "----------\n" + + "2. WARNING in X.java (at line 20)\n" + + " goo(new X()::foo);\n" + + " ^^^^^^^^^^^^\n" + + "Type safety: The method foo(Object) belongs to the raw type Y. References to generic type Y<T> should be parameterized\n" + + "----------\n" + + "3. WARNING in X.java (at line 20)\n" + + " goo(new X()::foo);\n" + + " ^\n" + + "X is a raw type. References to generic type X<T> should be parameterized\n" + + "----------\n"; + runner.javacTestOptions = JavacTestOptions.Excuse.JavacCompilesIncorrectSource; + runner.runNegativeTest(); +} +public void test4008712q_diamond() { + this.runConformTest( + new String[] { + "X.java", + "interface I {\n" + + " void foo(String x);\n" + + "}\n" + + "interface J {\n" + + " String foo(String x);\n" + + "}\n" + + "class Y<T> {\n" + + " public T foo(T x) {\n" + + " return null;\n" + + " }\n" + + "}\n" + + "public class X<T> extends Y<String> {\n" + + " static void goo(I i) {\n" + + " System.out.println(\"foo(I)\");\n" + + " }\n" + + " static void goo(J j) {\n" + + " System.out.println(\"foo(J)\");\n" + + " }\n" + + " public static void main(String[] args) { \n" + + " goo(new X<>()::foo);\n" + + " }\n" + + "}\n", }, - "foo(I)"); + "foo(J)"); } public void test4008712r() { - this.runConformTest( + Runner runner = new Runner(); + runner.testFiles = new String[] { "X.java", "interface I {\n" + @@ -1639,8 +1688,16 @@ public void test4008712r() { " goo(new X[0]::clone);\n" + " }\n" + "}\n", - }, - "foo(I)"); + }; + runner.expectedCompilerLog = + "----------\n" + + "1. ERROR in X.java (at line 20)\n" + + " goo(new X[0]::clone);\n" + + " ^^^\n" + + "The method goo(I) is ambiguous for the type X<T>\n" + + "----------\n"; + runner.javacTestOptions = JavacTestOptions.Excuse.JavacCompilesIncorrectSource; + runner.runNegativeTest(); } public void test4008712s() { this.runConformTest( diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index c7b59bd6da..dbe2b6067e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -1876,6 +1876,10 @@ void setSourceStart(int sourceStart); /** @since 3.10 */ int IllegalTypeArgumentsInRawConstructorReference = TypeRelated + 1003; + // more on lambdas: + /** @since 3.18 */ + int MissingValueFromLambda = Internal + 1004; + // default methods: /** @since 3.10 */ int IllegalModifierForInterfaceMethod18 = MethodRelated + 1050; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java index 83bb061160..eb3f1abce1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -48,6 +48,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -677,11 +678,13 @@ public abstract class ASTNode implements TypeConstants, TypeIds { * @param method the method produced by lookup (possibly involving type inference). * @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup. * @param scope scope for resolution. + * @return either the original method or a problem method */ - public static void resolvePolyExpressionArguments(Invocation invocation, MethodBinding method, TypeBinding[] argumentTypes, BlockScope scope) { + public static MethodBinding resolvePolyExpressionArguments(Invocation invocation, MethodBinding method, TypeBinding[] argumentTypes, BlockScope scope) { MethodBinding candidateMethod = method.isValidBinding() ? method : method instanceof ProblemMethodBinding ? ((ProblemMethodBinding) method).closestMatch : null; if (candidateMethod == null) - return; + return method; + ProblemMethodBinding problemMethod = null; boolean variableArity = candidateMethod.isVarargs(); final TypeBinding[] parameters = candidateMethod.parameters; Expression[] arguments = invocation.arguments(); @@ -704,8 +707,20 @@ public abstract class ASTNode implements TypeConstants, TypeIds { boolean skipKosherCheck = method.problemId() == ProblemReasons.Ambiguous; updatedArgumentType = lambda.resolveType(scope, skipKosherCheck); // additional checks, because LE.resolveType may return a valid binding even in the presence of structural errors - if (!lambda.isCompatibleWith(parameterType, scope) || lambda.hasErrors()) + if (lambda.hasErrors() || lambda.hasDescripterProblem) { + continue; + } + if (!lambda.isCompatibleWith(parameterType, scope)) { + if (method.isValidBinding() && problemMethod == null) { + TypeBinding[] originalArguments = Arrays.copyOf(argumentTypes, argumentTypes.length); + if (lambda.reportShapeError(parameterType, scope)) { + problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.ErrorAlreadyReported); + } else { + problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.NotFound); + } + } continue; + } // avoid that preliminary local type bindings escape beyond this point: lambda.updateLocalTypesInMethod(candidateMethod); } else { @@ -723,6 +738,9 @@ public abstract class ASTNode implements TypeConstants, TypeIds { if (ic18 != null) ic18.flushBoundOutbox(); // overload resolution is done, now perform the push of bounds from inner to outer } + if (problemMethod != null) + return problemMethod; + return method; } public static void resolveAnnotations(BlockScope scope, Annotation[] sourceAnnotations, Binding recipient) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 58f80466f9..3e53caeae7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -486,7 +486,7 @@ public TypeBinding resolveType(BlockScope scope) { return this.resolvedType = null; } } - resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); + this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); } else { this.binding = findConstructorBinding(scope, this, (ReferenceBinding) this.resolvedType, this.argumentTypes); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java index 625cb97625..ec8105264c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2017 IBM Corporation and others. + * Copyright (c) 2013, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -67,6 +67,7 @@ public abstract class FunctionalExpression extends Expression { public boolean shouldCaptureInstance = false; // Whether the expression needs access to instance data of enclosing type protected static IErrorHandlingPolicy silentErrorHandlingPolicy = DefaultErrorHandlingPolicies.ignoreAllProblems(); private boolean hasReportedSamProblem = false; + public boolean hasDescripterProblem; public boolean isSerializable; public int ordinal; @@ -303,6 +304,7 @@ public abstract class FunctionalExpression extends Expression { status = false; if (!inspector.visible(this.expectedType)) status = false; + this.hasDescripterProblem |= !status; return status; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java index 08fa9c818f..d680669dcc 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java @@ -868,44 +868,61 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre } return true; } - + + private enum CompatibilityResult { COMPATIBLE, INCOMPATIBLE, REPORTED } + + public boolean reportShapeError(TypeBinding targetType, Scope skope) { + return internalIsCompatibleWith(targetType, skope, true) == CompatibilityResult.REPORTED; + } + @Override public boolean isCompatibleWith(TypeBinding targetType, final Scope skope) { + return internalIsCompatibleWith(targetType, skope, false) == CompatibilityResult.COMPATIBLE; + } + CompatibilityResult internalIsCompatibleWith(TypeBinding targetType, Scope skope, boolean reportShapeProblem) { if (!super.isPertinentToApplicability(targetType, null)) - return true; + return CompatibilityResult.COMPATIBLE; LambdaExpression copy = null; try { copy = cachedResolvedCopy(targetType, argumentsTypeElided(), false, null); // if argument types are elided, we don't care for result expressions against *this* target, any valid target is OK. } catch (CopyFailureException cfe) { if (this.assistNode) - return true; // can't type check result expressions, just say yes. - return !isPertinentToApplicability(targetType, null); // don't expect to hit this ever. + return CompatibilityResult.COMPATIBLE; // can't type check result expressions, just say yes. + return isPertinentToApplicability(targetType, null) ? CompatibilityResult.INCOMPATIBLE : CompatibilityResult.COMPATIBLE; // don't expect to hit this ever. } if (copy == null) - return false; + return CompatibilityResult.INCOMPATIBLE; // copy here is potentially compatible with the target type and has its shape fully computed: i.e value/void compatibility is determined and result expressions have been gathered. targetType = findGroundTargetType(this.enclosingScope, targetType, targetType, argumentsTypeElided()); MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope, true); if (sam == null || sam.problemId() == ProblemReasons.NoSuchSingleAbstractMethod) { - return false; + return CompatibilityResult.INCOMPATIBLE; } if (sam.returnType.id == TypeIds.T_void) { - if (!copy.voidCompatible) - return false; + if (!copy.voidCompatible) { + return CompatibilityResult.INCOMPATIBLE; + } } else { - if (!copy.valueCompatible) - return false; + if (!copy.valueCompatible) { + if (reportShapeProblem) { + skope.problemReporter().missingValueFromLambda(this, sam.returnType); + return CompatibilityResult.REPORTED; + } + return CompatibilityResult.INCOMPATIBLE; + } } + if (reportShapeProblem) + return CompatibilityResult.COMPATIBLE; // enough seen if (!isPertinentToApplicability(targetType, null)) - return true; + return CompatibilityResult.COMPATIBLE; // catch up on one check deferred via skipKosherCheck=true (only if pertinent for applicability) if (!kosherDescriptor(this.enclosingScope, sam, false)) - return false; + return CompatibilityResult.INCOMPATIBLE; Expression [] returnExpressions = copy.resultExpressions; for (int i = 0, length = returnExpressions.length; i < length; i++) { @@ -913,10 +930,10 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre && this.enclosingScope.parameterCompatibilityLevel(returnExpressions[i].resolvedType, sam.returnType) == Scope.NOT_COMPATIBLE) { if (!returnExpressions[i].isConstantValueOfTypeAssignableToType(returnExpressions[i].resolvedType, sam.returnType)) if (sam.returnType.id != TypeIds.T_void || this.body instanceof Block) - return false; + return CompatibilityResult.INCOMPATIBLE; } } - return true; + return CompatibilityResult.COMPATIBLE; } class CopyFailureException extends RuntimeException { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index f6e8a51e2d..b605963daf 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -957,7 +957,7 @@ protected TypeBinding findMethodBinding(BlockScope scope) { return new PolyTypeBinding(this); } } - resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); + this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); return this.binding.returnType; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index bd4ba12a44..2dd1101d27 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -547,7 +547,7 @@ public class QualifiedAllocationExpression extends AllocationExpression { } } } - resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); + this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); } else { if (this.anonymousType != null) { constructorBinding = getAnonymousConstructorBinding((ReferenceBinding) receiverType, scope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java index 97a404cc47..091157bbd4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -499,7 +499,6 @@ public ExpressionContext getExpressionContext() { */ protected MethodBinding findConstructorBinding(BlockScope scope, Invocation site, ReferenceBinding receiverType, TypeBinding[] argumentTypes) { MethodBinding ctorBinding = scope.getConstructor(receiverType, argumentTypes, site); - resolvePolyExpressionArguments(site, ctorBinding, argumentTypes, scope); - return ctorBinding; + return resolvePolyExpressionArguments(site, ctorBinding, argumentTypes, scope); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java index 3c9378e547..822d4c9278 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java @@ -1645,6 +1645,8 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi for (int i = 0, length = choices.length; i < length; i++) { MethodBinding method = choices[i]; if (!method.isAbstract() || method.redeclaresPublicObjectMethod(scope)) continue; // (re)skip statics, defaults, public object methods ... + if (method.problemId() == ProblemReasons.ContradictoryNullAnnotations) + method = ((ProblemMethodBinding) method).closestMatch; this.singleAbstractMethod[index] = method; break; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java index 8182b77fae..5c550bf624 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java @@ -51,4 +51,5 @@ public interface ProblemReasons { final int NoProperEnclosingInstance = 28; final int InterfaceMethodInvocationNotBelow18 = 29; final int NotAccessible = 30; // JLS 6.6.1 - module aspects + final int ErrorAlreadyReported = 31; } 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 7a085094e8..5be2772bb6 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 @@ -4871,14 +4871,14 @@ public abstract class Scope { TypeBinding param = parameters[lastIndex]; // is an ArrayBinding by definition TypeBinding arg = arguments[lastIndex]; if (TypeBinding.notEquals(param, arg)) { - level = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods); + level = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method); if (level == NOT_COMPATIBLE) { // expect X[], is it called with X param = ((ArrayBinding) param).elementsType(); if (tiebreakingVarargsMethods) { arg = ((ArrayBinding) arg).elementsType(); } - if (parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods) == NOT_COMPATIBLE) + if (parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method) == NOT_COMPATIBLE) return NOT_COMPATIBLE; level = VARARGS_COMPATIBLE; // varargs support needed } @@ -4888,7 +4888,7 @@ public abstract class Scope { TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType(); for (int i = lastIndex; i < argLength; i++) { TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i]; - if (TypeBinding.notEquals(param, arg) && parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods) == NOT_COMPATIBLE) + if (TypeBinding.notEquals(param, arg) && parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method) == NOT_COMPATIBLE) return NOT_COMPATIBLE; } } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo(); @@ -4904,7 +4904,7 @@ public abstract class Scope { TypeBinding param = parameters[i]; TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i]; if (TypeBinding.notEquals(arg,param)) { - int newLevel = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods); + int newLevel = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method); if (newLevel == NOT_COMPATIBLE) return NOT_COMPATIBLE; if (newLevel > level) @@ -4933,12 +4933,16 @@ public abstract class Scope { return NOT_COMPATIBLE; } - private int parameterCompatibilityLevel(TypeBinding arg, TypeBinding param, LookupEnvironment env, boolean tieBreakingVarargsMethods) { + private int parameterCompatibilityLevel(TypeBinding arg, TypeBinding param, LookupEnvironment env, boolean tieBreakingVarargsMethods, MethodBinding method) { // only called if env.options.sourceLevel >= ClassFileConstants.JDK1_5 if (arg == null || param == null) return NOT_COMPATIBLE; - if (arg.isCompatibleWith(param, this)) + if (arg instanceof PolyTypeBinding && !((PolyTypeBinding) arg).expression.isPertinentToApplicability(param, method)) { + if (arg.isPotentiallyCompatibleWith(param, this)) + return COMPATIBLE; + } else if (arg.isCompatibleWith(param, this)) { return COMPATIBLE; + } if (tieBreakingVarargsMethods && (this.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_7 || !CompilerOptions.tolerateIllegalAmbiguousVarargsInvocation)) { /* 15.12.2.5 Choosing the Most Specific Method, ... One variable arity member method named m is more specific than another variable arity member method of the same name if either ... Only subtypes relationship should be used. diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 40eca8656d..496ceb709b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -1527,6 +1527,13 @@ public void lambdaExpressionCannotImplementGenericMethod(LambdaExpression lambda lambda.sourceStart, lambda.diagnosticsSourceEnd()); } +public void missingValueFromLambda(LambdaExpression lambda, TypeBinding returnType) { + this.handle(IProblem.MissingValueFromLambda, + new String[] {new String(returnType.readableName())}, + new String[] {new String(returnType.shortReadableName())}, + lambda.sourceStart, + lambda.diagnosticsSourceEnd()); +} public void caseExpressionMustBeConstant(Expression expression) { this.handle( IProblem.NonConstantExpression, @@ -4341,6 +4348,8 @@ public void invalidMethod(MessageSend messageSend, MethodBinding method, Scope s int id = IProblem.UndefinedMethod; //default... MethodBinding shownMethod = method; switch (method.problemId()) { + case ProblemReasons.ErrorAlreadyReported: + return; case ProblemReasons.NoSuchMethodOnArray : return; // secondary error. case ProblemReasons.NotFound : diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index 0f079fa529..c55d8022d1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -854,6 +854,8 @@ 1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided 1002 = Syntax error, modifiers are not allowed here 1003 = Explicit type arguments cannot be specified in raw constructor reference expression +# more lambda: +1004 = This lambda expression must return a result of type {0} # Default methods: # variant of 359: |