Ensure that merged parameter is api safe
Bug: b/289361079
Change-Id: Ifa30fed27c283906b9ce89835ba8c268c9430190
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java b/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
index 62531ba..625b127 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.utils.AndroidApiLevelUtils;
import com.google.common.collect.Iterables;
public class DexTypeUtils {
@@ -15,7 +16,7 @@
AppView<? extends AppInfoWithClassHierarchy> appView, Iterable<DexType> types) {
TypeElement join =
TypeElement.join(Iterables.transform(types, type -> type.toTypeElement(appView)), appView);
- return toDexType(appView, join);
+ return findApiSafeUpperBound(appView, toDexType(appView, join));
}
public static DexType toDexType(
@@ -39,4 +40,23 @@
}
return dexItemFactory.objectType;
}
+
+ public static DexType findApiSafeUpperBound(
+ AppView<? extends AppInfoWithClassHierarchy> appView, DexType type) {
+ DexItemFactory factory = appView.dexItemFactory();
+ if (type.toBaseType(factory).isPrimitiveType()) {
+ return type;
+ }
+ DexClass clazz = appView.definitionFor(type.isArrayType() ? type.toBaseType(factory) : type);
+ if (clazz == null) {
+ assert false : "We should not have found an upper bound if the hierarchy is missing";
+ return type;
+ }
+ if (!clazz.isLibraryClass()
+ || AndroidApiLevelUtils.isApiSafeForReference(clazz.asLibraryClass(), appView)) {
+ return type;
+ }
+ // Always just return the object type since this is safe for all api versions.
+ return factory.objectType;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java
index 54bf153..27890cf 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClInitMergeSuperTypeApiLevelTest.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Constructor;
@@ -38,11 +39,18 @@
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
+ private TypeReference getMergeReferenceForApiLevel() {
+ boolean canUseExecutable =
+ parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O);
+ return Reference.typeFromTypeName(typeName(canUseExecutable ? Executable.class : Object.class));
+ }
+
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
// Emulate a standard AGP setup where we compile with a new android jar on boot classpath.
- .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST))
.addInnerClasses(getClass())
.setMinApi(parameters)
.addKeepClassAndMembersRules(Main.class)
@@ -56,17 +64,11 @@
assertThat(clazz, isPresent());
MethodSubject init = clazz.uniqueInstanceInitializer();
assertThat(init, isPresent());
- TypeReference executableTypeRef =
- Reference.typeFromTypeName(typeName(Executable.class));
- // TODO(b/289361079): This should not be of type Executable since this was introduced
- // at api 26.
- assertEquals(executableTypeRef, init.getParameter(0).getTypeReference());
- // TODO(b/289361079): This should not be of type Executable since this was introduced
- // at api 26.
+ TypeReference mergeTypeRef = getMergeReferenceForApiLevel();
+ assertEquals(mergeTypeRef, init.getParameter(0).getTypeReference());
assertTrue(
clazz.allFields().stream()
- .anyMatch(
- f -> executableTypeRef.equals(f.getFinalReference().getFieldType())));
+ .anyMatch(f -> mergeTypeRef.equals(f.getFinalReference().getFieldType())));
})
.run(parameters.getRuntime(), Main.class)
// The test succeeds for some unknown reason.