Add tests showing issue with missing classes when desugaring.

Bug: 123506120
Change-Id: I62d45d4c4308ad7f5a058bb392391a05e0f98d2f
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index 21900a01..eac7058 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -11,7 +11,9 @@
 import java.io.PrintStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.function.Consumer;
 
 public abstract class DexByteCodeWriter {
@@ -62,7 +64,8 @@
   private void write(ThrowingFunction<DexClass, PrintStream, IOException> outputStreamProvider,
       Consumer<PrintStream> closer)
       throws IOException {
-    for (DexProgramClass clazz : application.classes()) {
+    Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
+    for (DexProgramClass clazz : classes) {
       if (anyMethodMatches(clazz)) {
         PrintStream ps = outputStreamProvider.apply(clazz);
         try {
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 37e4dec..c807a5d 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -87,8 +87,8 @@
     return self();
   }
 
-  public D8TestBuilder setIntermediate(boolean b) {
-    builder.setIntermediate(true);
+  public D8TestBuilder setIntermediate(boolean intermediate) {
+    builder.setIntermediate(intermediate);
     return self();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index 15c03dc..7ad544b 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -8,6 +8,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 
+import com.android.tools.r8.utils.ListUtils;
 import java.util.ArrayList;
 import java.util.List;
 import org.hamcrest.Matcher;
@@ -44,25 +45,34 @@
     return errors;
   }
 
+  private void assertEmpty(String type, List<Diagnostic> messages) {
+    assertEquals(
+        "Expected no "
+            + type
+            + " messages, got:\n"
+            + String.join("\n", ListUtils.map(messages, m -> m.getDiagnosticMessage())),
+        0,
+        messages.size());
+  }
 
   public TestDiagnosticMessages assertNoMessages() {
-    assertEquals(0, getInfos().size());
-    assertEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("info", getInfos());
+    assertEmpty("warning", getWarnings());
+    assertEmpty("error", getErrors());
     return this;
   }
 
   public TestDiagnosticMessages assertOnlyInfos() {
     assertNotEquals(0, getInfos().size());
-    assertEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("warning", getWarnings());
+    assertEmpty("error", getErrors());
     return this;
   }
 
   public TestDiagnosticMessages assertOnlyWarnings() {
-    assertEquals(0, getInfos().size());
+    assertEmpty("info", getInfos());
     assertNotEquals(0, getWarnings().size());
-    assertEquals(0, getErrors().size());
+    assertEmpty("error", getErrors());
     return this;
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
new file mode 100644
index 0000000..e9b1b8c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTest.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar;
+
+public class DefaultLambdaWithInvokeInterfaceTest {
+
+  public interface I {
+    int run();
+  }
+
+  public interface J {
+    default String stateless() {
+      return "hest";
+    }
+
+    default I stateful() {
+      return () -> stateless().length();
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(new J() {}.stateful().run());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
new file mode 100644
index 0000000..732612d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithInvokeInterfaceTestRunner.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+
+public class DefaultLambdaWithInvokeInterfaceTestRunner extends TestBase {
+
+  final Class<?> CLASS = DefaultLambdaWithInvokeInterfaceTest.class;
+  final String EXPECTED = StringUtils.lines("4");
+
+  @Test
+  public void testJvm() throws Exception {
+    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForD8()
+        .addProgramClassesAndInnerClasses(CLASS)
+        .setMinApi(AndroidApiLevel.K)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED)
+        .inspect(inspector -> assertThat(inspector.clazz(CLASS), isPresent()));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
new file mode 100644
index 0000000..eb4e75b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTest.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar;
+
+public class DefaultLambdaWithSelfReferenceTest {
+
+  interface I {
+    String foo();
+
+    default I stateless() {
+      return () -> "stateless";
+    }
+
+    default I stateful() {
+      return () -> "stateful(" + stateless().foo() + ")";
+    }
+  }
+
+  public static void main(String[] args) {
+    System.out.println(((I) () -> "foo").stateful().foo());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
new file mode 100644
index 0000000..bc193c8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultLambdaWithSelfReferenceTestRunner.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2019, 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 com.android.tools.r8.desugar;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.Disassemble;
+import com.android.tools.r8.Disassemble.DisassembleCommand;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class DefaultLambdaWithSelfReferenceTestRunner extends TestBase {
+
+  final Class<?> CLASS = DefaultLambdaWithSelfReferenceTest.class;
+  final String EXPECTED = StringUtils.lines("stateful(stateless)");
+
+  @Test
+  public void testJvm() throws Exception {
+    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void test() throws Exception {
+    Path out1 = temp.newFolder().toPath().resolve("out1.zip");
+    testForD8()
+        .addProgramClassesAndInnerClasses(CLASS)
+        .setMinApi(AndroidApiLevel.K)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .writeToZip(out1)
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+
+    Path outPerClassDir = temp.newFolder().toPath();
+    Collection<Path> innerClasses =
+        ToolHelper.getClassFilesForInnerClasses(Collections.singleton(CLASS));
+
+    int i = 0;
+    List<Path> outs = new ArrayList<>();
+    {
+      Path mainOut = outPerClassDir.resolve("class" + i++ + ".zip");
+      outs.add(mainOut);
+      testForD8()
+          .addProgramClasses(CLASS)
+          .addClasspathFiles(ToolHelper.getClassPathForTests())
+          .setIntermediate(true)
+          .setMinApi(AndroidApiLevel.K)
+          .compile()
+          // TODO(b/123506120): Add .assertNoMessages()
+          .writeToZip(mainOut);
+    }
+    for (Path innerClass : innerClasses) {
+      Path out = outPerClassDir.resolve("class" + i++ + ".zip");
+      outs.add(out);
+      testForD8()
+          .addProgramFiles(innerClass)
+          .addClasspathFiles(ToolHelper.getClassPathForTests())
+          .setIntermediate(true)
+          .setMinApi(AndroidApiLevel.K)
+          .compile()
+          // TODO(b/123506120): Add .assertNoMessages()
+          .writeToZip(out);
+    }
+
+    Path out2 = temp.newFolder().toPath().resolve("out2.zip");
+    testForD8()
+        .addProgramFiles(outs)
+        .compile()
+        // TODO(b/123506120): Add .assertNoMessages()
+        .writeToZip(out2)
+        .run(CLASS)
+        .assertSuccessWithOutput(EXPECTED);
+
+    Path dissasemble1 = temp.newFolder().toPath().resolve("disassemble1.txt");
+    Path dissasemble2 = temp.newFolder().toPath().resolve("disassemble2.txt");
+    Disassemble.disassemble(
+        DisassembleCommand.builder().addProgramFiles(out1).setOutputPath(dissasemble1).build());
+    Disassemble.disassemble(
+        DisassembleCommand.builder().addProgramFiles(out2).setOutputPath(dissasemble2).build());
+    String content1 = StringUtils.join(Files.readAllLines(dissasemble1), "\n");
+    String content2 = StringUtils.join(Files.readAllLines(dissasemble2), "\n");
+    assertEquals(content1, content2);
+  }
+}