Loosen desugaring constraints

And enable all desugaring by by default.

Loosening as defined in the discussion document:
- Skip desugaring of anything if the target method is defined in the
  bootclasspath (i.e. API android.jar).
- Just warn about invokestatic, invokesuper and call to method handle
  when the target class or interface is missing.
- Change handling of hierarchy:
  - If all declared interfaces (and their super interfaces hierarchies)
    of a class are known and the class has an implementation for all
    default methods found in the declared interface of the class (even
    those hidden in subinterfaces), skip default method desugaring for
    the class.
  - In any other case of missing element in the hierachy is reported as
    a warning. missing interfaces are ignored, missing class cause the
    subclasses to be ignored during default method desugaring.

Change-Id: I8d7043616bbfff26ac09a17a3e953a4a4e5aa4c8
diff --git a/src/test/examplesAndroidO/desugaringwithandroidjar25/DefaultMethodInAndroidJar25.java b/src/test/examplesAndroidO/desugaringwithandroidjar25/DefaultMethodInAndroidJar25.java
new file mode 100644
index 0000000..bec4e67
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithandroidjar25/DefaultMethodInAndroidJar25.java
@@ -0,0 +1,100 @@
+// 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.
+package desugaringwithandroidjar25;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Predicate;
+
+public class DefaultMethodInAndroidJar25 {
+  public static void main(String[] args) throws Exception {
+    ClassWithDefaultPlatformMethods.test();
+  }
+}
+
+class ClassWithDefaultPlatformMethods implements Collection<String> {
+  private final ArrayList<String> list =
+      new ArrayList<String>() {{
+        add("First");
+        add("Second");
+      }};
+
+  static void test() {
+    ClassWithDefaultPlatformMethods instance = new ClassWithDefaultPlatformMethods();
+    instance.forEach(x -> System.out.println("BEFORE: " + x));
+    instance.removeIf(x -> true);
+    instance.forEach(x -> System.out.println("AFTER: " + x));
+  }
+
+  @Override
+  public int size() {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean contains(Object o) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public Iterator<String> iterator() {
+    return list.iterator();
+  }
+
+  @Override
+  public Object[] toArray() {
+    throw new AssertionError();
+  }
+
+  @Override
+  public <T> T[] toArray(T[] a) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean add(String s) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean remove(Object o) {
+    return list.remove(o);
+  }
+
+  @Override
+  public boolean containsAll(Collection<?> c) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends String> c) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    throw new AssertionError();
+  }
+
+  @Override
+  public void clear() {
+    throw new AssertionError();
+  }
+
+  @Override
+  public boolean removeIf(Predicate<? super String> filter) {
+    return Collection.super.removeIf(filter);
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithandroidjar25/StaticMethodInAndroidJar25.java b/src/test/examplesAndroidO/desugaringwithandroidjar25/StaticMethodInAndroidJar25.java
new file mode 100644
index 0000000..f07ea8f
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithandroidjar25/StaticMethodInAndroidJar25.java
@@ -0,0 +1,17 @@
+// 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.
+
+package desugaringwithandroidjar25;
+
+import java.util.Comparator;
+
+public class StaticMethodInAndroidJar25 {
+  public static void main(String[] args) throws Exception {
+    Comparator<String> comparing =
+        Comparator.comparing(x -> x, String::compareTo);
+    System.out.println("'a' <> 'b' = " + comparing.compare("a", "b"));
+    System.out.println("'b' <> 'b' = " + comparing.compare("b", "b"));
+    System.out.println("'c' <> 'b' = " + comparing.compare("c", "b"));
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A.java b/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A.java
new file mode 100644
index 0000000..98504bd
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A.java
@@ -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.
+package desugaringwithmissingclasslib1;
+
+public interface A {
+  default String foo() {
+    return "A";
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A2.java b/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A2.java
new file mode 100644
index 0000000..ff42039
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasslib1/A2.java
@@ -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.
+package desugaringwithmissingclasslib1;
+
+public interface A2 {
+  default String foo() {
+    return "A2";
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasslib2/B.java b/src/test/examplesAndroidO/desugaringwithmissingclasslib2/B.java
new file mode 100644
index 0000000..1ab424e
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasslib2/B.java
@@ -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.
+package desugaringwithmissingclasslib2;
+
+import desugaringwithmissingclasslib1.A;
+
+public interface B extends A {
+  @Override
+  default String foo() {
+    return "B";
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasslib3/C.java b/src/test/examplesAndroidO/desugaringwithmissingclasslib3/C.java
new file mode 100644
index 0000000..029f9f4
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasslib3/C.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.
+package desugaringwithmissingclasslib3;
+
+import desugaringwithmissingclasslib1.A;
+
+public class C implements A {
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasslib4/C2.java b/src/test/examplesAndroidO/desugaringwithmissingclasslib4/C2.java
new file mode 100644
index 0000000..b2aee3b
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasslib4/C2.java
@@ -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.
+package desugaringwithmissingclasslib4;
+
+import desugaringwithmissingclasslib3.C;
+
+public class C2 extends C {
+  public String foo2() {
+    return "C2";
+  }
+}
+
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest1/ImplementMethodsWithDefault.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest1/ImplementMethodsWithDefault.java
new file mode 100644
index 0000000..5f3c1c2
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest1/ImplementMethodsWithDefault.java
@@ -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.
+package desugaringwithmissingclasstest1;
+
+import desugaringwithmissingclasslib1.A;
+import desugaringwithmissingclasslib2.B;
+
+public class ImplementMethodsWithDefault implements A, B {
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest1/Main.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest1/Main.java
new file mode 100644
index 0000000..411a016
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest1/Main.java
@@ -0,0 +1,21 @@
+// 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.
+package desugaringwithmissingclasstest1;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ImplementMethodsWithDefault instance = new ImplementMethodsWithDefault();
+    try {
+      String foo = instance.foo();
+      if (foo.equals("B")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest2/ImplementMethodsWithDefault.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest2/ImplementMethodsWithDefault.java
new file mode 100644
index 0000000..f2ef1b6
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest2/ImplementMethodsWithDefault.java
@@ -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.
+package desugaringwithmissingclasstest2;
+
+import desugaringwithmissingclasslib2.B;
+import desugaringwithmissingclasslib3.C;
+
+public class ImplementMethodsWithDefault extends C implements B {
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest2/Main.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest2/Main.java
new file mode 100644
index 0000000..c42ac81
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest2/Main.java
@@ -0,0 +1,21 @@
+// 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.
+package desugaringwithmissingclasstest2;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ImplementMethodsWithDefault instance = new ImplementMethodsWithDefault();
+    try {
+      String foo = instance.foo();
+      if (foo.equals("B")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest3/ImplementMethodsWithDefault.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest3/ImplementMethodsWithDefault.java
new file mode 100644
index 0000000..4826237
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest3/ImplementMethodsWithDefault.java
@@ -0,0 +1,18 @@
+// 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.
+package desugaringwithmissingclasstest3;
+
+import desugaringwithmissingclasslib2.B;
+import desugaringwithmissingclasslib3.C;
+
+public class ImplementMethodsWithDefault extends C implements B {
+  @Override
+  public String foo() {
+    return "ImplementMethodsWithDefault";
+  }
+
+  public String getB() {
+    return B.super.foo();
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest3/Main.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest3/Main.java
new file mode 100644
index 0000000..bde4d09
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest3/Main.java
@@ -0,0 +1,32 @@
+// 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.
+package desugaringwithmissingclasstest3;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ImplementMethodsWithDefault instance = new ImplementMethodsWithDefault();
+    try {
+      String b = instance.getB();
+      if (b.equals("B")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + b);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+    try {
+      String foo = instance.foo();
+      if (foo.equals("ImplementMethodsWithDefault")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest4/C2.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/C2.java
new file mode 100644
index 0000000..cea6324
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/C2.java
@@ -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.
+package desugaringwithmissingclasstest4;
+
+import desugaringwithmissingclasslib3.C;
+
+public class C2 extends C {
+  public String foo2() {
+    return "C2";
+  }
+}
+
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest4/ImplementMethodsWithDefault.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/ImplementMethodsWithDefault.java
new file mode 100644
index 0000000..c62bc2c
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/ImplementMethodsWithDefault.java
@@ -0,0 +1,14 @@
+// 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.
+package desugaringwithmissingclasstest4;
+
+import desugaringwithmissingclasslib1.A;
+import desugaringwithmissingclasslib1.A2;
+
+public class ImplementMethodsWithDefault extends C2 implements A, A2 {
+  @Override
+  public String foo() {
+    return "ImplementMethodsWithDefault";
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest4/Main.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/Main.java
new file mode 100644
index 0000000..e439c5c
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest4/Main.java
@@ -0,0 +1,32 @@
+// 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.
+package desugaringwithmissingclasstest4;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ImplementMethodsWithDefault instance = new ImplementMethodsWithDefault();
+    try {
+      String foo = instance.foo();
+      if (foo.equals("ImplementMethodsWithDefault")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+    try {
+      String foo = instance.foo2();
+      if (foo.equals("C2")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest5/ImplementMethodsWithDefault.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest5/ImplementMethodsWithDefault.java
new file mode 100644
index 0000000..f8dfc3b
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest5/ImplementMethodsWithDefault.java
@@ -0,0 +1,15 @@
+// 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.
+package desugaringwithmissingclasstest5;
+
+import desugaringwithmissingclasslib1.A;
+import desugaringwithmissingclasslib1.A2;
+import desugaringwithmissingclasslib4.C2;
+
+public class ImplementMethodsWithDefault extends C2 implements A, A2 {
+  @Override
+  public String foo() {
+    return "ImplementMethodsWithDefault";
+  }
+}
diff --git a/src/test/examplesAndroidO/desugaringwithmissingclasstest5/Main.java b/src/test/examplesAndroidO/desugaringwithmissingclasstest5/Main.java
new file mode 100644
index 0000000..d1ee997
--- /dev/null
+++ b/src/test/examplesAndroidO/desugaringwithmissingclasstest5/Main.java
@@ -0,0 +1,32 @@
+// 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.
+package desugaringwithmissingclasstest5;
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    ImplementMethodsWithDefault instance = new ImplementMethodsWithDefault();
+    try {
+      String foo = instance.foo();
+      if (foo.equals("ImplementMethodsWithDefault")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+    try {
+      String foo = instance.foo2();
+      if (foo.equals("C2")) {
+        System.out.println("OK");
+      } else {
+        System.out.println("NOT OK: " + foo);
+      }
+    } catch (Throwable t) {
+      System.out.println("NOT OK " + t.getClass() + " " + t.getMessage());
+      t.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index 803d760..2159d6b 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -38,14 +38,14 @@
 public abstract class D8IncrementalRunExamplesAndroidOTest
     extends RunExamplesAndroidOTest<D8Command.Builder> {
 
-  abstract class D8IncrementalTestRunner extends TestRunner {
+  abstract class D8IncrementalTestRunner extends TestRunner<D8IncrementalTestRunner> {
 
     D8IncrementalTestRunner(String testName, String packageName, String mainClass) {
       super(testName, packageName, mainClass);
     }
 
     @Override
-    TestRunner withMinApiLevel(int minApiLevel) {
+    D8IncrementalTestRunner withMinApiLevel(int minApiLevel) {
       return withBuilderTransformation(builder -> builder.setMinApiLevel(minApiLevel));
     }
 
@@ -154,12 +154,11 @@
         builder = transformation.apply(builder);
       }
       builder = builder.setOutputMode(outputMode);
-      builder = builder.addLibraryFiles(
-          Paths.get(ToolHelper.getAndroidJar(builder.getMinApiLevel())));
       if (output != null) {
         builder = builder.setOutputPath(output);
       }
-      addLibraryReference(builder, Paths.get(ToolHelper.getAndroidJar(builder.getMinApiLevel())));
+      addLibraryReference(builder, Paths.get(ToolHelper.getAndroidJar(
+          androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion)));
       D8Command command = builder.build();
       try {
         return ToolHelper.runD8(command, this::combinedOptionConsumer);
@@ -288,6 +287,7 @@
     Assert.assertArrayEquals(expectedFileNames, dexFiles);
   }
 
+  @Override
   abstract D8IncrementalTestRunner test(String testName, String packageName, String mainClass);
 
   static byte[] readFromResource(Resource resource) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
index d707614..c2ac969 100644
--- a/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
@@ -52,6 +52,11 @@
       builder.addLibraryResourceProvider(
           PreloadedClassFileProvider.fromArchive(location));
     }
+
+    @Override
+    D8LazyTestRunner self() {
+      return this;
+    }
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
index 5b2977c..99fe81c 100644
--- a/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
@@ -23,7 +23,13 @@
 
     @Override
     void addLibraryReference(D8Command.Builder builder, Path location) throws IOException {
-      builder.addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(builder.getMinApiLevel())));
+      builder.addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(
+          androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion)));
+    }
+
+    @Override
+    D8LazyTestRunner self() {
+      return this;
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
index 6f51624..7a56e3c 100644
--- a/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8RunExamplesAndroidOTest.java
@@ -4,33 +4,58 @@
 
 package com.android.tools.r8;
 
+import static com.android.tools.r8.dex.Constants.ANDROID_K_API;
+import static com.android.tools.r8.dex.Constants.ANDROID_O_API;
+
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.OffOrAuto;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.function.UnaryOperator;
+import org.hamcrest.core.CombinableMatcher;
+import org.hamcrest.core.IsInstanceOf;
+import org.hamcrest.core.StringContains;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.internal.matchers.ThrowableMessageMatcher;
 
 public class D8RunExamplesAndroidOTest extends RunExamplesAndroidOTest<D8Command.Builder> {
 
-  class D8TestRunner extends TestRunner {
+  class D8TestRunner extends TestRunner<D8TestRunner> {
 
     D8TestRunner(String testName, String packageName, String mainClass) {
       super(testName, packageName, mainClass);
     }
 
     @Override
-    TestRunner withMinApiLevel(int minApiLevel) {
+    D8TestRunner withMinApiLevel(int minApiLevel) {
       return withBuilderTransformation(builder -> builder.setMinApiLevel(minApiLevel));
     }
 
+    D8TestRunner withClasspath(Path... classpath) {
+      return withBuilderTransformation(b -> {
+        try {
+          return b.addClasspathFiles(classpath);
+        } catch (IOException e) {
+          throw new AssertionError(e);
+        }
+      });
+    }
+
+
     @Override
     void build(Path inputFile, Path out) throws Throwable {
       D8Command.Builder builder = D8Command.builder();
       for (UnaryOperator<D8Command.Builder> transformation : builderTransformations) {
         builder = transformation.apply(builder);
       }
-      builder.addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(builder.getMinApiLevel())));
+      builder.addLibraryFiles(
+          Paths.get(
+              ToolHelper.getAndroidJar(
+                  androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion)));
       D8Command command = builder.addProgramFiles(inputFile).setOutputPath(out).build();
       try {
         ToolHelper.runD8(command, this::combinedOptionConsumer);
@@ -40,10 +65,462 @@
         throw re.getCause() == null ? re : re.getCause();
       }
     }
+
+    @Override
+    D8TestRunner self() {
+      return this;
+    }
   }
 
+  @Test
+  public void testDefaultInInterfaceWithoutDesugaring() throws Throwable {
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("testDefaultInInterfaceWithoutDesugaring", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Off)
+            .withMinApiLevel(ANDROID_K_API);
+    try  {
+      lib1.build();
+
+      // compilation should have failed on CompilationError since A is declaring a default method.
+      Assert.fail();
+    } catch (CompilationError | CompilationException e) {
+      // Expected.
+    }
+  }
+
+  @Test
+  public void testMissingInterfaceDesugared() throws Throwable {
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(ANDROID_K_API);
+    lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(ANDROID_K_API);
+    lib2.build();
+
+    // test: class ImplementMethodsWithDefault implements A, B {} should get its foo implementation
+    // from B.
+    // test is compiled with incomplete classpath: lib2 is missing so ImplementMethodsWithDefault is
+    // missing one of it interfaces.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest1", "desugaringwithmissingclasstest1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(ANDROID_K_API);
+    test.build();
+
+    // TODO check compilation warnings are correctly reported
+    // B is missing so compiled code makes no sense, no need to test execution.
+  }
+
+  @Test
+  public void testMissingInterfaceDesugared2AndroidK() throws Throwable {
+    int minApi = ANDROID_K_API;
+
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib2Dex = lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B should get its foo
+    // implementation from B.
+    // test is compiled with incomplete classpath: lib2 and lib3 are missing so
+    // ImplementMethodsWithDefault is missing all its hierarchy.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest2", "desugaringwithmissingclasstest2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+    // TODO check compilation warnings are correctly reported
+
+    // Missing interface B is causing the wrong code to be executed.
+    if (ToolHelper.artSupported()) {
+      thrown.expect(AssertionError.class);
+      execute(
+          "testMissingInterfaceDesugared2AndroidK",
+          "desugaringwithmissingclasstest2.Main",
+          new Path[] {
+              lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+          },
+          new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+    }
+  }
+
+  @Test
+  public void testMissingInterfaceDesugared2AndroidO() throws Throwable {
+    int minApi = ANDROID_O_API;
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib2Dex = lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B should get its foo
+    // implementation from B.
+    // test is compiled with incomplete classpath: lib2 and lib3 are missing so
+    // ImplementMethodsWithDefault is missing all its hierarchy.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest2", "desugaringwithmissingclasstest2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+    execute(
+        "testMissingInterfaceDesugared2AndroidO",
+        "desugaringwithmissingclasstest2.Main",
+        new Path[] {
+          lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+        },
+        new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+  }
+
+  @Test
+  public void testCallToMissingSuperInterfaceDesugaredAndroidK() throws Throwable {
+
+    int minApi = ANDROID_K_API;
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib2Dex = lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B
+    // { String getB() { return B.super.foo(); }
+    // Should be able to call implementation from B.
+    // test is compiled with incomplete classpath: lib2, i.e. B definition, is missing.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest3", "desugaringwithmissingclasstest3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar(), lib3.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+    // TODO check compilation warnings are correctly reported
+
+    // Missing interface B is causing the wrong method to be executed.
+    if (ToolHelper.artSupported()) {
+      thrown.expect(AssertionError.class);
+      execute(
+          "testCallToMissingSuperInterfaceDesugaredAndroidK",
+          "desugaringwithmissingclasstest3.Main",
+          new Path[] {
+              lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+          },
+          new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+    }
+  }
+
+  @Test
+  public void testCallToMissingSuperInterfaceDesugaredAndroidO() throws Throwable {
+    int minApi = ANDROID_O_API;
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib2Dex = lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B
+    // { String getB() { return B.super.foo(); }
+    // Should be able to call implementation from B.
+    // test is compiled with incomplete classpath: lib2, i.e. B definition, is missing.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest3", "desugaringwithmissingclasstest3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar(), lib3.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+    execute(
+        "testCallToMissingSuperInterfaceDesugaredAndroidO",
+        "desugaringwithmissingclasstest3.Main",
+        new Path[] {
+          lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+        },
+        new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+  }
+
+  @Test
+  public void testMissingSuperDesugaredAndroidK() throws Throwable {
+    int minApi = ANDROID_K_API;
+
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B should get its foo
+    // implementation from B.
+    // test is compiled with incomplete classpath: lib3 is missing so
+    // ImplementMethodsWithDefault is missing its super class.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest2", "desugaringwithmissingclasstest2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withClasspath(lib2.getInputJar())
+            .withMinApiLevel(minApi);
+    thrown.expect(
+        new CombinableMatcher<CompilationError>(new IsInstanceOf(CompilationError.class))
+        .and(new ThrowableMessageMatcher<CompilationError>(
+            new StringContains("desugaringwithmissingclasstest2.ImplementMethodsWithDefault")))
+        .and(new ThrowableMessageMatcher<CompilationError>(
+            new StringContains("desugaringwithmissingclasslib3.C"))));
+    test.build();
+  }
+
+  @Test
+  public void testMissingSuperDesugaredAndroidO() throws Throwable {
+    int minApi = ANDROID_O_API;
+
+    // lib1: interface A { default String foo() { return "A"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib2: interface B extends A { default String foo() { return "B"; } }
+    // lib2 is compiled with full classpath
+    D8TestRunner lib2 =
+        test("desugaringwithmissingclasslib2", "desugaringwithmissingclasslib2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib2Dex = lib2.build();
+
+    // lib3:  class C implements A {}
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class ImplementMethodsWithDefault extends C implements B should get its foo
+    // implementation from B.
+    // test is compiled with incomplete classpath: lib3 is missing so
+    // ImplementMethodsWithDefault is missing its super class.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest2", "desugaringwithmissingclasstest2", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withClasspath(lib2.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+
+    execute(
+        "testMissingSuperDesugaredAndroidO",
+        "desugaringwithmissingclasstest2.Main",
+        new Path[] {
+          lib1.getInputJar(), lib2.getInputJar(), lib3.getInputJar(), test.getInputJar()
+        },
+        new Path[] {lib1Dex, lib2Dex, lib3Dex, testDex});
+  }
+
+  @Test
+  public void testMissingSuperDesugaredWithProgramCrossImplementationAndroidK() throws Throwable {
+    int minApi = ANDROID_K_API;
+
+    // lib1: interface A { default String foo() { return "A"; } }
+    //       interface A2 { default String foo2() { return "A2"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib3: class C { /* content irrelevant }
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // test: class C2 extends C { public String foo2() { return "C2"; } }
+    //       class ImplementMethodsWithDefault extends C2 implements A, A2 {
+    //            public String foo() { return "ImplementMethodsWithDefault"; }
+    //       }
+    // test is compiled with incomplete classpath: lib3 is missing so
+    // C2 is missing its super class. But desugaring should be OK since all
+    // interface methods are explicitly defined in program classes of the hierarchy.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest4", "desugaringwithmissingclasstest4", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+
+    execute(
+        "testMissingSuperDesugaredAndroidKWithCrossImplementation",
+        "desugaringwithmissingclasstest4.Main",
+        new Path[] {
+          lib1.getInputJar(), lib3.getInputJar(), test.getInputJar()
+        },
+        new Path[] {lib1Dex, lib3Dex, testDex});
+
+  }
+
+  @Test
+  public void testMissingSuperDesugaredWithClasspathCrossImplementationAndroidK() throws Throwable {
+    int minApi = ANDROID_K_API;
+
+    // lib1: interface A { default String foo() { return "A"; } }
+    //       interface A2 { default String foo2() { return "A2"; } }
+    D8TestRunner lib1 =
+        test("desugaringwithmissingclasslib1", "desugaringwithmissingclasslib1", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withMinApiLevel(minApi);
+    Path lib1Dex = lib1.build();
+
+    // lib3: class C { /* content irrelevant }
+    // lib3 is compiled with full classpath
+    D8TestRunner lib3 =
+        test("desugaringwithmissingclasslib3", "desugaringwithmissingclasslib3", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib3Dex = lib3.build();
+
+    // lib4: class C2 extends C { public String foo2() { return "C2"; } }
+    // lib4 is compiled with full classpath
+    D8TestRunner lib4 =
+        test("desugaringwithmissingclasslib4", "desugaringwithmissingclasslib4", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar(), lib3.getInputJar())
+            .withMinApiLevel(minApi);
+    Path lib4Dex = lib4.build();
+
+    // test: class ImplementMethodsWithDefault extends C2 implements A, A2 {
+    //            public String foo() { return "ImplementMethodsWithDefault"; }
+    //       }
+    // test is compiled with incomplete classpath: lib3 is missing so
+    // C2 is missing its super class. But desugaring should be OK since all
+    // interface methods are explicitly defined in program classes of the hierarchy.
+    D8TestRunner test =
+        test("desugaringwithmissingclasstest4", "desugaringwithmissingclasstest4", "N/A")
+            .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+            .withClasspath(lib1.getInputJar(), lib4.getInputJar())
+            .withMinApiLevel(minApi);
+    Path testDex = test.build();
+
+    execute(
+        "testMissingSuperDesugaredAndroidKWithCrossImplementation",
+        "desugaringwithmissingclasstest4.Main",
+        new Path[] {
+          lib1.getInputJar(), lib3.getInputJar(), lib4.getInputJar(), test.getInputJar()
+        },
+        new Path[] {lib1Dex, lib3Dex, lib4Dex, testDex});
+
+  }
   @Override
-  TestRunner test(String testName, String packageName, String mainClass) {
+  D8TestRunner test(String testName, String packageName, String mainClass) {
     return new D8TestRunner(testName, packageName, mainClass);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 8ffab3c..7cb47e2 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -142,21 +142,6 @@
           .put("975-iface-private", Constants.ANDROID_N_API)
           .build();
 
-  // Tests requiring interface method desugaring because they explicitly or
-  // implicitly define static or default interface methods and are enabled
-  // on pre-N Android.
-  private static List<String> enableInterfaceMethodDesugaring =
-      ImmutableList.of(
-          "563-checker-invoke-super",
-          "604-hot-static-interface",
-          "961-default-iface-resolution-gen",
-          "963-default-range-smali",
-          "965-default-verify",
-          "967-default-ame",
-          "969-iface-super",
-          "978-virtual-interface"
-      );
-
   // Tests that timeout when run with Art.
   private static final Multimap<String, TestCondition> timeoutOrSkipRunWithArt =
       new ImmutableListMultimap.Builder<String, TestCondition>()
@@ -205,8 +190,9 @@
 
   // Tests that are never compiled or run.
   private static List<String> skipAltogether = ImmutableList.of(
-      // This test contains an invalid type hierarchy, which we cannot currently handle.
+      // Those tests contains an invalid type hierarchy, which we cannot currently handle.
       "065-mismatched-implements",
+      "066-mismatched-super",
       // This test contains invalid dex code that reads uninitialized registers after an
       // an instruction that would in any case throw (implicit via aget null 0).
       "706-jit-skip-compilation",
@@ -1130,7 +1116,12 @@
         Integer minSdkVersion = needMinSdkVersion.get(name);
         if (minSdkVersion != null) {
           builder.setMinApiLevel(minSdkVersion);
+          builder.addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(minSdkVersion)));
+        } else {
+          builder.addLibraryFiles(Paths.get(
+              ToolHelper.getAndroidJar(Constants.DEFAULT_ANDROID_API)));
         }
+
         D8Output output = D8.run(builder.build());
         output.write(Paths.get(resultPath));
         break;
@@ -1153,9 +1144,6 @@
         ToolHelper.runR8(
             builder.build(),
             options -> {
-              if (enableInterfaceMethodDesugaring.contains(name)) {
-                options.interfaceMethodDesugaring = OffOrAuto.Auto;
-              }
               if (disableInlining) {
                 options.inlineAccessors = false;
               }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
index 6c45f40..e63b155 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesAndroidOTest.java
@@ -46,14 +46,14 @@
         .run();
   }
 
-  class R8TestRunner extends TestRunner {
+  class R8TestRunner extends TestRunner<R8TestRunner> {
 
     R8TestRunner(String testName, String packageName, String mainClass) {
       super(testName, packageName, mainClass);
     }
 
     @Override
-    TestRunner withMinApiLevel(int minApiLevel) {
+    R8TestRunner withMinApiLevel(int minApiLevel) {
       return withBuilderTransformation(builder -> builder.setMinApiLevel(minApiLevel));
     }
 
@@ -64,16 +64,23 @@
         for (UnaryOperator<R8Command.Builder> transformation : builderTransformations) {
           builder = transformation.apply(builder);
         }
+        builder.addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(
+            androidJarVersion == null ? builder.getMinApiLevel() : androidJarVersion)));
         R8Command command = builder.addProgramFiles(inputFile).setOutputPath(out).build();
         ToolHelper.runR8(command, this::combinedOptionConsumer);
       } catch (ExecutionException e) {
         throw e.getCause();
       }
     }
+
+    @Override
+    R8TestRunner self() {
+      return this;
+    }
   }
 
   @Override
-  TestRunner test(String testName, String packageName, String mainClass) {
+  R8TestRunner test(String testName, String packageName, String mainClass) {
     return new R8TestRunner(testName, packageName, mainClass);
   }
 
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
index 7594b0c..9d745f6 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidNTest.java
@@ -133,7 +133,8 @@
     thrown.expect(ApiLevelException.class);
     test("staticinterfacemethods-error-due-to-min-sdk", "interfacemethods",
         "StaticInterfaceMethods")
-        .run();
+        .withInterfaceMethodDesugaring(OffOrAuto.Off)
+       .run();
   }
 
   @Test
@@ -149,6 +150,7 @@
     thrown.expect(ApiLevelException.class);
     test("defaultmethods-error-due-to-min-sdk", "interfacemethods",
         "DefaultMethods")
+        .withInterfaceMethodDesugaring(OffOrAuto.Off)
         .run();
   }
 
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 0ca84a1..7a0e793 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -22,29 +22,35 @@
 import com.android.tools.r8.utils.OffOrAuto;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 
-public abstract class RunExamplesAndroidOTest<B> {
+public abstract class RunExamplesAndroidOTest
+      <B extends BaseCommand.Builder<? extends BaseCommand, B>> {
   static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_ANDROID_O_BUILD_DIR;
 
-  abstract class TestRunner {
+  abstract class TestRunner<C extends TestRunner<C>> {
     final String testName;
     final String packageName;
     final String mainClass;
 
+    Integer androidJarVersion = null;
+
     final List<Consumer<InternalOptions>> optionConsumers = new ArrayList<>();
     final List<Consumer<DexInspector>> dexInspectorChecks = new ArrayList<>();
     final List<UnaryOperator<B>> builderTransformations = new ArrayList<>();
@@ -55,20 +61,22 @@
       this.mainClass = mainClass;
     }
 
-    TestRunner withDexCheck(Consumer<DexInspector> check) {
+    abstract C self();
+
+    C withDexCheck(Consumer<DexInspector> check) {
       dexInspectorChecks.add(check);
-      return this;
+      return self();
     }
 
-    TestRunner withClassCheck(Consumer<FoundClassSubject> check) {
+    C withClassCheck(Consumer<FoundClassSubject> check) {
       return withDexCheck(inspector -> inspector.forAllClasses(check));
     }
 
-    TestRunner withMethodCheck(Consumer<FoundMethodSubject> check) {
+    C withMethodCheck(Consumer<FoundMethodSubject> check) {
       return withClassCheck(clazz -> clazz.forAllMethods(check));
     }
 
-    <T extends InstructionSubject> TestRunner withInstructionCheck(
+    <T extends InstructionSubject> C withInstructionCheck(
         Predicate<InstructionSubject> filter, Consumer<T> check) {
       return withMethodCheck(method -> {
         if (method.isAbstract()) {
@@ -81,22 +89,22 @@
       });
     }
 
-    TestRunner withOptionConsumer(Consumer<InternalOptions> consumer) {
+    C withOptionConsumer(Consumer<InternalOptions> consumer) {
       optionConsumers.add(consumer);
-      return this;
+      return self();
     }
 
-    TestRunner withInterfaceMethodDesugaring(OffOrAuto behavior) {
+    C withInterfaceMethodDesugaring(OffOrAuto behavior) {
       return withOptionConsumer(o -> o.interfaceMethodDesugaring = behavior);
     }
 
-    TestRunner withTryWithResourcesDesugaring(OffOrAuto behavior) {
+    C withTryWithResourcesDesugaring(OffOrAuto behavior) {
       return withOptionConsumer(o -> o.tryWithResourcesDesugaring = behavior);
     }
 
-    TestRunner withBuilderTransformation(UnaryOperator<B> builderTransformation) {
+    C withBuilderTransformation(UnaryOperator<B> builderTransformation) {
       builderTransformations.add(builderTransformation);
-      return this;
+      return self();
     }
 
     void combinedOptionConsumer(InternalOptions options) {
@@ -105,13 +113,25 @@
       }
     }
 
+    Path build() throws Throwable {
+      Path inputFile = getInputJar();
+      Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);
+
+      build(inputFile, out);
+      return out;
+    }
+
+    Path getInputJar() {
+      return Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION);
+    }
+
     void run() throws Throwable {
       if (minSdkErrorExpected(testName)) {
         thrown.expect(ApiLevelException.class);
       }
 
       String qualifiedMainClass = packageName + "." + mainClass;
-      Path inputFile = Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION);
+      Path inputFile = getInputJar();
       Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);
 
       build(inputFile, out);
@@ -120,11 +140,6 @@
         return;
       }
 
-      boolean expectedToFail = expectedToFail(testName);
-      if (expectedToFail) {
-        thrown.expect(Throwable.class);
-      }
-
       if (!dexInspectorChecks.isEmpty()) {
         DexInspector inspector = new DexInspector(out);
         for (Consumer<DexInspector> check : dexInspectorChecks) {
@@ -132,21 +147,16 @@
         }
       }
 
-      String output = ToolHelper.runArtNoVerificationErrors(out.toString(), qualifiedMainClass);
-      if (!expectedToFail) {
-        ToolHelper.ProcessResult javaResult =
-            ToolHelper.runJava(ImmutableList.of(inputFile.toString()), qualifiedMainClass);
-        assertEquals("JVM run failed", javaResult.exitCode, 0);
-        assertTrue(
-            "JVM output does not match art output.\n\tjvm: "
-                + javaResult.stdout
-                + "\n\tart: "
-                + output,
-            output.equals(javaResult.stdout));
-      }
+      execute(testName, qualifiedMainClass, new Path[]{inputFile}, new Path[]{out});
     }
 
-    abstract TestRunner withMinApiLevel(int minApiLevel);
+    abstract C withMinApiLevel(int minApiLevel);
+
+    C withAndroidJar(int androidJarVersion) {
+      assert this.androidJarVersion == null;
+      this.androidJarVersion = androidJarVersion;
+      return self();
+    }
 
     abstract void build(Path inputFile, Path out) throws Throwable;
   }
@@ -164,7 +174,12 @@
               // Dex version not supported
               "invokepolymorphic",
               "invokecustom",
-              "invokecustom2"
+              "invokecustom2",
+              "DefaultMethodInAndroidJar25",
+              "StaticMethodInAndroidJar25",
+              "testMissingInterfaceDesugared2AndroidO",
+              "testCallToMissingSuperInterfaceDesugaredAndroidO",
+              "testMissingSuperDesugaredAndroidO"
           ),
           DexVm.ART_5_1_1, ImmutableList.of(
               // API not supported
@@ -173,7 +188,12 @@
               // Dex version not supported
               "invokepolymorphic",
               "invokecustom",
-              "invokecustom2"
+              "invokecustom2",
+              "DefaultMethodInAndroidJar25",
+              "StaticMethodInAndroidJar25",
+              "testMissingInterfaceDesugared2AndroidO",
+              "testCallToMissingSuperInterfaceDesugaredAndroidO",
+              "testMissingSuperDesugaredAndroidO"
           ),
           DexVm.ART_6_0_1, ImmutableList.of(
               // API not supported
@@ -182,7 +202,12 @@
               // Dex version not supported
               "invokepolymorphic",
               "invokecustom",
-              "invokecustom2"
+              "invokecustom2",
+              "DefaultMethodInAndroidJar25",
+              "StaticMethodInAndroidJar25",
+              "testMissingInterfaceDesugared2AndroidO",
+              "testCallToMissingSuperInterfaceDesugaredAndroidO",
+              "testMissingSuperDesugaredAndroidO"
           ),
           DexVm.ART_7_0_0, ImmutableList.of(
               // API not supported
@@ -190,7 +215,10 @@
               // Dex version not supported
               "invokepolymorphic",
               "invokecustom",
-              "invokecustom2"
+              "invokecustom2",
+              "testMissingInterfaceDesugared2AndroidO",
+              "testCallToMissingSuperInterfaceDesugaredAndroidO",
+              "testMissingSuperDesugaredAndroidO"
           ),
           DexVm.ART_DEFAULT, ImmutableList.of(
           )
@@ -266,6 +294,24 @@
   }
 
   @Test
+  public void desugarDefaultMethodInAndroidJar25() throws Throwable {
+    test("DefaultMethodInAndroidJar25", "desugaringwithandroidjar25", "DefaultMethodInAndroidJar25")
+        .withMinApiLevel(ANDROID_K_API)
+        .withAndroidJar(ANDROID_O_API)
+        .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+        .run();
+  }
+
+  @Test
+  public void desugarStaticMethodInAndroidJar25() throws Throwable {
+    test("StaticMethodInAndroidJar25", "desugaringwithandroidjar25", "StaticMethodInAndroidJar25")
+        .withMinApiLevel(ANDROID_K_API)
+        .withAndroidJar(ANDROID_O_API)
+        .withInterfaceMethodDesugaring(OffOrAuto.Auto)
+        .run();
+  }
+
+  @Test
   public void lambdaDesugaringValueAdjustments() throws Throwable {
     test("lambdadesugaring-value-adjustments", "lambdadesugaring", "ValueAdjustments")
         .withMinApiLevel(ANDROID_K_API)
@@ -315,5 +361,34 @@
         .run();
   }
 
-  abstract TestRunner test(String testName, String packageName, String mainClass);
+  abstract RunExamplesAndroidOTest<B>.TestRunner<?> test(String testName, String packageName, String mainClass);
+
+  void execute(
+      String testName,
+      String qualifiedMainClass, Path[] jars, Path[] dexes)
+      throws IOException {
+
+    boolean expectedToFail = expectedToFail(testName);
+    if (expectedToFail) {
+      thrown.expect(Throwable.class);
+    }
+    String output = ToolHelper.runArtNoVerificationErrors(
+        Arrays.stream(dexes).map(path -> path.toString()).collect(Collectors.toList()),
+        qualifiedMainClass,
+        null);
+    if (!expectedToFail) {
+      ToolHelper.ProcessResult javaResult =
+          ToolHelper.runJava(
+              Arrays.stream(jars).map(path -> path.toString()).collect(Collectors.toList()),
+              qualifiedMainClass);
+      assertEquals("JVM run failed", javaResult.exitCode, 0);
+      assertTrue(
+          "JVM output does not match art output.\n\tjvm: "
+              + javaResult.stdout
+              + "\n\tart: "
+              + output,
+          output.equals(javaResult.stdout));
+    }
+  }
+
 }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 4f84303..3767286 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -14,15 +14,11 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationParser;
-import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.shaking.RootSetBuilder;
-import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index fa78fd0..c89e792 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -135,6 +135,7 @@
             .setOutputPath(dexOutputDir)
             .setMinApiLevel(minSdk)
             .setMode(CompilationMode.DEBUG)
+            .addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(minSdk)))
             .build(),
         optionsConsumer);
     return dexOutputDir.resolve("classes.dex");
diff --git a/src/test/java/com/android/tools/r8/desugar/BasicTestDependenciesDesugaringTest.java b/src/test/java/com/android/tools/r8/desugar/BasicTestDependenciesDesugaringTest.java
index b6debff..39d90d6 100644
--- a/src/test/java/com/android/tools/r8/desugar/BasicTestDependenciesDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/BasicTestDependenciesDesugaringTest.java
@@ -45,14 +45,6 @@
   }
 
   private static Set<String> knownIssues = Sets.newHashSet(new String[]{
-      "espresso-core-3.0.0.jar",
-      "hamcrest-integration-1.3.jar",
-      "hamcrest-library-1.3.jar",
-      "junit-4.12.jar",
-      "support-core-ui-25.4.0.jar",
-      "support-media-compat-25.4.0.jar",
-      "support-fragment-25.4.0.jar",
-      "support-compat-25.4.0.jar"
   });
 
   @Rule
@@ -98,4 +90,18 @@
         .build(),
         options -> options.interfaceMethodDesugaring = OffOrAuto.Auto);
   }
+
+  @Test
+  public void testCompileDontDesugarDefault() throws IOException, CompilationException {
+    if (knownIssues.contains(name)) {
+      thrown.expect(CompilationError.class);
+    }
+    ToolHelper.runD8(
+        D8Command.builder().addClasspathFiles(classpath)
+        .addProgramFiles(toCompile)
+        .addLibraryFiles(Paths.get(ToolHelper.getAndroidJar(Constants.ANDROID_K_API)))
+        .setMinApiLevel(Constants.ANDROID_K_API)
+        .build(),
+        options -> options.interfaceMethodDesugaring = OffOrAuto.Off);
+  }
 }