JDK-6738538 : javac crashes when using a type parameter as a covariant method return type
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6,7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_xp
  • CPU: generic,x86
  • Submitted: 2008-08-19
  • Updated: 2012-10-01
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b39Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_10-rc"
Java(TM) SE Runtime Environment (build 1.6.0_10-rc-b28)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
Linux 2.6.22-14-generic i686 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
When trying to compile the two sample files attached to this case, javac crashes. The crash is probably caused while parsing the line "public T getObject()" in the class GraphNode<T> .

Please note that this problem only happens when the classes and interfaces are distributed over two source files (as seen in the Workarounds section)

This was tested with 1.6.0_03 (Windows + Linux) as well as with javac 1.6.0_10-rc (Windows)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create the two files from the sample source code attached to this case
2. javac *.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The two files are compiled properly although I'm not too sure about this. It might also be a case that should lead to a compiler error.
ACTUAL -
javac crashes

ERROR MESSAGES/STACK TRACES THAT OCCUR :
An exception has occurred in the compiler (1.6.0_10-rc). Please file a bug at th
e Java Developer Connection (http://java.sun.com/webapps/bugreport)  after check
ing the Bug Parade for duplicates. Include your program and the following diagno
stic in your report.  Thank you.
java.lang.AssertionError: isSubtype 15
        at com.sun.tools.javac.code.Types$5.visitType(Types.java:347)
        at com.sun.tools.javac.code.Types$5.visitType(Types.java:328)
        at com.sun.tools.javac.code.Types$DefaultTypeVisitor.visitWildcardType(T
ypes.java:3163)
        at com.sun.tools.javac.code.Type$WildcardType.accept(Type.java:416)
        at com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:31
61)
        at com.sun.tools.javac.code.Types.isSubtype(Types.java:324)
        at com.sun.tools.javac.code.Types.isSubtype(Types.java:308)
        at com.sun.tools.javac.code.Types.isSubtypeUnchecked(Types.java:288)
        at com.sun.tools.javac.code.Types.isConvertible(Types.java:257)
        at com.sun.tools.javac.code.Types.isAssignable(Types.java:1476)
        at com.sun.tools.javac.code.Types.covariantReturnType(Types.java:2677)
        at com.sun.tools.javac.code.Types.returnTypeSubstitutable(Types.java:266
1)
        at com.sun.tools.javac.comp.Check.checkOverride(Check.java:1120)
        at com.sun.tools.javac.comp.Check.checkImplementations(Check.java:1540)
        at com.sun.tools.javac.comp.Check.checkImplementations(Check.java:1515)
        at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:2693)
        at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2628)
        at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2564)
        at com.sun.tools.javac.comp.Attr.attribBounds(Attr.java:442)
        at com.sun.tools.javac.comp.MemberEnter.finishClass(MemberEnter.java:409
)
        at com.sun.tools.javac.comp.MemberEnter.finish(MemberEnter.java:1000)
        at com.sun.tools.javac.comp.MemberEnter.complete(MemberEnter.java:967)
        at com.sun.tools.javac.code.Symbol.complete(Symbol.java:386)
        at com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:758)

        at com.sun.tools.javac.comp.Enter.complete(Enter.java:451)
        at com.sun.tools.javac.comp.Enter.main(Enter.java:429)
        at com.sun.tools.javac.main.JavaCompiler.enterTrees(JavaCompiler.java:81
9)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:727)
        at com.sun.tools.javac.main.Main.compile(Main.java:353)
        at com.sun.tools.javac.main.Main.compile(Main.java:279)
        at com.sun.tools.javac.main.Main.compile(Main.java:270)
        at com.sun.tools.javac.Main.compile(Main.java:69)
        at com.sun.tools.javac.Main.main(Main.java:54)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// File GraphNode.java

interface IObjectNode
{
	Object getObject();
}

public class GraphNode<T> implements IObjectNode
{
	// The important line is the following one
	public T getObject()
	{
		return null;
	}
}

// File UnusedObject.java

interface ISelectableNode
{
	boolean isSelected();
}

public class UnusedObject<NodeType extends GraphNode<?> & ISelectableNode>
{
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
1. Use type "Object" instead of type "T" as the return method of getObject in class GraphNode<T>

OR

2. Change "class UnusedObject<NodeType extends GraphNode<?> & ISelectableNode>" to "class UnusedObject<NodeType extends GraphNode & ISelectableNode>"

OR

3. Move all interfaces and classes into the same file.

Comments
SUGGESTED FIX A webrev of this fix is available at the following URL http://sa.sfbay.sun.com/projects/langtools_data/7/6738538
09-10-2008

EVALUATION This bug can be fixed by applying capture conversion before accessing members of an intersection type - as described in 6718388
09-09-2008

EVALUATION This bug is due to the interplay of the following factors (in order of relevance): *) Type variable with multiple bounds *) Wildcards *) Covariant overriding checking That is, when javac encounter a type-variable with multiple bounds, a synthetic classtype is generated (the type of a class extending the class bound and implementing any interface bound defined in the typevar declaration). Such a type is then attributed, and this is when problem start; in our case the synthetic type is: class T extends A<?> implements Serializable Obviously Serializable is unrelevant here (any interface will work here). The important bits are in the extends clause; as it can be seen, this synthetic supertype A<?> is, to some extents, ill-formed; the JLS requires that a supertype must not have wildcards in its outermost type arguments (so that A<A<?>> is a proper supertype, while A<?>, A<? extends String> is not) - see JLS 8.1.4, 8.1.5 This means that javac is in a quite strange situation here; among the problems, it can be seen that a member of this synthetic type is the method ? m() - that is A.m() where the return type (X in the supertype) has been substituted with the 'actual' parameter '?'. When javac checks that A<?>.m() overrides I.m() a problem occurs, since the following subtyping test is issued ? <: Object At this point javac crashes with an assertion error, as the LHS of a subtyping judgment must not be a wildcard. An obvious solution would be to capture the supertypes of such synthetic generated types, so that the supertype would become A<#>, where # <: Object. This solution has the side-effect of removing any toplevel wildcard from the subtypes of a given synthetic class (non-synthetic class' suoertypes can be left unchanged, as this situation cannot occur). However, capturing supertypes could result in dangerous uncompatibilities; moreover, javac is known not to handle captured types correctly, esp. during subtyping test. I think that a more conservative fix would be to adjust the covariant method checking routine in order to handle return types that are wildcard types. I'm afraid that nothing more than this can be done until JLS 4.5.2 is fixed (which are the members of a wildcard types? The JLS says that members are of an unspecified type, but that this has no consequences, because of the restriction which applies to wildcards; as it can be seen in the example reported in this CR, this is not true and this issue shold be tackled). Actually, an even better fix would be to disable override checking completely for synthetic compound classtypes (as those types do not define any member); the only required checking is supertypes well-formedness, in order to be able to catch errors like the following: interface I1 { String m(); interface I2 { Integer m(); } class<X extends Object & I1 & I2> {} //should be flagged as error The above code should *not* compile, as I1.m() and I2.m() cannot coexhist (same signature, unrelated return types).
19-08-2008