Clean up throwing function abstractions.

Change-Id: I1edbc875d3a3d57001147521aff4e8a01acd5a05
diff --git a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
index 9710fe8..a81e59c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/DexByteCodeWriter.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThrowingFunction;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -15,6 +14,10 @@
 
 public abstract class DexByteCodeWriter {
 
+  private interface OutputStreamProvider {
+    PrintStream get(DexClass clazz) throws IOException;
+  }
+
   final DexApplication application;
   final InternalOptions options;
 
@@ -31,7 +34,7 @@
     }
   }
 
-  private ThrowingFunction<DexClass, PrintStream, IOException> oneFilePerClass(Path path) {
+  private OutputStreamProvider oneFilePerClass(Path path) {
     return (clazz) -> {
       String className = DescriptorUtils.descriptorToJavaType(clazz.type.toDescriptorString(),
           application.getProguardMap());
@@ -58,13 +61,12 @@
     });
   }
 
-  private void write(ThrowingFunction<DexClass, PrintStream, IOException> outputStreamProvider,
-      Consumer<PrintStream> closer)
+  private void write(OutputStreamProvider outputStreamProvider, Consumer<PrintStream> closer)
       throws IOException {
     Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
     for (DexProgramClass clazz : classes) {
       if (anyMethodMatches(clazz)) {
-        PrintStream ps = outputStreamProvider.apply(clazz);
+        PrintStream ps = outputStreamProvider.get(clazz);
         try {
           writeClass(clazz, ps);
         } finally {
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java b/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java
deleted file mode 100644
index 01d00d2..0000000
--- a/src/main/java/com/android/tools/r8/utils/ThrowingBiFunction.java
+++ /dev/null
@@ -1,20 +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.utils;
-
-import java.util.function.BiFunction;
-
-/**
- * Similar to a {@link BiFunction} but throws a single {@link Throwable}.
- *
- * @param <T> the type of the first argument
- * @param <U> the type of the second argument
- * @param <R> the return type
- * @param <E> the type of the {@link Throwable}
- */
-@FunctionalInterface
-public interface ThrowingBiFunction<T, U, R, E extends Throwable> {
-
-  R apply(T t, U u) throws E;
-}
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java b/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java
deleted file mode 100644
index ab33e81..0000000
--- a/src/main/java/com/android/tools/r8/utils/ThrowingFunction.java
+++ /dev/null
@@ -1,19 +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.utils;
-
-import java.util.function.Function;
-
-/**
- * Similar to a {@link Function} but throws a single {@link Throwable}.
- *
- * @param <T> the type of the first argument
- * @param <R> the return type
- * @param <E> the type of the {@link Throwable}
- */
-@FunctionalInterface
-public interface ThrowingFunction<T, R, E extends Throwable> {
-
-  R apply(T t) throws E;
-}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index d1d53f3..01b5efb 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -189,7 +189,8 @@
     return TestParametersBuilder.builder();
   }
 
-  protected static <S, T> Function<S, T> memoizeFunction(ThrowableFunction<S, T> fn) {
+  protected static <S, T, E extends Throwable> Function<S, T> memoizeFunction(
+      ThrowingFunction<S, T, E> fn) {
     return CacheBuilder.newBuilder()
         .build(
             CacheLoader.from(
@@ -202,8 +203,8 @@
                 }));
   }
 
-  protected static <S, T, U> BiFunction<S, T, U> memoizeBiFunction(
-      ThrowableBiFunction<S, T, U> fn) {
+  protected static <S, T, U, E extends Throwable> BiFunction<S, T, U> memoizeBiFunction(
+      ThrowingBiFunction<S, T, U, E> fn) {
     class Pair {
       final S first;
       final T second;
diff --git a/src/test/java/com/android/tools/r8/TestBaseResult.java b/src/test/java/com/android/tools/r8/TestBaseResult.java
index 11b7bd3..392b4b0 100644
--- a/src/test/java/com/android/tools/r8/TestBaseResult.java
+++ b/src/test/java/com/android/tools/r8/TestBaseResult.java
@@ -14,7 +14,7 @@
 
   public abstract CR self();
 
-  public <S> S map(ThrowableFunction<CR, S> fn) {
+  public <S, E extends Throwable> S map(ThrowingFunction<CR, S, E> fn) {
     return fn.applyWithRuntimeException(self());
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 350293d..ab6533f 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -25,7 +25,7 @@
 
   abstract T self();
 
-  public <S> S map(ThrowableFunction<T, S> fn) {
+  public <S, E extends Throwable> S map(ThrowingFunction<T, S, E> fn) {
     return fn.applyWithRuntimeException(self());
   }
 
diff --git a/src/test/java/com/android/tools/r8/ThrowableBiFunction.java b/src/test/java/com/android/tools/r8/ThrowableBiFunction.java
deleted file mode 100644
index 4ef9ef2..0000000
--- a/src/test/java/com/android/tools/r8/ThrowableBiFunction.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2019, 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;
-
-import java.util.function.Function;
-
-public interface ThrowableBiFunction<Formal1, Formal2, Return> {
-  Return apply(Formal1 formal1, Formal2 formal2) throws Throwable;
-
-  default <T extends Throwable> Return applyWithHandler(
-      Formal1 formal1, Formal2 formal2, Function<Throwable, T> handler) throws T {
-    try {
-      return apply(formal1, formal2);
-    } catch (Throwable e) {
-      throw handler.apply(e);
-    }
-  }
-
-  default Return applyWithRuntimeException(Formal1 formal1, Formal2 formal2) {
-    return applyWithHandler(formal1, formal2, RuntimeException::new);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/ThrowableFunction.java b/src/test/java/com/android/tools/r8/ThrowableFunction.java
deleted file mode 100644
index b97d42b..0000000
--- a/src/test/java/com/android/tools/r8/ThrowableFunction.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2019, 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;
-
-import java.util.function.Function;
-
-public interface ThrowableFunction<Formal, Return> {
-  Return apply(Formal formal) throws Throwable;
-
-  default <T extends Throwable> Return applyWithHandler(
-      Formal formal, Function<Throwable, T> handler) throws T {
-    try {
-      return apply(formal);
-    } catch (Throwable e) {
-      throw handler.apply(e);
-    }
-  }
-
-  default Return applyWithRuntimeException(Formal formal) {
-    return applyWithHandler(formal, RuntimeException::new);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/ThrowingBiFunction.java b/src/test/java/com/android/tools/r8/ThrowingBiFunction.java
new file mode 100644
index 0000000..ad3bd04
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ThrowingBiFunction.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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;
+
+import java.util.function.Function;
+
+@FunctionalInterface
+public interface ThrowingBiFunction<Formal1, Formal2, Return, Exc extends Throwable> {
+  Return apply(Formal1 formal1, Formal2 formal2) throws Exc;
+
+  @SuppressWarnings("unchecked")
+  default <T extends Throwable> ThrowingBiFunction<Formal1, Formal2, Return, T> withHandler(
+      Function<Exc, T> handler) {
+    return (argument1, argument2) -> {
+      try {
+        return apply(argument1, argument2);
+      } catch (Throwable e) {
+        Exc expected;
+        try {
+          expected = (Exc) e;
+        } catch (ClassCastException failedCast) {
+          // A failed cast must be on an unchecked exception for the types to be sound.
+          throw (RuntimeException) e;
+        }
+        throw handler.apply(expected);
+      }
+    };
+  }
+
+  default Return applyWithRuntimeException(Formal1 formal1, Formal2 formal2) {
+    return withHandler(RuntimeException::new).apply(formal1, formal2);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ThrowingFunction.java b/src/test/java/com/android/tools/r8/ThrowingFunction.java
new file mode 100644
index 0000000..f695d09
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ThrowingFunction.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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;
+
+import java.util.function.Function;
+
+@FunctionalInterface
+public interface ThrowingFunction<Formal, Return, Exc extends Throwable> {
+  Return apply(Formal formal) throws Exc;
+
+  @SuppressWarnings("unchecked")
+  default <T extends Throwable> ThrowingFunction<Formal, Return, T> withHandler(
+      Function<Exc, T> handler) {
+    return argument -> {
+      try {
+        return apply(argument);
+      } catch (Throwable e) {
+        Exc expected;
+        try {
+          expected = (Exc) e;
+        } catch (ClassCastException failedCast) {
+          // A failed cast must be on an unchecked exception for the types to be sound.
+          throw (RuntimeException) e;
+        }
+        throw handler.apply(expected);
+      }
+    };
+  }
+
+  default Return applyWithRuntimeException(Formal argument) {
+    return withHandler(RuntimeException::new).apply(argument);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
index ea8ed0b..b4dc614 100644
--- a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
+import com.android.tools.r8.ThrowingBiFunction;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.VmTestRunner;
@@ -14,7 +15,6 @@
 import com.android.tools.r8.VmTestRunner.IgnoreForVmVersions;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
-import com.android.tools.r8.utils.ThrowingBiFunction;
 import com.android.tools.r8.utils.ThrowingSupplier;
 import java.util.function.BiConsumer;
 import java.util.function.Predicate;
diff --git a/src/test/java/com/android/tools/r8/shaking/FilteredClassPathTest.java b/src/test/java/com/android/tools/r8/shaking/FilteredClassPathTest.java
index 7c243ae..f5d642e 100644
--- a/src/test/java/com/android/tools/r8/shaking/FilteredClassPathTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/FilteredClassPathTest.java
@@ -7,14 +7,13 @@
 import com.android.tools.r8.ProgramResource;
 import com.android.tools.r8.ProgramResourceProvider;
 import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.ThrowingBiFunction;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidApp.Builder;
 import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.ThrowingBiFunction;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;