Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2018-08-16 18:55:45 +0000
committerStephan Herrmann2019-05-19 13:56:21 +0000
commitc3bca83c3ba740ea3abc5cd2e334d9ab35a56b82 (patch)
tree244fe08313f6da2b0a30cb806507cec53227f62d
parent5147f38abb400d33a4aa49de5af5318835c60b88 (diff)
downloadeclipse.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>
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java2
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java25
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaExpressionsTest.java16
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java8
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java21
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/OverloadResolutionTest8.java69
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java24
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java45
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReasons.java1
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java9
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties2
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:

Back to the top