Make ResolutionResult a class.

This is in preparation for refactoring resolution and lookup to have a
single definitive implementation.

Bug: 140204899
Change-Id: I33caf64c8af3929229629aed0738052f48976213
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 773f4ad..d569852 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -6,8 +6,9 @@
 import com.android.tools.r8.graph.ResolutionResult.ArrayCloneMethodResult;
 import com.android.tools.r8.graph.ResolutionResult.ClassNotFoundResult;
 import com.android.tools.r8.graph.ResolutionResult.IncompatibleClassResult;
-import com.android.tools.r8.graph.ResolutionResult.MultiResult;
+import com.android.tools.r8.graph.ResolutionResult.MultiResolutionResult;
 import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
+import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
@@ -190,7 +191,7 @@
   public DexEncodedMethod lookupStaticTarget(DexMethod method) {
     assert checkIfObsolete();
     ResolutionResult resolutionResult = resolveMethod(method.holder, method);
-    DexEncodedMethod target = resolutionResult.asSingleTarget();
+    DexEncodedMethod target = resolutionResult.getSingleTarget();
     return target == null || target.isStatic() ? target : null;
   }
 
@@ -215,7 +216,7 @@
     // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokespecial, use
     // the "symbolic reference" if the "symbolic reference" does not name a class.
     if (definitionFor(method.holder).isInterface()) {
-      return resolveMethodOnInterface(method.holder, method).asSingleTarget();
+      return resolveMethodOnInterface(method.holder, method).getSingleTarget();
     }
     // Then, resume on the search, but this time, starting from the holder of the caller.
     DexClass contextClass = definitionFor(invocationContext);
@@ -223,7 +224,7 @@
       return null;
     }
     resolutionResult = resolveMethod(contextClass.superType, method);
-    DexEncodedMethod target = resolutionResult.asSingleTarget();
+    DexEncodedMethod target = resolutionResult.getSingleTarget();
     return target == null || !target.isStatic() ? target : null;
   }
 
@@ -238,7 +239,7 @@
   public DexEncodedMethod lookupDirectTarget(DexMethod method) {
     assert checkIfObsolete();
     ResolutionResult resolutionResult = resolveMethod(method.holder, method);
-    DexEncodedMethod target = resolutionResult.asSingleTarget();
+    DexEncodedMethod target = resolutionResult.getSingleTarget();
     return target == null || target.isDirectMethod() ? target : null;
   }
 
@@ -252,7 +253,7 @@
     assert checkIfObsolete();
     assert type.isClassType() || type.isArrayType();
     ResolutionResult resolutionResult = resolveMethod(type, method);
-    DexEncodedMethod target = resolutionResult.asSingleTarget();
+    DexEncodedMethod target = resolutionResult.getSingleTarget();
     return target == null || target.isVirtualMethod() ? target : null;
   }
 
@@ -352,7 +353,7 @@
     // Step 2:
     DexEncodedMethod singleTarget = resolveMethodOnClassStep2(clazz, method);
     if (singleTarget != null) {
-      return singleTarget;
+      return new SingleResolutionResult(singleTarget);
     }
     // Finally Step 3:
     return resolveMethodStep3(clazz, method);
@@ -414,7 +415,7 @@
       return result;
     }
     // Return any of the non-default methods.
-    return anyTarget == null ? NoSuchMethodResult.INSTANCE : anyTarget;
+    return anyTarget == null ? NoSuchMethodResult.INSTANCE : new SingleResolutionResult(anyTarget);
   }
 
   /**
@@ -491,7 +492,7 @@
     // Step 2: Look for exact method on interface.
     DexEncodedMethod result = definition.lookupMethod(desc);
     if (result != null) {
-      return result;
+      return new SingleResolutionResult(result);
     }
     // Step 3: Look for matching method on object class.
     DexClass objectClass = definitionFor(dexItemFactory.objectType);
@@ -500,7 +501,7 @@
     }
     result = objectClass.lookupMethod(desc);
     if (result != null && result.accessFlags.isPublic() && !result.accessFlags.isAbstract()) {
-      return result;
+      return new SingleResolutionResult(result);
     }
     // Step 3: Look for maximally-specific superinterface methods or any interface definition.
     //         This is the same for classes and interfaces.
@@ -583,7 +584,7 @@
    */
   public DexEncodedMethod dispatchStaticInvoke(ResolutionResult resolvedMethod) {
     assert checkIfObsolete();
-    DexEncodedMethod target = resolvedMethod.asSingleTarget();
+    DexEncodedMethod target = resolvedMethod.getSingleTarget();
     if (target != null && target.accessFlags.isStatic()) {
       return target;
     }
@@ -597,7 +598,7 @@
    */
   public DexEncodedMethod dispatchDirectInvoke(ResolutionResult resolvedMethod) {
     assert checkIfObsolete();
-    DexEncodedMethod target = resolvedMethod.asSingleTarget();
+    DexEncodedMethod target = resolvedMethod.getSingleTarget();
     if (target != null && !target.accessFlags.isStatic()) {
       return target;
     }
@@ -669,10 +670,12 @@
 
     ResolutionResult build() {
       if (builder != null) {
-        return new MultiResult(builder.build().asList());
-      } else {
-        return singleResult;
+        return new MultiResolutionResult(builder.build().asList());
       }
+      if (singleResult != null) {
+        return new SingleResolutionResult(singleResult);
+      }
+      return null;
     }
   }
 
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 3425946..edec812 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -746,7 +746,7 @@
     if (clazz.isProgramClass()) {
       if (lookUpwards) {
         DexEncodedMethod resolutionResult =
-            resolveMethod(type, dexItemFactory().objectMethods.finalize).asSingleTarget();
+            resolveMethod(type, dexItemFactory().objectMethods.finalize).getSingleTarget();
         if (resolutionResult != null && resolutionResult.isProgramMethod(this)) {
           mayHaveFinalizeMethodDirectlyOrIndirectlyCache.put(type, true);
           return true;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 200240c..776cbaf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -77,7 +77,7 @@
 import java.util.function.IntPredicate;
 import org.objectweb.asm.Opcodes;
 
-public class DexEncodedMethod extends KeyedDexItem<DexMethod> implements ResolutionResult {
+public class DexEncodedMethod extends KeyedDexItem<DexMethod> {
 
   public static final String CONFIGURATION_DEBUGGING_PREFIX = "Shaking error: Missing method in ";
 
@@ -1311,46 +1311,4 @@
       return result;
     }
   }
-
-  @Override
-  public boolean isValidVirtualTarget(InternalOptions options) {
-    return options.canUseNestBasedAccess()
-        ? (!accessFlags.isStatic() && !accessFlags.isConstructor())
-        : isVirtualMethod();
-  }
-
-  @Override
-  public boolean isValidVirtualTargetForDynamicDispatch() {
-    return isVirtualMethod();
-  }
-
-  @Override
-  public DexEncodedMethod asResultOfResolve() {
-    checkIfObsolete();
-    return this;
-  }
-
-  @Override
-  public DexEncodedMethod asSingleTarget() {
-    checkIfObsolete();
-    return this;
-  }
-
-  @Override
-  public boolean hasSingleTarget() {
-    checkIfObsolete();
-    return true;
-  }
-
-  @Override
-  public List<DexEncodedMethod> asListOfTargets() {
-    checkIfObsolete();
-    return Collections.singletonList(this);
-  }
-
-  @Override
-  public void forEachTarget(Consumer<DexEncodedMethod> consumer) {
-    checkIfObsolete();
-    consumer.accept(this);
-  }
 }
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 dfd31fb..6a9a22a 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -11,30 +11,30 @@
 import java.util.Set;
 import java.util.function.Consumer;
 
-public interface ResolutionResult {
+public abstract class ResolutionResult {
 
   // TODO(b/140214802): Remove this method as its usage is questionable.
-  DexEncodedMethod asResultOfResolve();
+  public abstract DexEncodedMethod asResultOfResolve();
 
-  DexEncodedMethod asSingleTarget();
+  public abstract DexEncodedMethod getSingleTarget();
 
-  boolean hasSingleTarget();
+  public abstract boolean hasSingleTarget();
 
-  List<DexEncodedMethod> asListOfTargets();
+  public abstract List<DexEncodedMethod> asListOfTargets();
 
-  void forEachTarget(Consumer<DexEncodedMethod> consumer);
+  public abstract void forEachTarget(Consumer<DexEncodedMethod> consumer);
 
-  boolean isValidVirtualTarget(InternalOptions options);
+  public abstract boolean isValidVirtualTarget(InternalOptions options);
 
-  boolean isValidVirtualTargetForDynamicDispatch();
+  public abstract boolean isValidVirtualTargetForDynamicDispatch();
 
-  default Set<DexEncodedMethod> lookupVirtualDispatchTargets(
+  public Set<DexEncodedMethod> lookupVirtualDispatchTargets(
       boolean isInterface, AppInfoWithSubtyping appInfo) {
     return isInterface ? lookupInterfaceTargets(appInfo) : lookupVirtualTargets(appInfo);
   }
 
   // TODO(b/140204899): Leverage refined receiver type if available.
-  default Set<DexEncodedMethod> lookupVirtualTargets(AppInfoWithSubtyping appInfo) {
+  public Set<DexEncodedMethod> lookupVirtualTargets(AppInfoWithSubtyping appInfo) {
     assert isValidVirtualTarget(appInfo.app().options);
     // First add the target for receiver type method.type.
     Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
@@ -60,7 +60,7 @@
   }
 
   // TODO(b/140204899): Leverage refined receiver type if available.
-  default Set<DexEncodedMethod> lookupInterfaceTargets(AppInfoWithSubtyping appInfo) {
+  public Set<DexEncodedMethod> lookupInterfaceTargets(AppInfoWithSubtyping appInfo) {
     assert isValidVirtualTarget(appInfo.app().options);
     Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
     if (hasSingleTarget()) {
@@ -86,7 +86,7 @@
       //     public void bar() { }
       //   }
       //
-      DexEncodedMethod singleTarget = asSingleTarget();
+      DexEncodedMethod singleTarget = getSingleTarget();
       if (singleTarget.getCode() != null
           && appInfo.hasAnyInstantiatedLambdas(singleTarget.method.holder)) {
         result.add(singleTarget);
@@ -128,11 +128,61 @@
     return result;
   }
 
-  class MultiResult implements ResolutionResult {
+  public static class SingleResolutionResult extends ResolutionResult {
+    final DexEncodedMethod resolutionTarget;
+
+    public static boolean isValidVirtualTarget(InternalOptions options, DexEncodedMethod target) {
+      return options.canUseNestBasedAccess()
+          ? (!target.accessFlags.isStatic() && !target.accessFlags.isConstructor())
+          : target.isVirtualMethod();
+    }
+
+    public SingleResolutionResult(DexEncodedMethod resolutionTarget) {
+      assert resolutionTarget != null;
+      this.resolutionTarget = resolutionTarget;
+    }
+
+    @Override
+    public boolean isValidVirtualTarget(InternalOptions options) {
+      return isValidVirtualTarget(options, resolutionTarget);
+    }
+
+    @Override
+    public boolean isValidVirtualTargetForDynamicDispatch() {
+      return resolutionTarget.isVirtualMethod();
+    }
+
+    @Override
+    public DexEncodedMethod asResultOfResolve() {
+      return resolutionTarget;
+    }
+
+    @Override
+    public DexEncodedMethod getSingleTarget() {
+      return resolutionTarget;
+    }
+
+    @Override
+    public boolean hasSingleTarget() {
+      return true;
+    }
+
+    @Override
+    public List<DexEncodedMethod> asListOfTargets() {
+      return Collections.singletonList(resolutionTarget);
+    }
+
+    @Override
+    public void forEachTarget(Consumer<DexEncodedMethod> consumer) {
+      consumer.accept(resolutionTarget);
+    }
+  }
+
+  public static class MultiResolutionResult extends ResolutionResult {
 
     private final ImmutableList<DexEncodedMethod> methods;
 
-    MultiResult(ImmutableList<DexEncodedMethod> results) {
+    public MultiResolutionResult(ImmutableList<DexEncodedMethod> results) {
       assert results.size() > 1;
       this.methods = results;
     }
@@ -140,7 +190,7 @@
     @Override
     public boolean isValidVirtualTarget(InternalOptions options) {
       for (DexEncodedMethod method : methods) {
-        if (!method.isValidVirtualTarget(options)) {
+        if (!SingleResolutionResult.isValidVirtualTarget(options, method)) {
           return false;
         }
       }
@@ -164,7 +214,7 @@
     }
 
     @Override
-    public DexEncodedMethod asSingleTarget() {
+    public DexEncodedMethod getSingleTarget() {
       // There is no single target that is guaranteed to be called.
       return null;
     }
@@ -185,7 +235,7 @@
     }
   }
 
-  abstract class EmptyResult implements ResolutionResult {
+  public abstract static class EmptyResult extends ResolutionResult {
 
     @Override
     public DexEncodedMethod asResultOfResolve() {
@@ -193,7 +243,7 @@
     }
 
     @Override
-    public DexEncodedMethod asSingleTarget() {
+    public DexEncodedMethod getSingleTarget() {
       return null;
     }
 
@@ -223,7 +273,7 @@
     }
   }
 
-  class ArrayCloneMethodResult extends EmptyResult {
+  public static class ArrayCloneMethodResult extends EmptyResult {
 
     static final ArrayCloneMethodResult INSTANCE = new ArrayCloneMethodResult();
 
@@ -242,7 +292,7 @@
     }
   }
 
-  abstract class FailedResolutionResult extends EmptyResult {
+  public abstract static class FailedResolutionResult extends EmptyResult {
 
     @Override
     public boolean isValidVirtualTarget(InternalOptions options) {
@@ -255,7 +305,7 @@
     }
   }
 
-  class ClassNotFoundResult extends FailedResolutionResult {
+  public static class ClassNotFoundResult extends FailedResolutionResult {
     static final ClassNotFoundResult INSTANCE = new ClassNotFoundResult();
 
     private ClassNotFoundResult() {
@@ -263,7 +313,7 @@
     }
   }
 
-  class IncompatibleClassResult extends FailedResolutionResult {
+  public static class IncompatibleClassResult extends FailedResolutionResult {
     static final IncompatibleClassResult INSTANCE = new IncompatibleClassResult();
 
     private IncompatibleClassResult() {
@@ -271,7 +321,7 @@
     }
   }
 
-  class NoSuchMethodResult extends FailedResolutionResult {
+  public static class NoSuchMethodResult extends FailedResolutionResult {
     static final NoSuchMethodResult INSTANCE = new NoSuchMethodResult();
 
     private NoSuchMethodResult() {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index e8583f6..827529a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -339,7 +339,7 @@
       if (!resolutionResult.hasSingleTarget()) {
         return false;
       }
-      DexType holder = resolutionResult.asSingleTarget().method.holder;
+      DexType holder = resolutionResult.getSingleTarget().method.holder;
       return appView.isSubtype(holder, type).isTrue();
     }
 
@@ -397,7 +397,7 @@
       if (!resolutionResult.hasSingleTarget()) {
         return false;
       }
-      DexType holder = resolutionResult.asSingleTarget().method.holder;
+      DexType holder = resolutionResult.getSingleTarget().method.holder;
       return appView.isSubtype(holder, type).isTrue();
     }
 
@@ -433,7 +433,7 @@
       if (!resolutionResult.hasSingleTarget()) {
         return false;
       }
-      DexType holder = resolutionResult.asSingleTarget().method.holder;
+      DexType holder = resolutionResult.getSingleTarget().method.holder;
       return appView.isSubtype(holder, type).isTrue();
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 72e4c9d..0e0c975 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -191,7 +191,7 @@
         DexEncodedMethod resolutionResult =
             appInfo
                 .resolveMethod(clazz.type, dexItemFactory.objectMethods.finalize)
-                .asSingleTarget();
+                .getSingleTarget();
         return resolutionResult != null && resolutionResult.isProgramMethod(appInfo);
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 6c22405..c6f919d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -109,7 +109,7 @@
       ResolutionResult refinedResolution =
           appView.appInfo().resolveMethod(refinedReceiverType, method);
       if (refinedResolution.hasSingleTarget()) {
-        DexEncodedMethod refinedTarget = refinedResolution.asSingleTarget();
+        DexEncodedMethod refinedTarget = refinedResolution.getSingleTarget();
         Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
         for (DexEncodedMethod target : targets) {
           if (target == refinedTarget
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 7a38882..d9d65e5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -176,7 +176,7 @@
     ResolutionResult finalizeResolutionResult =
         appView.appInfo().resolveMethod(clazz, dexItemFactory.objectMethods.finalize);
     if (finalizeResolutionResult.hasSingleTarget()) {
-      DexMethod finalizeMethod = finalizeResolutionResult.asSingleTarget().method;
+      DexMethod finalizeMethod = finalizeResolutionResult.getSingleTarget().method;
       if (finalizeMethod != dexItemFactory.enumMethods.finalize
           && finalizeMethod != dexItemFactory.objectMethods.finalize) {
         return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index cea6258..adc1112 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -270,7 +270,7 @@
       // references that have actual definitions are marked by the root set builder. So, here, we
       // try again with a resolved target, not the direct definition, which may not exist.
       DexEncodedMethod resolutionTarget =
-          appView.appInfo().resolveMethod(invokedHolder, invokedMethod).asSingleTarget();
+          appView.appInfo().resolveMethod(invokedHolder, invokedMethod).getSingleTarget();
       lookup = lookupMemberRule(resolutionTarget);
     }
     boolean invokeReplaced = false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 084f3d3..40cb024 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -733,7 +733,7 @@
     // signature of the invocation resolves to a private or static method.
     ResolutionResult resolutionResult = appView.appInfo().resolveMethod(callee.holder, callee);
     if (resolutionResult.hasSingleTarget()
-        && !resolutionResult.asSingleTarget().isVirtualMethod()) {
+        && !resolutionResult.getSingleTarget().isVirtualMethod()) {
       return null;
     }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index 8101b6b..942cb91 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -85,7 +85,7 @@
       if (kind == InvokeKind.SUPER) {
         // This is a visibility forward, so check for the direct target.
         DexEncodedMethod targetMethod =
-            appView.appInfo().resolveMethod(target.holder, target).asSingleTarget();
+            appView.appInfo().resolveMethod(target.holder, target).getSingleTarget();
         if (targetMethod != null && targetMethod.accessFlags.isPublic()) {
           if (Log.ENABLED) {
             Log.info(
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 829c227..77d29ab 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.optimize.NestUtils;
@@ -904,7 +905,7 @@
 
   private DexEncodedMethod validateSingleVirtualTarget(
       DexEncodedMethod singleTarget, DexEncodedMethod resolutionResult) {
-    assert resolutionResult.isValidVirtualTarget(options());
+    assert SingleResolutionResult.isValidVirtualTarget(options(), resolutionResult);
 
     if (singleTarget == null || singleTarget == DexEncodedMethod.SENTINEL) {
       return null;
@@ -921,7 +922,7 @@
 
   private boolean isInvalidSingleVirtualTarget(
       DexEncodedMethod singleTarget, DexEncodedMethod resolutionResult) {
-    assert resolutionResult.isValidVirtualTarget(options());
+    assert SingleResolutionResult.isValidVirtualTarget(options(), resolutionResult);
     // Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception
     // at runtime.
     return !singleTarget.accessFlags.isAtLeastAsVisibleAs(resolutionResult.accessFlags);
@@ -956,7 +957,7 @@
           if (refinedResolutionResult.hasSingleTarget()
               && refinedResolutionResult.isValidVirtualTargetForDynamicDispatch()) {
             return validateSingleVirtualTarget(
-                refinedResolutionResult.asSingleTarget(), resolutionResult.asSingleTarget());
+                refinedResolutionResult.getSingleTarget(), resolutionResult.getSingleTarget());
           }
         }
         return null;
@@ -998,7 +999,7 @@
     // Now, resolve the target with the refined receiver type.
     ResolutionResult refinedResolutionResult =
         refinedReceiverIsStrictSubType ? resolveMethodOnClass(refinedHolder, method) : topMethod;
-    DexEncodedMethod topSingleTarget = refinedResolutionResult.asSingleTarget();
+    DexEncodedMethod topSingleTarget = refinedResolutionResult.getSingleTarget();
     DexClass topHolder = definitionFor(topSingleTarget.method.holder);
     // We need to know whether the top method is from an interface, as that would allow it to be
     // shadowed by a default method from an interface further down.
@@ -1012,7 +1013,7 @@
                 topSingleTarget,
                 !refinedHolder.accessFlags.isAbstract(),
                 topIsFromInterface),
-            topMethod.asSingleTarget());
+            topMethod.getSingleTarget());
     assert result != DexEncodedMethod.SENTINEL;
     method.setSingleVirtualMethodCache(refinedReceiverType, result);
     return result;
@@ -1154,7 +1155,7 @@
           if (refinedResolutionResult.hasSingleTarget()
               && refinedResolutionResult.isValidVirtualTargetForDynamicDispatch()) {
             return validateSingleVirtualTarget(
-                refinedResolutionResult.asSingleTarget(), resolutionResult.asSingleTarget());
+                refinedResolutionResult.getSingleTarget(), resolutionResult.getSingleTarget());
           }
         }
         return null;
@@ -1170,8 +1171,8 @@
     }
     // First check that there is a target for this invoke-interface to hit. If there is none,
     // this will fail at runtime.
-    DexEncodedMethod topTarget = resolveMethodOnInterface(holder, method).asSingleTarget();
-    if (topTarget == null || !topTarget.isValidVirtualTarget(options())) {
+    DexEncodedMethod topTarget = resolveMethodOnInterface(holder, method).getSingleTarget();
+    if (topTarget == null || !SingleResolutionResult.isValidVirtualTarget(options(), topTarget)) {
       return null;
     }
     // For kept types we cannot ensure a single target.
@@ -1200,7 +1201,7 @@
         // override them, so we ignore interface methods here. Otherwise, we would look up
         // default methods that are factually never used.
       } else if (!clazz.accessFlags.isAbstract()) {
-        DexEncodedMethod resolutionResult = resolveMethodOnClass(clazz, method).asSingleTarget();
+        DexEncodedMethod resolutionResult = resolveMethodOnClass(clazz, method).getSingleTarget();
         if (resolutionResult == null || isInvalidSingleVirtualTarget(resolutionResult, topTarget)) {
           // This will fail at runtime.
           return null;
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 e7ab7ed..46895aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -39,6 +39,7 @@
 import com.android.tools.r8.graph.KeyedDexItem;
 import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.graph.ResolutionResult;
+import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
 import com.android.tools.r8.ir.analysis.proto.schema.ProtoEnqueuerExtension;
 import com.android.tools.r8.ir.code.ArrayPut;
@@ -1305,7 +1306,7 @@
       reportMissingMethod(method);
       return;
     }
-    DexEncodedMethod encodedMethod = resolutionResult.asSingleTarget();
+    DexEncodedMethod encodedMethod = resolutionResult.getSingleTarget();
     if (encodedMethod == null) {
       // Note: should this be reported too? Or is this unreachable?
       return;
@@ -1927,7 +1928,8 @@
     // Otherwise, the resolution target is marked and cached, and all possible targets identified.
     resolution = findAndMarkResolutionTarget(method, interfaceInvoke, reason);
     virtualTargetsMarkedAsReachable.put(method, resolution);
-    if (resolution.isUnresolved() || !resolution.method.isValidVirtualTarget(options)) {
+    if (resolution.isUnresolved()
+        || !SingleResolutionResult.isValidVirtualTarget(options, resolution.method)) {
       // There is no valid resolution, so any call will lead to a runtime exception.
       return;
     }
@@ -1940,7 +1942,9 @@
 
     assert interfaceInvoke == holder.isInterface();
     Set<DexEncodedMethod> possibleTargets =
-        resolution.method.lookupVirtualDispatchTargets(interfaceInvoke, appInfo);
+        // TODO(b/140214802): Call on the resolution once proper resolution and lookup is resolved.
+        new SingleResolutionResult(resolution.method)
+            .lookupVirtualDispatchTargets(interfaceInvoke, appInfo);
     if (possibleTargets == null || possibleTargets.isEmpty()) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 85da345..a9ec234 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1283,7 +1283,7 @@
         abortMerge = true;
         return null;
       }
-      DexEncodedMethod actual = resolutionResult.asSingleTarget();
+      DexEncodedMethod actual = resolutionResult.getSingleTarget();
       if (actual != method) {
         assert actual.isVirtualMethod() == method.isVirtualMethod();
         return actual;
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
index e914a7b..ccdb49b 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -84,7 +84,7 @@
   public void lookupSingleTarget() {
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnA, resolved.method);
     DexEncodedMethod singleVirtualTarget =
         appInfo.lookupSingleVirtualTarget(methodOnB, methodOnB.holder);
@@ -94,7 +94,7 @@
   @Test
   public void lookupVirtualTargets() {
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnA, resolved.method);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
index 8d867d8..952cfe7 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -143,7 +143,7 @@
   @Test
   public void lookupVirtualTargets() {
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnA, resolved.method);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
index f968c03..7c435d3 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -121,7 +121,7 @@
   public void lookupSingleTarget() {
     ResolutionResult resolutionResult =
         appInfo.resolveMethodOnInterface(methodOnB.holder, methodOnB);
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnB, resolved.method);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
     DexEncodedMethod singleVirtualTarget =
@@ -132,7 +132,7 @@
   @Test
   public void lookupVirtualTargets() {
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(methodOnB.holder, methodOnB);
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnB, resolved.method);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
   }
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
index 20c3cab..c17ed49 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -167,7 +167,7 @@
   @Test
   public void lookupSingleTarget() {
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(methodOnB.holder, methodOnB);
-    DexEncodedMethod resolved = resolutionResult.asSingleTarget();
+    DexEncodedMethod resolved = resolutionResult.getSingleTarget();
     assertEquals(methodOnA, resolved.method);
     assertFalse(resolutionResult.isValidVirtualTarget(appInfo.app().options));
     DexEncodedMethod singleVirtualTarget =