### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java,v retrieving revision 1.35 diff -u -r1.35 AmbiguousMethodTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java 15 Jan 2007 12:16:58 -0000 1.35 +++ src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java 24 Jan 2007 08:04:40 -0000 @@ -1457,7 +1457,7 @@ ""); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 -public void _test032() { +public void test032() { this.runConformTest( new String[] { "X.java", @@ -1476,7 +1476,7 @@ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 // variant that shows that the use of a substitution is needed during the bounds // check -public void _test032a() { +public void test032a() { this.runConformTest( new String[] { "X.java", @@ -1496,6 +1496,63 @@ } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 // variant +public void test032b() { + this.runConformTest( + new String[] { + "X.java", + "class A { }" + + "interface I {\n" + + " A foo(Number n);\n" + + "}\n" + + "interface J extends I {\n" + + " A foo(Number n);\n" + + "}\n" + + "public abstract class X implements J {\n" + + "}\n" + + "abstract class XX extends Exception implements Cloneable {}" + }, + ""); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 +// variant +public void test032c() { + this.runConformTest( + new String[] { + "X.java", + "class A { }" + + "interface I {\n" + + " A foo(Number n);\n" + + "}\n" + + "interface J extends I {\n" + + " A foo(Number n);\n" + + "}\n" + + "public abstract class X implements J {\n" + + "}\n" + + "abstract class XX extends Exception implements Cloneable {}" + }, + ""); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 +// variant +public void test032d() { + this.runConformTest( + new String[] { + "X.java", + "class A { }" + + "interface I {\n" + + " A foo(Number n);\n" + + "}\n" + + "interface J extends I {\n" + + " A foo(Number n);\n" + + "}\n" + + "public abstract class X implements J {\n" + + "}\n" + + "abstract class XX extends Exception implements Cloneable {}" + }, + ""); +} +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=162073 +// variant public void test033() { this.runConformTest( new String[] { @@ -1545,7 +1602,7 @@ "2. ERROR in X.java (at line 10)\n" + " public abstract class X implements J, K {\n" + " ^\n" + - "The return type is incompatible with I.foo(Number), K.foo(Number), J.foo(Number)\n" + + "The return type is incompatible with K.foo(Number), J.foo(Number)\n" + "----------\n"); } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=162065 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java,v retrieving revision 1.66 diff -u -r1.66 MethodVerifier15.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 23 Jan 2007 14:51:04 -0000 1.66 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java 24 Jan 2007 08:04:46 -0000 @@ -316,6 +316,46 @@ boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { if (methods[0].declaringClass.isClass()) return super.checkInheritedReturnTypes(methods, length); + if (length <= 1) { + return true; // no need to continue since only 1 inherited method is left + } + // get rid of overriden methods coming from interfaces - if any + MethodBinding methodsToCheck[] = new MethodBinding[length]; // must not nullify methods slots in place + int count = length; + for (int i = 0; i < length; i++) { + methodsToCheck[i] = methods[i]; + } + for (int i = 0; i < length; i++) { + MethodBinding existingMethod; + if ((existingMethod = methodsToCheck[i]) != null) { + for (int j = 0; j < length; j++) { + MethodBinding inheritedMethod; + if (i != j && (inheritedMethod = methodsToCheck[j]) != null && + existingMethod.declaringClass.implementsInterface(inheritedMethod.declaringClass, true)) { + MethodBinding substitute = computeSubstituteMethod(inheritedMethod, existingMethod); + if (substitute != null && + doesSubstituteMethodOverride(existingMethod, substitute) && + (existingMethod.returnType.isCompatibleWith(substitute.returnType) || + isReturnTypeSubstituable(substitute, existingMethod))) { + count--; + methodsToCheck[j] = null; + } + } + } + } + } + if (count < length) { + if (count == 1) { + return true; // no need to continue since only 1 inherited method is left + } + for (int i = 0, j = 0; j < count; i++) { + if (methodsToCheck[i] != null) { + methodsToCheck[j++] = methodsToCheck[i]; + } + } + methods = methodsToCheck; + length = count; + } // else keep methods unchanged for further checks // its possible in 1.5 that A is compatible with B & C, but B is not compatible with C for (int i = 0, l = length - 1; i < l;) { @@ -564,6 +604,74 @@ && inheritedMethod.returnType == existingMethod.returnType && super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType); } +/** + * Return true iff the return type of existingMethod is a valid replacement for + * the one of substituteMethod in a method declaration, in the context specified + * thereafter. It is expected that substituteMethod is the result of the + * substitution of the type parameters of an inheritedMethod method according to + * the type parameters of existingMethod and the inheritance relationship + * between existingMethod's declaring type and inheritedMethod's declaring type, + * where inheritedMethod is a method inherited by existingMethod's declaring + * type which is override compatible with existingMethod, except maybe for + * their respective return types. If those conditions are not met, the result is + * unspecified. + * @param substituteMethod a proper substitute of a method inherited by existingMethod + * @param existingMethod the existing method under examination + * @return true if the return type of existingMethod is a valid substitute for + * the one of substituteMethod + */ +boolean isReturnTypeSubstituable(MethodBinding substituteMethod, MethodBinding existingMethod) { + class ReturnTypeSubstitution implements Substitution { + TypeBinding replaced, replacer; + ReturnTypeSubstitution(TypeBinding replaced, TypeBinding replacer) { + this.replaced = replaced; + this.replacer = replacer; + } + public LookupEnvironment environment() { + return environment; + } + public boolean isRawSubstitution() { + return false; + } + public TypeBinding substitute(TypeVariableBinding typeVariable) { + return typeVariable == replaced ? replacer : typeVariable; + } + } + if (substituteMethod.returnType instanceof TypeVariableBinding) { + return ((TypeVariableBinding) substituteMethod.returnType). + boundCheck( + new ReturnTypeSubstitution(substituteMethod.returnType, existingMethod.returnType), + existingMethod.returnType) == TypeConstants.OK; + } else if (substituteMethod.returnType instanceof ParameterizedTypeBinding) { + if (! (existingMethod.returnType instanceof ParameterizedTypeBinding)) { + return false; + } + ParameterizedTypeBinding substituteReturnType = (ParameterizedTypeBinding) substituteMethod.returnType, + existingReturnType = (ParameterizedTypeBinding) existingMethod.returnType; + if (substituteReturnType.type != existingReturnType.type) { + return false; + } + for (int i = 0; i < substituteReturnType.arguments.length; i++) { + TypeBinding substituteArgumentType, existingArgumentType; + if (! (existingArgumentType = existingReturnType.arguments[i]).isCompatibleWith( + substituteArgumentType = substituteReturnType.arguments[i])) { + if (substituteArgumentType instanceof TypeVariableBinding) { + if (((TypeVariableBinding) substituteArgumentType). + boundCheck( + new ReturnTypeSubstitution(substituteArgumentType, existingArgumentType), + // we do not address the most general pattern of multiple type variables, nor the recursive case either + existingArgumentType) != TypeConstants.OK) { + return false; + } + } else { + return false; + } + } + } + return true; + } + return false; +} SimpleSet findSuperinterfaceCollisions(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) { ReferenceBinding[] interfacesToVisit = null; int nextPosition = 0; Index: buildnotes_jdt-core.html =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/buildnotes_jdt-core.html,v retrieving revision 1.5645 diff -u -r1.5645 buildnotes_jdt-core.html --- buildnotes_jdt-core.html 23 Jan 2007 14:59:23 -0000 1.5645 +++ buildnotes_jdt-core.html 24 Jan 2007 08:04:46 -0000 @@ -172,7 +172,9 @@

Problem Reports Fixed

-171066 +162073 +[compiler] extraneous interface compatibility error +
171066 Provide TextEdit when sorting compilation unit
170318 [1.5][compiler] improve message on nameclash when overriding method with "wildcard" parameter