Version 2.0.32 Backport fix for classinlining static roots with instance fields. The diff is part of the CL below which fixes the issue. CL: https://r8-review.googlesource.com/47320/ Bug: 149781762 Change-Id: I0bd7afef5e70380fff379adc5a53d27ec8b3a6f5
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java index d38eb99..7944c37 100644 --- a/src/main/java/com/android/tools/r8/Version.java +++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@ // This field is accessed from release scripts using simple pattern matching. // Therefore, changing this field could break our release scripts. - public static final String LABEL = "2.0.32"; + public static final String LABEL = "2.0.33"; private Version() { }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java index 5683361..f78ba2c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -306,10 +306,24 @@ indirectUsers.addAll(alias.uniqueUsers()); continue; } - // Field read/write. - if (user.isInstanceGet() - || (user.isInstancePut() - && receivers.addIllegalReceiverAlias(user.asInstancePut().value()))) { + + if (user.isInstanceGet()) { + if (root.isStaticGet()) { + // We don't have a replacement for this field read. + return user; // Not eligible. + } + DexEncodedField field = + appView.appInfo().resolveField(user.asFieldInstruction().getField()); + if (field == null || field.isStatic()) { + return user; // Not eligible. + } + continue; + } + + if (user.isInstancePut()) { + if (!receivers.addIllegalReceiverAlias(user.asInstancePut().value())) { + return user; // Not eligible. + } DexEncodedField field = appView.appInfo().resolveField(user.asFieldInstruction().getField()); if (field == null || field.isStatic()) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java new file mode 100644 index 0000000..0d809d2 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
@@ -0,0 +1,78 @@ +// Copyright (c) 2020, 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.kotlin.sealed; + +import static com.android.tools.r8.KotlinCompilerTool.KOTLINC; +import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass; + +import com.android.tools.r8.CompilationFailedException; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestRuntime; +import com.android.tools.r8.TestRuntime.CfRuntime; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.ToolHelper.KotlinTargetVersion; +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.function.BiFunction; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class SealedClassTest extends TestBase { + + private static final String MAIN = "com.android.tools.r8.kotlin.sealed.kt.FormatKt"; + private static final String[] EXPECTED = new String[] {"ZIP"}; + + private final TestParameters parameters; + private final KotlinTargetVersion targetVersion; + + @Parameters(name = "{0}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values()); + } + + public SealedClassTest(TestParameters parameters, KotlinTargetVersion targetVersion) { + this.parameters = parameters; + this.targetVersion = targetVersion; + } + + private static BiFunction<TestRuntime, KotlinTargetVersion, Path> compilationResults = + memoizeBiFunction(SealedClassTest::compileKotlinCode); + + private static Path compileKotlinCode(TestRuntime runtime, KotlinTargetVersion targetVersion) + throws IOException { + CfRuntime cfRuntime = runtime.isCf() ? runtime.asCf() : TestRuntime.getCheckedInJdk9(); + return kotlinc(cfRuntime, getStaticTemp(), KOTLINC, targetVersion) + .addSourceFiles(getFilesInTestFolderRelativeToClass(SealedClassTest.class, "kt", ".kt")) + .compile(); + } + + @Test + public void testRuntime() throws ExecutionException, CompilationFailedException, IOException { + testForRuntime(parameters) + .addProgramFiles(compilationResults.apply(parameters.getRuntime(), targetVersion)) + .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar())) + .run(parameters.getRuntime(), MAIN) + .assertSuccessWithOutputLines(EXPECTED); + } + + @Test + public void testR8() throws ExecutionException, CompilationFailedException, IOException { + testForR8(parameters.getBackend()) + .addProgramFiles(compilationResults.apply(parameters.getRuntime(), targetVersion)) + .addProgramFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar())) + .setMinApi(parameters.getApiLevel()) + .allowAccessModification() + .addKeepMainRule(MAIN) + .run(parameters.getRuntime(), MAIN) + .assertSuccessWithOutputLines(EXPECTED); + } +}
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/kt/Format.kt b/src/test/java/com/android/tools/r8/kotlin/sealed/kt/Format.kt new file mode 100644 index 0000000..2c1e189 --- /dev/null +++ b/src/test/java/com/android/tools/r8/kotlin/sealed/kt/Format.kt
@@ -0,0 +1,20 @@ +// Copyright (c) 2020, 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.kotlin.sealed.kt + +public sealed class Format(val name: String) { + object Zip : Format("ZIP") + object Directory : Format("DIRECTORY") +} + +fun main() { + val value = when ("ZIP") { + Format.Zip.name -> Format.Zip + Format.Directory.name -> Format.Directory + else -> throw IllegalArgumentException( + "Valid formats: ${Format.Zip.name} or ${Format.Directory.name}.") + } + println(value.name) +} \ No newline at end of file