Cleanup repeated code pattern using ReferenceTypeElement#toDexType

Fixes: b/338356577
Change-Id: I4a83dbde557cf5f2c5295634ae9785b518b2126e
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 4869bc5..e6f6a54 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.Argument;
@@ -189,15 +188,9 @@
       result = result.join(toTypeElement(iterator.next()), appView);
     }
     // All types are reference types so the join is either a class, an interface or an array.
-    if (result.isClassType()) {
-      ClassTypeElement classType = result.asClassType();
-      if (classType.getClassType().isIdenticalTo(appView.dexItemFactory().objectType)
-          && classType.getInterfaces().hasSingleKnownInterface()) {
-        return classType.getInterfaces().getSingleKnownInterface();
-      }
-      return classType.getClassType();
-    } else if (result.isArrayType()) {
-      return result.asArrayType().toDexType(appView.dexItemFactory());
+    if (result.isReferenceType()) {
+      assert !result.isNullType();
+      return result.asReferenceType().toDexType(appView.dexItemFactory());
     }
     throw new CompilationError("Unexpected join " + result + " of types: " +
         String.join(", ",
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 bdc9c67..205ab44 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeUtils.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.graph;
 
 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;
@@ -48,14 +47,7 @@
       return baseType.toArrayType(arrayType.getNesting(), dexItemFactory);
     }
     assert type.isClassType();
-    ClassTypeElement classType = type.asClassType();
-    if (classType.getClassType().isNotIdenticalTo(dexItemFactory.objectType)) {
-      return classType.getClassType();
-    }
-    if (classType.getInterfaces().hasSingleKnownInterface()) {
-      return classType.getInterfaces().getSingleKnownInterface();
-    }
-    return dexItemFactory.objectType;
+    return type.asClassType().toDexType(dexItemFactory);
   }
 
   public static DexType findApiSafeUpperBound(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
index e966ed6..86d79b1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -154,9 +154,8 @@
   }
 
   @Override
-  @SuppressWarnings("ReferenceEquality")
   public DexType toDexType(DexItemFactory dexItemFactory) {
-    if (type == dexItemFactory.objectType) {
+    if (type.isIdenticalTo(dexItemFactory.objectType)) {
       DexType singleKnownInterface = getInterfaces().getSingleKnownInterface();
       if (singleKnownInterface != null) {
         return singleKnownInterface;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
index 9eeb1f9..248e04b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
@@ -265,14 +265,7 @@
     if (dynamicReceiverUpperBoundType.isClassType()) {
       ClassTypeElement dynamicReceiverUpperBoundClassType =
           dynamicReceiverUpperBoundType.asClassType();
-      DexType refinedType = dynamicReceiverUpperBoundClassType.getClassType();
-      if (refinedType == appView.dexItemFactory().objectType) {
-        DexType singleKnownInterface =
-            dynamicReceiverUpperBoundClassType.getInterfaces().getSingleKnownInterface();
-        if (singleKnownInterface != null) {
-          refinedType = singleKnownInterface;
-        }
-      }
+      DexType refinedType = dynamicReceiverUpperBoundClassType.toDexType(appView.dexItemFactory());
       if (appView.appInfo().isSubtype(refinedType, staticReceiverType)) {
         return refinedType;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index 55a301c..2936553 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.lens.GraphLens;
 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.Nullability;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -1020,34 +1019,24 @@
     @SuppressWarnings("ReferenceEquality")
     private DexType argumentTypeFromValue(Value value, InvokeMethod invoke, int argumentIndex) {
       assert supportedArgumentType(value);
-      DexItemFactory itemFactory = appView.options().itemFactory;
-      DexType objectType = itemFactory.objectType;
       TypeElement valueType = value.getType();
-      if (valueType.isClassType()) {
-        ClassTypeElement valueClassType = value.getType().asClassType();
+      if (valueType.isArrayType() || valueType.isClassType()) {
         // For values of lattice type java.lang.Object and only one interface use the interface as
         // the type of the outline argument. If there are several interfaces these interfaces don't
         // have a common super interface nor are they implemented by a common superclass so the
         // argument type of the outline will be java.lang.Object.
-        if (valueClassType.getClassType() == objectType
-            && valueClassType.getInterfaces().hasSingleKnownInterface()) {
-          return valueClassType.getInterfaces().getSingleKnownInterface();
-        } else {
-          return valueClassType.getClassType();
-        }
-      } else if (valueType.isArrayType()) {
-        return value.getType().asArrayType().toDexType(itemFactory);
+        return value.getType().asReferenceType().toDexType(dexItemFactory);
       } else if (valueType.isNullType()) {
         // For values which are always null use the actual type at the call site.
         return argumentTypeFromInvoke(invoke, argumentIndex);
       } else {
         assert valueType.isPrimitiveType();
         assert valueType.asPrimitiveType().hasDexType();
-        DexType type = valueType.asPrimitiveType().toDexType(itemFactory);
+        DexType type = valueType.asPrimitiveType().toDexType(dexItemFactory);
         if (valueType.isInt()) {
           // In the type lattice boolean, byte, short and char are all int. However, as the
           // outline argument type use the actual primitive type at the call site.
-          assert type == itemFactory.intType;
+          assert type == dexItemFactory.intType;
           type = argumentTypeFromInvoke(invoke, argumentIndex);
         } else {
           assert type == argumentTypeFromInvoke(invoke, argumentIndex);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index 3f9880b..5291e19 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -706,23 +706,8 @@
         return staticType;
       }
 
-      DexType newStaticFieldType;
-      if (dynamicUpperBoundType.isClassType()) {
-        ClassTypeElement dynamicUpperBoundClassType = dynamicUpperBoundType.asClassType();
-        if (dynamicUpperBoundClassType.getClassType() == dexItemFactory.objectType) {
-          if (dynamicUpperBoundClassType.getInterfaces().hasSingleKnownInterface()) {
-            newStaticFieldType =
-                dynamicUpperBoundClassType.getInterfaces().getSingleKnownInterface();
-          } else {
-            return staticType;
-          }
-        } else {
-          newStaticFieldType = dynamicUpperBoundClassType.getClassType();
-        }
-      } else {
-        newStaticFieldType = dynamicUpperBoundType.asArrayType().toDexType(dexItemFactory);
-      }
-
+      DexType newStaticFieldType =
+          dynamicUpperBoundType.asReferenceType().toDexType(dexItemFactory);
       if (newStaticFieldType == staticType) {
         return staticType;
       }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
index 6bc6ad0..22b1a0e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InterfaceMethodArgumentPropagator.java
@@ -191,11 +191,7 @@
               boolean shouldPropagateMethodStateForBounds;
               if (bounds.isExactClassType()) {
                 ClassTypeElement exactClassType = bounds.getExactClassType();
-                DexType exactType =
-                    exactClassType.getClassType().isIdenticalTo(appView.dexItemFactory().objectType)
-                            && exactClassType.getInterfaces().hasSingleKnownInterface()
-                        ? exactClassType.getInterfaces().getSingleKnownInterface()
-                        : exactClassType.getClassType();
+                DexType exactType = exactClassType.toDexType(appView.dexItemFactory());
                 shouldPropagateMethodStateForBounds =
                     exactType.isIdenticalTo(resolvedMethod.getHolderType());
               } else if (bounds.isUnknown()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
index 305d88d..e14addb 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/VirtualDispatchMethodArgumentPropagator.java
@@ -111,11 +111,7 @@
               ClassTypeElement lowerBound = bounds.getDynamicLowerBoundType();
               TypeElement currentType = clazz.getType().toTypeElement(appView);
               if (lowerBound.lessThanOrEqual(currentType, appView)) {
-                DexType activeUntilLowerBoundType =
-                    lowerBound.getClassType().isIdenticalTo(appView.dexItemFactory().objectType)
-                            && lowerBound.getInterfaces().hasSingleKnownInterface()
-                        ? lowerBound.getInterfaces().getSingleKnownInterface()
-                        : lowerBound.getClassType();
+                DexType activeUntilLowerBoundType = lowerBound.toDexType(appView.dexItemFactory());
                 addActiveUntilLowerBound(activeUntilLowerBoundType, inactiveMethodStates);
               } else {
                 return;
@@ -351,12 +347,7 @@
                       //  class.
                       ClassTypeElement lowerBound = bounds.getDynamicLowerBoundType();
                       DexType activeUntilLowerBoundType =
-                          lowerBound
-                                      .getClassType()
-                                      .isIdenticalTo(appView.dexItemFactory().objectType)
-                                  && lowerBound.getInterfaces().hasSingleKnownInterface()
-                              ? lowerBound.getInterfaces().getSingleKnownInterface()
-                              : lowerBound.getClassType();
+                          lowerBound.toDexType(appView.dexItemFactory());
                       assert !bounds.isExactClassType()
                           || activeUntilLowerBoundType.isIdenticalTo(clazz.getType());
                       propagationState.addActiveUntilLowerBound(
@@ -381,11 +372,7 @@
   }
 
   private boolean isUpperBoundSatisfied(ClassTypeElement upperBound, DexProgramClass currentClass) {
-    DexType upperBoundType =
-        upperBound.getClassType().isIdenticalTo(appView.dexItemFactory().objectType)
-                && upperBound.getInterfaces().hasSingleKnownInterface()
-            ? upperBound.getInterfaces().getSingleKnownInterface()
-            : upperBound.getClassType();
+    DexType upperBoundType = upperBound.toDexType(appView.dexItemFactory());
     DexProgramClass upperBoundClass = asProgramClassOrNull(appView.definitionFor(upperBoundType));
     if (upperBoundClass == null) {
       // We should generally never have a dynamic receiver upper bound for a program method which is