Unify codepaths for discovered input processing, fixing a subtle bug: if we discovered a tree artifact post-execution, we would crash.

PiperOrigin-RevId: 252433844
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
index 5158026..f0ed9d2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
@@ -653,21 +653,27 @@
           return null;
         }
       }
-      addDiscoveredInputs(
-          state.inputArtifactData, state.expandedArtifacts, state.discoveredInputs, env);
-      if (env.valuesMissing()) {
-        return null;
+      switch (addDiscoveredInputs(
+          state.inputArtifactData,
+          state.expandedArtifacts,
+          filterKnownInputs(state.discoveredInputs, state.inputArtifactData),
+          env)) {
+        case VALUES_MISSING:
+          return null;
+        case NO_DISCOVERED_DATA:
+          break;
+        case DISCOVERED_DATA:
+          metadataHandler =
+              new ActionMetadataHandler(
+                  state.inputArtifactData,
+                  /*missingArtifactsAllowed=*/ false,
+                  action.getOutputs(),
+                  tsgm.get(),
+                  pathResolver,
+                  newOutputStore(state));
+          // Set the MetadataHandler to accept output information.
+          metadataHandler.discardOutputMetadata();
       }
-      metadataHandler =
-          new ActionMetadataHandler(
-              state.inputArtifactData,
-              /* missingArtifactsAllowed= */ false,
-              action.getOutputs(),
-              tsgm.get(),
-              pathResolver,
-              newOutputStore(state));
-      // Set the MetadataHandler to accept output information.
-      metadataHandler.discardOutputMetadata();
     }
 
     // Make sure this is a regular HashMap rather than ImmutableMapBuilder so that we are safe
@@ -757,28 +763,25 @@
       if (action.discoversInputs()) {
         Iterable<Artifact> newInputs =
             filterKnownInputs(action.getInputs(), state.inputArtifactData);
-        Map<SkyKey, SkyValue> metadataFoundDuringActionExecution =
-            env.getValues(toKeys(newInputs, action.getMandatoryInputs()));
         state.discoveredInputs = newInputs;
-        if (env.valuesMissing()) {
-          return;
-        }
-        if (!metadataFoundDuringActionExecution.isEmpty()) {
-          // We are in the interesting case of an action that discovered its inputs during
-          // execution, and found some new ones, but the new ones were already present in the graph.
-          // We must therefore cache the metadata for those new ones.
-          for (Map.Entry<SkyKey, SkyValue> entry : metadataFoundDuringActionExecution.entrySet()) {
-            state.inputArtifactData.putWithNoDepOwner(
-                ArtifactSkyKey.artifact(entry.getKey()), (FileArtifactValue) entry.getValue());
-          }
-          metadataHandler =
-              new ActionMetadataHandler(
-                  state.inputArtifactData,
-                  /*missingArtifactsAllowed=*/ false,
-                  action.getOutputs(),
-                  tsgm.get(),
-                  metadataHandler.getArtifactPathResolver(),
-                  metadataHandler.getOutputStore());
+        switch (addDiscoveredInputs(
+            state.inputArtifactData, state.expandedArtifacts, newInputs, env)) {
+          case VALUES_MISSING:
+            return;
+          case NO_DISCOVERED_DATA:
+            break;
+          case DISCOVERED_DATA:
+            // We are in the interesting case of an action that discovered its inputs during
+            // execution, and found some new ones, but the new ones were already present in the
+            // graph. We must therefore cache the metadata for those new ones.
+            metadataHandler =
+                new ActionMetadataHandler(
+                    state.inputArtifactData,
+                    /*missingArtifactsAllowed=*/ false,
+                    action.getOutputs(),
+                    tsgm.get(),
+                    metadataHandler.getArtifactPathResolver(),
+                    metadataHandler.getOutputStore());
         }
       }
       Preconditions.checkState(!env.valuesMissing(), action);
@@ -787,21 +790,15 @@
   }
 
   private static final Function<Artifact, SkyKey> TO_NONMANDATORY_SKYKEY =
-      new Function<Artifact, SkyKey>() {
-        @Nullable
-        @Override
-        public SkyKey apply(@Nullable Artifact artifact) {
-          return ArtifactSkyKey.key(artifact, /*isMandatory=*/ false);
-        }
-      };
+      artifact -> ArtifactSkyKey.key(artifact, /*isMandatory=*/ false);
 
-  private static Iterable<SkyKey> newlyDiscoveredInputsToSkyKeys(
-      Iterable<Artifact> discoveredInputs, ActionInputMap inputArtifactData) {
-    return Iterables.transform(
-        filterKnownInputs(discoveredInputs, inputArtifactData), TO_NONMANDATORY_SKYKEY);
+  private enum DiscoveredState {
+    VALUES_MISSING,
+    NO_DISCOVERED_DATA,
+    DISCOVERED_DATA
   }
 
-  private static void addDiscoveredInputs(
+  private static DiscoveredState addDiscoveredInputs(
       ActionInputMap inputData,
       Map<Artifact, Collection<Artifact>> expandedArtifacts,
       Iterable<Artifact> discoveredInputs,
@@ -815,23 +812,28 @@
     // discovery.
     // Therefore there is no need to catch and rethrow exceptions as there is with #checkInputs.
     Map<SkyKey, SkyValue> nonMandatoryDiscovered =
-        env.getValues(newlyDiscoveredInputsToSkyKeys(discoveredInputs, inputData));
-    if (!env.valuesMissing()) {
-      for (Map.Entry<SkyKey, SkyValue> entry : nonMandatoryDiscovered.entrySet()) {
-        Artifact input = ArtifactSkyKey.artifact(entry.getKey());
-        if (entry.getValue() instanceof TreeArtifactValue) {
-          TreeArtifactValue treeValue = (TreeArtifactValue) entry.getValue();
-          expandedArtifacts.put(input, ImmutableSet.<Artifact>copyOf(treeValue.getChildren()));
-          for (Map.Entry<Artifact.TreeFileArtifact, FileArtifactValue> child :
-              treeValue.getChildValues().entrySet()) {
-            inputData.putWithNoDepOwner(child.getKey(), child.getValue());
-          }
-          inputData.putWithNoDepOwner(input, treeValue.getSelfData());
-        } else {
-          inputData.putWithNoDepOwner(input, (FileArtifactValue) entry.getValue());
+        env.getValues(Iterables.transform(discoveredInputs, TO_NONMANDATORY_SKYKEY));
+    if (env.valuesMissing()) {
+      return DiscoveredState.VALUES_MISSING;
+    }
+    if (nonMandatoryDiscovered.isEmpty()) {
+      return DiscoveredState.NO_DISCOVERED_DATA;
+    }
+    for (Map.Entry<SkyKey, SkyValue> entry : nonMandatoryDiscovered.entrySet()) {
+      Artifact input = ArtifactSkyKey.artifact(entry.getKey());
+      if (entry.getValue() instanceof TreeArtifactValue) {
+        TreeArtifactValue treeValue = (TreeArtifactValue) entry.getValue();
+        expandedArtifacts.put(input, ImmutableSet.copyOf(treeValue.getChildren()));
+        for (Map.Entry<Artifact.TreeFileArtifact, FileArtifactValue> child :
+            treeValue.getChildValues().entrySet()) {
+          inputData.putWithNoDepOwner(child.getKey(), child.getValue());
         }
+        inputData.putWithNoDepOwner(input, treeValue.getSelfData());
+      } else {
+        inputData.putWithNoDepOwner(input, (FileArtifactValue) entry.getValue());
       }
     }
+    return DiscoveredState.DISCOVERED_DATA;
   }
 
   private static <E extends Exception> Object establishSkyframeDependencies(