Add getNoneableValue to StructImpl

This helper method has been used before and copied around.

I guess the reason for copying was to hide the "defect" of providers, which can, even when they define fields, either omit them or set them to None.

PiperOrigin-RevId: 624902043
Change-Id: If7dc3b4929b899808829a98ed5e6dd6dc7a496ad
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java b/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
index 626c24a..5b97b89 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
@@ -46,6 +46,7 @@
    * Returns the result of {@link #getValue(String)}, cast as the given type, throwing {@link
    * EvalException} if the cast fails.
    */
+  @Nullable
   public final <T> T getValue(String key, Class<T> type) throws EvalException {
     Object obj = getValue(key);
     if (obj == null) {
@@ -60,6 +61,24 @@
   }
 
   /**
+   * Returns the result of {@link #getValue(String)}, cast as the given type, throwing {@link
+   * EvalException} if the cast fails. If the value is {@link Starlark#NONE}, returns null.
+   */
+  @Nullable
+  public final <T> T getNoneableValue(String key, Class<T> type) throws EvalException {
+    Object obj = getValue(key);
+    if (obj == null || obj == Starlark.NONE) {
+      return null;
+    }
+    try {
+      return type.cast(obj);
+    } catch (ClassCastException unused) {
+      throw Starlark.errorf(
+          "for %s field, got %s, want %s", key, Starlark.type(obj), Starlark.classType(type));
+    }
+  }
+
+  /**
    * Returns the error message format to use for unknown fields.
    *
    * <p>By default, it is the one specified by the provider.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
index 5c551bb..a2f0b5e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
@@ -113,14 +113,6 @@
     return PathFragment.create(value.getValue(key, String.class));
   }
 
-  private static final <T> T nullIfNone(StarlarkInfo value, String key, Class<T> type)
-      throws EvalException {
-    if (value.getValue(key) == null || value.getValue(key) == Starlark.NONE) {
-      return null;
-    }
-    return value.getValue(key, type);
-  }
-
   private static final ImmutableList<PathFragment> convertStarlarkListToPathFragments(
       StarlarkInfo value, String key) throws EvalException {
     ImmutableList.Builder<PathFragment> pathFragments = ImmutableList.builder();
@@ -434,7 +426,7 @@
   /** Returns the grep-includes tool which is needing during linking because of linkstamping. */
   @Nullable
   public Artifact getGrepIncludes() throws EvalException {
-    return nullIfNone(value, "_grep_includes", Artifact.class);
+    return value.getNoneableValue("_grep_includes", Artifact.class);
   }
 
   /** Returns the tool that builds interface libraries from dynamic libraries. */
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchainProvider.java
index 1dc6e5c..e530482 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchainProvider.java
@@ -29,7 +29,6 @@
 import java.util.Map;
 import javax.annotation.Nullable;
 import net.starlark.java.eval.EvalException;
-import net.starlark.java.eval.NoneType;
 import net.starlark.java.eval.Starlark;
 import net.starlark.java.eval.StarlarkList;
 import net.starlark.java.syntax.Location;
@@ -158,15 +157,9 @@
       try {
         return new AutoValue_ProtoLangToolchainProvider(
             provider.getValue("out_replacement_format_flag", String.class),
-            provider.getValue("plugin_format_flag") instanceof NoneType
-                ? null
-                : provider.getValue("plugin_format_flag", String.class),
-            provider.getValue("plugin") instanceof NoneType
-                ? null
-                : provider.getValue("plugin", FilesToRunProvider.class),
-            provider.getValue("runtime") instanceof NoneType
-                ? null
-                : provider.getValue("runtime", TransitiveInfoCollection.class),
+            provider.getNoneableValue("plugin_format_flag", String.class),
+            provider.getNoneableValue("plugin", FilesToRunProvider.class),
+            provider.getNoneableValue("runtime", TransitiveInfoCollection.class),
             ImmutableList.copyOf(
                 (StarlarkList<StarlarkInfo>) provider.getValue("provided_proto_sources")),
             provider.getValue("proto_compiler", FilesToRunProvider.class),