Refactor lookupVirtualDispatchTargets to use LiveSubTypeInfo

This CL also introduces a LookupResult instead of a set of
DexEncodedMethods, to allow for queries later, such as if it is
incomplete or not.

Bug: 148271337
Change-Id: I034636e6900e676d504944145bafe6028881e49d
diff --git a/src/main/java/com/android/tools/r8/graph/LookupResult.java b/src/main/java/com/android/tools/r8/graph/LookupResult.java
new file mode 100644
index 0000000..7a923de
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/LookupResult.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, 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.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState;
+import java.util.Collections;
+import java.util.Set;
+
+public abstract class LookupResult {
+
+  public boolean isLookupResultFailure() {
+    return false;
+  }
+
+  public boolean isLookupResultSuccess() {
+    return false;
+  }
+
+  public LookupResultFailure asLookupResultFailure() {
+    return null;
+  }
+
+  public LookupResultSuccess asLookupResultSuccess() {
+    return null;
+  }
+
+  public static LookupResultSuccess createResult(
+      Set<DexEncodedMethod> methodTargets, LookupResultCollectionState state) {
+    return new LookupResultSuccess(methodTargets, state);
+  }
+
+  public static LookupResultFailure createFailedResult() {
+    return LookupResultFailure.INSTANCE;
+  }
+
+  public static LookupResultSuccess getIncompleteEmptyResult() {
+    return LookupResultSuccess.EMPTY_INSTANCE;
+  }
+
+  public static class LookupResultSuccess extends LookupResult {
+
+    private static final LookupResultSuccess EMPTY_INSTANCE =
+        new LookupResultSuccess(Collections.emptySet(), LookupResultCollectionState.Incomplete);
+
+    private final Set<DexEncodedMethod> methodTargets;
+    private final LookupResultCollectionState state;
+
+    private LookupResultSuccess(
+        Set<DexEncodedMethod> methodTargets, LookupResultCollectionState state) {
+      this.methodTargets = methodTargets;
+      this.state = state;
+    }
+
+    public boolean isEmpty() {
+      return methodTargets == null || methodTargets.isEmpty();
+    }
+
+    public Set<DexEncodedMethod> getMethodTargets() {
+      return methodTargets;
+    }
+
+    @Override
+    public LookupResultSuccess asLookupResultSuccess() {
+      return this;
+    }
+
+    @Override
+    public boolean isLookupResultSuccess() {
+      return true;
+    }
+
+    public boolean isIncomplete() {
+      return state == LookupResultCollectionState.Incomplete;
+    }
+
+    public enum LookupResultCollectionState {
+      Complete,
+      Incomplete,
+    }
+  }
+
+  public static class LookupResultFailure extends LookupResult {
+
+    private static final LookupResultFailure INSTANCE = new LookupResultFailure();
+
+    private LookupResultFailure() {
+      // Empty to only allow creation locally.
+    }
+
+    @Override
+    public LookupResultFailure asLookupResultFailure() {
+      return this;
+    }
+
+    @Override
+    public boolean isLookupResultFailure() {
+      return true;
+    }
+  }
+}
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 f3f308f..c2bd3a4 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -4,6 +4,9 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.LiveSubTypeInfo.LiveSubTypeResult;
+import com.android.tools.r8.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.Sets;
 import java.util.Collection;
@@ -75,7 +78,12 @@
   public abstract DexEncodedMethod lookupInvokeStaticTarget(
       DexProgramClass context, AppInfoWithClassHierarchy appInfo);
 
-  public abstract Set<DexEncodedMethod> lookupVirtualDispatchTargets(AppInfoWithSubtyping appInfo);
+  public abstract LookupResult lookupVirtualDispatchTargets(
+      AppView<?> appView, LiveSubTypeInfo liveSubTypes);
+
+  public final LookupResult lookupVirtualDispatchTargets(AppView<AppInfoWithLiveness> appView) {
+    return lookupVirtualDispatchTargets(appView, appView.appInfo());
+  }
 
   /** Result for a resolution that succeeds with a known declaration/definition. */
   public static class SingleResolutionResult extends ResolutionResult {
@@ -322,19 +330,21 @@
     }
 
     @Override
-    public Set<DexEncodedMethod> lookupVirtualDispatchTargets(AppInfoWithSubtyping appInfo) {
+    public LookupResult lookupVirtualDispatchTargets(
+        AppView<?> appView, LiveSubTypeInfo liveSubTypeInfo) {
       return initialResolutionHolder.isInterface()
-          ? lookupInterfaceTargets(appInfo)
-          : lookupVirtualTargets(appInfo);
+          ? lookupInterfaceTargets(appView, liveSubTypeInfo)
+          : lookupVirtualTargets(appView, liveSubTypeInfo);
     }
 
     // TODO(b/140204899): Leverage refined receiver type if available.
-    private Set<DexEncodedMethod> lookupVirtualTargets(AppInfoWithSubtyping appInfo) {
+    private LookupResult lookupVirtualTargets(AppView<?> appView, LiveSubTypeInfo liveSubTypeInfo) {
       assert !initialResolutionHolder.isInterface();
       if (resolvedMethod.isPrivateMethod()) {
         // If the resolved reference is private there is no dispatch.
         // This is assuming that the method is accessible, which implies self/nest access.
-        return Collections.singleton(resolvedMethod);
+        return LookupResult.createResult(
+            Collections.singleton(resolvedMethod), LookupResultCollectionState.Complete);
       }
       assert resolvedMethod.isNonPrivateVirtualMethod();
       // First add the target for receiver type method.type.
@@ -343,27 +353,29 @@
       DexMethod method = resolvedMethod.method;
       // TODO(b/140204899): Instead of subtypes of holder, we could iterate subtypes of refined
       //   receiver type if available.
-      for (DexType type : appInfo.subtypes(method.holder)) {
-        DexClass clazz = appInfo.definitionFor(type);
-        if (!clazz.isInterface()) {
-          ResolutionResult methods = appInfo.resolveMethodOnClass(clazz, method);
+      for (DexProgramClass programClass :
+          liveSubTypeInfo.getLiveSubTypes(method.holder).getProgramClasses()) {
+        if (!programClass.isInterface()) {
+          ResolutionResult methods = appView.appInfo().resolveMethodOnClass(programClass, method);
           DexEncodedMethod target = methods.getSingleTarget();
           if (target != null && target.isNonPrivateVirtualMethod()) {
             result.add(target);
           }
         }
       }
-      return result;
+      return LookupResult.createResult(result, LookupResultCollectionState.Complete);
     }
 
     // TODO(b/140204899): Leverage refined receiver type if available.
-    private Set<DexEncodedMethod> lookupInterfaceTargets(AppInfoWithSubtyping appInfo) {
+    private LookupResult lookupInterfaceTargets(
+        AppView<?> appView, LiveSubTypeInfo liveSubTypeInfo) {
       assert initialResolutionHolder.isInterface();
       if (resolvedMethod.isPrivateMethod()) {
         // If the resolved reference is private there is no dispatch.
         // This is assuming that the method is accessible, which implies self/nest access.
         assert resolvedMethod.hasCode();
-        return Collections.singleton(resolvedMethod);
+        return LookupResult.createResult(
+            Collections.singleton(resolvedMethod), LookupResultCollectionState.Complete);
       }
       assert resolvedMethod.isNonPrivateVirtualMethod();
       Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
@@ -389,7 +401,7 @@
       //     public void bar() { }
       //   }
       //
-      addIfDefaultMethodWithLambdaInstantiations(appInfo, resolvedMethod, result);
+      addIfDefaultMethodWithLambdaInstantiations(liveSubTypeInfo, resolvedMethod, result);
 
       DexMethod method = resolvedMethod.method;
       Consumer<DexEncodedMethod> addIfNotAbstract =
@@ -410,35 +422,38 @@
 
       // TODO(b/140204899): Instead of subtypes of holder, we could iterate subtypes of refined
       //   receiver type if available.
-      for (DexType type : appInfo.subtypes(method.holder)) {
-        DexClass clazz = appInfo.definitionFor(type);
+      for (DexProgramClass clazz :
+          liveSubTypeInfo.getLiveSubTypes(method.holder).getProgramClasses()) {
         if (clazz.isInterface()) {
-          ResolutionResult targetMethods = appInfo.resolveMethodOnInterface(clazz, method);
+          ResolutionResult targetMethods =
+              appView.appInfo().resolveMethodOnInterface(clazz, method);
           if (targetMethods.isSingleResolution()) {
             // Sub-interfaces can have default implementations that override the resolved method.
             // Therefore we have to add default methods in sub interfaces.
             DexEncodedMethod singleTarget = targetMethods.getSingleTarget();
-            addIfDefaultMethodWithLambdaInstantiations(appInfo, singleTarget, result);
+            addIfDefaultMethodWithLambdaInstantiations(liveSubTypeInfo, singleTarget, result);
             addIfNotAbstractAndBridge.accept(singleTarget);
           }
         } else {
-          ResolutionResult targetMethods = appInfo.resolveMethodOnClass(clazz, method);
+          ResolutionResult targetMethods = appView.appInfo().resolveMethodOnClass(clazz, method);
           if (targetMethods.isSingleResolution()) {
             addIfNotAbstract.accept(targetMethods.getSingleTarget());
           }
         }
       }
-      return result;
+      return LookupResult.createResult(result, LookupResultCollectionState.Complete);
     }
 
     private void addIfDefaultMethodWithLambdaInstantiations(
-        AppInfoWithSubtyping appInfo, DexEncodedMethod method, Set<DexEncodedMethod> result) {
+        LiveSubTypeInfo liveSubTypesInfo, DexEncodedMethod method, Set<DexEncodedMethod> result) {
       if (method == null) {
         return;
       }
       if (method.hasCode()) {
-        DexProgramClass holder = appInfo.definitionForProgramType(method.method.holder);
-        if (appInfo.hasAnyInstantiatedLambdas(holder)) {
+        LiveSubTypeResult liveSubTypes = liveSubTypesInfo.getLiveSubTypes(method.method.holder);
+        // TODO(b/148769279): The below is basically if (true), but should be changed when we
+        //  have live sub type information.
+        if (liveSubTypes.getCallSites() == null || liveSubTypes.getCallSites() != null) {
           result.add(method);
         }
       }
@@ -472,8 +487,9 @@
     }
 
     @Override
-    public Set<DexEncodedMethod> lookupVirtualDispatchTargets(AppInfoWithSubtyping appInfo) {
-      return null;
+    public LookupResult lookupVirtualDispatchTargets(
+        AppView<?> appView, LiveSubTypeInfo liveSubTypeInfo) {
+      return LookupResult.getIncompleteEmptyResult();
     }
   }
 
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 7624412..bdba162 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
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.LookupResult.LookupResultSuccess;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
@@ -83,14 +84,16 @@
     if (!isInvokeMethodWithDynamicDispatch() || !appView.appInfo().hasLiveness()) {
       return null;
     }
-    Collection<DexEncodedMethod> targets =
+    LookupResultSuccess lookupResult =
         appView
             .appInfo()
             .resolveMethod(method.holder, method)
-            .lookupVirtualDispatchTargets(appView.appInfo());
-    if (targets == null) {
+            .lookupVirtualDispatchTargets(appView.withLiveness())
+            .asLookupResultSuccess();
+    if (lookupResult == null) {
       return null;
     }
+    assert lookupResult.getMethodTargets() != null;
     DexType staticReceiverType = getInvokedMethod().holder;
     DexType refinedReceiverType =
         TypeAnalysis.getRefinedReceiverType(
@@ -103,7 +106,7 @@
       if (refinedResolution.isSingleResolution()) {
         DexEncodedMethod refinedTarget = refinedResolution.getSingleTarget();
         Set<DexEncodedMethod> result = Sets.newIdentityHashSet();
-        for (DexEncodedMethod target : targets) {
+        for (DexEncodedMethod target : lookupResult.getMethodTargets()) {
           if (target == refinedTarget
               || appView.isSubtype(target.method.holder, refinedReceiverType).isPossiblyTrue()) {
             result.add(target);
@@ -113,7 +116,7 @@
       }
       // If resolution at the refined type fails, conservatively return the full set of targets.
     }
-    return targets;
+    return lookupResult.getMethodTargets();
   }
 
   public abstract InlineAction computeInlining(
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 610240e..56462db 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -18,6 +18,7 @@
 import com.android.tools.r8.graph.FieldAccessInfo;
 import com.android.tools.r8.graph.FieldAccessInfoCollection;
 import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.Invoke;
@@ -212,7 +213,11 @@
                 ResolutionResult resolution =
                     appView.appInfo().resolveMethod(method.holder, method, isInterface);
                 if (resolution.isVirtualTarget()) {
-                  return resolution.lookupVirtualDispatchTargets(appView.appInfo());
+                  LookupResult lookupResult =
+                      resolution.lookupVirtualDispatchTargets(appView, appView.appInfo());
+                  if (lookupResult.isLookupResultSuccess()) {
+                    return lookupResult.asLookupResultSuccess().getMethodTargets();
+                  }
                 }
                 return null;
               });
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index a4c70be..96819d0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -15,13 +15,13 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.optimize.Inliner.Constraint;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.Collection;
 import java.util.function.BiFunction;
 
 // Computes the inlining constraint for a given instruction.
@@ -442,9 +442,11 @@
 
     // For each of the actual potential targets, derive constraints based on the accessibility
     // of the method itself.
-    Collection<DexEncodedMethod> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appView.appInfo());
-    for (DexEncodedMethod target : targets) {
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    if (lookupResult.isLookupResultFailure()) {
+      return ConstraintWithTarget.NEVER;
+    }
+    for (DexEncodedMethod target : lookupResult.asLookupResultSuccess().getMethodTargets()) {
       methodHolder = graphLense.lookupType(target.method.holder);
       assert appView.definitionFor(methodHolder) != null;
       methodConstraintWithTarget =
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 f744579..04c6c72 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -51,6 +51,7 @@
 import com.android.tools.r8.graph.FieldAccessInfoImpl;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.KeyedDexItem;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ResolutionResult;
@@ -2123,14 +2124,15 @@
     assert resolution.holder.isProgramClass();
 
     assert interfaceInvoke == holder.isInterface();
-    Set<DexEncodedMethod> possibleTargets =
+    LookupResult lookupResult =
         // TODO(b/140214802): Call on the resolution once proper resolution and lookup is resolved.
         new SingleResolutionResult(holder, resolution.holder, resolution.method)
-            .lookupVirtualDispatchTargets(appInfo);
-    if (possibleTargets == null || possibleTargets.isEmpty()) {
+            .lookupVirtualDispatchTargets(appView, appInfo);
+    if (!lookupResult.isLookupResultSuccess()) {
       return;
     }
-    for (DexEncodedMethod encodedPossibleTarget : possibleTargets) {
+    for (DexEncodedMethod encodedPossibleTarget :
+        lookupResult.asLookupResultSuccess().getMethodTargets()) {
       if (encodedPossibleTarget.isAbstract()) {
         continue;
       }
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 8217920..4e17ad6 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
 import com.android.tools.r8.graph.KeyedDexItem;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.PresortedComparable;
@@ -734,11 +735,17 @@
       //   }
       for (DexEncodedMethod method : defaultMethods) {
         // Conservatively find all possible targets for this method.
-        Set<DexEncodedMethod> interfaceTargets =
+        LookupResult lookupResult =
             appInfo
                 .resolveMethodOnInterface(method.method.holder, method.method)
-                .lookupVirtualDispatchTargets(appInfo);
-
+                .lookupVirtualDispatchTargets(appView, appInfo);
+        assert lookupResult.isLookupResultSuccess();
+        if (lookupResult.isLookupResultFailure()) {
+          return true;
+        }
+        assert lookupResult.isLookupResultSuccess();
+        Set<DexEncodedMethod> interfaceTargets =
+            lookupResult.asLookupResultSuccess().getMethodTargets();
         // If [method] is not even an interface-target, then we can safely merge it. Otherwise we
         // need to check for a conflict.
         if (interfaceTargets.remove(method)) {
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index 0924546..4484311 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -7,36 +7,39 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
-import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import org.junit.Before;
 import org.junit.Test;
 
-public class R8GMSCoreLookupTest {
+public class R8GMSCoreLookupTest extends TestBase {
 
   static final String APP_DIR = "third_party/gmscore/v5/";
   private AndroidApp app;
   private DirectMappedDexApplication program;
   private AppInfoWithSubtyping appInfo;
+  private AppView<?> appView;
 
   @Before
-  public void readGMSCore() throws IOException, ExecutionException {
+  public void readGMSCore() throws Exception {
     Path directory = Paths.get(APP_DIR);
     app = ToolHelper.builderFromProgramDirectory(directory).build();
     Path mapFile = directory.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE);
@@ -51,6 +54,7 @@
             .read(proguardMap, executorService)
             .toDirect();
     appInfo = new AppInfoWithSubtyping(program);
+    appView = computeAppViewWithSubtyping(app);
   }
 
   private void testVirtualLookup(DexProgramClass clazz, DexEncodedMethod method) {
@@ -59,16 +63,20 @@
     assertEquals(appInfo.resolveMethod(id.holder, method.method).getSingleTarget(), method);
 
     // Check lookup targets with include method.
-    Set<DexEncodedMethod> targets =
-        appInfo.resolveMethodOnClass(clazz, method.method).lookupVirtualDispatchTargets(appInfo);
+    ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(clazz, method.method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView, appInfo);
+    assertTrue(lookupResult.isLookupResultSuccess());
+    Set<DexEncodedMethod> targets = lookupResult.asLookupResultSuccess().getMethodTargets();
     assertTrue(targets.contains(method));
   }
 
   private void testInterfaceLookup(DexProgramClass clazz, DexEncodedMethod method) {
-    Set<DexEncodedMethod> targets =
+    LookupResult lookupResult =
         appInfo
             .resolveMethodOnInterface(clazz, method.method)
-            .lookupVirtualDispatchTargets(appInfo);
+            .lookupVirtualDispatchTargets(appView, appInfo);
+    assertTrue(lookupResult.isLookupResultSuccess());
+    Set<DexEncodedMethod> targets = lookupResult.asLookupResultSuccess().getMethodTargets();
     if (appInfo.subtypes(method.method.holder).stream()
         .allMatch(t -> appInfo.definitionFor(t).isInterface())) {
       assertEquals(
@@ -81,8 +89,6 @@
     }
   }
 
-
-
   private void testLookup(DexProgramClass clazz) {
     if (clazz.isInterface()) {
       for (DexEncodedMethod method : clazz.virtualMethods()) {
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 45a9a20..ba27c33 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -7,9 +7,11 @@
 
 import com.android.tools.r8.AsmTestBase;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.resolution.singletarget.Main;
 import com.android.tools.r8.resolution.singletarget.one.AbstractSubClass;
@@ -43,9 +45,9 @@
 @RunWith(Parameterized.class)
 public class SingleTargetLookupTest extends AsmTestBase {
 
-  /**
-   * Initialized in @Before rule.
-   */
+  /** Initialized in @Before rule. */
+  public static AppView<AppInfoWithLiveness> appView;
+
   public static AppInfoWithLiveness appInfo;
 
   public static List<Class<?>> CLASSES =
@@ -83,9 +85,8 @@
 
   @BeforeClass
   public static void computeAppInfo() throws Exception {
-    appInfo =
-        computeAppViewWithLiveness(readClassesAndAsmDump(CLASSES, ASM_CLASSES), Main.class)
-            .appInfo();
+    appView = computeAppViewWithLiveness(readClassesAndAsmDump(CLASSES, ASM_CLASSES), Main.class);
+    appInfo = appView.appInfo();
   }
 
   private static Object[] singleTarget(String name, Class<?> receiverAndTarget) {
@@ -222,7 +223,9 @@
         appInfo.resolveMethod(toType(invokeReceiver, appInfo), method).getSingleTarget());
     ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
     if (resolutionResult.isVirtualTarget()) {
-      Set<DexEncodedMethod> targets = resolutionResult.lookupVirtualDispatchTargets(appInfo);
+      LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView, appInfo);
+      assertTrue(lookupResult.isLookupResultSuccess());
+      Set<DexEncodedMethod> targets = lookupResult.asLookupResultSuccess().getMethodTargets();
       Set<DexType> targetHolders =
           targets.stream().map(m -> m.method.holder).collect(Collectors.toSet());
       Assert.assertEquals(allTargetHolders.size(), targetHolders.size());
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
index b119874..3fcc33d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -48,18 +51,23 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
-        ImmutableSet.of(A.class.getTypeName() + ".bar", J.class.getTypeName() + ".bar");
+        ImmutableSet.of(
+            I.class.getTypeName() + ".bar",
+            A.class.getTypeName() + ".bar",
+            J.class.getTypeName() + ".bar");
     assertEquals(expected, targets);
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
index f926d4b..bdd5dd3 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -47,13 +50,15 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(buildClasses(I.class, A.class, Main.class).build(), Main.class)
-            .appInfo();
+    AppView<AppInfoWithLiveness> appView =
+        computeAppViewWithLiveness(buildClasses(I.class, A.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
index 61e872e..266cb48 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -6,6 +6,7 @@
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -15,8 +16,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -47,16 +51,19 @@
   @Test
   public void testDynamicLookupTargets() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, Main.class)
-                    .addClassProgramData(setAImplementsIAndJ())
-                    .build(),
-                Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, Main.class)
+                .addClassProgramData(setAImplementsIAndJ())
+                .build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected = ImmutableSet.of(J.class.getTypeName() + ".foo");
@@ -84,18 +91,21 @@
   }
 
   @Test
-  public void testtestDynamicLookupTargetsWithIndirectDefault() throws Exception {
+  public void testDynamicLookupTargetsWithIndirectDefault() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, K.class, Main.class)
-                    .addClassProgramData(setAimplementsIandK())
-                    .build(),
-                Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, K.class, Main.class)
+                .addClassProgramData(setAimplementsIandK())
+                .build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected = ImmutableSet.of(J.class.getTypeName() + ".foo");
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
index a69a18b..2614319 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.TestRuntime.DexRuntime;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.transformers.ClassTransformer;
@@ -49,19 +50,17 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(A.class, B.class)
-                    .addClassProgramData(transformI(), transformMain())
-                    .build(),
-                Main.class)
-            .appInfo();
+            buildClasses(A.class, B.class)
+                .addClassProgramData(transformI(), transformMain())
+                .build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "<clinit>", appInfo.dexItemFactory());
     Assert.assertThrows(
         AssertionError.class,
-        () -> {
-          appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo);
-        });
+        () -> appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appView));
   }
 
   private Matcher<String> getExpected() {
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
index 3b6022b..1ca966b 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -42,15 +43,15 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.getRuntime().equals(TestRuntime.getDefaultJavaRuntime()));
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(A.class, I.class).addClassProgramData(transformMain()).build(),
-                Main.class)
-            .appInfo();
+            buildClasses(A.class, I.class).addClassProgramData(transformMain()).build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
     Assert.assertThrows(
         AssertionError.class,
-        () -> appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo));
+        () -> appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appView));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
index 88fd988..251fa37 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -47,14 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(J.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
index 23c2215..eff0088 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -47,14 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
index 03a6141..9552212 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -48,14 +51,16 @@
   public void testResolution() throws Exception {
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
index e73a10e..41d4879 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -13,8 +14,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -46,15 +49,17 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, A.class, B.class, C.class, Main.class).build(),
-                Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, A.class, B.class, C.class, Main.class).build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
index 24916b0..84236e5 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -13,8 +14,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -46,14 +49,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
index a9b34f2..a952bb3 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.interfacetargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -13,8 +14,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -46,14 +49,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
index 8a52035..9538dec 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -46,13 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     // TODO(b/148591377): Should we report B.foo()?
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
index 34b536b..4133fbe 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -46,13 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, A.class, B.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, A.class, B.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     // TODO(b/148591377): I.foo() should ideally not be included in the set.
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
index 399ad7d..264ddb0 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -46,13 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected = ImmutableSet.of(J.class.getTypeName() + ".foo");
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
index 4759dc3..ff58047 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -46,16 +50,19 @@
   @Test
   public void testDynamicLookupTargets() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, J.class, Main.class)
-                    .addClassProgramData(setAImplementsIAndJ())
-                    .build(),
-                Main.class)
-            .appInfo();
+            buildClasses(I.class, J.class, Main.class)
+                .addClassProgramData(setAImplementsIAndJ())
+                .build(),
+            Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected = ImmutableSet.of(J.class.getTypeName() + ".foo");
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
index ebbfcef..055c113 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,11 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
+import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
@@ -46,12 +50,15 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(buildClasses(A.class, I.class, Main.class).build(), Main.class)
-            .appInfo();
+    AppView<AppInfoWithLiveness> appView =
+        computeAppViewWithLiveness(buildClasses(A.class, I.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
+    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        appInfo.resolveMethod(method.holder, method).lookupVirtualDispatchTargets(appInfo).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected = ImmutableSet.of(I.class.getTypeName() + ".foo");
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
index e4d1f55..570527c 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.resolution.virtualtargets;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -14,8 +15,10 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.LookupResult;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.google.common.collect.ImmutableSet;
@@ -47,14 +50,16 @@
   @Test
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AppInfoWithLiveness appInfo =
+    AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-                buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class)
-            .appInfo();
+            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+    AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    LookupResult lookupResult = resolutionResult.lookupVirtualDispatchTargets(appView);
+    assertTrue(lookupResult.isLookupResultSuccess());
     Set<String> targets =
-        resolutionResult.lookupVirtualDispatchTargets(appInfo.withSubtyping()).stream()
+        lookupResult.asLookupResultSuccess().getMethodTargets().stream()
             .map(DexEncodedMethod::qualifiedName)
             .collect(Collectors.toSet());
     ImmutableSet<String> expected =