Require a DexProgramClass in AppInfoWithLiveness where DexType is assumed to be a program class

Change-Id: I7026240b79c10764ea4c24a33017c6e257f348de
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index fa4cea3..e7ca421 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -363,7 +363,7 @@
     return super.lookupSuperTarget(method, invocationContext);
   }
 
-  protected boolean hasAnyInstantiatedLambdas(DexType type) {
+  protected boolean hasAnyInstantiatedLambdas(DexProgramClass clazz) {
     assert checkIfObsolete();
     return true; // Don't know, there might be.
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 5a89dcf..5904f98 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -244,7 +244,7 @@
       if (appInfo.isPinned(type)) {
         return false;
       }
-      return !appInfo.hasSubtypes(type) || !appInfo.isInstantiatedIndirectly(type);
+      return !appInfo.hasSubtypes(type) || !appInfo.isInstantiatedIndirectly(this);
     }
     return false;
   }
@@ -259,6 +259,10 @@
     return this;
   }
 
+  public static DexProgramClass asProgramClassOrNull(DexClass clazz) {
+    return clazz != null ? clazz.asProgramClass() : null;
+  }
+
   @Override
   public boolean isNotProgramClass() {
     return false;
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 488b6c7..e3d78cf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.TYPE_WRAPPER_SUFFIX;
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.VIVIFIED_TYPE_WRAPPER_SUFFIX;
 import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
@@ -74,10 +75,8 @@
 
   public boolean isAlwaysNull(AppView<AppInfoWithLiveness> appView) {
     if (isClassType()) {
-      DexClass clazz = appView.definitionFor(this);
-      return clazz != null
-          && clazz.isProgramClass()
-          && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(this);
+      DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(this));
+      return clazz != null && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz);
     }
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index ec2f8e3..1f8343e 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Sets;
@@ -85,9 +87,12 @@
       //   }
       //
       DexEncodedMethod singleTarget = getSingleTarget();
-      if (singleTarget.getCode() != null
-          && appInfo.hasAnyInstantiatedLambdas(singleTarget.method.holder)) {
-        result.add(singleTarget);
+      if (singleTarget.hasCode()) {
+        DexProgramClass holder =
+            asProgramClassOrNull(appInfo.definitionFor(singleTarget.method.holder));
+        if (appInfo.hasAnyInstantiatedLambdas(holder)) {
+          result.add(singleTarget);
+        }
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 3a78425..04dd590 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.optimize;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 import static com.android.tools.r8.optimize.MemberRebindingAnalysis.isTypeVisibleFromContext;
@@ -19,6 +20,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexItemFactory.ThrowableMethods;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
@@ -1577,10 +1579,9 @@
   private boolean isNeverInstantiatedDirectlyOrIndirectly(DexType type) {
     assert appView.appInfo().hasLiveness();
     assert type.isClassType();
-    DexClass clazz = appView.definitionFor(type);
+    DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
     return clazz != null
-        && clazz.isProgramClass()
-        && !appView.appInfo().withLiveness().isInstantiatedDirectlyOrIndirectly(type);
+        && !appView.appInfo().withLiveness().isInstantiatedDirectlyOrIndirectly(clazz);
   }
 
   public static void removeOrReplaceByDebugLocalWrite(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index b14a47a..f94b7a7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.CatchHandlers;
@@ -173,10 +175,8 @@
       // We can exploit that a catch handler must be dead if its guard is never instantiated
       // directly or indirectly.
       if (appInfoWithLiveness != null && appView.options().enableUninstantiatedTypeOptimization) {
-        DexClass clazz = appView.definitionFor(guard);
-        if (clazz != null
-            && clazz.isProgramClass()
-            && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(guard)) {
+        DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(guard));
+        if (clazz != null && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(clazz)) {
           builder.add(new CatchHandler<>(guard, target));
           continue;
         }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 11f8a6e..11f0a08 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -3,12 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -106,13 +108,13 @@
     }
     // Only consider program class, e.g., platform can introduce subtypes in different
     // versions.
-    DexClass clazz = appView.definitionFor(baseType);
-    if (clazz == null || !clazz.isProgramClass()) {
+    DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(baseType));
+    if (clazz == null) {
       return null;
     }
     // Only consider effectively final class. Exception: new Base().getClass().
     if (appView.appInfo().hasSubtypes(baseType)
-        && appView.appInfo().isInstantiatedIndirectly(baseType)
+        && appView.appInfo().isInstantiatedIndirectly(clazz)
         && (in.isPhi() || !in.definition.isCreatingInstanceOrArray())) {
       return null;
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index d004c90..797d178 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.graph.GraphLense.rewriteReferenceKeys;
 
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -71,7 +72,7 @@
   public final Set<DexType> instantiatedAppServices;
   /** Set of types that are actually instantiated. These cannot be abstract. */
   final Set<DexType> instantiatedTypes;
-  /** Cache for {@link #isInstantiatedDirectlyOrIndirectly(DexType)}. */
+  /** Cache for {@link #isInstantiatedDirectlyOrIndirectly(DexProgramClass)}. */
   private final IdentityHashMap<DexType, Boolean> indirectlyInstantiatedTypes =
       new IdentityHashMap<>();
   /**
@@ -687,24 +688,25 @@
     return true;
   }
 
-  public boolean isInstantiatedDirectly(DexType type) {
+  public boolean isInstantiatedDirectly(DexProgramClass clazz) {
     assert checkIfObsolete();
-    assert type.isClassType();
+    DexType type = clazz.type;
     return type.isD8R8SynthesizedClassType()
         || instantiatedTypes.contains(type)
         || instantiatedLambdas.contains(type)
         || instantiatedAnnotationTypes.contains(type);
   }
 
-  public boolean isInstantiatedIndirectly(DexType type) {
+  public boolean isInstantiatedIndirectly(DexProgramClass clazz) {
     assert checkIfObsolete();
-    assert type.isClassType();
+    DexType type = clazz.type;
     synchronized (indirectlyInstantiatedTypes) {
       if (indirectlyInstantiatedTypes.containsKey(type)) {
         return indirectlyInstantiatedTypes.get(type).booleanValue();
       }
       for (DexType directSubtype : allImmediateSubtypes(type)) {
-        if (isInstantiatedDirectlyOrIndirectly(directSubtype)) {
+        DexProgramClass directSubClass = asProgramClassOrNull(definitionFor(directSubtype));
+        if (directSubClass == null || isInstantiatedDirectlyOrIndirectly(directSubClass)) {
           indirectlyInstantiatedTypes.put(type, Boolean.TRUE);
           return true;
         }
@@ -714,10 +716,9 @@
     }
   }
 
-  public boolean isInstantiatedDirectlyOrIndirectly(DexType type) {
+  public boolean isInstantiatedDirectlyOrIndirectly(DexProgramClass clazz) {
     assert checkIfObsolete();
-    assert type.isClassType();
-    return isInstantiatedDirectly(type) || isInstantiatedIndirectly(type);
+    return isInstantiatedDirectly(clazz) || isInstantiatedIndirectly(clazz);
   }
 
   public boolean isFieldRead(DexEncodedField encodedField) {
@@ -809,9 +810,9 @@
   }
 
   @Override
-  protected boolean hasAnyInstantiatedLambdas(DexType type) {
+  protected boolean hasAnyInstantiatedLambdas(DexProgramClass clazz) {
     assert checkIfObsolete();
-    return instantiatedLambdas.contains(type);
+    return instantiatedLambdas.contains(clazz.type);
   }
 
   @Override
@@ -997,10 +998,10 @@
       return null;
     }
     boolean refinedReceiverIsStrictSubType = refinedReceiverType != method.holder;
-    DexClass refinedHolder =
-        refinedReceiverIsStrictSubType ? definitionFor(refinedReceiverType) : holder;
+    DexProgramClass refinedHolder =
+        (refinedReceiverIsStrictSubType ? definitionFor(refinedReceiverType) : holder)
+            .asProgramClass();
     assert refinedHolder != null;
-    assert refinedHolder.isProgramClass();
     assert !refinedHolder.isInterface();
     if (method.isSingleVirtualMethodCached(refinedReceiverType)) {
       return method.getSingleVirtualMethodCache(refinedReceiverType);
@@ -1024,7 +1025,7 @@
     DexEncodedMethod result =
         validateSingleVirtualTarget(
             findSingleTargetFromSubtypes(
-                refinedReceiverType,
+                refinedHolder,
                 method,
                 topSingleTarget,
                 !refinedHolder.accessFlags.isAbstract(),
@@ -1063,24 +1064,24 @@
    * single virtual target otherwise.
    */
   private DexEncodedMethod findSingleTargetFromSubtypes(
-      DexType type,
+      DexProgramClass clazz,
       DexMethod method,
       DexEncodedMethod candidate,
       boolean candidateIsReachable,
       boolean checkForInterfaceConflicts) {
     // For kept types we do not know all subtypes, so abort if the method is also kept.
-    if (isPinned(type) && isMethodPinnedDirectlyOrInAncestor(candidate.method)) {
+    if (isPinned(clazz.type) && isMethodPinnedDirectlyOrInAncestor(candidate.method)) {
       return DexEncodedMethod.SENTINEL;
     }
     // If the candidate is reachable, we already have a previous result.
     DexEncodedMethod result = candidateIsReachable ? candidate : null;
-    for (DexType subtype : allImmediateExtendsSubtypes(type)) {
-      DexClass clazz = definitionFor(subtype);
-      DexEncodedMethod target = clazz.lookupVirtualMethod(method);
+    for (DexType subtype : allImmediateExtendsSubtypes(clazz.type)) {
+      DexProgramClass subclass = definitionFor(subtype).asProgramClass();
+      DexEncodedMethod target = subclass.lookupVirtualMethod(method);
       if (target != null && !target.isPrivateMethod()) {
         // We found a method on this class. If this class is not abstract it is a runtime
         // reachable override and hence a conflict.
-        if (!clazz.accessFlags.isAbstract()) {
+        if (!subclass.accessFlags.isAbstract()) {
           if (result != null && result != target) {
             // We found a new target on this subtype that does not match the previous one. Fail.
             return DexEncodedMethod.SENTINEL;
@@ -1091,7 +1092,7 @@
       }
       if (checkForInterfaceConflicts) {
         // We have to check whether there are any default methods in implemented interfaces.
-        if (interfacesMayHaveDefaultFor(clazz.interfaces, method)) {
+        if (interfacesMayHaveDefaultFor(subclass.interfaces, method)) {
           return DexEncodedMethod.SENTINEL;
         }
       }
@@ -1101,10 +1102,10 @@
       // If we did not find a new target, the candidate is reachable if it was before, or if this
       // class is not abstract.
       boolean newCandidateIsReachable =
-          !clazz.accessFlags.isAbstract() || ((target == null) && candidateIsReachable);
+          !subclass.accessFlags.isAbstract() || ((target == null) && candidateIsReachable);
       DexEncodedMethod subtypeTarget =
           findSingleTargetFromSubtypes(
-              subtype, method, newCandidate, newCandidateIsReachable, checkForInterfaceConflicts);
+              subclass, method, newCandidate, newCandidateIsReachable, checkForInterfaceConflicts);
       if (subtypeTarget != null) {
         // We found a target in the subclasses. If we already have a different result, fail.
         if (result != null && result != subtypeTarget) {
@@ -1181,8 +1182,8 @@
       }
     }
 
-    DexClass holder = definitionFor(method.holder);
-    if ((holder == null) || holder.isNotProgramClass() || !holder.accessFlags.isInterface()) {
+    DexProgramClass holder = asProgramClassOrNull(definitionFor(method.holder));
+    if (holder == null || !holder.accessFlags.isInterface()) {
       return null;
     }
     // First check that there is a target for this invoke-interface to hit. If there is none,
diff --git a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
index bfdfc00..f73139d 100644
--- a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
+++ b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
@@ -149,7 +149,7 @@
   private boolean verifyNoUninstantiatedTypesEscapeIntoLibrary() {
     Set<DexType> classesWithLibraryMethodOverrides = getClassesWithLibraryMethodOverrides(appView);
     for (DexProgramClass clazz : appView.appInfo().classes()) {
-      assert appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz.type)
+      assert appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz)
           || !classesWithLibraryMethodOverrides.contains(clazz.type)
           || nonEscapingClassesWithLibraryMethodOverrides.contains(clazz.type);
     }