Keep illegal invokes illegal.

BUG=

Change-Id: I7b72f0f42f5d85ceea114f54471903e471600818

diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 2d5d803..1eb8707 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -96,7 +96,7 @@
             continue;
           }
           DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method);
-          Invoke.Type invokeType = getInvokeType(invoke, actualTarget);
+          Invoke.Type invokeType = getInvokeType(invoke, actualTarget, invokedMethod);
           if (actualTarget != invokedMethod || invoke.getType() != invokeType) {
             Invoke newInvoke = Invoke
                 .create(invokeType, actualTarget, null,
@@ -228,16 +228,26 @@
     return methodHandle;
   }
 
-  private Type getInvokeType(InvokeMethod invoke, DexMethod actualTarget) {
+  private Type getInvokeType(InvokeMethod invoke, DexMethod actualTarget,
+      DexMethod originalTarget) {
     if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
       // Get the invoke type of the actual definition.
-      DexClass clazz = appInfo.definitionFor(actualTarget.holder);
-      if (clazz == null) {
+      DexClass newTargetClass = appInfo.definitionFor(actualTarget.holder);
+      if (newTargetClass == null) {
         return invoke.getType();
       } else {
-        return clazz.accessFlags.isInterface()
-            ? Type.INTERFACE
-            : Type.VIRTUAL;
+        DexClass originalTargetClass = appInfo.definitionFor(originalTarget.holder);
+        if (originalTargetClass.isInterface() ^ (invoke.getType() == Type.INTERFACE)) {
+          // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
+          // the IncompatibleClassChangeError the original invoke would have triggered.
+          return newTargetClass.accessFlags.isInterface()
+              ? Type.VIRTUAL
+              : Type.INTERFACE;
+        } else {
+          return newTargetClass.accessFlags.isInterface()
+              ? Type.INTERFACE
+              : Type.VIRTUAL;
+        }
       }
     } else {
       return invoke.getType();
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 3fe2173..8c5e094 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -78,13 +78,14 @@
             "java.lang.NullPointerException: Attempt to read from field " +
                 "'Test Test.a' on a null object reference\n"},
         {"merge-blocks-regression", "java.lang.NullPointerException: Attempt to invoke virtual"
-            +" method 'Test Test.bW_()' on a null object reference\n"},
+            + " method 'Test Test.bW_()' on a null object reference\n"},
         {"self-is-catch-block", "100\n-1\n"},
         {"infinite-loop", ""},
         {"regression/33336471",
             "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n" +
                 "START\n0\n2\nLOOP\n1\n2\nLOOP\n2\n2\nDONE\n"},
         {"regression/33846227", ""},
+        {"illegal-invokes", "ICCE\nICCE\n"},
     });
   }
 
@@ -123,7 +124,8 @@
         thrown.expect(Throwable.class);
       }
       output =
-          ToolHelper.checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null);
+          ToolHelper
+              .checkArtOutputIdentical(originalDexFile.toString(), generated, mainClass, null);
     }
     assertEquals(expectedOutput, output);
   }
diff --git a/src/test/smali/illegal-invokes/Iface.java b/src/test/smali/illegal-invokes/Iface.java
new file mode 100644
index 0000000..dd11626
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Iface.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+public class Iface {
+
+  public void bar() {
+  }
+}
diff --git a/src/test/smali/illegal-invokes/Iface.smali b/src/test/smali/illegal-invokes/Iface.smali
new file mode 100644
index 0000000..d66777c
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Iface.smali
@@ -0,0 +1,10 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+.class interface public LIface;
+.super Ljava/lang/Object;
+
+.method public abstract bar()V
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Lowest.java b/src/test/smali/illegal-invokes/Lowest.java
new file mode 100644
index 0000000..e464313
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Lowest.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+public class Lowest extends Iface implements Super {
+
+  @Override
+  public void foo() {
+
+  }
+}
diff --git a/src/test/smali/illegal-invokes/Lowest.smali b/src/test/smali/illegal-invokes/Lowest.smali
new file mode 100644
index 0000000..d6c5787
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Lowest.smali
@@ -0,0 +1,12 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+.class public LLowest;
+.super LSuper;
+
+.method public bar()V
+    .locals 0
+    return-void
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Super.java b/src/test/smali/illegal-invokes/Super.java
new file mode 100644
index 0000000..54a8714
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Super.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+public interface Super {
+
+  public void foo();
+}
diff --git a/src/test/smali/illegal-invokes/Super.smali b/src/test/smali/illegal-invokes/Super.smali
new file mode 100644
index 0000000..1ec4f0e
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Super.smali
@@ -0,0 +1,13 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+.class public LSuper;
+.super Ljava/lang/Object;
+.implements LIface;
+
+.method public foo()V
+    .locals 0
+    return-void
+.end method
+
diff --git a/src/test/smali/illegal-invokes/Test.java b/src/test/smali/illegal-invokes/Test.java
new file mode 100644
index 0000000..8ddd18e
--- /dev/null
+++ b/src/test/smali/illegal-invokes/Test.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+public class Test {
+
+  int ignore;
+
+  public static void main(String... args) {
+    Lowest l = new Lowest();
+    callVirtualOnIface(l);
+    callIfaceOnVirtual(l);
+  }
+
+  private static void callVirtualOnIface(Iface i) {
+    try {
+      i.bar();
+    } catch (IncompatibleClassChangeError e) {
+      System.out.println("ICCE");
+    }
+  }
+
+  private static void callIfaceOnVirtual(Super s) {
+    try {
+      s.foo();
+    } catch (IncompatibleClassChangeError e) {
+      System.out.println("ICCE");
+    }
+  }
+}