Skyfunctions can now catch up to five exceptions.

This is a prerequisite to making some changes to PackageFunction that require handling another exception.

--
MOS_MIGRATED_REVID=112172100
diff --git a/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java b/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
index 3d95e97..f457575 100644
--- a/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/skyframe/AbstractSkyFunctionEnvironment.java
@@ -46,65 +46,108 @@
   }
 
   private <E1 extends Exception, E2 extends Exception, E3 extends Exception>
-  ValueOrException3<E1, E2, E3> getValueOrException(SkyKey depKey, Class<E1> exceptionClass1,
-      Class<E2> exceptionClass2, Class<E3> exceptionClass3) {
-    return ValueOrExceptionUtils.downconvert(getValueOrException(depKey, exceptionClass1,
-            exceptionClass2, exceptionClass3, BottomException.class), exceptionClass1,
-        exceptionClass2, exceptionClass3);
+      ValueOrException3<E1, E2, E3> getValueOrException(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3) {
+    return ValueOrExceptionUtils.downconvert(
+        getValueOrException(depKey, exceptionClass1, exceptionClass2, exceptionClass3,
+            BottomException.class),
+        exceptionClass1,
+        exceptionClass2,
+        exceptionClass3);
+  }
+
+  private <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+      ValueOrException4<E1, E2, E3, E4> getValueOrException(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4) {
+    return ValueOrExceptionUtils.downconvert(
+        getValueOrException(depKey, exceptionClass1, exceptionClass2, exceptionClass3,
+            exceptionClass4, BottomException.class),
+        exceptionClass1,
+        exceptionClass2,
+        exceptionClass3,
+        exceptionClass4);
   }
 
   private <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> getValueOrException(SkyKey depKey,
-      Class<E1> exceptionClass1, Class<E2> exceptionClass2, Class<E3> exceptionClass3,
-      Class<E4> exceptionClass4) {
-    return getValueOrExceptions(ImmutableSet.of(depKey), exceptionClass1, exceptionClass2,
-        exceptionClass3, exceptionClass4).get(depKey);
+           E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> getValueOrException(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4,
+          Class<E5> exceptionClass5) {
+    return getValueOrExceptions(
+        ImmutableSet.of(depKey),
+        exceptionClass1,
+        exceptionClass2,
+        exceptionClass3,
+        exceptionClass4,
+        exceptionClass5).get(depKey);
   }
 
   private <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> getValueOrExceptions(
-      Set<SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2,
-      Class<E3> exceptionClass3, Class<E4> exceptionClass4) {
+           E4 extends Exception, E5 extends Exception>
+      Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> getValueOrExceptions(
+          Set<SkyKey> depKeys,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4,
+          Class<E5> exceptionClass5) {
     SkyFunctionException.validateExceptionType(exceptionClass1);
     SkyFunctionException.validateExceptionType(exceptionClass2);
     SkyFunctionException.validateExceptionType(exceptionClass3);
     SkyFunctionException.validateExceptionType(exceptionClass4);
+    SkyFunctionException.validateExceptionType(exceptionClass5);
     Map<SkyKey, ValueOrUntypedException> valueOrExceptions =
         getValueOrUntypedExceptions(depKeys);
-    ImmutableMap.Builder<SkyKey, ValueOrException4<E1, E2, E3, E4>> builder =
+    ImmutableMap.Builder<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> builder =
         ImmutableMap.builder();
     for (SkyKey depKey : depKeys) {
       ValueOrUntypedException voe = valueOrExceptions.get(depKey);
       SkyValue value = voe.getValue();
       if (value != null) {
-        builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofValue(value));
+        builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofValue(value));
         continue;
       }
       Exception e = voe.getException();
       if (e != null) {
         if (exceptionClass1.isInstance(e)) {
-          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofExn1(
+          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofExn1(
               exceptionClass1.cast(e)));
           continue;
         }
         if (exceptionClass2.isInstance(e)) {
-          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofExn2(
+          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofExn2(
               exceptionClass2.cast(e)));
           continue;
         }
         if (exceptionClass3.isInstance(e)) {
-          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofExn3(
+          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofExn3(
               exceptionClass3.cast(e)));
           continue;
         }
         if (exceptionClass4.isInstance(e)) {
-          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofExn4(
+          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofExn4(
               exceptionClass4.cast(e)));
           continue;
         }
+        if (exceptionClass5.isInstance(e)) {
+          builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofExn5(
+              exceptionClass5.cast(e)));
+          continue;
+        }
       }
       valuesMissing = true;
-      builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4>ofNullValue());
+      builder.put(depKey, ValueOrExceptionUtils.<E1, E2, E3, E4, E5>ofNullValue());
     }
     return builder.build();
   }
@@ -132,29 +175,61 @@
 
   @Override
   @Nullable
-  public <E1 extends Exception, E2 extends Exception> SkyValue getValueOrThrow(SkyKey depKey,
-      Class<E1> exceptionClass1, Class<E2> exceptionClass2) throws E1, E2 {
+  public <E1 extends Exception, E2 extends Exception> SkyValue getValueOrThrow(
+      SkyKey depKey,
+      Class<E1> exceptionClass1,
+      Class<E2> exceptionClass2) throws E1, E2 {
     return getValueOrException(depKey, exceptionClass1, exceptionClass2).get();
   }
 
   @Override
   @Nullable
-  public <E1 extends Exception, E2 extends Exception,
-      E3 extends Exception> SkyValue getValueOrThrow(SkyKey depKey, Class<E1> exceptionClass1,
-      Class<E2> exceptionClass2, Class<E3> exceptionClass3) throws E1, E2, E3 {
+  public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+      SkyValue getValueOrThrow(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3) throws E1, E2, E3 {
     return getValueOrException(depKey, exceptionClass1, exceptionClass2, exceptionClass3).get();
   }
 
   @Override
-  public <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> SkyValue getValueOrThrow(SkyKey depKey, Class<E1> exceptionClass1,
-      Class<E2> exceptionClass2, Class<E3> exceptionClass3, Class<E4> exceptionClass4) throws E1,
-      E2, E3, E4 {
-    return getValueOrException(depKey, exceptionClass1, exceptionClass2, exceptionClass3,
+  public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+      SkyValue getValueOrThrow(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4) throws E1, E2, E3, E4 {
+    return getValueOrException(
+        depKey,
+        exceptionClass1,
+        exceptionClass2,
+        exceptionClass3,
         exceptionClass4).get();
   }
 
   @Override
+  public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception,
+          E5 extends Exception>
+      SkyValue getValueOrThrow(
+          SkyKey depKey,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4,
+          Class<E5> exceptionClass5
+  ) throws E1, E2, E3, E4, E5 {
+    return getValueOrException(
+        depKey,
+        exceptionClass1,
+        exceptionClass2,
+        exceptionClass3,
+        exceptionClass4,
+        exceptionClass5).get();
+  }
+
+  @Override
   public Map<SkyKey, SkyValue> getValues(Iterable<SkyKey> depKeys) {
     return Maps.transformValues(getValuesOrThrow(depKeys, BottomException.class),
         GET_VALUE_FROM_VOE);
@@ -163,36 +238,63 @@
   @Override
   public <E extends Exception> Map<SkyKey, ValueOrException<E>> getValuesOrThrow(
       Iterable<SkyKey> depKeys, Class<E> exceptionClass) {
-    return Maps.transformValues(getValuesOrThrow(depKeys, exceptionClass, BottomException.class),
+    return Maps.transformValues(
+        getValuesOrThrow(depKeys, exceptionClass, BottomException.class),
         makeSafeDowncastToVOEFunction(exceptionClass));
   }
 
   @Override
-  public <E1 extends Exception,
-      E2 extends Exception> Map<SkyKey, ValueOrException2<E1, E2>> getValuesOrThrow(
-      Iterable<SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2) {
-    return Maps.transformValues(getValuesOrThrow(depKeys, exceptionClass1, exceptionClass2,
-        BottomException.class), makeSafeDowncastToVOE2Function(exceptionClass1,
-        exceptionClass2));
+  public <E1 extends Exception, E2 extends Exception>
+      Map<SkyKey, ValueOrException2<E1, E2>> getValuesOrThrow(
+          Iterable<SkyKey> depKeys,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2) {
+    return Maps.transformValues(
+        getValuesOrThrow(depKeys, exceptionClass1, exceptionClass2, BottomException.class),
+        makeSafeDowncastToVOE2Function(exceptionClass1, exceptionClass2));
   }
 
   @Override
-  public <E1 extends Exception, E2 extends Exception, E3 extends Exception> Map<SkyKey,
-      ValueOrException3<E1, E2, E3>> getValuesOrThrow(Iterable<SkyKey> depKeys,
-      Class<E1> exceptionClass1, Class<E2> exceptionClass2, Class<E3> exceptionClass3) {
-    return Maps.transformValues(getValuesOrThrow(depKeys, exceptionClass1, exceptionClass2,
-        exceptionClass3, BottomException.class), makeSafeDowncastToVOE3Function(exceptionClass1,
-        exceptionClass2, exceptionClass3));
+  public <E1 extends Exception, E2 extends Exception, E3 extends Exception>
+      Map<SkyKey, ValueOrException3<E1, E2, E3>> getValuesOrThrow(
+          Iterable<SkyKey> depKeys,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3) {
+    return Maps.transformValues(
+        getValuesOrThrow(depKeys, exceptionClass1, exceptionClass2, exceptionClass3,
+            BottomException.class),
+        makeSafeDowncastToVOE3Function(exceptionClass1, exceptionClass2, exceptionClass3));
+  }
+
+  @Override
+  public <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception>
+      Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> getValuesOrThrow(
+          Iterable<SkyKey> depKeys,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4) {
+    return Maps.transformValues(
+        getValuesOrThrow(depKeys, exceptionClass1, exceptionClass2, exceptionClass3,
+            exceptionClass4, BottomException.class),
+        makeSafeDowncastToVOE4Function(exceptionClass1, exceptionClass2, exceptionClass3,
+            exceptionClass4));
   }
 
   @Override
   public <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> getValuesOrThrow(
-      Iterable<SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2,
-      Class<E3> exceptionClass3, Class<E4> exceptionClass4) {
+          E4 extends Exception, E5 extends Exception>
+      Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> getValuesOrThrow(
+          Iterable<SkyKey> depKeys,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4,
+          Class<E5> exceptionClass5) {
     Set<SkyKey> keys = ImmutableSet.copyOf(depKeys);
-    Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> result = getValueOrExceptions(keys,
-        exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
+    Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> result = getValueOrExceptions(keys,
+        exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4, exceptionClass5);
     return Collections.unmodifiableMap(result);
   }
 
@@ -211,8 +313,8 @@
       };
 
   private static <E extends Exception>
-  Function<ValueOrException2<E, BottomException>, ValueOrException<E>>
-  makeSafeDowncastToVOEFunction(final Class<E> exceptionClass) {
+      Function<ValueOrException2<E, BottomException>, ValueOrException<E>>
+          makeSafeDowncastToVOEFunction(final Class<E> exceptionClass) {
     return new Function<ValueOrException2<E, BottomException>, ValueOrException<E>>() {
       @Override
       public ValueOrException<E> apply(ValueOrException2<E, BottomException> voe) {
@@ -222,11 +324,11 @@
   }
 
   private static <E1 extends Exception, E2 extends Exception>
-  Function<ValueOrException3<E1, E2, BottomException>, ValueOrException2<E1, E2>>
-  makeSafeDowncastToVOE2Function(final Class<E1> exceptionClass1,
-      final Class<E2> exceptionClass2) {
-    return new Function<ValueOrException3<E1, E2, BottomException>,
-        ValueOrException2<E1, E2>>() {
+      Function<ValueOrException3<E1, E2, BottomException>, ValueOrException2<E1, E2>>
+      makeSafeDowncastToVOE2Function(
+          final Class<E1> exceptionClass1,
+          final Class<E2> exceptionClass2) {
+    return new Function<ValueOrException3<E1, E2, BottomException>, ValueOrException2<E1, E2>>() {
       @Override
       public ValueOrException2<E1, E2> apply(ValueOrException3<E1, E2, BottomException> voe) {
         return ValueOrExceptionUtils.downconvert(voe, exceptionClass1, exceptionClass2);
@@ -235,16 +337,38 @@
   }
 
   private static <E1 extends Exception, E2 extends Exception, E3 extends Exception>
-  Function<ValueOrException4<E1, E2, E3, BottomException>, ValueOrException3<E1, E2, E3>>
-  makeSafeDowncastToVOE3Function(final Class<E1> exceptionClass1,
-      final Class<E2> exceptionClass2, final Class<E3> exceptionClass3) {
+      Function<ValueOrException4<E1, E2, E3, BottomException>, ValueOrException3<E1, E2, E3>>
+      makeSafeDowncastToVOE3Function(
+          final Class<E1> exceptionClass1,
+          final Class<E2> exceptionClass2,
+          final Class<E3> exceptionClass3) {
     return new Function<ValueOrException4<E1, E2, E3, BottomException>,
         ValueOrException3<E1, E2, E3>>() {
       @Override
-      public ValueOrException3<E1, E2, E3> apply(ValueOrException4<E1, E2, E3,
-          BottomException> voe) {
-        return ValueOrExceptionUtils.downconvert(voe, exceptionClass1, exceptionClass2,
-            exceptionClass3);
+      public ValueOrException3<E1, E2, E3> apply(
+          ValueOrException4<E1, E2, E3, BottomException> voe) {
+        return ValueOrExceptionUtils.downconvert(
+            voe, exceptionClass1, exceptionClass2, exceptionClass3);
+      }
+    };
+  }
+
+  private static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
+                  E4 extends Exception>
+      Function<ValueOrException5<E1, E2, E3, E4, BottomException>,
+          ValueOrException4<E1, E2, E3, E4>>
+      makeSafeDowncastToVOE4Function(
+          final Class<E1> exceptionClass1,
+          final Class<E2> exceptionClass2,
+          final Class<E3> exceptionClass3,
+          final Class<E4> exceptionClass4) {
+    return new Function<ValueOrException5<E1, E2, E3, E4, BottomException>,
+                        ValueOrException4<E1, E2, E3, E4>>() {
+      @Override
+      public ValueOrException4<E1, E2, E3, E4> apply(
+          ValueOrException5<E1, E2, E3, E4, BottomException> voe) {
+        return ValueOrExceptionUtils.downconvert(
+            voe, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
       }
     };
   }
diff --git a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
index 54b3cfd..d443175 100644
--- a/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
+++ b/src/main/java/com/google/devtools/build/skyframe/ParallelEvaluator.java
@@ -501,12 +501,22 @@
 
     @Override
     public <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-        E4 extends Exception> Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> getValuesOrThrow(
-        Iterable<SkyKey> depKeys, Class<E1> exceptionClass1, Class<E2> exceptionClass2,
-        Class<E3> exceptionClass3, Class<E4> exceptionClass4) {
+            E4 extends Exception, E5 extends Exception>
+        Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> getValuesOrThrow(
+            Iterable<SkyKey> depKeys,
+            Class<E1> exceptionClass1,
+            Class<E2> exceptionClass2,
+            Class<E3> exceptionClass3,
+            Class<E4> exceptionClass4,
+            Class<E5> exceptionClass5) {
       newlyRequestedDeps.startGroup();
-      Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> result = super.getValuesOrThrow(
-          depKeys, exceptionClass1, exceptionClass2, exceptionClass3, exceptionClass4);
+      Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> result = super.getValuesOrThrow(
+          depKeys,
+          exceptionClass1,
+          exceptionClass2,
+          exceptionClass3,
+          exceptionClass4,
+          exceptionClass5);
       newlyRequestedDeps.endGroup();
       return result;
     }
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
index ee5611a..637c202 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunction.java
@@ -111,6 +111,12 @@
         SkyValue getValueOrThrow(SkyKey depKey, Class<E1> exceptionClass1,
         Class<E2> exceptionClass2, Class<E3> exceptionClass3, Class<E4> exceptionClass4)
             throws E1, E2, E3, E4;
+    @Nullable
+    <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception,
+     E5 extends Exception>
+        SkyValue getValueOrThrow(SkyKey depKey, Class<E1> exceptionClass1,
+        Class<E2> exceptionClass2, Class<E3> exceptionClass3, Class<E4> exceptionClass4,
+        Class<E5> exceptionClass5) throws E1, E2, E3, E4, E5;
 
     /**
      * Requests {@code depKeys} "in parallel", independent of each others' values. These keys may be
@@ -191,6 +197,11 @@
     Map<SkyKey, ValueOrException4<E1, E2, E3, E4>> getValuesOrThrow(Iterable<SkyKey> depKeys,
         Class<E1> exceptionClass1, Class<E2> exceptionClass2, Class<E3> exceptionClass3,
         Class<E4> exceptionClass4);
+    <E1 extends Exception, E2 extends Exception, E3 extends Exception, E4 extends Exception,
+     E5 extends Exception>
+    Map<SkyKey, ValueOrException5<E1, E2, E3, E4, E5>> getValuesOrThrow(Iterable<SkyKey> depKeys,
+        Class<E1> exceptionClass1, Class<E2> exceptionClass2, Class<E3> exceptionClass3,
+        Class<E4> exceptionClass4, Class<E5> exceptionClass5);
 
     /**
      * Returns whether there was a previous getValue[s][OrThrow] that indicated a missing
diff --git a/src/main/java/com/google/devtools/build/skyframe/ValueOrException5.java b/src/main/java/com/google/devtools/build/skyframe/ValueOrException5.java
new file mode 100644
index 0000000..36efa2e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skyframe/ValueOrException5.java
@@ -0,0 +1,26 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.skyframe;
+
+import javax.annotation.Nullable;
+
+/** Wrapper for a value or the typed exception thrown when trying to compute it. */
+public abstract class ValueOrException5<E1 extends Exception, E2 extends Exception,
+    E3 extends Exception, E4 extends Exception, E5 extends Exception>
+    extends ValueOrUntypedException {
+
+  /** Gets the stored value. Throws an exception if one was thrown when computing this value. */
+  @Nullable
+  public abstract SkyValue get() throws E1, E2, E3, E4, E5;
+}
diff --git a/src/main/java/com/google/devtools/build/skyframe/ValueOrExceptionUtils.java b/src/main/java/com/google/devtools/build/skyframe/ValueOrExceptionUtils.java
index 0968711..3785685 100644
--- a/src/main/java/com/google/devtools/build/skyframe/ValueOrExceptionUtils.java
+++ b/src/main/java/com/google/devtools/build/skyframe/ValueOrExceptionUtils.java
@@ -46,7 +46,8 @@
   }
 
   public static <E1 extends Exception, E2 extends Exception> ValueOrException2<E1, E2> downconvert(
-      ValueOrException3<E1, E2, BottomException> voe, Class<E1> exceptionClass1,
+      ValueOrException3<E1, E2, BottomException> voe,
+      Class<E1> exceptionClass1,
       Class<E2> exceptionClass2) {
     Exception e = voe.getException();
     if (e == null) {
@@ -63,8 +64,11 @@
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception>
-      ValueOrException3<E1, E2, E3> downconvert(ValueOrException4<E1, E2, E3, BottomException> voe,
-          Class<E1> exceptionClass1, Class<E2> exceptionClass2, Class<E3> exceptionClass3) {
+      ValueOrException3<E1, E2, E3> downconvert(
+          ValueOrException4<E1, E2, E3, BottomException> voe,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3) {
     Exception e = voe.getException();
     if (e == null) {
       return new ValueOrException3ValueImpl<>(voe.getValue());
@@ -82,6 +86,35 @@
         + " " + exceptionClass2 + " " + exceptionClass3, e);
   }
 
+  public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
+                 E4 extends Exception>
+      ValueOrException4<E1, E2, E3, E4> downconvert(
+          ValueOrException5<E1, E2, E3, E4, BottomException> voe,
+          Class<E1> exceptionClass1,
+          Class<E2> exceptionClass2,
+          Class<E3> exceptionClass3,
+          Class<E4> exceptionClass4) {
+    Exception e = voe.getException();
+    if (e == null) {
+      return new ValueOrException4ValueImpl<>(voe.getValue());
+    }
+    if (exceptionClass1.isInstance(e)) {
+      return new ValueOrException4Exn1Impl<>(exceptionClass1.cast(e));
+    }
+    if (exceptionClass2.isInstance(e)) {
+      return new ValueOrException4Exn2Impl<>(exceptionClass2.cast(e));
+    }
+    if (exceptionClass3.isInstance(e)) {
+      return new ValueOrException4Exn3Impl<>(exceptionClass3.cast(e));
+    }
+    if (exceptionClass4.isInstance(e)) {
+      return new ValueOrException4Exn4Impl<>(exceptionClass4.cast(e));
+    }
+    throw new IllegalStateException("shouldn't reach here " + e.getClass() + " " + exceptionClass1
+        + " " + exceptionClass2 + " " + exceptionClass3 + " " + exceptionClass4, e);
+  }
+
+
   public static <E extends Exception> ValueOrException<E> ofNull() {
     return ValueOrExceptionValueImpl.ofNull();
   }
@@ -95,33 +128,45 @@
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofNullValue() {
-    return ValueOrException4ValueImpl.ofNullValue();
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofNullValue() {
+    return ValueOrException5ValueImpl.ofNullValue();
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofValue(SkyValue value) {
-    return new ValueOrException4ValueImpl<>(value);
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofValue(SkyValue value) {
+    return new ValueOrException5ValueImpl<>(value);
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofExn1(E1 e) {
-    return new ValueOrException4Exn1Impl<>(e);
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofExn1(E1 e) {
+    return new ValueOrException5Exn1Impl<>(e);
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofExn2(E2 e) {
-    return new ValueOrException4Exn2Impl<>(e);
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofExn2(E2 e) {
+    return new ValueOrException5Exn2Impl<>(e);
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofExn3(E3 e) {
-    return new ValueOrException4Exn3Impl<>(e);
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofExn3(E3 e) {
+    return new ValueOrException5Exn3Impl<>(e);
   }
 
   public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-      E4 extends Exception> ValueOrException4<E1, E2, E3, E4> ofExn4(E4 e) {
-    return new ValueOrException4Exn4Impl<>(e);
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofExn4(E4 e) {
+    return new ValueOrException5Exn4Impl<>(e);
+  }
+
+  public static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
+                 E4 extends Exception, E5 extends Exception>
+      ValueOrException5<E1, E2, E3, E4, E5> ofExn5(E5 e) {
+    return new ValueOrException5Exn5Impl<>(e);
   }
 
   private static class ValueOrUntypedExceptionImpl extends ValueOrUntypedException {
@@ -214,7 +259,7 @@
 
     @Override
     @Nullable
-    public SkyValue get() throws E1, E2 {
+    public SkyValue get() {
       return value;
     }
 
@@ -292,7 +337,7 @@
 
     @Override
     @Nullable
-    public SkyValue get() throws E1, E2 {
+    public SkyValue get() {
       return value;
     }
 
@@ -386,9 +431,7 @@
 
   private static class ValueOrException4ValueImpl<E1 extends Exception, E2 extends Exception,
       E3 extends Exception, E4 extends Exception> extends ValueOrException4<E1, E2, E3, E4> {
-    private static final ValueOrException4ValueImpl<Exception, Exception, Exception,
-        Exception> NULL = new ValueOrException4ValueImpl<>((SkyValue) null);
-
+ 
     @Nullable
     private final SkyValue value;
 
@@ -398,7 +441,7 @@
 
     @Override
     @Nullable
-    public SkyValue get() throws E1, E2 {
+    public SkyValue get() {
       return value;
     }
 
@@ -413,12 +456,6 @@
     public SkyValue getValue() {
       return value;
     }
-
-    @SuppressWarnings("unchecked")
-    private static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
-        E4 extends Exception>ValueOrException4ValueImpl<E1, E2, E3, E4> ofNullValue() {
-      return (ValueOrException4ValueImpl<E1, E2, E3, E4>) NULL;
-    }
   }
 
   private static class ValueOrException4Exn1Impl<E1 extends Exception, E2 extends Exception,
@@ -520,4 +557,174 @@
       return null;
     }
   }
+
+  private static class ValueOrException5ValueImpl<E1 extends Exception, E2 extends Exception,
+      E3 extends Exception, E4 extends Exception, E5 extends Exception>
+      extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private static final ValueOrException5ValueImpl<Exception, Exception, Exception,
+        Exception, Exception> NULL = new ValueOrException5ValueImpl<>((SkyValue) null);
+
+    @Nullable
+    private final SkyValue value;
+
+    ValueOrException5ValueImpl(@Nullable SkyValue value) {
+      this.value = value;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue get() {
+      return value;
+    }
+
+    @Override
+    @Nullable
+    public Exception getException() {
+      return null;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return value;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <E1 extends Exception, E2 extends Exception, E3 extends Exception,
+                    E4 extends Exception, E5 extends Exception>
+        ValueOrException5ValueImpl<E1, E2, E3, E4, E5> ofNullValue() {
+      return (ValueOrException5ValueImpl<E1, E2, E3, E4, E5>) NULL;
+    }
+  }
+
+  private static class ValueOrException5Exn1Impl<E1 extends Exception, E2 extends Exception,
+      E3 extends Exception, E4 extends Exception, E5 extends Exception>
+      extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private final E1 e;
+
+    private ValueOrException5Exn1Impl(E1 e) {
+      this.e = e;
+    }
+
+    @Override
+    public SkyValue get() throws E1 {
+      throw e;
+    }
+
+    @Override
+    public Exception getException() {
+      return e;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return null;
+    }
+  }
+
+  private static class ValueOrException5Exn2Impl<E1 extends Exception, E2 extends Exception,
+      E3 extends Exception, E4 extends Exception, E5 extends Exception>
+      extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private final E2 e;
+
+    private ValueOrException5Exn2Impl(E2 e) {
+      this.e = e;
+    }
+
+    @Override
+    public SkyValue get() throws E2 {
+      throw e;
+    }
+
+    @Override
+    public Exception getException() {
+      return e;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return null;
+    }
+  }
+
+  private static class ValueOrException5Exn3Impl<E1 extends Exception, E2 extends Exception,
+      E3 extends Exception, E4 extends Exception, E5 extends Exception>
+      extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private final E3 e;
+
+    private ValueOrException5Exn3Impl(E3 e) {
+      this.e = e;
+    }
+
+    @Override
+    public SkyValue get() throws E3 {
+      throw e;
+    }
+
+    @Override
+    public Exception getException() {
+      return e;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return null;
+    }
+  }
+
+  private static class ValueOrException5Exn4Impl<E1 extends Exception, E2 extends Exception,
+      E3 extends Exception, E4 extends Exception, E5 extends Exception>
+      extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private final E4 e;
+
+    private ValueOrException5Exn4Impl(E4 e) {
+      this.e = e;
+    }
+
+    @Override
+    public SkyValue get() throws E4 {
+      throw e;
+    }
+
+    @Override
+    public Exception getException() {
+      return e;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return null;
+    }
+  }
+
+    private static class ValueOrException5Exn5Impl<E1 extends Exception, E2 extends Exception,
+        E3 extends Exception, E4 extends Exception, E5 extends Exception>
+        extends ValueOrException5<E1, E2, E3, E4, E5> {
+    private final E5 e;
+
+    private ValueOrException5Exn5Impl(E5 e) {
+      this.e = e;
+    }
+
+    @Override
+    public SkyValue get() throws E5 {
+      throw e;
+    }
+
+    @Override
+    public Exception getException() {
+      return e;
+    }
+
+    @Override
+    @Nullable
+    public SkyValue getValue() {
+      return null;
+    }
+  }
+
 }