United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6548436 Incorrect inconvertible types error
JDK-6548436 : Incorrect inconvertible types error

Details
Type:
Bug
Submit Date:
2007-04-20
Status:
Closed
Updated Date:
2011-05-18
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
tools
OS:
linux,generic,windows_xp
Sub-Component:
javac
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
6,6u14
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Backport:
Duplicate:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Linux lotp-laptop 2.6.20-15-generic #2 SMP Sun Apr 15 07:36:31 UTC 2007 i686 GNU

A DESCRIPTION OF THE PROBLEM :
In some cases javac outputs errors about inconvertible types. The circumstances in which this happens seem to be rather complicated. Trying to reduce the problem to a canonical form eradicates it.

Full discussion can be found at http://forum.java.sun.com/thread.jspa?threadID=5162196&tstart=0

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Try to compile the supplied source code example.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should compile without errors
ACTUAL -
javac outputs the following errors:

javac Bug.java
  Bug.java:27: inconvertible types
found   : JETEvent<capture#608 of ?>
required: FSDEvent
                if(event == null || ! (event instanceof FSDEvent)) { // <-- doesn't compile
                                       ^
  Bug.java:30: inconvertible types
found   : JETEvent<capture#870 of ?>
required: FSDEvent
                FSDEvent fsdEvent = (FSDEvent)event;
                                              ^
2 errors

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

abstract class JETEvent<E extends Enum<E>> {}
 
class FSDEvent extends JETEvent<FSDEvent.SUBTYPE> {
    public enum SUBTYPE {
	TYPE_A,
	TYPE_B
    }
}
 
interface State<T extends Task> {
    public Transition<T> getTransition(JETEvent<?> event);
}
 
class DefaultState<T extends Task> implements State<T> {
    public Transition<T> getTransition(JETEvent<?> event) {
    	return null;
    }
}
 
class FSDState extends DefaultState<FSDTask> {
	@Override
	public FSDTransition getTransition(JETEvent<?> event) {
		if(event == null || ! (event instanceof FSDEvent)) { // <-- doesn't compile
			return null;
		}
		FSDEvent fsdEvent = (FSDEvent)event; // <-- doesn't compile either
		return null;
        }
}
 
interface Task<T extends Task> {}
 
class FSDTask extends DefaultTask<FSDTask> {}
 
class DefaultTask<T extends DefaultTask> implements Task<T> {}
 
interface Transition<T extends Task> {}
 
class DefaultTransition<T extends Task> implements Transition<T> {}
 
class FSDTransition extends DefaultTransition<FSDTask> {}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Casting to Object first solves the problem. The two problematic lines must be

if(event == null || ! ((Object)event instanceof FSDEvent)) { // <-- This compiles
FSDEvent fsdEvent = (FSDEvent)(Object)event; // <-- This now also compiles

for the compilation to work

Release Regression From : 5.0u11
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

Release Regression From : 5.0u11
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
EVALUATION

This problem is due to the function Types.notSoftSubtype exploiting a containment relation that is too strong for the purposes of a cast conversion.

In fact, when the type Base<?> is cast converted to the type Base<Integer>, the method notSoftSubtypes is invoked (as part of the algorithm for proving distinctess of type arguments) on the two type arguments namely ? and Integer.

This method is in charge for answering this question: is it impossible that a given type X can ever be a subtype of another type Y?

In this case: it is impossible that Integer is a subtype of #Cap, where ub(#Cap) === Comparable<#Cap> ?

Following standard subtyping rules the answer is: yes, it's impossible, as:

Integer <: ub(#Cap) = Comparable<#Cap> (the algorithm starts by computing ub of rhs)
Comparable<Integer> <: Comparable<#Cap>
Integer <= #Cap No, no type-containment defined for captured type variables, see JLS 4.5.1.1)

However this is not the right answer, as there is a possibility that types Integer and #Cap are indeed related (e.g. if #Cap happens to *be* Integer - which means that the type behind the wildcard that has been captured converted was an Integer).
 
To solve this problem the containment relation to be used ONLY within notSoftSubtype should be weakened so that:

Integer <= #Cap iff lb(#Cap) <: Integer <: ub(#Cap)

in other words if Integer fit the bounds of the captured type-variable. Note that since #Cap has an fbound (Comparable<#Cap>) special handling is required, otherwise we end up in repeating the same test again and again as:

Integer <= #Cap
Integer <: ub(#Cap)
Integer <: Comparable<#Cap>
Comparabe<Integer> <: Comparable<#Cap>
Integer <= #Cap //oops, back where we started

In fact the correct formula is

Integer <: #Cap iff [Integer/#Cap]lb(#Cap) <: Integer <: [Integer/#Cap]ub(#Cap)

where the notation [Integer/#Cap]T means that we have to replace each occurrence of #Cap with Integer in the type T.
                                     
2008-02-29
SUGGESTED FIX

A webrev of this fix is available at the following URL
http://hg.openjdk.java.net/jdk7/tl/langtools/rev/433ee48257c0
                                     
2008-02-29
SUGGESTED FIX

An interesting idea would be to make the subtyping relation exploited within Types.java parameterized in another TypeRelation representing the type-containment relation to be used within that given subtyping test. Thi solution would allow the code to be more readable and to maximize the reuse of existing subtyping and type-containment algorithms. Some care is required since when no explicit type-containment relation is given to the subtyping algorithm javac should default to the JLS relation (this way we *override* the behaviour of subtyping only when we want to, e.g. during cast).
                                     
2008-02-29
EVALUATION

Fixing this requires also adding some additional subtyping rules between intersection types. Given a classtype D and an intersection type S = C & I1 & I2 ... & In we say that D <: S iff D <: C, D <: I1, D <: I2 ... , D <: In

This rule is needed e.g. to prove that:

Integer <: Number & Comparable<Integer>

in fact

1) Integer <: Number
2) Integer <: Comparable<Integer>

Note however that the above rules are not part of the JLS (neither section 4.9 - intersection types - nor 4.10 - subtyping).

Alex seems to agree with the above rules.
                                     
2008-02-29
EVALUATION

Note that this problems might seem to be caused by an unnecessary capture conversion being applied to the expression of a cast (if instead of Base<#Cap> we'd have simply Base<?> things would have been much more easier!). We could in principle remove the redundant capture conversion when attributing the target expression of a cast, but we'd still have problems in a more general example as the following:

class Base<E extends Comparable<E>> {
    Base<E> base;
    void m(Base<?> je) {        
        Object o = (Base<Integer>)je.base;
    }
}

Here we have that the 'je' MUST be capture converted before the field access (accordingly to the JLS). This results in accessing the 'base' field on an instance of type Base<#Cap> and, since 'base' is again of type Base<E>, we end up in the exactly same erroeous behavior we described above.
                                     
2008-02-29
EVALUATION

This fix requires a minor change to the subtyping between intersection types. I filed the spec rfe 6718388 for this.
                                     
2008-07-24
EVALUATION

Looks like a bug in the cast implementation.
                                     
2007-05-15



Hardware and Software, Engineered to Work Together