Fix ICE due to intersection types appearing as erasure casts.

Ideally a cast should be inserted that matches the context but
that information is not directly available and some redesign
would be needed.

This patch makes the compiler insert all the casts in the intersection
type.

Bug: #9476
Bug-Link: https://github.com/gwtproject/gwt/issues/9476
Change-Id: I753986c74f078422a4acdabedcce421f7a512e40
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
index f89f10d..fb03ec8 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
@@ -362,6 +362,7 @@
   }
 
   public static String signature(TypeBinding binding) {
+    assert !binding.isIntersectionType18() && !binding.isIntersectionType();
     if (binding.isBaseType()) {
       return String.valueOf(binding.sourceName());
     } else {
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 dbdba1c..b6c10c3 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
@@ -862,12 +862,12 @@
         JExpression instance = pop(x.receiver);
         JExpression expr = createFieldRef(instance, info, fieldBinding);
         if (x.genericCast != null) {
-          JType castType = typeMap.get(x.genericCast);
+          JType[] castTypes = processCastType(x.genericCast);
           /*
            * Note, this may result in an invalid AST due to an LHS cast
            * operation. We fix this up in FixAssignmentsToUnboxOrCast.
            */
-          expr = maybeCast(castType, expr);
+          expr = maybeCast(castTypes, expr);
         }
         push(expr);
       } catch (Throwable e) {
@@ -1558,10 +1558,10 @@
         methodCall.addArgs(arguments);
 
         if (x.valueCast != null) {
-          JType targetType = typeMap.get(x.valueCast);
+          JType[] targetTypes = processCastType(x.valueCast);
           push(isUncheckedGenericMethodCall(x)
-              ? maybeInsertUnsafeTypeCoersion(targetType, methodCall)
-              : maybeCast(targetType, methodCall));
+              ? maybeInsertUnsafeTypeCoersion(targetTypes[0], methodCall)
+              : maybeCast(targetTypes, methodCall));
         } else {
           push(methodCall);
         }
@@ -3070,12 +3070,18 @@
       return original;
     }
 
+    private JExpression maybeCast(JType[] expected, JExpression expression) {
+      for (JType type : expected) {
+        expression = maybeCast(type, expression);
+      }
+      return expression;
+    }
+
     private JExpression maybeCast(JType expected, JExpression expression) {
       if (expected != expression.getType()) {
         // Must be a generic cast; insert a cast operation.
         return new JCastOperation(expression.getSourceInfo(), expected, expression);
       }
-
       return expression;
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index 46453a4..1a9c4a3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -142,6 +142,8 @@
       }
       return arrayType;
     } else {
+      assert binding.isClass() || binding.isInterface() || binding.isEnum()
+          : "Expecting a declared type binding but got " + binding;
       ReferenceBinding refBinding = (ReferenceBinding) binding;
       JDeclaredType declType = createType(refBinding);
       try {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
index 79728e7..cbf53f1 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/GwtAstBuilderTest.java
@@ -26,12 +26,17 @@
 import com.google.gwt.dev.jjs.JavaAstConstructor;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JArrayType;
+import com.google.gwt.dev.jjs.ast.JCastOperation;
 import com.google.gwt.dev.jjs.ast.JClassLiteral;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JExpressionStatement;
 import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodBody;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
+import com.google.gwt.dev.jjs.ast.JStatement;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JVariable;
 import com.google.gwt.dev.jjs.ast.JVisitor;
@@ -40,6 +45,7 @@
 import com.google.gwt.thirdparty.guava.common.collect.Lists;
 import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -137,8 +143,8 @@
     sources.add(JavaResourceBase.createMockJavaResource("test.DalTile",
         "package test;",
         "public class DalTile {"
-        + "{ new DalRow().getTiles();"
-        + "}",
+            + "{ new DalRow().getTiles();"
+            + "}",
         "}"
     ));
 
@@ -146,30 +152,30 @@
         "package test;",
         "public class DalGrid {",
         "  public DalNavigationTile getNavigationTile() {"
-        + "  DalRow row = new DalRow();"
-        + "  DalNavigationTile found = null;"
-        + "  for (DalTile dalTile : row.getTiles()) {"
-        + "    if (dalTile instanceof DalNavigationTile) {"
-        + "      found = (DalNavigationTile) dalTile;"
-        + "      break;"
-        + "    }"
-        + "  }"
-        + "  return found;"
-        + "}",
+            + "  DalRow row = new DalRow();"
+            + "  DalNavigationTile found = null;"
+            + "  for (DalTile dalTile : row.getTiles()) {"
+            + "    if (dalTile instanceof DalNavigationTile) {"
+            + "      found = (DalNavigationTile) dalTile;"
+            + "      break;"
+            + "    }"
+            + "  }"
+            + "  return found;"
+            + "}",
         "}"
     ));
 
     sources.add(JavaResourceBase.createMockJavaResource("test.DalRow",
         "package test;",
         "public class DalRow {"
-        + "  public DalTile[] getTiles() {"
-        + "    int length = 5;"
-        + "    DalTile[] result = new DalTile[length];"
-        + "    for (int i = 0; i < length; i++) {"
-        + "      result[i] = new DalTile();"
-        + "    }"
-        + "    return result;"
-        + "  }",
+            + "  public DalTile[] getTiles() {"
+            + "    int length = 5;"
+            + "    DalTile[] result = new DalTile[length];"
+            + "    for (int i = 0; i < length; i++) {"
+            + "      result[i] = new DalTile();"
+            + "    }"
+            + "    return result;"
+            + "  }",
         "}"
     ));
 
@@ -217,7 +223,6 @@
     JDeclaredType lambdaNested = program.getFromTypeMap("test.NestedClasses$lambda$0$Type");
     assertEquals(JDeclaredType.NestedClassDisposition.LAMBDA, lambdaNested.getClassDisposition());
 
-
     JDeclaredType referenceNested =
         program.getFromTypeMap("test.NestedClasses$0methodref$referencedMethod$Type");
     assertEquals(JDeclaredType.NestedClassDisposition.LAMBDA,
@@ -231,6 +236,46 @@
         .getClassDisposition());
   }
 
+  public void testIntersectionBound() throws UnableToCompleteException {
+    sourceLevel = SourceLevel.JAVA8;
+
+    sources.add(JavaResourceBase.createMockJavaResource("test.IntersectionBound",
+        "package test;",
+        "public class IntersectionBound {",
+        "  public void main() {",
+        "    get().f();",
+        "    get().g();",
+        "    get().h();",
+        "  }",
+        "  public interface A<T> { void f(); }",
+        "  public interface B { void g(); }",
+        "  public interface C { void h(); }",
+        "  <T extends B & A<String> & C> T get() { return null;} ",
+        "}"
+    ));
+
+    JProgram program = compileProgram("test.IntersectionBound");
+    JMethod mainMethod = findQualifiedMethod(program, "test.IntersectionBound.main");
+    for (JStatement statement : ((JMethodBody) mainMethod.getBody()).getStatements()) {
+      // TODO: should have inserted only a cast to the type needed in the specific context context,
+      // but that would require some redesign. For now make sure all the casts from the intersection
+      // type are emitted.
+      JExpression maybeCastOperation =
+          ((JMethodCall) ((JExpressionStatement) statement).getExpr()).getInstance();
+      Set<String> castToTypeNames = Sets.newHashSet();
+      while (maybeCastOperation instanceof  JCastOperation) {
+        JCastOperation castOperation = (JCastOperation) maybeCastOperation;
+        castToTypeNames.add(castOperation.getCastType().getName());
+        maybeCastOperation = castOperation.getExpr();
+      }
+
+      assertEquals(
+          Sets.newHashSet(Arrays.asList(
+              "test.IntersectionBound$A", "test.IntersectionBound$B", "test.IntersectionBound$C")),
+          castToTypeNames);
+    }
+  }
+
   public void testUniqueArrayTypeInstance() throws UnableToCompleteException {
     JProgram program = compileProgram("test.DalGrid");
     Set<String> arrayTypeNames = Sets.newHashSet();
@@ -250,7 +295,7 @@
   private CompilationState buildCompilationState() throws UnableToCompleteException {
     CompilerContext compilerContext =
         new CompilerContext.Builder().options(new PrecompileTaskOptionsImpl() {
-            @Override
+          @Override
           public boolean shouldJDTInlineCompileTimeConstants() {
             return false;
           }
@@ -264,7 +309,7 @@
 
   private JProgram compileProgram(String entryType) throws UnableToCompleteException {
     CompilerContext compilerContext = provideCompilerContext();
-;
+    ;
     CompilationState state = CompilationStateBuilder.buildFrom(logger, compilerContext, sources,
         getAdditionalTypeProviderDelegate());
     JProgram program = JavaAstConstructor.construct(logger, state, compilerContext,