Test partial record desugaring
Bug: b/357021427
Change-Id: I067ed42a3cc0235f29c714731410b32487d0a8e6
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index e4aa9dc..3c858a9 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -877,7 +877,7 @@
clazz.getPermittedSubclassAttributes(), options.itemFactory));
}
- if (clazz.isRecord() && options.canUseRecords()) {
+ if (clazz.isRecord() && options.emitRecordAnnotationsInDex) {
annotations.add(DexAnnotation.createRecordAnnotation(clazz, appView));
}
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
index 63636d9..0b301d4 100644
--- a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
+++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -16,7 +16,7 @@
public static ApplicationReaderMap getInstance(InternalOptions options) {
ApplicationReaderMap result = new EmptyMap();
- if (options.desugarRecordState().isNotOff()
+ if (options.desugarRecordState().isFull()
&& !options.testing.disableRecordApplicationReaderMap) {
result = new RecordMap(options.dexItemFactory());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
index 268c8a3..fb6b45b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordInstructionDesugaring.java
@@ -119,7 +119,6 @@
throw new Unreachable("Invoke dynamic needs record desugaring but could not be desugared.");
}
-
@Override
@SuppressWarnings("ReferenceEquality")
public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) {
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 4e50c82..cd63846 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -510,8 +510,12 @@
// TODO(b/293591931): Remove this flag when records are stable in Platform
// Flag to allow record annotations in DEX. See b/231930852 for context.
- private final boolean emitRecordAnnotationsInDex =
+ public boolean emitRecordAnnotationsInDex =
System.getProperty("com.android.tools.r8.emitRecordAnnotationsInDex") != null;
+ // This flag to allows platform to disable partial desugaring, so when the annotation is set
+ // platform can use the invoke-dynamic for records.
+ public boolean recordPartialDesugaring =
+ System.getProperty("com.android.tools.r8.disableRecordPartialDesugaring") == null;
// Flag to allow nest annotations in DEX. See b/231930852 for context.
public boolean emitNestAnnotationsInDex =
@@ -713,17 +717,15 @@
}
}
- public boolean recordPartialDesugaring =
- System.getProperty("com.android.tools.r8.recordPartialDesugaring") != null;
-
public DesugarRecordState desugarRecordState() {
if (desugarState.isOff()) {
return DesugarRecordState.OFF;
}
- if (!canUseRecords()) {
- return DesugarRecordState.FULL;
+ // The class java.lang.Record is present from U with a GC issue so we enable from V.
+ if (hasFeaturePresentFrom(AndroidApiLevel.V) && recordPartialDesugaring) {
+ return DesugarRecordState.PARTIAL;
}
- return recordPartialDesugaring ? DesugarRecordState.PARTIAL : DesugarRecordState.OFF;
+ return emitRecordAnnotationsInDex ? DesugarRecordState.OFF : DesugarRecordState.FULL;
}
public boolean canUseDesugarBufferCovariantReturnType() {
@@ -2739,10 +2741,6 @@
return (hasFeaturePresentFrom(null) || emitNestAnnotationsInDex) && !forceNestDesugaring;
}
- public boolean canUseRecords() {
- return hasFeaturePresentFrom(null) || emitRecordAnnotationsInDex;
- }
-
public boolean canUseSealedClasses() {
return hasFeaturePresentFrom(AndroidApiLevel.U) || emitPermittedSubclassesAnnotationsInDex;
}
diff --git a/src/test/examplesJava17/records/RecordHashCodeTest.java b/src/test/examplesJava17/records/RecordHashCodeTest.java
index 59d4666..2f2609d 100644
--- a/src/test/examplesJava17/records/RecordHashCodeTest.java
+++ b/src/test/examplesJava17/records/RecordHashCodeTest.java
@@ -57,7 +57,7 @@
.setMinApi(parameters)
.run(parameters.getRuntime(), TestClass.class)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
index 5c08537..84f3ea9 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
@@ -20,7 +20,7 @@
private static final String RECORD_NAME = "EmptyRecordAnnotation";
private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String EXPECTED_RESULT_NATIVE_RECORD =
+ private static final String EXPECTED_RESULT_NATIVE_OR_PARTIALLY_DESUGARED_RECORD =
StringUtils.lines("class java.lang.Record", "class records.EmptyRecordAnnotation$Empty");
private static final String EXPECTED_RESULT_DESUGARED_RECORD =
StringUtils.lines(
@@ -47,7 +47,7 @@
testForJvm(parameters)
.addProgramClassFileData(PROGRAM_DATA)
.run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_RECORD);
+ .assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_OR_PARTIALLY_DESUGARED_RECORD);
}
@Test
@@ -59,9 +59,9 @@
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForD8(parameters),
+ isRecordsFullyDesugaredForD8(parameters),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED_RECORD),
- r -> r.assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_RECORD));
+ r -> r.assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_OR_PARTIALLY_DESUGARED_RECORD));
}
@Test
@@ -77,14 +77,14 @@
.addKeepMainRule(MAIN_TYPE)
// This is used to avoid renaming com.android.tools.r8.RecordTag.
.applyIf(
- isRecordsDesugaredForR8(parameters),
+ isRecordsFullyDesugaredForR8(parameters),
b -> b.addKeepRules("-keep class java.lang.Record"))
.compile()
.applyIf(parameters.isCfRuntime(), r -> r.inspect(RecordTestUtils::assertRecordsAreRecords))
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForR8(parameters),
+ isRecordsFullyDesugaredForR8(parameters),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED_RECORD),
- r -> r.assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_RECORD));
+ r -> r.assertSuccessWithOutput(EXPECTED_RESULT_NATIVE_OR_PARTIALLY_DESUGARED_RECORD));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
index 05fdb8d..10f10f4 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordBlogTest.java
@@ -83,7 +83,7 @@
.setMinApi(parameters)
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(computeOutput(REFERENCE_OUTPUT_FORMAT)),
r -> r.assertFailureWithErrorThatThrows(ClassNotFoundException.class));
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
index d2c05af..41f97f8 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentAnnotationsTest.java
@@ -202,6 +202,9 @@
@Parameter(1)
public Boolean keepAnnotations;
+ // Enable once records are no longer partially desugared on platform.
+ public boolean recordDesugaringIsOffOnDex = false;
+
@Parameters(name = "{0}, keepAnnotations: {1}")
public static List<Object[]> data() {
return buildParameters(
@@ -234,7 +237,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForD8(parameters),
+ parameters.isDexRuntime(),
r ->
r.assertSuccessWithOutput(
runtimeWithRecordsSupport(parameters.getRuntime())
@@ -306,7 +309,7 @@
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
- // TODO(b/231930852): Change to android.jar for Androud U when that contains
+ // TODO(b/231930852): Change to android.jar for Android U when that contains
// java.lang.Record.
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
.addKeepMainRule(MAIN_TYPE)
@@ -323,7 +326,7 @@
ClassSubject person = inspector.clazz("records.RecordWithAnnotations$Person");
FieldSubject name = person.uniqueFieldWithOriginalName("name");
FieldSubject age = person.uniqueFieldWithOriginalName("age");
- if (!isRecordsDesugaredForR8(parameters)) {
+ if (parameters.isCfRuntime()) {
assertEquals(2, person.getFinalRecordComponents().size());
assertEquals(
@@ -376,7 +379,7 @@
keepAnnotations
? JVM_EXPECTED_RESULT_R8
: JVM_EXPECTED_RESULT_R8_NO_KEEP_ANNOTATIONS),
- !isRecordsDesugaredForR8(parameters),
+ recordDesugaringIsOffOnDex,
r ->
r.assertSuccessWithOutput(
keepAnnotations
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
index 58f0da0..27e7e0b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordComponentSignatureTest.java
@@ -88,8 +88,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- !isRecordsDesugaredForD8(parameters),
- // Current Art 14 build does not support the java.lang.Record class.
+ parameters.isCfRuntime(),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
r ->
r.assertSuccessWithOutput(
@@ -100,7 +99,7 @@
inspector -> {
ClassSubject person =
inspector.clazz("records.RecordWithSignature$Person");
- if (!isRecordsDesugaredForD8(parameters)) {
+ if (parameters.isCfRuntime()) {
assertEquals(2, person.getFinalRecordComponents().size());
assertEquals(
@@ -159,7 +158,7 @@
runtimeWithRecordsSupport(parameters.getRuntime()),
r ->
r.assertSuccessWithOutput(
- isRecordsDesugaredForR8(parameters)
+ parameters.isDexRuntime()
? EXPECTED_RESULT_DESUGARED_NATIVE_RECORD_SUPPORT
: EXPECTED_RESULT_R8),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_DESUGARED_NO_NATIVE_RECORDS_SUPPORT));
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
index 8eb35d5..169ef16 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInterfaceTest.java
@@ -66,7 +66,7 @@
.setMinApi(parameters)
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
@@ -81,7 +81,7 @@
testForD8()
.addProgramFiles(path)
.applyIf(
- isRecordsDesugaredForD8(parameters),
+ isRecordsFullyDesugaredForD8(parameters),
b ->
b.getBuilder()
.addGlobalSyntheticsResourceProviders(globals.getIndexedModeProvider()),
@@ -105,7 +105,7 @@
testForD8()
.addProgramFiles(path)
.applyIf(
- isRecordsDesugaredForD8(parameters),
+ isRecordsFullyDesugaredForD8(parameters),
b ->
b.getBuilder()
.addGlobalSyntheticsResourceProviders(globals.getIndexedModeProvider()),
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
index fa22262..b782568 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ZipUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,11 +45,9 @@
"true",
"false",
"false",
- "%s[%s=Jane Doe, %s=42]");
+ "%s[name=Jane Doe, age=42]");
private static final String EXPECTED_RESULT_D8 =
- String.format(EXPECTED_RESULT, "Empty", "Person", "name", "age");
- private static final String EXPECTED_RESULT_R8 =
- String.format(EXPECTED_RESULT, "a", "b", "name", "age");
+ String.format(EXPECTED_RESULT, "Empty", "Person");
private final TestParameters parameters;
@@ -86,11 +85,12 @@
.setMinApi(parameters)
.compile()
.writeToZip();
- if (isRecordsDesugaredForD8(parameters)) {
+ if (isRecordsFullyDesugaredForR8(parameters)) {
assertTrue(ZipUtils.containsEntry(desugared, "com/android/tools/r8/RecordTag.class"));
} else {
assertFalse(ZipUtils.containsEntry(desugared, "com/android/tools/r8/RecordTag.class"));
}
+ String[] minifiedNames = {null, null};
testForR8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters)
@@ -98,9 +98,10 @@
.allowDiagnosticMessages()
.compileWithExpectedDiagnostics(
// Class com.android.tools.r8.RecordTag in desugared input is seen as java.lang.Record
- // when reading causing the duplicate class.
+ // when reading causing the duplicate class. From Android V the issue is solved by
+ // partial desugaring.
diagnostics -> {
- if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.U)) {
+ if (parameters.getApiLevel().isEqualTo(AndroidApiLevel.U)) {
diagnostics
.assertNoErrors()
.assertInfosMatch(
@@ -116,7 +117,18 @@
diagnostics.assertNoMessages();
}
})
+ .inspect(
+ i -> {
+ minifiedNames[0] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Empty");
+ minifiedNames[1] = extractSimpleFinalName(i, "records.RecordInvokeCustom$Person");
+ })
.run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+ .assertSuccessWithOutput(
+ String.format(EXPECTED_RESULT, minifiedNames[0], minifiedNames[1]));
+ }
+
+ private static String extractSimpleFinalName(CodeInspector i, String name) {
+ String finalName = i.clazz(name).getFinalName();
+ return finalName.split("\\.")[1];
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
index a46c400..d05a57a 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -74,7 +74,7 @@
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters)
.setIntermediate(true);
- if (isRecordsDesugaredForD8(parameters)) {
+ if (isRecordsFullyDesugaredForD8(parameters)) {
assertThrows(
CompilationFailedException.class,
() ->
@@ -129,8 +129,8 @@
.inspect(this::assertDoesNotHaveRecordTag)
.writeToZip();
- assertTrue(isRecordsDesugaredForD8(parameters) ^ !globals1.hasGlobals());
- assertTrue(isRecordsDesugaredForD8(parameters) ^ !globals2.hasGlobals());
+ assertTrue(isRecordsFullyDesugaredForD8(parameters) ^ !globals1.hasGlobals());
+ assertTrue(isRecordsFullyDesugaredForD8(parameters) ^ !globals2.hasGlobals());
D8TestCompileResult result =
testForD8(parameters.getBackend())
@@ -147,14 +147,14 @@
result
.run(parameters.getRuntime(), MAIN_TYPE_1)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
.run(parameters.getRuntime(), MAIN_TYPE_2)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_2),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
@@ -183,14 +183,14 @@
result
.run(parameters.getRuntime(), MAIN_TYPE_1)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
.run(parameters.getRuntime(), MAIN_TYPE_2)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_2),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
@@ -214,7 +214,7 @@
.inspect(this::assertHasRecordTag)
.writeToZip();
- if (!isRecordsDesugaredForD8(parameters)) {
+ if (!isRecordsFullyDesugaredForD8(parameters)) {
D8TestCompileResult result =
testForD8(parameters.getBackend())
.addProgramFiles(output1, output2)
@@ -223,14 +223,14 @@
result
.run(parameters.getRuntime(), MAIN_TYPE_1)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_1),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
result
.run(parameters.getRuntime(), MAIN_TYPE_2)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT_2),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
@@ -252,7 +252,7 @@
private void assertHasRecordTag(CodeInspector inspector) {
// Note: this should be asserting on record tag.
assertThat(
- inspector.clazz("java.lang.Record"), isPresentIf(isRecordsDesugaredForD8(parameters)));
+ inspector.clazz("java.lang.Record"), isPresentIf(isRecordsFullyDesugaredForD8(parameters)));
}
private void assertDoesNotHaveRecordTag(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
index 35725b8..1194f76 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
-import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.LibraryFilesHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -89,7 +90,11 @@
}
}
- public static void assertNoJavaLangRecord(CodeInspector inspector) {
- assertThat(inspector.clazz("java.lang.Record"), isAbsent());
+ public static void assertNoJavaLangRecord(CodeInspector inspector, TestParameters parameters) {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.V)) {
+ assertFalse(inspector.clazz("java.lang.RecordTag").isPresent());
+ } else {
+ assertFalse(inspector.clazz("java.lang.Record").isPresent());
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 31cf89a..9dbd8d2 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.records;
+import static com.android.tools.r8.desugar.records.RecordTestUtils.assertNoJavaLangRecord;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -81,11 +82,11 @@
.setMinApi(parameters)
.compile()
.inspectWithOptions(
- RecordTestUtils::assertNoJavaLangRecord,
+ i -> assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
.run(parameters.getRuntime(), MAIN_TYPE)
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
@@ -100,7 +101,8 @@
Path path = compileIntermediate(globals);
testForD8()
.addProgramFiles(path)
- .apply(
+ .applyIf(
+ isRecordsFullyDesugaredForD8(parameters),
b ->
b.getBuilder()
.addGlobalSyntheticsResourceProviders(globals.getIndexedModeProvider()))
@@ -119,7 +121,8 @@
// In Android Studio they disable desugaring at this point to improve build speed.
testForD8()
.addProgramFiles(path)
- .apply(
+ .applyIf(
+ isRecordsFullyDesugaredForD8(parameters),
b ->
b.getBuilder()
.addGlobalSyntheticsResourceProviders(globals.getIndexedModeProvider()))
@@ -161,10 +164,7 @@
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
- .inspect(
- inspector -> {
- inspector.clazz("records.SimpleRecord$Person").isRenamed();
- })
+ .inspect(inspector -> inspector.clazz("records.SimpleRecord$Person").isRenamed())
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
return;
@@ -172,7 +172,7 @@
builder
.compile()
.inspectWithOptions(
- RecordTestUtils::assertNoJavaLangRecord,
+ i -> assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -201,7 +201,7 @@
builder
.compile()
.inspectWithOptions(
- RecordTestUtils::assertNoJavaLangRecord,
+ i -> assertNoJavaLangRecord(i, parameters),
options -> options.testing.disableRecordApplicationReaderMap = true)
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
index 448acc4..602cdfc 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
@@ -102,7 +102,7 @@
options -> options.testing.disableRecordApplicationReaderMap = true))
.run(parameters.getRuntime(), MAIN_REFERENCE.getTypeName())
.applyIf(
- isRecordsDesugaredForD8(parameters)
+ isRecordsFullyDesugaredForD8(parameters)
|| runtimeWithRecordsSupport(parameters.getRuntime()),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
r -> r.assertFailureWithErrorThatThrows(ClassNotFoundException.class));
@@ -168,7 +168,8 @@
false,
false,
parameters.canUseNestBasedAccessesWhenDesugaring(),
- !isRecordsDesugaredForD8(parameters));
+ !isRecordsFullyDesugaredForD8(parameters),
+ false);
}
private void inspectR8(ArtProfileInspector profileInspector, CodeInspector inspector) {
@@ -179,7 +180,8 @@
parameters.canHaveNonReboundConstructorInvoke(),
true,
parameters.canUseNestBasedAccesses(),
- !isRecordsDesugaredForR8(parameters));
+ !isRecordsFullyDesugaredForR8(parameters),
+ parameters.isCfRuntime());
}
private void inspect(
@@ -189,7 +191,8 @@
boolean canHaveNonReboundConstructorInvoke,
boolean canMergeRecordTag,
boolean canUseNestBasedAccesses,
- boolean canUseRecords) {
+ boolean partialDesugaring,
+ boolean recordDesugaringIsOff) { // Record desugaring is partial or full.
ClassSubject mainClassSubject = inspector.clazz(MAIN_REFERENCE);
assertThat(mainClassSubject, isPresent());
@@ -197,7 +200,7 @@
assertThat(mainMethodSubject, isPresent());
ClassSubject recordTagClassSubject = inspector.clazz(recordClassReference);
- assertThat(recordTagClassSubject, isAbsentIf(canMergeRecordTag || canUseRecords));
+ assertThat(recordTagClassSubject, isAbsentIf(canMergeRecordTag || partialDesugaring));
if (recordTagClassSubject.isPresent()) {
assertEquals(1, recordTagClassSubject.allMethods().size());
}
@@ -208,19 +211,20 @@
ClassSubject personRecordClassSubject = inspector.clazz(PERSON_REFERENCE);
assertThat(personRecordClassSubject, isPresent());
assertEquals(
- canUseRecords
+ partialDesugaring
? inspector.getTypeSubject(RECORD_REFERENCE.getTypeName())
: canMergeRecordTag
? inspector.getTypeSubject(Object.class.getTypeName())
: recordTagClassSubject.asTypeSubject(),
personRecordClassSubject.getSuperType());
assertEquals(
- canUseRecords ? 6 : canMergeRecordTag ? 11 : 10,
+ recordDesugaringIsOff ? 6 : (canMergeRecordTag && !partialDesugaring) ? 11 : 10,
personRecordClassSubject.allMethods().size());
MethodSubject personDefaultInstanceInitializerSubject = personRecordClassSubject.init();
assertThat(
- personDefaultInstanceInitializerSubject, isPresentIf(canMergeRecordTag && !canUseRecords));
+ personDefaultInstanceInitializerSubject,
+ isPresentIf(canMergeRecordTag && !partialDesugaring));
MethodSubject personInstanceInitializerSubject =
canMergeRecordTag
@@ -253,51 +257,54 @@
// boolean equals(Object)
MethodSubject getFieldsAsObjectsMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName(GET_FIELDS_AS_OBJECTS_METHOD_NAME);
- assertThat(getFieldsAsObjectsMethodSubject, isAbsentIf(canUseRecords));
+ assertThat(getFieldsAsObjectsMethodSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject equalsHelperMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName(EQUALS_RECORD_METHOD_NAME);
- assertThat(equalsHelperMethodSubject, isAbsentIf(canUseRecords));
+ assertThat(equalsHelperMethodSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject equalsMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName("equals");
assertThat(equalsMethodSubject, isPresent());
assertThat(
- equalsMethodSubject, ifThen(!canUseRecords, invokesMethod(equalsHelperMethodSubject)));
+ equalsMethodSubject,
+ ifThen(!recordDesugaringIsOff, invokesMethod(equalsHelperMethodSubject)));
// int hashCode()
ClassSubject hashCodeHelperClassSubject =
inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 1));
- assertThat(hashCodeHelperClassSubject, isAbsentIf(canUseRecords));
+ assertThat(hashCodeHelperClassSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject hashCodeHelperMethodSubject = hashCodeHelperClassSubject.uniqueMethod();
- assertThat(hashCodeHelperMethodSubject, isAbsentIf(canUseRecords));
+ assertThat(hashCodeHelperMethodSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject hashCodeMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName("hashCode");
assertThat(hashCodeMethodSubject, isPresent());
assertThat(
hashCodeMethodSubject,
- ifThen(!canUseRecords, invokesMethod(getFieldsAsObjectsMethodSubject)));
+ ifThen(!recordDesugaringIsOff, invokesMethod(getFieldsAsObjectsMethodSubject)));
assertThat(
- hashCodeMethodSubject, ifThen(!canUseRecords, invokesMethod(hashCodeHelperMethodSubject)));
+ hashCodeMethodSubject,
+ ifThen(!recordDesugaringIsOff, invokesMethod(hashCodeHelperMethodSubject)));
// String toString()
ClassSubject toStringHelperClassSubject =
inspector.clazz(SyntheticItemsTestUtils.syntheticRecordHelperClass(PERSON_REFERENCE, 0));
- assertThat(toStringHelperClassSubject, isAbsentIf(canUseRecords));
+ assertThat(toStringHelperClassSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject toStringHelperMethodSubject = toStringHelperClassSubject.uniqueMethod();
- assertThat(toStringHelperMethodSubject, isAbsentIf(canUseRecords));
+ assertThat(toStringHelperMethodSubject, isAbsentIf(recordDesugaringIsOff));
MethodSubject toStringMethodSubject =
personRecordClassSubject.uniqueMethodWithOriginalName("toString");
assertThat(toStringMethodSubject, isPresent());
assertThat(
toStringMethodSubject,
- ifThen(!canUseRecords, invokesMethod(getFieldsAsObjectsMethodSubject)));
+ ifThen(!recordDesugaringIsOff, invokesMethod(getFieldsAsObjectsMethodSubject)));
assertThat(
- toStringMethodSubject, ifThen(!canUseRecords, invokesMethod(toStringHelperMethodSubject)));
+ toStringMethodSubject,
+ ifThen(!recordDesugaringIsOff, invokesMethod(toStringHelperMethodSubject)));
profileInspector
.assertContainsClassRules(mainClassSubject, personRecordClassSubject)
@@ -315,22 +322,22 @@
i.assertContainsMethodRules(
nameNestAccessorMethodSubject, ageNestAccessorMethodSubject))
.applyIf(
- canMergeRecordTag && !canUseRecords,
+ canMergeRecordTag && !partialDesugaring,
i -> i.assertContainsMethodRule(personDefaultInstanceInitializerSubject))
.applyIf(
- !canUseRecords,
+ !canMergeRecordTag && !partialDesugaring,
+ j ->
+ j.assertContainsClassRules(recordTagClassSubject)
+ .assertContainsMethodRule(recordTagInstanceInitializerSubject))
+ .applyIf(
+ !recordDesugaringIsOff,
i ->
i.assertContainsClassRules(hashCodeHelperClassSubject, toStringHelperClassSubject)
.assertContainsMethodRules(
equalsHelperMethodSubject,
getFieldsAsObjectsMethodSubject,
hashCodeHelperMethodSubject,
- toStringHelperMethodSubject)
- .applyIf(
- !canMergeRecordTag,
- j ->
- j.assertContainsClassRules(recordTagClassSubject)
- .assertContainsMethodRule(recordTagInstanceInitializerSubject)))
+ toStringHelperMethodSubject))
.assertContainsNoOtherRules();
}
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBase.java b/src/test/testbase/java/com/android/tools/r8/TestBase.java
index b4a809b..e3cc4c8 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBase.java
@@ -1761,19 +1761,14 @@
throw new Unreachable();
}
- public static boolean isRecordsDesugaredForD8(TestParameters parameters) {
+ public static boolean isRecordsFullyDesugaredForD8(TestParameters parameters) {
assert parameters.getApiLevel() != null;
- // TODO(b/293591931): Return true for some API level when records are stable in Platform
- // (expecting Android V) using TestBase.apiLevelWithRecordSupport().
- return true;
+ return parameters.getApiLevel().isLessThan(AndroidApiLevel.V);
}
- public static boolean isRecordsDesugaredForR8(TestParameters parameters) {
+ public static boolean isRecordsFullyDesugaredForR8(TestParameters parameters) {
assert parameters.getApiLevel() != null;
- // TODO(b/293591931): Also return true for some API level when records are stable in Platform
- // (expecting Android V) using TestBase.apiLevelWithRecordSupport(). Note that R8 with class
- // file output never performs desugaring.
- return !parameters.getRuntime().isCf();
+ return !parameters.getRuntime().isCf() && isRecordsFullyDesugaredForD8(parameters);
}
public static boolean canUseJavaUtilObjects(TestParameters parameters) {