Fix for Bug 430310 - [1.8][compiler] Functional interface incorrectly
rejected as not being.
Signed-off-by: Srikanth Sankaran <srikanth_sankaran@in.ibm.com>
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 7e5c6b6..b6a5ef1 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
@@ -4017,6 +4017,89 @@
},
"null");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430310, [1.8][compiler] Functional interface incorrectly rejected as not being.
+public void test430310() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface Func1<T1, R> {\n" +
+ " R apply(T1 v1);\n" +
+ " void other();\n" +
+ "}\n" +
+ "@FunctionalInterface // spurious error: F1<T, R> is not a functional interface\n" +
+ "public interface X<T1, R> extends Func1<T1, R> {\n" +
+ " default void other() {}\n" +
+ " public static void main(String [] args) {\n" +
+ " System.out.println(\"OK\");\n" +
+ " }\n" +
+ "}\n"
+ },
+ "OK");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430310, [1.8][compiler] Functional interface incorrectly rejected as not being.
+public void test430310a() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "@FunctionalInterface\n" +
+ "public interface X<T1, T2, R> {\n" +
+ " R apply(T1 v1, T2 v2);\n" +
+ " default void other() {}\n" +
+ " public static void main(String[] args) {\n" +
+ " System.out.println(\"OK\");\n" +
+ " }\n" +
+ "}\n"
+ },
+ "OK");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430310, [1.8][compiler] Functional interface incorrectly rejected as not being.
+public void test430310b() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I1 {\n" +
+ " int foo(String s);\n" +
+ "}\n" +
+ "@FunctionalInterface\n" +
+ "interface A1 extends I1 {\n" +
+ " @Override\n" +
+ " default int foo(String s) {\n" +
+ " return -1;\n" +
+ " }\n" +
+ " int foo(java.io.Serializable s);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " System.out.println(\"OK\");\n" +
+ " }\n" +
+ "}\n"
+ },
+ "OK");
+}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430310, [1.8][compiler] Functional interface incorrectly rejected as not being.
+public void test430310c() {
+ this.runConformTest(
+ new String[] {
+ "X.java",
+ "interface I2 {\n" +
+ " int foo(String s);\n" +
+ "}\n" +
+ "@FunctionalInterface\n" +
+ "interface A2 extends I2 {\n" +
+ " @Override\n" +
+ " default int foo(String s) {\n" +
+ " return -1;\n" +
+ " }\n" +
+ " int bar(java.io.Serializable s);\n" +
+ "}\n" +
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " System.out.println(\"OK\");\n" +
+ " }\n" +
+ "}\n"
+ },
+ "OK");
+}
public static Class testClass() {
return LambdaExpressionsTest.class;
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeLambdaExpressionsTest.java
index 3727dbc..c53c769 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
@@ -8963,6 +8963,30 @@
"Unhandled exception type Exception\n" +
"----------\n");
}
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430310, [1.8][compiler] Functional interface incorrectly rejected as not being.
+public void test430310() {
+ this.runNegativeTest(
+ new String[] {
+ "X.java",
+ "interface Func1<T1, R> {\n" +
+ " R apply(T1 v1);\n" +
+ " void other();\n" +
+ "}\n" +
+ "@FunctionalInterface // spurious error: F1<T, R> is not a functional interface\n" +
+ "interface F1<T1, R> extends Func1<T1, R> {\n" +
+ " default void other() {}\n" +
+ "}\n" +
+ "@FunctionalInterface\n" +
+ "interface F2<T1, R> extends Func1<T1, R> {\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in X.java (at line 10)\n" +
+ " interface F2<T1, R> extends Func1<T1, R> {\n" +
+ " ^^\n" +
+ "Invalid \'@FunctionalInterface\' annotation; F2<T1,R> is not a functional interface\n" +
+ "----------\n");
+}
public static Class testClass() {
return NegativeLambdaExpressionsTest.class;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 75933ff..d3a6ab0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1867,48 +1867,29 @@
int contractsCount = 0;
int contractsLength = 0;
- // -- the following are used for early termination.
- MethodBinding aContract = null;
- int contractParameterLength = 0;
- char [] contractSelector = null;
- // ---
-
ReferenceBinding [] superInterfaces = superInterfaces();
for (int i = 0, length = superInterfaces.length; i < length; i++) {
MethodBinding [] superInterfaceContracts = superInterfaces[i].getInterfaceAbstractContracts(scope);
final int superInterfaceContractsLength = superInterfaceContracts == null ? 0 : superInterfaceContracts.length;
-
if (superInterfaceContractsLength == 0) continue;
- if (aContract == null) {
- aContract = superInterfaceContracts[0];
- contractParameterLength = aContract.parameters.length;
- contractSelector = aContract.selector;
- contracts = superInterfaceContracts;
- contractsCount = contractsLength = superInterfaceContractsLength;
- } else {
- if (superInterfaceContracts[0].parameters.length != contractParameterLength || !CharOperation.equals(contractSelector, superInterfaceContracts[0].selector)) {
- throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
- }
- if (contractsLength < contractsCount + superInterfaceContractsLength) {
- System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength = contractsCount + superInterfaceContractsLength], 0, contractsCount);
- }
- System.arraycopy(superInterfaceContracts, 0, contracts, contractsCount, superInterfaceContractsLength);
- contractsCount += superInterfaceContractsLength;
+ if (contractsLength < contractsCount + superInterfaceContractsLength) {
+ System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength = contractsCount + superInterfaceContractsLength], 0, contractsCount);
}
+ System.arraycopy(superInterfaceContracts, 0, contracts, contractsCount, superInterfaceContractsLength);
+ contractsCount += superInterfaceContractsLength;
}
+
for (int i = 0, length = methods == null ? 0 : methods.length; i < length; i++) {
final MethodBinding method = methods[i];
- if (method.isStatic() || method.redeclaresPublicObjectMethod(scope)) continue;
+ if (method == null || method.isStatic() || method.redeclaresPublicObjectMethod(scope))
+ continue;
+ if (!method.isValidBinding())
+ throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
if (method.isDefaultMethod()) {
for (int j = 0; j < contractsCount; j++) {
if (contracts[j] == null)
continue;
if (MethodVerifier.doesMethodOverride(method, contracts[j], scope.environment())) {
- if (aContract == contracts[j]) {
- aContract = null;
- contractParameterLength = 0;
- contractSelector = null;
- }
contractsCount--;
// abstract method from super type rendered default by present interface ==> contracts[j] = null;
if (j < contractsCount)
@@ -1917,16 +1898,6 @@
}
continue; // skip default method itself
}
- final boolean validBinding = method.isValidBinding();
- if (aContract == null && validBinding) {
- aContract = method;
- contractParameterLength = aContract.parameters.length;
- contractSelector = aContract.selector;
- } else {
- if (!validBinding || method.parameters.length != contractParameterLength || !CharOperation.equals(contractSelector, method.selector)) {
- throw new InvalidInputException("Not a functional interface"); //$NON-NLS-1$
- }
- }
if (contractsCount == contractsLength) {
System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength += 16], 0, contractsCount);
}
@@ -1952,15 +1923,32 @@
MethodBinding[] methods = null;
try {
methods = getInterfaceAbstractContracts(scope);
+ if (methods == null || methods.length == 0)
+ return this.singleAbstractMethod[index] = samProblemBinding;
+ int contractParameterLength = 0;
+ char [] contractSelector = null;
+ for (int i = 0, length = methods.length; i < length; i++) {
+ MethodBinding method = methods[i];
+ if (method == null) continue;
+ if (contractSelector == null) {
+ contractSelector = method.selector;
+ contractParameterLength = method.parameters == null ? 0 : method.parameters.length;
+ } else {
+ int methodParameterLength = method.parameters == null ? 0 : method.parameters.length;
+ if (methodParameterLength != contractParameterLength || !CharOperation.equals(method.selector, contractSelector))
+ return this.singleAbstractMethod[index] = samProblemBinding;
+ }
+ }
} catch (InvalidInputException e) {
return this.singleAbstractMethod[index] = samProblemBinding;
}
- if (methods != null && methods.length == 1)
+ if (methods.length == 1)
return this.singleAbstractMethod[index] = methods[0];
final LookupEnvironment environment = scope.environment();
boolean genericMethodSeen = false;
int length = methods.length;
+
next:for (int i = length - 1; i >= 0; --i) {
MethodBinding method = methods[i], otherMethod = null;
if (method.typeVariables != Binding.NO_TYPE_VARIABLES)