Don't duplicate emulated interface
When input has already been library desugared the emulated interface is
already implemented.
Bug: 171867367
Bug: 172433489
Change-Id: I9bdde7ccd430b9a24ab680b84a1eabd8ecb65208
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 758830d..2a4225f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -429,6 +429,26 @@
extraInterfaceSignatures.add(
new GenericSignature.ClassTypeSignature(rewriter.getEmulatedInterface(extraInterface)));
}
+ // The emulated interface might already be implemented if the input class has gone through
+ // library desugaring already.
+ clazz
+ .getInterfaces()
+ .forEach(
+ iface -> {
+ for (int i = 0; i < extraInterfaceSignatures.size(); i++) {
+ if (extraInterfaceSignatures.get(i).type() == iface) {
+ if (!appView.options().desugarSpecificOptions().allowDesugaredInput) {
+ throw new CompilationError(
+ "Code has already been library desugared. Interface "
+ + iface.getDescriptor()
+ + " is already implemented by "
+ + clazz.getType().getDescriptor());
+ }
+ extraInterfaceSignatures.remove(i);
+ break;
+ }
+ }
+ });
clazz.asProgramClass().addExtraInterfaces(extraInterfaceSignatures);
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index c74ed38..bb54770 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1176,6 +1176,8 @@
// b/172508621
public boolean sortMethodsOnCfOutput =
System.getProperty("com.android.tools.r8.sortMethodsOnCfWriting") != null;
+ public boolean allowDesugaredInput =
+ System.getProperty("com.android.tools.r8.allowDesugaredInput") != null;
}
public static class CallSiteOptimizationOptions {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
index 1146f66..70da258 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/IteratorTest.java
@@ -4,9 +4,14 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.fail;
+import static org.hamcrest.CoreMatchers.containsString;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -93,9 +98,34 @@
canUseDefaultAndStaticInterfaceMethods ? 1 : 2,
info.getMethodNames().stream().filter(name -> name.equals("forEachRemaining")).count());
+ AndroidApiLevel apiLevelNotRequiringDesugaring = AndroidApiLevel.N;
+ if (parameters.getApiLevel().isLessThan(apiLevelNotRequiringDesugaring)) {
+ try {
+ // Use D8 to desugar with Java classfile output.
+ testForD8(Backend.CF)
+ .setMinApi(parameters.getApiLevel())
+ .addProgramFiles(firstJar)
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorsMatch(
+ diagnosticMessage(
+ containsString(
+ "Code has already been library desugared. "
+ + "Interface Lj$/util/Iterator; is already implemented"))));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
// Use D8 to desugar with Java classfile output.
Path secondJar =
testForD8(Backend.CF)
+ .addOptionsModification(
+ options ->
+ options.desugarSpecificOptions().allowDesugaredInput =
+ parameters.getApiLevel().isLessThan(apiLevelNotRequiringDesugaring))
.setMinApi(parameters.getApiLevel())
.addProgramFiles(firstJar)
.enableCoreLibraryDesugaring(parameters.getApiLevel(), new AbsentKeepRuleConsumer())
@@ -108,9 +138,8 @@
assertEquals(
MyIterator.class.getTypeName(),
DescriptorUtils.getJavaTypeFromBinaryName(info.getClassBinaryName()));
- // TODO(b/171867367): This should only be 1.
assertEquals(
- canUseDefaultAndStaticInterfaceMethods ? 0 : 2,
+ canUseDefaultAndStaticInterfaceMethods ? 0 : 1,
info.getInterfaces().stream().filter(name -> name.equals("j$/util/Iterator")).count());
// TODO(b/171867367): This should only be 2.
assertEquals(