FULL PRODUCT VERSION :
$ java -version
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.6) (fedora-33.b16.fc12-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)
Also latest jdk 1.6 on windows, and jdk 1.7 prerelease.
ADDITIONAL OS VERSION INFORMATION :
(irrelevant).
A DESCRIPTION OF THE PROBLEM :
Attached code contains two loops; one an enhanced for-loop, the other the for-loop manually desugared as per JLS3 14.14.2.
They should behave identically. They do not. The manually desugared loop generates a class-cast exception, while the enhanced for-loop does not.
Inspecting the byte-code output from the compiler, the result of .iterator() is not-being run-time type-checked before being stored to the synthesized variable. Such a check is necessary when the type after erasure differs from the unerased type: the desugar from the JLS is:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
VariableModifiersopt Type Identifier = #i.next();
Statement
}
In the example below, Expression.iterator() has type MyIterator, but after erasure the type is Iterator, and thus a run-time type check is necessary.
Plausibly, this could be resolved by changing the JLS, rather than javac, by specifying the type of #i to be Iterator<Type>, where Type is as per 14.14.2.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.Iterator;
class MyIterable<T extends Iterator<String> > implements Iterable<String> {
public T iterator() { return stored; }
public T stored;
}
class MyIterator implements Iterator<String> {
public boolean hasNext() { return stored.hasNext(); }
public String next() { return stored.next(); }
public void remove() { }
public Iterator<String> stored;
}
public class Temp
{
public static void main(String[] args) {
MyIterable<MyIterator> u = new MyIterable<MyIterator>();
MyIterable unsafe = u;
unsafe.stored = new ArrayList<String>().iterator();
System.out.println ("Sugared....");
for (String s : u)
System.out.println (s);
System.out.println ("Unsugared....");
for (MyIterator i = u.iterator(); i.hasNext(); ) {
String s = i.next();
System.out.println (s);
}
}
}
---------- END SOURCE ----------