Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6923689

Enhanced for loop with unsafe generics is incorrectly desugared.

    XMLWordPrintable

Details

    • rc
    • x86
    • windows_xp
    • Verified

    Description

      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 ----------

      Attachments

        Issue Links

          Activity

            People

              dlsmith Dan Smith
              ndcosta Nelson Dcosta (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: