Merge "Prevent class merging from hiding IncompatibleClassChangeErrors"
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 86ff5a5..9fcca89 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -531,7 +531,8 @@
   InternalOptions getInternalOptions() {
     InternalOptions internal = new InternalOptions(proguardConfiguration, getReporter());
     assert !internal.debug;
-    internal.debug = getMode() == CompilationMode.DEBUG;
+    internal.debug = getMode() == CompilationMode.DEBUG
+        || (forceProguardCompatibility && !proguardConfiguration.isObfuscating());
     internal.programConsumer = getProgramConsumer();
     internal.minApiLevel = getMinApiLevel();
     internal.enableDesugaring = getEnableDesugaring();
diff --git a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
index 22e8537..59ce62f 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
@@ -13,7 +13,9 @@
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.StringUtils.BraceType;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -44,6 +46,60 @@
     }
   }
 
+  private static class StreamState {
+    static final int ENTRY_LINE = -1;
+    static final int PLACEHOLDER_LINE = -2;
+
+    final Iterator<DebuggeeState> iterator;
+    final Deque<Integer> frameEntryLines = new ArrayDeque<>();
+    int currentLine = ENTRY_LINE;
+
+    StreamState(Stream<DebuggeeState> stream) {
+      iterator = stream.iterator();
+    }
+
+    DebuggeeState next() {
+      while (true) {
+        DebuggeeState state = iterator.next();
+        if (state == null) {
+          return null;
+        }
+        int nextDepth = state.getFrameDepth();
+        int nextLine = state.getLineNumber();
+        if (nextDepth == frameEntryLines.size()) {
+          currentLine = nextLine;
+          return state;
+        }
+        if (nextDepth > frameEntryLines.size()) {
+          frameEntryLines.push(currentLine);
+          while (nextDepth > frameEntryLines.size()) {
+            // If the depth grows by more than one we have entered into filtered out frames, eg,
+            // java/android internals. In this case push placeholder lines on the stack.
+            frameEntryLines.push(PLACEHOLDER_LINE);
+          }
+          currentLine = nextLine;
+          assert nextDepth == frameEntryLines.size();
+          return state;
+        }
+        currentLine = nextLine;
+        while (frameEntryLines.size() > nextDepth + 1) {
+          // If the depth decreases by more than one we have popped the filtered frames.
+          // Verify they are placeholder lines.
+          int placeholder = frameEntryLines.pop();
+          assert placeholder == PLACEHOLDER_LINE;
+        }
+        int lineOnEntry = frameEntryLines.pop();
+        assert nextDepth == frameEntryLines.size();
+        if (lineOnEntry != nextLine) {
+          return state;
+        }
+        // A frame was popped and the current line is the same as when the frame was entered.
+        // In this case we advance again to avoid comparing that a function call returns to the
+        // same line (which may not be the case if no stores are needed after the call).
+      }
+    }
+  }
+
   private boolean verifyLines = true;
   private boolean verifyFiles = true;
   private boolean verifyMethods = true;
@@ -140,13 +196,13 @@
   }
 
   private void internal() {
-    List<Iterator<DebuggeeState>> iterators =
-        streams.stream().map(Stream::iterator).collect(Collectors.toList());
+    List<StreamState> streamStates =
+        streams.stream().map(StreamState::new).collect(Collectors.toList());
     while (true) {
-      List<DebuggeeState> states = new ArrayList<>(iterators.size());
+      List<DebuggeeState> states = new ArrayList<>(streamStates.size());
       boolean done = false;
-      for (Iterator<DebuggeeState> iterator : iterators) {
-        DebuggeeState state = iterator.next();
+      for (StreamState streamState : streamStates) {
+        DebuggeeState state = streamState.next();
         states.add(state);
         if (state == null) {
           done = true;
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index 02e995f..6de20c6 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -75,7 +75,7 @@
 
   @Test
   public void testBridgeMethod() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
+    // TODO(b/79671093): D8 has local variables with empty names.
     testDebuggingJvmOnly("bridge", "BridgeMethod");
   }
 
@@ -122,8 +122,7 @@
 
   @Test
   public void testInstanceVariable() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("instancevariable", "InstanceVariable");
+    testDebugging("instancevariable", "InstanceVariable");
   }
 
   @Test
@@ -133,8 +132,7 @@
 
   @Test
   public void testInvoke() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("invoke", "Invoke");
+    testDebugging("invoke", "Invoke");
   }
 
   @Test
@@ -155,8 +153,7 @@
 
   @Test
   public void testNewArray() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("newarray", "NewArray");
+    testDebugging("newarray", "NewArray");
   }
 
   @Test
@@ -166,8 +163,7 @@
 
   @Test
   public void testReturns() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("returns", "Returns");
+    testDebugging("returns", "Returns");
   }
 
   @Test
@@ -222,8 +218,7 @@
 
   @Test
   public void testInvokeEmpty() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("invokeempty", "InvokeEmpty");
+    testDebugging("invokeempty", "InvokeEmpty");
   }
 
   @Test
@@ -233,21 +228,17 @@
 
   @Test
   public void testRegress2() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("regress2", "Regress2");
+    testDebugging("regress2", "Regress2");
   }
 
-  @Ignore("TODO(mathiasr): Different behavior CfSourceCode vs JarSourceCode")
   @Test
   public void testRegress37726195() throws Exception {
-    // TODO(b/79671093): We don't match JVM's behavior on this example.
-    testDebuggingJvmOutputOnly("regress_37726195", "Regress");
+    testDebugging("regress_37726195", "Regress");
   }
 
   @Test
   public void testRegress37658666() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("regress_37658666", "Regress");
+    testDebugging("regress_37658666", "Regress");
   }
 
   @Test
@@ -257,8 +248,7 @@
 
   @Test
   public void testRegress37955340() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("regress_37955340", "Regress");
+    testDebugging("regress_37955340", "Regress");
   }
 
   @Test
@@ -304,8 +294,7 @@
 
   @Test
   public void testMemberrebinding2() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("memberrebinding2", "Memberrebinding");
+    testDebugging("memberrebinding2", "Memberrebinding");
   }
 
   @Test
@@ -315,14 +304,12 @@
 
   @Test
   public void testMinification() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("minification", "Minification");
+    testDebugging("minification", "Minification");
   }
 
   @Test
   public void testEnclosingmethod() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("enclosingmethod", "Main");
+    testDebugging("enclosingmethod", "Main");
   }
 
   @Test