### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java,v retrieving revision 1.168 diff -u -r1.168 CodeStream.java --- compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java 25 Sep 2008 23:10:29 -0000 1.168 +++ compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java 26 Sep 2008 16:47:43 -0000 @@ -2932,10 +2932,9 @@ * @param codegenBinding * @param actualReceiverType * @param isImplicitThisReceiver - * @param hasGenericCast * @return the receiver type to use in constant pool */ -public static TypeBinding getConstantPoolDeclaringClass(Scope currentScope, MethodBinding codegenBinding, TypeBinding actualReceiverType, boolean isImplicitThisReceiver, boolean hasGenericCast) { +public static TypeBinding getConstantPoolDeclaringClass(Scope currentScope, MethodBinding codegenBinding, TypeBinding actualReceiverType, boolean isImplicitThisReceiver) { TypeBinding constantPoolDeclaringClass = codegenBinding.declaringClass; // Post 1.4.0 target, array clone() invocations are qualified with array type // This is handled in array type #clone method binding resolution (see Scope and UpdatedMethodBinding) @@ -2949,7 +2948,7 @@ // for runtime compatibility on 1.2 VMs : change the declaring class of the binding // NOTE: from target 1.2 on, method's declaring class is touched if any different from receiver type // and not from Object or implicit static method call. - if (constantPoolDeclaringClass != actualReceiverType.erasure() && !hasGenericCast && !actualReceiverType.isArrayType()) { + if (constantPoolDeclaringClass != actualReceiverType.erasure() && !actualReceiverType.isArrayType()) { CompilerOptions options = currentScope.compilerOptions(); if ((options.targetJDK >= ClassFileConstants.JDK1_2 && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(isImplicitThisReceiver && codegenBinding.isStatic())) Index: eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java,v retrieving revision 1.59 diff -u -r1.59 CodeSnippetMessageSend.java --- eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java 25 Sep 2008 23:10:29 -0000 1.59 +++ eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java 26 Sep 2008 16:47:44 -0000 @@ -51,7 +51,8 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { int pc = codeStream.position; MethodBinding codegenBinding = this.binding.original(); - if (codegenBinding.canBeSeenBy(this.actualReceiverType, this, currentScope)) { + TypeBinding codeGenReceiverType = this.actualReceiverType; + if (codegenBinding.canBeSeenBy(codeGenReceiverType, this, currentScope)) { // generate receiver/enclosing instance access boolean isStatic = codegenBinding.isStatic(); // outer access ? @@ -67,14 +68,18 @@ } } else { this.receiver.generateCode(currentScope, codeStream, !isStatic); - if (this.receiverGenericCast != null) - codeStream.checkcast(this.receiverGenericCast); + // compute generic cast if necessary + TypeBinding upperBound = ((ReferenceBinding) codeGenReceiverType).getReceiverTypeErasure(this.binding.declaringClass); + if (upperBound != null && upperBound != codeGenReceiverType.erasure()) { + codeStream.checkcast(upperBound); // handle indirect inheritance thru variable secondary bound + codeGenReceiverType = upperBound; + } codeStream.recordPositionsFrom(pc, this.sourceStart); } // generate arguments generateArguments(this.binding, this.arguments, currentScope, codeStream); // actual message invocation - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis(), this.receiverGenericCast != null); + TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, codeGenReceiverType, this.receiver.isImplicitThis()); if (isStatic) { codeStream.invoke(Opcodes.OPC_invokestatic, codegenBinding, constantPoolDeclaringClass); } else if( (this.receiver.isSuper()) || codegenBinding.isPrivate()){ @@ -96,8 +101,13 @@ currentScope.problemReporter().needImplementation(this); } else { this.receiver.generateCode(currentScope, codeStream, !isStatic); - if (this.receiverGenericCast != null) - codeStream.checkcast(this.receiverGenericCast); + // compute generic cast if necessary + TypeBinding upperBound = codeGenReceiverType.getReceiverTypeErasure(this.binding.declaringClass); + if (upperBound != null && upperBound != codeGenReceiverType.erasure()) { + codeStream.checkcast(upperBound); // handle indirect inheritance thru variable secondary bound + codeGenReceiverType = upperBound; + } + codeStream.recordPositionsFrom(pc, this.sourceStart); } if (isStatic) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java,v retrieving revision 1.121 diff -u -r1.121 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 25 Sep 2008 23:10:29 -0000 1.121 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 26 Sep 2008 16:47:42 -0000 @@ -545,12 +545,11 @@ scope.problemReporter().invalidField(this, this.actualReceiverType); return null; } - TypeBinding receiverErasure = this.actualReceiverType.erasure(); - if (receiverErasure instanceof ReferenceBinding) { - if (receiverErasure.findSuperTypeOriginatingFrom(fieldBinding.declaringClass) == null) { - this.actualReceiverType = fieldBinding.declaringClass; // handle indirect inheritance thru variable secondary bound - } - } + // compute generic cast if necessary + TypeBinding upperBound = this.actualReceiverType.getReceiverTypeErasure(fieldBinding.declaringClass); + if (upperBound != null && upperBound != this.actualReceiverType.erasure()) { + this.actualReceiverType = upperBound; // handle indirect inheritance thru variable secondary bound + } this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & ASTNode.IsStrictlyAssigned) !=0)) { scope.problemReporter().deprecatedField(fieldBinding, this); Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v retrieving revision 1.135 diff -u -r1.135 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 25 Sep 2008 23:10:29 -0000 1.135 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 26 Sep 2008 16:47:43 -0000 @@ -50,7 +50,6 @@ public long nameSourcePosition ; //(start<<32)+end public TypeBinding actualReceiverType; - public TypeBinding receiverGenericCast; // extra reference type cast to perform on generic receiver public TypeBinding valueCast; // extra reference type cast to perform on method returned value public TypeReference[] typeArguments; public TypeBinding[] genericTypeArguments; @@ -123,12 +122,11 @@ * @param valueRequired boolean */ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - // generate receiver/enclosing instance access MethodBinding codegenBinding = this.binding.original(); boolean isStatic = codegenBinding.isStatic(); + TypeBinding codeGenReceiverType = this.actualReceiverType; if (isStatic) { this.receiver.generateCode(currentScope, codeStream, false); codeStream.recordPositionsFrom(pc, this.sourceStart); @@ -139,17 +137,14 @@ codeStream.generateOuterAccess(path, this, targetType, currentScope); } else { this.receiver.generateCode(currentScope, codeStream, true); - if (this.receiverGenericCast != null) - codeStream.checkcast(this.receiverGenericCast); codeStream.recordPositionsFrom(pc, this.sourceStart); - } // generate arguments generateArguments(this.binding, this.arguments, currentScope, codeStream); // actual message invocation if (this.syntheticAccessor == null){ - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis(), this.receiverGenericCast != null); + TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, codeGenReceiverType, this.receiver.isImplicitThis()); if (isStatic){ codeStream.invoke(Opcodes.OPC_invokestatic, codegenBinding, constantPoolDeclaringClass); } else if( (this.receiver.isSuper()) || codegenBinding.isPrivate()){ @@ -443,6 +438,11 @@ if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInMethod(this, this.binding); } + // compute generic cast if necessary + TypeBinding upperBound = this.actualReceiverType.getReceiverTypeErasure(this.binding.declaringClass); + if (upperBound != null && upperBound != this.actualReceiverType.erasure()) { + this.actualReceiverType = upperBound; // handle indirect inheritance thru variable secondary bound + } final CompilerOptions compilerOptions = scope.compilerOptions(); if (!this.binding.isStatic()) { // the "receiver" must not be a type @@ -455,13 +455,6 @@ } } else { this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); - // compute generic cast if necessary - TypeBinding receiverErasure = this.actualReceiverType.erasure(); - if (receiverErasure instanceof ReferenceBinding) { - if (receiverErasure.findSuperTypeOriginatingFrom(this.binding.declaringClass) == null) { - this.receiverGenericCast = this.binding.declaringClass; // handle indirect inheritance thru variable secondary bound - } - } } } else { // static message invoked through receiver? legal but unoptimal (optional warning). @@ -507,9 +500,7 @@ if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments); } - return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 - ? this.resolvedType - : null; + return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 ? this.resolvedType : null; } public void setActualReceiverType(ReferenceBinding receiverType) { Index: compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java,v retrieving revision 1.101 diff -u -r1.101 TypeBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java 9 Sep 2008 18:40:56 -0000 1.101 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java 26 Sep 2008 16:47:44 -0000 @@ -358,6 +358,45 @@ return signature(); } +/** + * Return erasure for the receiver type which is compatible with a given declaring class. + * This is different from standard erasure when dealing with types with multiple upper bounds where + * the first compatible bound is to be considered. + * NOTE: the declaringClass is already know to be compatible with the receiver + * @param declaringClass to look for + * @return the first compatible bound, or null if none found + */ +public TypeBinding getReceiverTypeErasure(TypeBinding declaringClass) { + switch(kind()) { + case Binding.TYPE_PARAMETER : + TypeVariableBinding variable = (TypeVariableBinding) this; + if (variable.superclass != null && variable.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) { + return variable.superclass.getReceiverTypeErasure(declaringClass); + } + for (int i = 0, otherLength = variable.superInterfaces.length; i < otherLength; i++) { + ReferenceBinding superInterface = variable.superInterfaces[i]; + if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) { + return superInterface.getReceiverTypeErasure(declaringClass); + } + } + return null; // cannot happen if declaringClass is compatible + case Binding.INTERSECTION_TYPE : + WildcardBinding intersection = (WildcardBinding) this; + if (intersection.superclass != null && intersection.superclass.findSuperTypeOriginatingFrom(declaringClass) != null) { + return intersection.superclass.getReceiverTypeErasure(declaringClass); + } + for (int i = 0, otherLength = intersection.superInterfaces.length; i < otherLength; i++) { + ReferenceBinding superInterface = intersection.superInterfaces[i]; + if (superInterface.findSuperTypeOriginatingFrom(declaringClass) != null) { + return superInterface.getReceiverTypeErasure(declaringClass); + } + } + return null; // cannot happen if declaringClass is compatible + default : + return erasure(); + } +} + public abstract PackageBinding getPackage(); void initializeForStaticImports() { #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java,v retrieving revision 1.757 diff -u -r1.757 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 23 Sep 2008 13:00:52 -0000 1.757 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 26 Sep 2008 16:47:52 -0000 @@ -46336,7 +46336,7 @@ "----------\n"); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 -public void _test1381() throws Exception { +public void test1381() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46361,30 +46361,28 @@ "}\n", "p/IB.java", // ===================== "package p;\n" + - "interface IA {\n" + + "interface IA {\n" + // non visible " void baz();\n" + "}\n" + "public interface IB extends IA {\n" + "}\n", }, "done"); - // check #baz() invocation declaring class is IA + // check #baz() invocation declaring class is IB String expectedOutput = - " // Method descriptor #21 (LX;)V\n" + - " // Signature: (LX;)V\n" + - " // Stack: 1, Locals: 2\n" + - " void foo(X xt);\n" + - " 0 aload_1 [xt]\n" + - " 1 invokevirtual X.get() : AA [23]\n" + - " 4 checkcast p.IA [25]\n" + - " 7 invokeinterface p.IA.baz() : void [27] [nargs: 1]\n" + + " // Method descriptor #10 ()V\n" + + " // Stack: 1, Locals: 1\n" + + " void foo();\n" + + " 0 aload_0 [this]\n" + + " 1 getfield X.t : AA [21]\n" + + " 4 checkcast p.IB [23]\n" + + " 7 invokeinterface p.IB.baz() : void [25] [nargs: 1]\n" + " 12 return\n" + " Line numbers:\n" + - " [pc: 0, line: 5]\n" + - " [pc: 12, line: 6]\n" + + " [pc: 0, line: 4]\n" + + " [pc: 12, line: 5]\n" + " Local variable table:\n" + - " [pc: 0, pc: 13] local: this index: 0 type: X\n" + - " [pc: 0, pc: 13] local: xt index: 1 type: X\n"; + " [pc: 0, pc: 13] local: this index: 0 type: X\n"; File f = new File(OUTPUT_DIR + File.separator + "X.class"); byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); @@ -46399,7 +46397,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1382() throws Exception { +public void test1382() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46452,7 +46450,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1383() throws Exception { +public void test1383() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46507,7 +46505,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1384() throws Exception { +public void test1384() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46561,7 +46559,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1385() throws Exception { +public void test1385() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46613,7 +46611,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1386() throws Exception { +public void test1386() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46635,7 +46633,7 @@ "public interface IB extends IA {\n" + "}\n", }, - "111"); + ""); // check #baz() invocation declaring class is not IA String expectedOutput = " // Method descriptor #21 (LX;)V\n" + @@ -46667,7 +46665,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1387() throws Exception { +public void test1387() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46698,21 +46696,22 @@ "done"); // check #baz declaring class is not IA String expectedOutput = - " // Method descriptor #21 (LX;)V\n" + - " // Signature: (LX;)V\n" + - " // Stack: 1, Locals: 2\n" + - " void foo(X xt);\n" + - " 0 aload_1 [xt]\n" + - " 1 invokevirtual X.get() : AA [23]\n" + - " 4 checkcast p.IB [25]\n" + - " 7 invokeinterface p.IB.baz() : void [27] [nargs: 1]\n" + - " 12 return\n" + + " // Method descriptor #10 ()V\n" + + " // Stack: 2, Locals: 1\n" + + " void foo();\n" + + " 0 getstatic java.lang.System.out : java.io.PrintStream [21]\n" + + " 3 aload_0 [this]\n" + + " 4 getfield X.t : AA [27]\n" + + " 7 checkcast p.IB [29]\n" + + " 10 pop\n" + + " 11 getstatic p.IB.baz : java.lang.Object [31]\n" + + " 14 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [35]\n" + + " 17 return\n" + " Line numbers:\n" + - " [pc: 0, line: 5]\n" + - " [pc: 12, line: 6]\n" + + " [pc: 0, line: 4]\n" + + " [pc: 17, line: 5]\n" + " Local variable table:\n" + - " [pc: 0, pc: 13] local: this index: 0 type: X\n" + - " [pc: 0, pc: 13] local: xt index: 1 type: X\n"; + " [pc: 0, pc: 18] local: this index: 0 type: X\n"; File f = new File(OUTPUT_DIR + File.separator + "X.class"); byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f); @@ -46727,7 +46726,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1388() throws Exception { +public void test1388() throws Exception { this.runConformTest( new String[] { "X.java", @@ -46787,7 +46786,7 @@ } } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=247953 - variation -public void _test1389() throws Exception { +public void test1389() throws Exception { this.runConformTest( new String[] { "X.java",