[tint][wgsl] Hide 'chromium' extensions in diagnostics

Unless the extension already starts with 'chromium'

We don't want to advertise all these experimental extensions, as they're
unlikely to be usable in Chrome without additional flags.

Change-Id: Ie26d950761376ac0ec868e0f799cb1aa6073e56f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/159061
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
index e43af72..26bd8dc 100644
--- a/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/enable_directive_test.cc
@@ -171,26 +171,40 @@
 }
 
 // Test an unknown extension identifier.
-TEST_F(EnableDirectiveTest, InvalidIdentifier) {
+TEST_F(EnableDirectiveTest, InvalidExtension) {
     auto p = parser("enable NotAValidExtensionName;");
     p->enable_directive();
     // Error when unknown extension found
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'f16')");
     auto program = p->program();
     auto& ast = program.AST();
     EXPECT_EQ(ast.Enables().Length(), 0u);
     EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
 }
 
-TEST_F(EnableDirectiveTest, InvalidIdentifierSuggest) {
+TEST_F(EnableDirectiveTest, InvalidExtensionSuggest) {
     auto p = parser("enable f15;");
     p->enable_directive();
     // Error when unknown extension found
     EXPECT_TRUE(p->has_error());
     EXPECT_EQ(p->error(), R"(1:8: expected extension
 Did you mean 'f16'?
+Possible values: 'f16')");
+    auto program = p->program();
+    auto& ast = program.AST();
+    EXPECT_EQ(ast.Enables().Length(), 0u);
+    EXPECT_EQ(ast.GlobalDeclarations().Length(), 0u);
+}
+
+// Test an unknown extension identifier, starting with 'chromium'
+TEST_F(EnableDirectiveTest, InvalidChromiumExtension) {
+    auto p = parser("enable chromium_blah;");
+    p->enable_directive();
+    // Error when unknown extension found
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), R"(1:8: expected extension
 Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
     auto program = p->program();
     auto& ast = program.AST();
@@ -239,7 +253,7 @@
         p->translation_unit();
         EXPECT_TRUE(p->has_error());
         EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'f16')");
         auto program = p->program();
         auto& ast = program.AST();
         EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -250,7 +264,7 @@
         p->translation_unit();
         EXPECT_TRUE(p->has_error());
         EXPECT_EQ(p->error(), R"(1:8: expected extension
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'f16')");
         auto program = p->program();
         auto& ast = program.AST();
         EXPECT_EQ(ast.Enables().Length(), 0u);
@@ -262,7 +276,7 @@
         EXPECT_TRUE(p->has_error());
         EXPECT_EQ(p->error(), R"(1:8: expected extension
 Did you mean 'f16'?
-Possible values: 'chromium_disable_uniformity_analysis', 'chromium_experimental_dp4a', 'chromium_experimental_full_ptr_parameters', 'chromium_experimental_pixel_local', 'chromium_experimental_push_constant', 'chromium_experimental_read_write_storage_texture', 'chromium_experimental_subgroups', 'chromium_internal_dual_source_blending', 'chromium_internal_relaxed_uniform_layout', 'f16')");
+Possible values: 'f16')");
         auto program = p->program();
         auto& ast = program.AST();
         EXPECT_EQ(ast.Enables().Length(), 0u);
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index 6ac0847..6a10c72 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -913,8 +913,9 @@
                                  Slice<const std::string_view> strings,
                                  std::string_view use) {
     auto& t = peek();
+    auto ident = t.to_str();
     if (t.IsIdentifier()) {
-        auto val = parse(t.to_str());
+        auto val = parse(ident);
         if (val != ENUM::kUndefined) {
             synchronized_ = true;
             next();
@@ -936,7 +937,20 @@
     }
     err << "\n";
 
-    tint::SuggestAlternatives(t.to_str(), strings, err);
+    if (strings == wgsl::kExtensionStrings && !HasPrefix(ident, "chromium")) {
+        // Filter out 'chromium' prefixed extensions. We don't want to advertise experimental
+        // extensions to end users (unless it looks like they've actually mis-typed a chromium
+        // extension name)
+        Vector<std::string_view, 8> filtered;
+        for (auto str : strings) {
+            if (!HasPrefix(str, "chromium")) {
+                filtered.Push(str);
+            }
+        }
+        tint::SuggestAlternatives(ident, filtered.Slice(), err);
+    } else {
+        tint::SuggestAlternatives(ident, strings, err);
+    }
 
     synchronized_ = false;
     return add_error(t.source(), err.str());
diff --git a/src/tint/utils/containers/slice.h b/src/tint/utils/containers/slice.h
index b88863a..f2cf7c3 100644
--- a/src/tint/utils/containers/slice.h
+++ b/src/tint/utils/containers/slice.h
@@ -265,6 +265,18 @@
 
     /// @returns the end for a reverse iterator
     auto rend() const { return std::reverse_iterator<const T*>(begin()); }
+
+    /// Equality operator.
+    /// @param other the other slice to compare against
+    /// @returns true if all fields of this slice are equal to the fields of @p other
+    bool operator==(const Slice& other) {
+        return data == other.data && len == other.len && cap == other.cap;
+    }
+
+    /// Inequality operator.
+    /// @param other the other slice to compare against
+    /// @returns false if any fields of this slice are not equal to the fields of @p other
+    bool operator!=(const Slice& other) { return !(*this == other); }
 };
 
 /// Deduction guide for Slice from c-array
diff --git a/src/tint/utils/containers/slice_test.cc b/src/tint/utils/containers/slice_test.cc
index 99f2f99..2432aeb 100644
--- a/src/tint/utils/containers/slice_test.cc
+++ b/src/tint/utils/containers/slice_test.cc
@@ -194,5 +194,33 @@
     EXPECT_EQ(truncated[2], 3);
 }
 
+TEST(TintSliceTest, Equality) {
+    int elements[] = {1, 2, 3};
+    auto a = Slice{elements};
+    {
+        auto b = a;
+        EXPECT_TRUE(a == b);
+        EXPECT_FALSE(a != b);
+    }
+    {
+        auto b = a;
+        b.data++;
+        EXPECT_FALSE(a == b);
+        EXPECT_TRUE(a != b);
+    }
+    {
+        auto b = a;
+        b.len++;
+        EXPECT_FALSE(a == b);
+        EXPECT_TRUE(a != b);
+    }
+    {
+        auto b = a;
+        b.cap++;
+        EXPECT_FALSE(a == b);
+        EXPECT_TRUE(a != b);
+    }
+}
+
 }  // namespace
 }  // namespace tint