Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6738538
Votes 0
Synopsis javac crashes when using a type parameter as a covariant method return type
Category java:compiler
Reported Against
Release Fixed 7(b39)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs 6687444 , 6718388
Submit Date 19-AUG-2008
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 :
 customer  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.
Posted Date : 2008-08-19 04:44:14.0
Work Around
N/A
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).
Posted Date : 2008-08-19 11:26:40.0

This bug can be fixed by applying capture conversion before accessing members of an intersection type - as described in 6718388
Posted Date : 2008-09-09 15:56:47.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang