blob: b6d9757ef5e20cae9f316f60ab9856bdd512c427 [file] [log] [blame]
// Copyright (c) 2021, 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.graph;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
import com.android.tools.r8.utils.ObjectUtils;
import java.util.Iterator;
public class DexTypeUtils {
public static DexType computeLeastUpperBound(
AppView<? extends AppInfoWithClassHierarchy> appView, Iterable<DexType> types) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
Iterator<DexType> iterator = types.iterator();
assert iterator.hasNext();
DexType result = iterator.next();
while (iterator.hasNext()) {
result = computeLeastUpperBound(appView, result, iterator.next());
}
return result;
}
public static DexType computeLeastUpperBound(
AppView<? extends AppInfoWithClassHierarchy> appView, DexType type, DexType other) {
if (type == other) {
return type;
}
DexItemFactory dexItemFactory = appView.dexItemFactory();
if (type == dexItemFactory.objectType
|| other == dexItemFactory.objectType
|| type.isArrayType() != other.isArrayType()) {
return dexItemFactory.objectType;
}
if (type.isArrayType()) {
assert other.isArrayType();
int arrayDimension = type.getNumberOfLeadingSquareBrackets();
if (other.getNumberOfLeadingSquareBrackets() != arrayDimension) {
return dexItemFactory.objectType;
}
DexType baseType = type.toBaseType(dexItemFactory);
DexType otherBaseType = other.toBaseType(dexItemFactory);
if (baseType.isPrimitiveType() || otherBaseType.isPrimitiveType()) {
assert baseType != otherBaseType;
return dexItemFactory.objectType;
}
return dexItemFactory.createArrayType(
arrayDimension, computeLeastUpperBound(appView, baseType, otherBaseType));
}
assert !type.isArrayType();
assert !other.isArrayType();
boolean isInterface =
type.isClassType()
&& ObjectUtils.getBooleanOrElse(
appView.definitionFor(type), DexClass::isInterface, false);
boolean otherIsInterface =
other.isClassType()
&& ObjectUtils.getBooleanOrElse(
appView.definitionFor(other), DexClass::isInterface, false);
if (isInterface != otherIsInterface) {
return dexItemFactory.objectType;
}
if (isInterface) {
assert otherIsInterface;
InterfaceCollection interfaceCollection =
ClassTypeElement.computeLeastUpperBoundOfInterfaces(
appView, InterfaceCollection.singleton(type), InterfaceCollection.singleton(other));
return interfaceCollection.hasSingleKnownInterface()
? interfaceCollection.getSingleKnownInterface()
: dexItemFactory.objectType;
}
assert !isInterface;
assert !otherIsInterface;
return ClassTypeElement.computeLeastUpperBoundOfClasses(appView.appInfo(), type, other);
}
}