SUGGESTED FIX
a webrev of this fix is available at the folllowing URL
http://sa.sfbay.sun.com/projects/langtools_data/7/6500343
|
|
|
WORK AROUND
add an explicit cast as in:
class Base {}
interface I {}
class A1 extends Base implements I {}
class A2 extends Base implements I {}
class Test {
Object crash(I i, A1 a1, A2 a2, boolean b1, boolean b2) {
return b1 ? i : b2 ? a2 : (I)a1;
}
}
or (in the original example):
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class Test extends JCheckBox implements TableCellRenderer {
protected TableCellRenderer getCellRenderer(JTable aTable) {
return aTable.getRowCount() == 0 ? aTable.getDefaultRenderer(Object.class)
: aTable.getRowCount() == 1 ? (TableCellRenderer)new Test() //cast here!!
: new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(JTable aTable, Object aValue,
boolean aSelectedFlag, boolean aHasFocusFlag, int aRowIndex, int aColumnIndex) {
return this;
}
};
}
public Component getTableCellRendererComponent(JTable aTable, Object aValue, boolean aSelectedFlag
, boolean aHasFocusFlag, int aRow, int aColumn) {
return this;
}
}
|
|
|
EVALUATION
JLS 15.25 says that, given a conditional expression of the kind:
a ? b : c
the type of this expression could be determined as follows (skipping unrelevant parts)
"[...]Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (??5.1.10) to lub(T1, T2) (??15.12.2.7)"
full description of lub is given in JLS 15.12.2.7; what it matters here is that, given two non-generic types T1 and T2, lub(T1,T2) = S1 & S2.& ... Sn, where S1, S2 ... Sn are the common supertypes between T1 and T2
In our case (simplified test-case) whe have that the expression is:
b1 ? i : b2 ? a2 : a1
then, accordingly to the above description the type of this expression should be:
lub(I, lub(A1, A2)) = lub(I, Base & I) = I
However, a bug in javac's Lower phase, prevents the compiler to type this expression correctly; here's what the compiler does:
*) type of true-part of the conditional expression is erased --> erasure(I) = I
*) type of false-part of the conditional expression is erased --> erasure(Base&I) = Base
at this point code generation fails since there's no way to merge the types I and Base.
The compiler should have inserted a cast expression when removing the synthetic intersection type in order to coerce the type of the false-part of the conditional expression to match the (previously attributed) type of the whole conditional expression (that we have shown to be I).
This missing synthetic cast is causing the failure.
Actually, this bug cannot be regarded as a regression, as all the compiler I tried (both 5, 6 an d 7) share the same buggy behaviour. If you try to compile this test-case with an elder compiler (1.4 or previous), the program is rejected, as conditional expression were typed differently in JLS 2 (because Java 1.4 is lacking lub and intersection types). Below is reported the former JLS typing rules for conditional expression:
"If the second and third operands are of different reference types, then it must be possible to convert one of the types to the other type (call this latter type T) by assignment conversion (??5.2); the type of the conditional expression is T. It is a compile-time error if neither type is assignment compatible with the other type."
Since in this case we have that neither Base <: I nor I <: Base, an 1.4 compiler would have rejected the submitted program.
For the above reasons, this hould be regarded as a simple bug in Lower.java, as javac doesn't take into account that the type of a conditional expression could be a synthetic type like an intersection type generated by lub.
|
|
|
EVALUATION
The operand stack has an incompatible type while joining a new state.
The type on the operand stack is javax.swing.JComponet, while the new
type is javax.swing.table.TableCellRenderer. Looks like the compiler
pushes a wrong type on the operand stack while resolving jump targets.
|
|
|
|