Redo FileType @AutoCodec: it is risky to assume that all subclasses are totally described by their extensions, since many are not. Instead, explicitly @AutoCodec those that are, and leave the rest to be individually handled. This also allows us to do equality checking.

There is a slight memory penalty here, but there are ~100s of FileTypes in a large build, so it should be negligible.

PiperOrigin-RevId: 190477427
diff --git a/src/main/java/com/google/devtools/build/lib/util/FileType.java b/src/main/java/com/google/devtools/build/lib/util/FileType.java
index 6cfead9..599851d 100644
--- a/src/main/java/com/google/devtools/build/lib/util/FileType.java
+++ b/src/main/java/com/google/devtools/build/lib/util/FileType.java
@@ -20,6 +20,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -27,9 +28,9 @@
 
 /** A base class for FileType matchers. */
 @Immutable
-@AutoCodec
 public abstract class FileType implements Predicate<String> {
   // A special file type
+  @AutoCodec @VisibleForSerialization
   public static final FileType NO_EXTENSION =
       new FileType() {
         @Override
@@ -40,37 +41,48 @@
       };
 
   public static FileType of(final String ext) {
-    return new FileType() {
-      @Override
-      public boolean apply(String path) {
-        return path.endsWith(ext);
-      }
-
-      @Override
-      public List<String> getExtensions() {
-        return ImmutableList.of(ext);
-      }
-    };
+    return new ListFileType(ImmutableList.of(ext));
   }
 
-  @AutoCodec.Instantiator
   public static FileType of(final List<String> extensions) {
-    return new FileType() {
-      @Override
-      public boolean apply(String path) {
-        for (String ext : extensions) {
-          if (path.endsWith(ext)) {
-            return true;
-          }
-        }
-        return false;
-      }
+    return new ListFileType(ImmutableList.copyOf(extensions));
+  }
 
-      @Override
-      public List<String> getExtensions() {
-        return ImmutableList.copyOf(extensions);
+  @AutoCodec.VisibleForSerialization
+  @AutoCodec
+  static final class ListFileType extends FileType {
+    private final ImmutableList<String> extensions;
+
+    @AutoCodec.VisibleForSerialization
+    ListFileType(ImmutableList<String> extensions) {
+      this.extensions = Preconditions.checkNotNull(extensions);
+    }
+
+    @Override
+    public boolean apply(String path) {
+      for (String ext : extensions) {
+        if (path.endsWith(ext)) {
+          return true;
+        }
       }
-    };
+      return false;
+    }
+
+    @Override
+    public List<String> getExtensions() {
+      return ImmutableList.copyOf(extensions);
+    }
+
+    @Override
+    public int hashCode() {
+      return extensions.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      return (obj instanceof ListFileType
+          && this.extensions.equals(((ListFileType) obj).extensions));
+    }
   }
 
   public static FileType of(final String... extensions) {