Soft-pin types referenced from unresolvable methods
Bug: b/236875523
Change-Id: I1d862f719172b1be6070308d101b7dca955a34ce
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6214a5a..40a566f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3436,6 +3436,20 @@
markMethodAsTargeted(new ProgramMethod(clazz, method), reason);
}
});
+
+ // Disallow optimization of types referenced from unresolvable methods. The graph lenses created
+ // by various optimizations only store mappings for method definitions, thus no lenses contain
+ // mappings for unresolvable methods. This can be problematic if an unresolvable method refers
+ // to a class that no longer exists as a result of an optimization.
+ for (DexType referencedType : symbolicMethod.getReferencedBaseTypes(appView.dexItemFactory())) {
+ if (referencedType.isClassType()) {
+ DexProgramClass clazz = asProgramClassOrNull(definitionFor(referencedType, context));
+ if (clazz != null) {
+ applyMinimumKeepInfoWhenLive(
+ clazz, KeepClassInfo.newEmptyJoiner().disallowOptimization());
+ }
+ }
+ }
}
private DexMethod generatedEnumValuesMethod(DexClass enumClass) {
@@ -3576,7 +3590,7 @@
.forEachRuleInstance(
appView,
(clazz, minimumKeepInfo) ->
- applyMinimumKeepInfoWhenLive(clazz, preconditionEvent, minimumKeepInfo),
+ applyMinimumKeepInfoWhenLive(clazz, minimumKeepInfo, preconditionEvent),
(field, minimumKeepInfo) ->
applyMinimumKeepInfoWhenLive(field, minimumKeepInfo, preconditionEvent),
this::applyMinimumKeepInfoWhenLiveOrTargeted);
@@ -3646,8 +3660,14 @@
private void applyMinimumKeepInfoWhenLive(
DexProgramClass clazz,
- EnqueuerEvent preconditionEvent,
KeepClassInfo.Joiner minimumKeepInfo) {
+ applyMinimumKeepInfoWhenLive(clazz, minimumKeepInfo, EnqueuerEvent.unconditional());
+ }
+
+ private void applyMinimumKeepInfoWhenLive(
+ DexProgramClass clazz,
+ KeepClassInfo.Joiner minimumKeepInfo,
+ EnqueuerEvent preconditionEvent) {
if (liveTypes.contains(clazz)) {
keepInfo.joinClass(clazz, info -> info.merge(minimumKeepInfo));
} else {
@@ -3674,7 +3694,7 @@
DexProgramClass clazz,
KeepClassInfo.Joiner minimumKeepInfo) {
if (isPreconditionForMinimumKeepInfoSatisfied(preconditionEvent)) {
- applyMinimumKeepInfoWhenLive(clazz, preconditionEvent, minimumKeepInfo);
+ applyMinimumKeepInfoWhenLive(clazz, minimumKeepInfo, preconditionEvent);
} else {
dependentMinimumKeepInfo
.getOrCreateMinimumKeepInfoFor(preconditionEvent)
@@ -3803,7 +3823,7 @@
minimumKeepClassInfoDependentOnPrecondition.forEach(
appView,
(clazz, minimumKeepInfoForClass) ->
- applyMinimumKeepInfoWhenLive(clazz, preconditionEvent, minimumKeepInfoForClass),
+ applyMinimumKeepInfoWhenLive(clazz, minimumKeepInfoForClass, preconditionEvent),
(field, minimumKeepInfoForField) ->
applyMinimumKeepInfoWhenLive(field, minimumKeepInfoForField, preconditionEvent),
(method, minimumKeepInfoForMethod) ->
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/UnresolvableMethodWithClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/UnresolvableMethodWithClassMergingTest.java
index 4a027fc..bfa57f9 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/UnresolvableMethodWithClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/UnresolvableMethodWithClassMergingTest.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.classmerging.horizontal;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import org.junit.Test;
public class UnresolvableMethodWithClassMergingTest extends HorizontalClassMergingTestBase {
@@ -14,15 +14,15 @@
super(parameters);
}
- // TODO(christofferqa): Should not fail compilation.
- @Test(expected = CompilationFailedException.class)
+ @Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(Main.class, A.class, B.class)
.addKeepMainRule(Main.class)
.addDontWarn(Missing.class)
.addHorizontallyMergedClassesInspector(
- inspector -> inspector.assertMergedInto(B.class, A.class).assertNoOtherClassesMerged())
+ HorizontallyMergedClassesInspector::assertNoOtherClassesMerged)
+ .noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
.addRunClasspathFiles(buildOnDexRuntime(parameters, Missing.class))