ForeachStatement fix for GwtAstBuilder.

Fixes a compile error that occurs with code like this:

interface SubIterator<E> extends Iterator<E> {
}

class Foo implements Iterable<String> {
@Override
public SubIterator<String> iterator() {
return null;
}
}

We were trying to find 'SubIterator.next()' which isn't modeled in JDT.  It turns out JDT has the right answer in a private field.

http://gwt-code-reviews.appspot.com/1450814/

Review by: jbrosenberg@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10313 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 7d0957b..50d98cb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -199,6 +199,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -979,16 +980,7 @@
           // Perform any implicit reference type casts (due to generics).
           // Note this occurs before potential unboxing.
           if (elementVar.getType() != javaLangObject) {
-            /*
-             * Compute the collection element type by walking the iterator()
-             * method, which may be parameterized.
-             */
-            ReferenceBinding collectionType = (ReferenceBinding) x.collection.resolvedType;
-            MethodBinding iteratorMethod =
-                collectionType.getExactMethod(ITERATOR, NO_TYPES, cudScope);
-            ReferenceBinding iteratorType = (ReferenceBinding) iteratorMethod.returnType;
-            MethodBinding nextMethod = iteratorType.getMethods(NEXT)[0];
-            TypeBinding collectionElementType = nextMethod.returnType;
+            TypeBinding collectionElementType = (TypeBinding) collectionElementTypeField.get(x);
             JType toType = typeMap.get(collectionElementType);
             assert (toType instanceof JReferenceType);
             elementDecl.initializer = maybeCast(toType, elementDecl.initializer);
@@ -2762,6 +2754,12 @@
 
   private static final char[] _STRING = "_String".toCharArray();
   private static final String ARRAY_LENGTH_FIELD = "length";
+
+  /**
+   * Reflective access to {@link ForeachStatement#collectionElementType}.
+   */
+  private static final Field collectionElementTypeField;
+
   private static final char[] CREATE_VALUE_OF_MAP = "createValueOfMap".toCharArray();
   private static final char[] HAS_NEXT = "hasNext".toCharArray();
   private static final char[] ITERATOR = "iterator".toCharArray();
@@ -2775,6 +2773,13 @@
 
   static {
     InternalCompilerException.preload();
+    try {
+      collectionElementTypeField = ForeachStatement.class.getDeclaredField("collectionElementType");
+      collectionElementTypeField.setAccessible(true);
+    } catch (Exception e) {
+      throw new RuntimeException(
+          "Unexpectedly unable to access ForeachStatement.collectionElementType via reflection", e);
+    }
   }
 
   static String dotify(char[][] name) {
diff --git a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
index daebfc7..2ba5ddd 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CoverageTest.java
@@ -17,6 +17,9 @@
 
 import com.google.gwt.junit.client.GWTTestCase;
 
+import java.util.Arrays;
+import java.util.Iterator;
+
 /**
  * This test is intended to exercise as many code paths and node types as
  * possible in the Java to JavaScript compiler. This test is not at all intended
@@ -412,9 +415,66 @@
     }
 
     private void testForeachStatement() {
+      // Array of primitive.
       for (int q : ia) {
         i = q;
       }
+      // Array of primitive with unboxing.
+      for (Integer q : ia) {
+        i = q;
+      }
+      // Array of object.
+      for (String str : sa) {
+        s = str;
+      }
+      // Iterable.
+      for (Object obj : Arrays.asList(new Object(), new Object())) {
+        o = obj;
+      }
+      // Iterable with unboxing.
+      for (int q : Arrays.asList(1, 2, 3)) {
+        i = q;
+      }
+      // Iterable with generic cast.
+      for (String str : Arrays.asList(sa)) {
+        s = str;
+      }
+      // Iterable with array element.
+      for (String[] stra : Arrays.asList(sa, sa, sa)) {
+        s = sa[0];
+      }
+      // Iterable Iterator subclass.
+      class SubIterator<T> implements Iterator<T> {
+        private final Iterator<T> it;
+
+        public SubIterator(Iterator<T> it) {
+          this.it = it;
+        }
+
+        @Override
+        public boolean hasNext() {
+          return it.hasNext();
+        }
+
+        @Override
+        public T next() {
+          return it.next();
+        }
+
+        @Override
+        public void remove() {
+          it.remove();
+        }
+      }
+      class SubIterableString implements Iterable<String> {
+        @Override
+        public SubIterator<String> iterator() {
+          return new SubIterator<String>(Arrays.asList(sa).iterator());
+        }
+      }
+      for (String str : new SubIterableString()) {
+        s = str;
+      }
     }
 
     private void testForStatement() {
@@ -751,6 +811,8 @@
 
   public static String s = "foo";
 
+  public static String[] sa = new String[]{"foo", "bar", "bar"};
+
   public static CoverageTest singleton;
 
   public static boolean z;