Merge "Removed DexClassPromise and LazyClassFileLoader."
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index 3497778..85c430a 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -5,13 +5,12 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.OutputMode;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.OutputMode;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
-import java.util.List;
 
 abstract class BaseCommand {
 
@@ -147,7 +146,7 @@
     }
 
     /** Add library file resources. */
-    public B addLibraryFiles(List<Path> files) throws IOException {
+    public B addLibraryFiles(Collection<Path> files) throws IOException {
       app.addLibraryFiles(files);
       return self();
     }
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 0ad793c..ceefac5 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -3,15 +3,20 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import static com.android.tools.r8.utils.FileUtils.isArchive;
+
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.OffOrAuto;
 import com.android.tools.r8.utils.OutputMode;
+import com.android.tools.r8.utils.PreloadedResourceProvider;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
 
 /**
  * Immutable command structure for an invocation of the {@code D8} compiler.
@@ -39,6 +44,40 @@
       super(app, CompilationMode.DEBUG);
     }
 
+    /** Add classpath file resources. */
+    public Builder addClasspathFiles(Path... files) throws IOException {
+      return addClasspathFiles(Arrays.asList(files));
+    }
+
+    /** Add classpath file resources. */
+    public Builder addClasspathFiles(Collection<Path> files) throws IOException {
+      for (Path file : files) {
+        if (isArchive(file)) {
+          addClasspathResourceProvider(PreloadedResourceProvider.fromArchive(file));
+        } else {
+          super.addClasspathFiles(file);
+        }
+      }
+      return this;
+    }
+
+    /** Add library file resources. */
+    public Builder addLibraryFiles(Path... files) throws IOException {
+      return addLibraryFiles(Arrays.asList(files));
+    }
+
+    /** Add library file resources. */
+    public Builder addLibraryFiles(Collection<Path> files) throws IOException {
+      for (Path file : files) {
+        if (isArchive(file)) {
+          addLibraryResourceProvider(PreloadedResourceProvider.fromArchive(file));
+        } else {
+          super.addLibraryFiles(file);
+        }
+      }
+      return this;
+    }
+
     public Builder addClasspathResourceProvider(ResourceProvider provider) {
       getAppBuilder().addClasspathResourceProvider(provider);
       return this;
@@ -171,8 +210,6 @@
     internal.removeSwitchMaps = false;
     assert internal.outline.enabled;
     internal.outline.enabled = false;
-    internal.lazyClasspathLoading = true;
-    internal.lazyLibraryLoading = true;
     internal.outputMode = getOutputMode();
     return internal;
   }
diff --git a/src/main/java/com/android/tools/r8/ResourceProvider.java b/src/main/java/com/android/tools/r8/ResourceProvider.java
index 2a5b0dc..bed36e3 100644
--- a/src/main/java/com/android/tools/r8/ResourceProvider.java
+++ b/src/main/java/com/android/tools/r8/ResourceProvider.java
@@ -5,13 +5,22 @@
 
 /**
  * Represents a provider for application resources. All resources returned
- * via this provider should be class file resources and will be loaded on-demand
- * or not loaded at all.
+ * via this provider should be class file resources, other resource kinds
+ * are not yet supported.
  *
- * NOTE: currently only resources representing Java class files can be loaded
- * with lazy resource providers.
+ * Note that the classes will only be created for resources provided by
+ * resource providers on-demand when they are needed by the tool. If
+ * never needed, the resource will never be loaded.
  */
 public interface ResourceProvider {
-  /** Get the class resource associated with the descriptor, or null. */
+  // TODO: Consider adding support for DEX resources.
+
+  /**
+   * Get the class resource associated with the descriptor, or null if
+   * this provider does not have one.
+   *
+   * Method may be called several times for the same resource, and should
+   * support concurrent calls from different threads.
+   */
   Resource getResource(String descriptor);
 }
diff --git a/src/main/java/com/android/tools/r8/bisect/BisectState.java b/src/main/java/com/android/tools/r8/bisect/BisectState.java
index 945578a..183e513 100644
--- a/src/main/java/com/android/tools/r8/bisect/BisectState.java
+++ b/src/main/java/com/android/tools/r8/bisect/BisectState.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexApplication.Builder;
-import com.android.tools.r8.graph.DexClassPromise;
+import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
@@ -261,7 +261,7 @@
     System.out.println("Next bisection range: " + nextRange);
     int goodClasses = 0;
     int badClasses = 0;
-    Map<DexType, DexClassPromise> classes = new HashMap<>();
+    Map<DexType, DexClass> classes = new HashMap<>();
     for (DexLibraryClass clazz : badApp.libraryClasses()) {
       classes.put(clazz.type, clazz);
     }
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index af6bebe..208d0f8 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -16,10 +16,8 @@
 import com.android.tools.r8.graph.ClassKind;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.JarApplicationReader;
 import com.android.tools.r8.graph.JarClassFileReader;
-import com.android.tools.r8.graph.LazyClassFileLoader;
 import com.android.tools.r8.naming.ProguardMapReader;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
@@ -32,7 +30,6 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -95,18 +92,10 @@
       reader.read(DEFAULT_DEX_FILENAME, ClassKind.PROGRAM, input.getStream(closer));
     }
     for (Resource input : inputApp.getClassClasspathResources()) {
-      if (options.lazyClasspathLoading && getResourceClassDescriptorOrNull(input) != null) {
-        addLazyLoader(application, ClassKind.CLASSPATH, builder, input);
-      } else {
-        reader.read(DEFAULT_DEX_FILENAME, ClassKind.CLASSPATH, input.getStream(closer));
-      }
+      reader.read(DEFAULT_DEX_FILENAME, ClassKind.CLASSPATH, input.getStream(closer));
     }
     for (Resource input : inputApp.getClassLibraryResources()) {
-      if (options.lazyLibraryLoading && getResourceClassDescriptorOrNull(input) != null) {
-        addLazyLoader(application, ClassKind.LIBRARY, builder, input);
-      } else {
-        reader.read(DEFAULT_DEX_FILENAME, ClassKind.LIBRARY, input.getStream(closer));
-      }
+      reader.read(DEFAULT_DEX_FILENAME, ClassKind.LIBRARY, input.getStream(closer));
     }
   }
 
@@ -119,16 +108,6 @@
     }
   }
 
-  private void addLazyLoader(JarApplicationReader application,
-      ClassKind classKind, DexApplication.Builder builder, Resource resource) {
-    // Generate expected DEX type.
-    String classDescriptor = getResourceClassDescriptorOrNull(resource);
-    assert classDescriptor != null;
-    DexType type = options.itemFactory.createType(classDescriptor);
-    LazyClassFileLoader newLoader = new LazyClassFileLoader(type, resource, classKind, application);
-    builder.addClassPromise(newLoader, true);
-  }
-
   private void readDexSources(DexApplication.Builder builder, ExecutorService executorService,
       List<Future<?>> futures, Closer closer)
       throws IOException, ExecutionException {
@@ -162,7 +141,7 @@
       for (DexFileReader reader : fileReaders) {
         futures.add(executorService.submit(() -> {
           reader.addCodeItemsTo();  // Depends on Everything for parsing.
-          reader.addClassDefsTo(builder::addClassPromise);  // Depends on Methods, Code items etc.
+          reader.addClassDefsTo(builder::addClass);  // Depends on Methods, Code items etc.
         }));
       }
     }
@@ -231,10 +210,4 @@
       }));
     }
   }
-
-  private static String getResourceClassDescriptorOrNull(Resource resource) {
-    Set<String> descriptors = resource.getClassDescriptors();
-    return (descriptors == null) || (descriptors.size() != 1)
-        ? null : descriptors.iterator().next();
-  }
 }
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 a558b3e..a5c8ff8 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -40,9 +40,8 @@
 
   private Map<Descriptor, KeyedDexItem> computeDefinitions(DexType type) {
     Builder<Descriptor, KeyedDexItem> builder = ImmutableMap.builder();
-    DexClassPromise promise = app.definitionFor(type);
-    if (promise != null) {
-      DexClass clazz = promise.get();
+    DexClass clazz = app.definitionFor(type);
+    if (clazz != null) {
       registerDefinitions(builder, clazz.directMethods());
       registerDefinitions(builder, clazz.virtualMethods());
       registerDefinitions(builder, clazz.instanceFields());
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 9330fdd..73c0533 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -84,22 +84,17 @@
     }
   }
 
-  private void populateSubtypeMap(
-      Map<DexType, DexClassPromise> classes, DexItemFactory dexItemFactory) {
+  private void populateSubtypeMap(Map<DexType, DexClass> classes, DexItemFactory dexItemFactory) {
     dexItemFactory.clearSubtypeInformation();
     dexItemFactory.objectType.tagAsSubtypeRoot();
     Hashtable<DexType, Set<DexType>> map = new Hashtable<>();
-    Function<DexType, DexClass> typeToClass = type -> {
-      DexClassPromise promise = classes.get(type);
-      return promise == null ? null : promise.get();
-    };
-    for (Map.Entry<DexType, DexClassPromise> entry : classes.entrySet()) {
-      populateAllSuperTypes(map, entry.getKey(), entry.getValue().get(), typeToClass);
+    for (Map.Entry<DexType, DexClass> entry : classes.entrySet()) {
+      populateAllSuperTypes(map, entry.getKey(), entry.getValue(), classes::get);
     }
     for (Map.Entry<DexType, Set<DexType>> entry : map.entrySet()) {
       subtypeMap.put(entry.getKey(), ImmutableSet.copyOf(entry.getValue()));
     }
-    assert DexType.validateLevelsAreCorrect(typeToClass, dexItemFactory);
+    assert DexType.validateLevelsAreCorrect(classes::get, dexItemFactory);
   }
 
   // For mapping invoke virtual instruction to target methods.
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index acbc205..33849e8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -34,8 +34,8 @@
 
 public class DexApplication {
 
-  // Maps type into class promise, may be used concurrently.
-  private final ImmutableMap<DexType, DexClassPromise> classMap;
+  // Maps type into class, may be used concurrently.
+  private final ImmutableMap<DexType, DexClass> classMap;
 
   // Lazily loaded classes.
   //
@@ -60,7 +60,7 @@
   /** Constructor should only be invoked by the DexApplication.Builder. */
   private DexApplication(
       ClassNameMapper proguardMap,
-      ImmutableMap<DexType, DexClassPromise> classMap,
+      ImmutableMap<DexType, DexClass> classMap,
       LazyClassCollection lazyClassCollection,
       ImmutableSet<DexType> mainDexList,
       DexItemFactory dexItemFactory,
@@ -75,7 +75,7 @@
     this.timing = timing;
   }
 
-  ImmutableMap<DexType, DexClassPromise> getClassMap() {
+  ImmutableMap<DexType, DexClass> getClassMap() {
     assert lazyClassCollection == null : "Only allowed in non-lazy scenarios.";
     return classMap;
   }
@@ -84,9 +84,9 @@
     List<DexProgramClass> result = new ArrayList<>();
     // Note: we ignore lazy class collection because it
     // is never supposed to be used for program classes.
-    for (DexClassPromise promise : classMap.values()) {
-      if (promise.isProgramClass()) {
-        result.add(promise.get().asProgramClass());
+    for (DexClass clazz : classMap.values()) {
+      if (clazz.isProgramClass()) {
+        result.add(clazz.asProgramClass());
       }
     }
     return result;
@@ -95,28 +95,28 @@
   public Iterable<DexLibraryClass> libraryClasses() {
     assert lazyClassCollection == null : "Only allowed in non-lazy scenarios.";
     List<DexLibraryClass> result = new ArrayList<>();
-    for (DexClassPromise promise : classMap.values()) {
-      if (promise.isLibraryClass()) {
-        result.add(promise.get().asLibraryClass());
+    for (DexClass clazz : classMap.values()) {
+      if (clazz.isLibraryClass()) {
+        result.add(clazz.asLibraryClass());
       }
     }
     return result;
   }
 
   public DexClass definitionFor(DexType type) {
-    DexClassPromise promise = classMap.get(type);
+    DexClass clazz = classMap.get(type);
     // In presence of lazy class collection we also reach out to it
     // as well unless the class found is already a program class.
-    if (lazyClassCollection != null && (promise == null || !promise.isProgramClass())) {
-      promise = lazyClassCollection.get(type, promise);
+    if (lazyClassCollection != null && (clazz == null || !clazz.isProgramClass())) {
+      clazz = lazyClassCollection.get(type, clazz);
     }
-    return promise == null ? null : promise.get();
+    return clazz;
   }
 
   public DexProgramClass programDefinitionFor(DexType type) {
-    DexClassPromise promise = classMap.get(type);
+    DexClass clazz = classMap.get(type);
     // Don't bother about lazy class collection, it should never load program classes.
-    return (promise == null || !promise.isProgramClass()) ? null : promise.get().asProgramClass();
+    return (clazz == null || !clazz.isProgramClass()) ? null : clazz.asProgramClass();
   }
 
   public String toString() {
@@ -239,7 +239,7 @@
 
   public static class Builder {
 
-    private final Hashtable<DexType, DexClassPromise> classMap = new Hashtable<>();
+    private final Hashtable<DexType, DexClass> classMap = new Hashtable<>();
     private LazyClassCollection lazyClassCollection;
 
     public final Hashtable<DexCode, DexCode> codeItems = new Hashtable<>();
@@ -261,7 +261,7 @@
       this(application, application.classMap);
     }
 
-    public Builder(DexApplication application, Map<DexType, DexClassPromise> classMap) {
+    public Builder(DexApplication application, Map<DexType, DexClass> classMap) {
       this.classMap.putAll(classMap);
       this.lazyClassCollection = application.lazyClassCollection;
       proguardMap = application.proguardMap;
@@ -282,8 +282,8 @@
       return this;
     }
 
-    public Builder addClassPromise(DexClassPromise promise) {
-      addClassPromise(promise, false);
+    public Builder addClass(DexClass clazz) {
+      addClass(clazz, false);
       return this;
     }
 
@@ -299,7 +299,7 @@
 
     public Builder addSynthesizedClass(DexProgramClass synthesizedClass, boolean addToMainDexList) {
       assert synthesizedClass.isProgramClass() : "All synthesized classes must be program classes";
-      addClassPromise(synthesizedClass);
+      addClass(synthesizedClass);
       if (addToMainDexList && !mainDexList.isEmpty()) {
         mainDexList.add(synthesizedClass.type);
       }
@@ -310,28 +310,24 @@
       List<DexProgramClass> result = new ArrayList<>();
       // Note: we ignore lazy class collection because it
       // is never supposed to be used for program classes.
-      for (DexClassPromise promise : classMap.values()) {
-        if (promise.isProgramClass()) {
-          result.add(promise.get().asProgramClass());
+      for (DexClass clazz : classMap.values()) {
+        if (clazz.isProgramClass()) {
+          result.add(clazz.asProgramClass());
         }
       }
       return result;
     }
 
     // Callback from FileReader when parsing a DexProgramClass (multi-threaded).
-    private void addClass(DexClass clazz, boolean skipLibDups) {
-      addClassPromise(clazz, skipLibDups);
-    }
-
-    public synchronized void addClassPromise(DexClassPromise promise, boolean skipLibDups) {
-      assert promise != null;
-      DexType type = promise.getType();
-      DexClassPromise oldPromise = classMap.get(type);
-      if (oldPromise != null) {
-        promise = chooseClass(promise, oldPromise, skipLibDups);
+    public synchronized void addClass(DexClass newClass, boolean skipLibDups) {
+      assert newClass != null;
+      DexType type = newClass.type;
+      DexClass oldClass = classMap.get(type);
+      if (oldClass != null) {
+        newClass = chooseClass(newClass, oldClass, skipLibDups);
       }
-      if (oldPromise != promise) {
-        classMap.put(type, promise);
+      if (oldClass != newClass) {
+        classMap.put(type, newClass);
       }
     }
 
@@ -352,53 +348,49 @@
     }
   }
 
-  public static DexClassPromise chooseClass(
-      DexClassPromise a, DexClassPromise b, boolean skipLibDups) {
+  public static DexClass chooseClass(DexClass a, DexClass b, boolean skipLibDups) {
     // NOTE: We assume that there should not be any conflicting names in user defined
     // classes and/or linked jars. If we ever want to allow 'keep first'-like policy
     // to resolve this kind of conflict between program and/or classpath classes, we'll
     // need to make sure we choose the class we keep deterministically.
     if (a.isProgramClass() && b.isProgramClass()) {
-      if (allowProgramClassConflict(a, b)) {
+      if (allowProgramClassConflict(a.asProgramClass(), b.asProgramClass())) {
         return a;
       }
-      throw new CompilationError(
-          "Program type already present: " + a.getType().toSourceString());
+      throw new CompilationError("Program type already present: " + a.type.toSourceString());
     }
     if (a.isProgramClass()) {
-      return chooseBetweenProgramAndOtherClass(a, b);
+      return chooseClass(a.asProgramClass(), b);
     }
     if (b.isProgramClass()) {
-      return chooseBetweenProgramAndOtherClass(b, a);
+      return chooseClass(b.asProgramClass(), a);
     }
 
     if (a.isClasspathClass() && b.isClasspathClass()) {
-      throw new CompilationError(
-          "Classpath type already present: " + a.getType().toSourceString());
+      throw new CompilationError("Classpath type already present: " + a.type.toSourceString());
     }
     if (a.isClasspathClass()) {
-      return chooseBetweenClasspathAndLibraryClass(a, b);
+      return chooseClass(a.asClasspathClass(), b.asLibraryClass());
     }
     if (b.isClasspathClass()) {
-      return chooseBetweenClasspathAndLibraryClass(b, a);
+      return chooseClass(b.asClasspathClass(), a.asLibraryClass());
     }
 
-    return chooseBetweenLibraryClasses(b, a, skipLibDups);
+    return chooseClasses(b.asLibraryClass(), a.asLibraryClass(), skipLibDups);
   }
 
-  private static boolean allowProgramClassConflict(DexClassPromise a, DexClassPromise b) {
+  private static boolean allowProgramClassConflict(DexProgramClass a, DexProgramClass b) {
     // Currently only allow collapsing synthetic lambda classes.
     return a.getOrigin() == Resource.Kind.DEX
         && b.getOrigin() == Resource.Kind.DEX
-        && a.get().accessFlags.isSynthetic()
-        && b.get().accessFlags.isSynthetic()
-        && LambdaRewriter.hasLambdaClassPrefix(a.getType())
-        && LambdaRewriter.hasLambdaClassPrefix(b.getType());
+        && a.accessFlags.isSynthetic()
+        && b.accessFlags.isSynthetic()
+        && LambdaRewriter.hasLambdaClassPrefix(a.type)
+        && LambdaRewriter.hasLambdaClassPrefix(b.type);
   }
 
-  private static DexClassPromise chooseBetweenProgramAndOtherClass(
-      DexClassPromise selected, DexClassPromise ignored) {
-    assert selected.isProgramClass() && !ignored.isProgramClass();
+  private static DexClass chooseClass(DexProgramClass selected, DexClass ignored) {
+    assert !ignored.isProgramClass();
     if (ignored.isLibraryClass()) {
       logIgnoredClass(ignored, "Class `%s` was specified as library and program type.");
     }
@@ -406,27 +398,24 @@
     return selected;
   }
 
-  private static DexClassPromise chooseBetweenClasspathAndLibraryClass(
-      DexClassPromise selected, DexClassPromise ignored) {
-    assert selected.isClasspathClass() && ignored.isLibraryClass();
+  private static DexClass chooseClass(DexClasspathClass selected, DexLibraryClass ignored) {
     logIgnoredClass(ignored, "Class `%s` was specified as library and classpath type.");
     return selected;
   }
 
-  private static DexClassPromise chooseBetweenLibraryClasses(
-      DexClassPromise selected, DexClassPromise ignored, boolean skipDups) {
-    assert selected.isLibraryClass() && ignored.isLibraryClass();
+  private static DexClass chooseClasses(
+      DexLibraryClass selected, DexLibraryClass ignored, boolean skipDups) {
     if (!skipDups) {
       throw new CompilationError(
-          "Library type already present: " + selected.getType().toSourceString());
+          "Library type already present: " + selected.type.toSourceString());
     }
     logIgnoredClass(ignored, "Class `%s` was specified twice as a library type.");
     return selected;
   }
 
-  private static void logIgnoredClass(DexClassPromise ignored, String message) {
+  private static void logIgnoredClass(DexClass ignored, String message) {
     if (Log.ENABLED) {
-      Log.warn(DexApplication.class, message, ignored.getType().toSourceString());
+      Log.warn(DexApplication.class, message, ignored.type.toSourceString());
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index f684309..3deec04 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.google.common.base.MoreObjects;
 
-public abstract class DexClass extends DexItem implements DexClassPromise {
+public abstract class DexClass extends DexItem {
 
   private static final DexEncodedMethod[] NO_METHODS = {};
   private static final DexEncodedField[] NO_FIELDS = {};
@@ -118,7 +118,6 @@
 
   public abstract void addDependencies(MixedSectionCollection collector);
 
-  @Override
   public boolean isProgramClass() {
     return false;
   }
@@ -127,7 +126,6 @@
     return null;
   }
 
-  @Override
   public boolean isClasspathClass() {
     return false;
   }
@@ -136,7 +134,6 @@
     return null;
   }
 
-  @Override
   public boolean isLibraryClass() {
     return false;
   }
@@ -154,21 +151,10 @@
     return null;
   }
 
-  @Override
   public Resource.Kind getOrigin() {
     return this.origin;
   }
 
-  @Override
-  public DexClass get() {
-    return this;
-  }
-
-  @Override
-  public DexType getType() {
-    return type;
-  }
-
   public boolean hasClassInitializer() {
     return getClassInitializer() != null;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassPromise.java b/src/main/java/com/android/tools/r8/graph/DexClassPromise.java
deleted file mode 100644
index c0bdf20..0000000
--- a/src/main/java/com/android/tools/r8/graph/DexClassPromise.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2017, 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.Resource;
-
-/**
- * Provides a way for delayed DexClass discovery.
- *
- * Provides minimal class details of the promised class and
- * provides the class when asked by calling method get().
- *
- * Note that DexClass also implements this interface, since it
- * represents a 'materialized' promise for a class.
- */
-public interface DexClassPromise {
-  DexType getType();
-
-  Resource.Kind getOrigin();
-
-  boolean isProgramClass();
-
-  boolean isClasspathClass();
-
-  boolean isLibraryClass();
-
-  DexClass get();
-}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java b/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java
deleted file mode 100644
index e5792cd..0000000
--- a/src/main/java/com/android/tools/r8/graph/LazyClassFileLoader.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2017, 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 static com.android.tools.r8.utils.FileUtils.DEFAULT_DEX_FILENAME;
-
-import com.android.tools.r8.Resource;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.Unreachable;
-import com.google.common.io.Closer;
-import java.io.IOException;
-
-// Lazily loads a class file represented by resource.
-public final class LazyClassFileLoader implements DexClassPromise {
-  // Resource representing file definition.
-  private final Resource resource;
-  // Class kind to be created.
-  private final ClassKind classKind;
-
-  // Application reader to be used. Note that the reader may be reused in
-  // many loaders and may be used concurrently, it is considered to be
-  // thread-safe since its only state is internal options which we
-  // consider immutable after they are initialized (barring dex factory
-  // which is thread-safe).
-  private final JarApplicationReader reader;
-
-  // Dex type of the class to be created.
-  private final DexType type;
-
-  // Cached loaded class if get(...) method has already been called, this
-  // field is only accessed in context synchronized on `this`.
-  private DexClass loadedClass = null;
-
-  public LazyClassFileLoader(DexType type,
-      Resource resource, ClassKind classKind, JarApplicationReader reader) {
-    this.resource = resource;
-    this.reader = reader;
-    this.type = type;
-    this.classKind = classKind;
-    assert classKind != ClassKind.PROGRAM;
-  }
-
-  // Callback method for JarClassFileReader, is always called in synchronized context.
-  private void addClass(DexClass clazz) {
-    assert clazz != null;
-    assert loadedClass == null;
-    loadedClass = clazz;
-  }
-
-  @Override
-  public DexType getType() {
-    return type;
-  }
-
-  @Override
-  public Resource.Kind getOrigin() {
-    return Resource.Kind.CLASSFILE;
-  }
-
-  @Override
-  public boolean isProgramClass() {
-    return false;
-  }
-
-  @Override
-  public boolean isClasspathClass() {
-    return classKind == ClassKind.CLASSPATH;
-  }
-
-  @Override
-  public boolean isLibraryClass() {
-    return classKind == ClassKind.LIBRARY;
-  }
-
-  // Loads the class from the resource. Synchronized on `this` to avoid
-  // unnecessary complications, thus all threads trying to load a class with
-  // this loader will wait for the first load to finish.
-  @Override
-  public synchronized DexClass get() {
-    if (loadedClass != null) {
-      return loadedClass;
-    }
-
-    try (Closer closer = Closer.create()) {
-      JarClassFileReader reader = new JarClassFileReader(this.reader, this::addClass);
-      reader.read(DEFAULT_DEX_FILENAME, classKind, resource.getStream(closer));
-    } catch (IOException e) {
-      throw new CompilationError("Failed to load class: " + type.toSourceString(), e);
-    }
-
-    if (loadedClass == null) {
-      throw new Unreachable("Class is supposed to be loaded: " + type.toSourceString());
-    }
-
-    if (loadedClass.type != type) {
-      throw new CompilationError("Class content provided for type descriptor "
-          + type.toSourceString() + " actually defines class " + loadedClass.type.toSourceString());
-    }
-
-    return loadedClass;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 01be50d..baaf7d0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -226,7 +226,7 @@
     InterfaceProcessor processor = new InterfaceProcessor(this);
     for (DexProgramClass clazz : builder.getProgramClasses()) {
       if (shouldProcess(clazz, flavour, true)) {
-        processor.process(clazz.get().asProgramClass());
+        processor.process(clazz.asProgramClass());
       }
     }
     return processor.companionClasses;
@@ -236,7 +236,7 @@
     ClassProcessor processor = new ClassProcessor(this);
     for (DexProgramClass clazz : builder.getProgramClasses()) {
       if (shouldProcess(clazz, flavour, false)) {
-        processor.process(clazz.get());
+        processor.process(clazz);
       }
     }
     return processor.getForwardMethods();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 37bfdaa..cb518a3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexAnnotationSetRefList;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassPromise;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -388,6 +387,10 @@
     DexClass definitionFor(DexType type) {
       return rewriter.converter.appInfo.app.definitionFor(type);
     }
+
+    DexProgramClass programDefinitionFor(DexType type) {
+      return rewriter.converter.appInfo.app.programDefinitionFor(type);
+    }
   }
 
   // Used for targeting methods referenced directly without creating accessors.
@@ -415,9 +418,7 @@
       // We already found the static method to be called, just relax its accessibility.
       assert descriptor.getAccessibility() != null;
       descriptor.getAccessibility().unsetPrivate();
-      DexClassPromise promise = definitionFor(descriptor.implHandle.asMethod().holder);
-      assert promise != null;
-      DexClass implMethodHolder = promise.get();
+      DexClass implMethodHolder = definitionFor(descriptor.implHandle.asMethod().holder);
       if (implMethodHolder.isInterface()) {
         descriptor.getAccessibility().setPublic();
       }
@@ -438,9 +439,7 @@
       // For all instantiation points for which compiler creates lambda$
       // methods, it creates these methods in the same class/interface.
       DexMethod implMethod = descriptor.implHandle.asMethod();
-      DexClassPromise promise = definitionFor(implMethod.holder);
-      assert promise != null;
-      DexClass implMethodHolder = promise.get();
+      DexClass implMethodHolder = definitionFor(implMethod.holder);
 
       DexEncodedMethod[] directMethods = implMethodHolder.directMethods;
       for (int i = 0; i < directMethods.length; i++) {
@@ -481,9 +480,8 @@
     @Override
     boolean ensureAccessibility() {
       // Create a static accessor with proper accessibility.
-      DexClassPromise promise = definitionFor(callTarget.holder);
-      assert promise != null && promise.isProgramClass();
-      DexClass accessorClass = promise.get();
+      DexProgramClass accessorClass = programDefinitionFor(callTarget.holder);
+      assert accessorClass != null;
 
       DexAccessFlags accessorFlags = new DexAccessFlags(
           Constants.ACC_SYNTHETIC | Constants.ACC_STATIC |
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index ee0614f..88d371b 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -162,12 +162,12 @@
     }
     DexProgramClass newHolder = null;
     // Recurse through supertype chain.
-    if (originalClass.superType.isSubtypeOf(targetClass.getType(), appInfo)) {
+    if (originalClass.superType.isSubtypeOf(targetClass.type, appInfo)) {
       DexClass superClass = appInfo.definitionFor(originalClass.superType);
       newHolder = findBridgeMethodHolder(superClass, targetClass, packageDescriptor);
     } else {
       for (DexType iface : originalClass.interfaces.values) {
-        if (iface.isSubtypeOf(targetClass.getType(), appInfo)) {
+        if (iface.isSubtypeOf(targetClass.type, appInfo)) {
           DexClass interfaceClass = appInfo.definitionFor(iface);
           newHolder = findBridgeMethodHolder(interfaceClass, targetClass, packageDescriptor);
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index f801cdd..21ab0d7 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassPromise;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexLibraryClass;
@@ -55,8 +54,8 @@
     return new DexApplication.Builder(application, removeUnusedClassStructure(application));
   }
 
-  private Map<DexType, DexClassPromise> removeUnusedClassStructure(DexApplication application) {
-    Map<DexType, DexClassPromise> classMap = new IdentityHashMap<>();
+  private Map<DexType, DexClass> removeUnusedClassStructure(DexApplication application) {
+    Map<DexType, DexClass> classMap = new IdentityHashMap<>();
     for (DexLibraryClass clazz : application.libraryClasses()) {
       classMap.put(clazz.type, clazz);
     }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 5945741..bb8bc7c 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -35,9 +35,6 @@
   public boolean skipDebugLineNumberOpt = false;
   public boolean skipClassMerging = true;
 
-  public boolean lazyClasspathLoading = false;
-  public boolean lazyLibraryLoading = false;
-
   // Number of threads to use while processing the dex files.
   public int numberOfThreads = NOT_SPECIFIED;
   // Print smali disassembly.
diff --git a/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java b/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
index 0e71973..d7379ef 100644
--- a/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/LazyClassCollection.java
@@ -3,41 +3,41 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils;
 
+import static com.android.tools.r8.utils.FileUtils.DEFAULT_DEX_FILENAME;
+
 import com.android.tools.r8.Resource;
 import com.android.tools.r8.ResourceProvider;
 import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.ClassKind;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassPromise;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.JarApplicationReader;
-import com.android.tools.r8.graph.LazyClassFileLoader;
+import com.android.tools.r8.graph.JarClassFileReader;
 import com.google.common.collect.ImmutableList;
+import com.google.common.io.Closer;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 
 /**
  * Represents a collection of classes loaded lazily from a set of lazy resource
- * providers. The collection is autonomous, it lazily collects promises but
+ * providers. The collection is autonomous, it lazily collects classes but
  * does not choose the classes in cases of conflicts, delaying it until
  * the class is asked for.
  *
  * NOTE: only java class resources are allowed to be lazy loaded.
  */
 public final class LazyClassCollection {
-  // Stores promises for types which have ever been asked for before. Special value
-  // EmptyPromise.INSTANCE indicates there were no resources for this type in any of
-  // the resource providers.
-  //
-  // Promises are potentially coming from different providers and chained, but in majority
-  // of the cases there will only be one promise per type. We store promises for all
-  // the resource providers and resolve the classes at the time it is queried.
+  // For each type which has ever been queried stores one or several classes loaded
+  // from resources provided by different resource providers. In majority of the
+  // cases there will only be one class per type. We store classes for all the
+  // resource providers and resolve the classes at the time it is queried.
   //
   // Must be synchronized on `classes`.
-  private final Map<DexType, DexClassPromise> classes = new IdentityHashMap<>();
+  private final Map<DexType, DexClass[]> classes = new IdentityHashMap<>();
 
   // Available lazy resource providers.
   private final List<ResourceProvider> classpathProviders;
@@ -59,150 +59,112 @@
 
   /**
    * Returns a definition for a class or `null` if there is no such class.
-   * Parameter `dominator` represents the class promise that is considered
+   * Parameter `dominator` represents a class that is considered
    * to be already loaded, it may be null but if specified it may affect
    * the conflict resolution. For example non-lazy loaded classpath class
    * provided as `dominator` will conflict with lazy-loaded classpath classes.
    */
-  public DexClassPromise get(DexType type, DexClassPromise dominator) {
-    DexClassPromise promise;
-
-    // Check if the promise already exists.
+  public DexClass get(DexType type, DexClass dominator) {
+    DexClass[] candidates;
     synchronized (classes) {
-      promise = classes.get(type);
+      candidates = classes.get(type);
     }
 
-    if (promise == null) {
-      // Building a promise may be time consuming, we do it outside
-      // the lock so others don't have to wait.
-      promise = buildPromiseChain(type);
+    if (candidates == null) {
+      String descriptor = type.descriptor.toString();
 
+      // Loading resources and constructing classes may be time consuming, we do it
+      // outside the global lock so others don't have to wait.
+      List<Resource> classpathResources = collectResources(classpathProviders, descriptor);
+      List<Resource> libraryResources = collectResources(libraryProviders, descriptor);
+
+      candidates = new DexClass[classpathResources.size() + libraryResources.size()];
+
+      // Check if someone else has already added the array for this type.
       synchronized (classes) {
-        DexClassPromise existing = classes.get(type);
+        DexClass[] existing = classes.get(type);
         if (existing != null) {
-          promise = existing;
+          assert candidates.length == existing.length;
+          candidates = existing;
         } else {
-          classes.put(type, promise);
+          classes.put(type, candidates);
         }
       }
 
-      assert promise != EmptyPromise.INSTANCE;
+      if (candidates.length > 0) {
+        // Load classes in synchronized content unique for the type.
+        synchronized (candidates) {
+          // Either all or none of the array classes will be loaded, so we use this
+          // as a criteria for checking if we need to load classes.
+          if (candidates[0] == null) {
+            new ClassLoader(type, candidates, reader, classpathResources, libraryResources).load();
+          }
+        }
+      }
     }
 
-    return promise == EmptyPromise.INSTANCE ? dominator : chooseClass(dominator, promise);
+    // Choose class in case there are conflicts.
+    DexClass candidate = dominator;
+    for (DexClass clazz : candidates) {
+      candidate = (candidate == null) ? clazz
+          : DexApplication.chooseClass(candidate, clazz, /* skipLibDups: */ true);
+    }
+    return candidate;
   }
 
-  // Build chain of lazy promises or `null` if none of the providers
-  // provided resource for this type.
-  private DexClassPromise buildPromiseChain(DexType type) {
-    String descriptor = type.descriptor.toString();
-    DexClassPromise promise = buildPromiseChain(
-        type, descriptor, null, classpathProviders, ClassKind.CLASSPATH);
-    promise = buildPromiseChain(
-        type, descriptor, promise, libraryProviders, ClassKind.LIBRARY);
-    return promise == null ? EmptyPromise.INSTANCE : promise;
-  }
-
-  private DexClassPromise buildPromiseChain(DexType type, String descriptor,
-      DexClassPromise promise, List<ResourceProvider> providers, ClassKind classKind) {
+  private List<Resource> collectResources(List<ResourceProvider> providers, String descriptor) {
+    List<Resource> resources = new ArrayList<>();
     for (ResourceProvider provider : providers) {
       Resource resource = provider.getResource(descriptor);
-      if (resource == null) {
-        continue;
+      if (resource != null) {
+        resources.add(resource);
       }
+    }
+    return resources;
+  }
 
-      if (resource.kind != Resource.Kind.CLASSFILE) {
-        throw new CompilationError("Resource returned by resource provider for type " +
-            type.toSourceString() + " must be a class file resource.");
+  private static final class ClassLoader {
+    int index = 0;
+    final DexType type;
+    final DexClass[] classes;
+    final JarApplicationReader reader;
+    final List<Resource> classpathResources;
+    final List<Resource> libraryResources;
+
+    ClassLoader(DexType type, DexClass[] classes, JarApplicationReader reader,
+        List<Resource> classpathResources, List<Resource> libraryResources) {
+      this.type = type;
+      this.classes = classes;
+      this.reader = reader;
+      this.classpathResources = classpathResources;
+      this.libraryResources = libraryResources;
+    }
+
+    void addClass(DexClass clazz) {
+      assert index < classes.length;
+      assert clazz != null;
+      if (clazz.type != type) {
+        throw new CompilationError("Class content provided for type descriptor "
+            + type.toSourceString() + " actually defines class " + clazz.type
+            .toSourceString());
       }
-
-      LazyClassFileLoader loader = new LazyClassFileLoader(type, resource, classKind, reader);
-      promise = (promise == null) ? loader : new DexClassPromiseChain(loader, promise);
-    }
-    return promise;
-  }
-
-  // Chooses the proper promise. Recursion is not expected to be deep.
-  private DexClassPromise chooseClass(DexClassPromise dominator, DexClassPromise candidate) {
-    DexClassPromise best = (dominator == null) ? candidate
-        : DexApplication.chooseClass(dominator, candidate, /* skipLibDups: */ true);
-    return (candidate instanceof DexClassPromiseChain)
-        ? chooseClass(best, ((DexClassPromiseChain) candidate).next) : best;
-  }
-
-  private static final class EmptyPromise implements DexClassPromise {
-    static final EmptyPromise INSTANCE = new EmptyPromise();
-
-    @Override
-    public DexType getType() {
-      throw new Unreachable();
+      classes[index++] = clazz;
     }
 
-    @Override
-    public Resource.Kind getOrigin() {
-      throw new Unreachable();
-    }
-
-    @Override
-    public boolean isProgramClass() {
-      throw new Unreachable();
-    }
-
-    @Override
-    public boolean isClasspathClass() {
-      throw new Unreachable();
-    }
-
-    @Override
-    public boolean isLibraryClass() {
-      throw new Unreachable();
-    }
-
-    @Override
-    public DexClass get() {
-      throw new Unreachable();
-    }
-  }
-
-  private static final class DexClassPromiseChain implements DexClassPromise {
-    final DexClassPromise promise;
-    final DexClassPromise next;
-
-    private DexClassPromiseChain(DexClassPromise promise, DexClassPromise next) {
-      assert promise != null;
-      assert next != null;
-      this.promise = promise;
-      this.next = next;
-    }
-
-    @Override
-    public DexType getType() {
-      return promise.getType();
-    }
-
-    @Override
-    public Resource.Kind getOrigin() {
-      return promise.getOrigin();
-    }
-
-    @Override
-    public boolean isProgramClass() {
-      return promise.isProgramClass();
-    }
-
-    @Override
-    public boolean isClasspathClass() {
-      return promise.isClasspathClass();
-    }
-
-    @Override
-    public boolean isLibraryClass() {
-      return promise.isLibraryClass();
-    }
-
-    @Override
-    public DexClass get() {
-      return promise.get();
+    void load() {
+      try (Closer closer = Closer.create()) {
+        for (Resource resource : classpathResources) {
+          JarClassFileReader classReader = new JarClassFileReader(reader, this::addClass);
+          classReader.read(DEFAULT_DEX_FILENAME, ClassKind.CLASSPATH, resource.getStream(closer));
+        }
+        for (Resource resource : libraryResources) {
+          JarClassFileReader classReader = new JarClassFileReader(reader, this::addClass);
+          classReader.read(DEFAULT_DEX_FILENAME, ClassKind.LIBRARY, resource.getStream(closer));
+        }
+      } catch (IOException e) {
+        throw new CompilationError("Failed to load class: " + type.toSourceString(), e);
+      }
+      assert index == classes.length;
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
similarity index 96%
rename from src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java
rename to src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
index 7cef1a4..8449bd9 100644
--- a/src/test/java/com/android/tools/r8/D8ResourceProviderRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8LazyRunExamplesAndroidOTest.java
@@ -9,7 +9,7 @@
 import java.io.IOException;
 import java.nio.file.Path;
 
-public class D8ResourceProviderRunExamplesAndroidOTest
+public class D8LazyRunExamplesAndroidOTest
     extends D8IncrementalRunExamplesAndroidOTest {
   class D8LazyTestRunner extends D8IncrementalTestRunner {
 
diff --git a/src/test/java/com/android/tools/r8/D8RegularLazyRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
similarity index 95%
rename from src/test/java/com/android/tools/r8/D8RegularLazyRunExamplesAndroidOTest.java
rename to src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
index 38acabe..42d3c47 100644
--- a/src/test/java/com/android/tools/r8/D8RegularLazyRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8NonLazyRunExamplesAndroidOTest.java
@@ -8,7 +8,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
-public class D8RegularLazyRunExamplesAndroidOTest
+public class D8NonLazyRunExamplesAndroidOTest
     extends D8IncrementalRunExamplesAndroidOTest {
   class D8LazyTestRunner extends D8IncrementalTestRunner {
 
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 44c2156..dc49caf 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -287,7 +287,7 @@
         method.setCode(ir, allocator, factory);
         virtualMethods[i] = method;
       }
-      builder.addClassPromise(
+      builder.addClass(
           new DexProgramClass(
               type,
               null,