[ir] Validate that uniform and storage vars have host-shareable types

Move the IsHostShareable() helper from the WGSL validator into
core::type::Type*, using flags to avoid re-computing it on every call.

Fixed: 409840687
Change-Id: I1edd77da419211c09c23e5ba324c3b082f0b8010
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/236077
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 2a4c3a4..e41a411 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -2552,9 +2552,15 @@
         }
     }
 
+    if (mv->AddressSpace() == AddressSpace::kStorage) {
+        if (mv->StoreType() && !mv->StoreType()->IsHostShareable()) {
+            AddError(var) << "vars in the 'storage' address space must be host-shareable";
+            return;
+        }
+    }
+
     if (mv->AddressSpace() == AddressSpace::kUniform) {
-        // TODO(409840687): Add host-shareable check.
-        if (!mv->StoreType()->IsConstructible()) {
+        if (!mv->StoreType()->IsConstructible() || !mv->StoreType()->IsHostShareable()) {
             AddError(var)
                 << "vars in the 'uniform' address space must be host-shareable and constructible";
             return;
diff --git a/src/tint/lang/core/ir/validator_value_test.cc b/src/tint/lang/core/ir/validator_value_test.cc
index 7c7d111..1b3abb2 100644
--- a/src/tint/lang/core/ir/validator_value_test.cc
+++ b/src/tint/lang/core/ir/validator_value_test.cc
@@ -455,6 +455,37 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Var_Uniform_NotHostShareable) {
+    auto* v = b.Var<uniform, bool>();
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(:2:33 error: var: vars in the 'uniform' address space must be host-shareable and constructible
+  %1:ptr<uniform, bool, read> = var undef @binding_point(0, 0)
+                                ^^^
+)")) << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Var_Storage_NotHostShareable) {
+    auto* v = b.Var<storage, bool, read>();
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr(
+                    R"(:2:33 error: var: vars in the 'storage' address space must be host-shareable
+  %1:ptr<storage, bool, read> = var undef @binding_point(0, 0)
+                                ^^^
+)")) << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Var_MultipleIOAnnotations) {
     auto* v = b.Var<AddressSpace::kIn, vec4<f32>>();
     IOAttributes attr;
diff --git a/src/tint/lang/core/type/BUILD.bazel b/src/tint/lang/core/type/BUILD.bazel
index b98f9b7..7771174 100644
--- a/src/tint/lang/core/type/BUILD.bazel
+++ b/src/tint/lang/core/type/BUILD.bazel
@@ -164,6 +164,7 @@
     "i32_test.cc",
     "i8_test.cc",
     "input_attachment_test.cc",
+    "is_host_shareable_test.cc",
     "manager_test.cc",
     "matrix_test.cc",
     "multisampled_texture_test.cc",
diff --git a/src/tint/lang/core/type/BUILD.cmake b/src/tint/lang/core/type/BUILD.cmake
index 91058d3..5d458a6 100644
--- a/src/tint/lang/core/type/BUILD.cmake
+++ b/src/tint/lang/core/type/BUILD.cmake
@@ -165,6 +165,7 @@
   lang/core/type/i32_test.cc
   lang/core/type/i8_test.cc
   lang/core/type/input_attachment_test.cc
+  lang/core/type/is_host_shareable_test.cc
   lang/core/type/manager_test.cc
   lang/core/type/matrix_test.cc
   lang/core/type/multisampled_texture_test.cc
diff --git a/src/tint/lang/core/type/BUILD.gn b/src/tint/lang/core/type/BUILD.gn
index 103e228..9737eb1 100644
--- a/src/tint/lang/core/type/BUILD.gn
+++ b/src/tint/lang/core/type/BUILD.gn
@@ -165,6 +165,7 @@
       "i32_test.cc",
       "i8_test.cc",
       "input_attachment_test.cc",
+      "is_host_shareable_test.cc",
       "manager_test.cc",
       "matrix_test.cc",
       "multisampled_texture_test.cc",
diff --git a/src/tint/lang/core/type/array.cc b/src/tint/lang/core/type/array.cc
index 2def0fe..3548e83 100644
--- a/src/tint/lang/core/type/array.cc
+++ b/src/tint/lang/core/type/array.cc
@@ -58,6 +58,9 @@
             flags.Add(Flag::kFixedFootprint);
         }
     }
+    if (element->IsHostShareable()) {
+        flags.Add(Flag::kHostShareable);
+    }
     return flags;
 }
 
diff --git a/src/tint/lang/core/type/atomic.cc b/src/tint/lang/core/type/atomic.cc
index a683f24..d72476d 100644
--- a/src/tint/lang/core/type/atomic.cc
+++ b/src/tint/lang/core/type/atomic.cc
@@ -43,6 +43,7 @@
            core::type::Flags{
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }),
       subtype_(subtype) {
     TINT_ASSERT(!subtype->Is<Reference>());
diff --git a/src/tint/lang/core/type/f16.cc b/src/tint/lang/core/type/f16.cc
index a73f394..0ee753d 100644
--- a/src/tint/lang/core/type/f16.cc
+++ b/src/tint/lang/core/type/f16.cc
@@ -39,6 +39,7 @@
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }) {}
 
 F16::~F16() = default;
diff --git a/src/tint/lang/core/type/f32.cc b/src/tint/lang/core/type/f32.cc
index 30153f1..a4cba58 100644
--- a/src/tint/lang/core/type/f32.cc
+++ b/src/tint/lang/core/type/f32.cc
@@ -39,6 +39,7 @@
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }) {}
 
 F32::~F32() = default;
diff --git a/src/tint/lang/core/type/i32.cc b/src/tint/lang/core/type/i32.cc
index d1d02ea..4942b48 100644
--- a/src/tint/lang/core/type/i32.cc
+++ b/src/tint/lang/core/type/i32.cc
@@ -39,6 +39,7 @@
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }) {}
 
 I32::~I32() = default;
diff --git a/src/tint/lang/core/type/is_host_shareable_test.cc b/src/tint/lang/core/type/is_host_shareable_test.cc
new file mode 100644
index 0000000..47d2d40
--- /dev/null
+++ b/src/tint/lang/core/type/is_host_shareable_test.cc
@@ -0,0 +1,171 @@
+// Copyright 2021 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/type/array.h"
+#include "src/tint/lang/core/type/bool.h"
+#include "src/tint/lang/core/type/f16.h"
+#include "src/tint/lang/core/type/f32.h"
+#include "src/tint/lang/core/type/helper_test.h"
+#include "src/tint/lang/core/type/i32.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/core/type/matrix.h"
+#include "src/tint/lang/core/type/pointer.h"
+#include "src/tint/lang/core/type/u32.h"
+#include "src/tint/lang/core/type/vector.h"
+#include "src/tint/lang/core/type/void.h"
+#include "src/tint/utils/symbol/symbol_table.h"
+
+namespace tint::core::type {
+namespace {
+
+class TypeIsHostShareableTest : public TestHelper {
+  protected:
+    Manager ty;
+    GenerationID id;
+    SymbolTable st{id};
+};
+
+TEST_F(TypeIsHostShareableTest, Void) {
+    EXPECT_FALSE(ty.void_()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Bool) {
+    EXPECT_FALSE(ty.bool_()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, NumericScalar) {
+    EXPECT_TRUE(ty.i32()->IsHostShareable());
+    EXPECT_TRUE(ty.u32()->IsHostShareable());
+    EXPECT_TRUE(ty.f32()->IsHostShareable());
+    EXPECT_TRUE(ty.f16()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, NumericVector) {
+    EXPECT_TRUE(ty.vec2<i32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec3<i32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec4<i32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec2<u32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec3<u32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec4<u32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec3<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec4<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec3<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.vec4<f16>()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, BoolVector) {
+    EXPECT_FALSE(ty.vec2<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec3<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec4<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec2<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec3<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec4<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec2<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec3<bool>()->IsHostShareable());
+    EXPECT_FALSE(ty.vec4<bool>()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Matrix) {
+    EXPECT_TRUE(ty.mat2x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat2x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat2x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f32>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f32>()->IsHostShareable());
+
+    EXPECT_TRUE(ty.mat2x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat2x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat2x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat3x2<f16>()->IsHostShareable());
+    EXPECT_TRUE(ty.mat4x2<f16>()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Pointer) {
+    auto* ptr = ty.ptr(core::AddressSpace::kPrivate, ty.i32());
+    EXPECT_FALSE(ptr->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Atomic) {
+    EXPECT_TRUE(ty.atomic<i32>()->IsHostShareable());
+    EXPECT_TRUE(ty.atomic<u32>()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Array_FixedSized) {
+    EXPECT_TRUE((ty.array<i32, 5>()->IsHostShareable()));
+    EXPECT_FALSE((ty.array<bool, 5>()->IsHostShareable()));
+}
+
+TEST_F(TypeIsHostShareableTest, Array_RuntimeSized) {
+    EXPECT_TRUE(ty.array<i32>()->IsHostShareable());
+    EXPECT_FALSE(ty.array<bool>()->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Struct_HostShareable) {
+    auto* inner = ty.Struct(st.New(), tint::Vector{
+                                          Manager::StructMemberDesc{st.New(), ty.i32()},
+                                          Manager::StructMemberDesc{st.New(), ty.u32()},
+                                          Manager::StructMemberDesc{st.New(), ty.f32()},
+                                          Manager::StructMemberDesc{st.New(), ty.vec3<f32>()},
+                                          Manager::StructMemberDesc{st.New(), ty.mat4x2<f32>()},
+                                          Manager::StructMemberDesc{st.New(), ty.array<f32, 4>()},
+                                      });
+    auto* outer = ty.Struct(st.New(), tint::Vector{
+                                          Manager::StructMemberDesc{st.New(), inner},
+                                      });
+    EXPECT_TRUE(inner->IsConstructible());
+    EXPECT_TRUE(inner->IsHostShareable());
+    EXPECT_TRUE(outer->IsHostShareable());
+}
+
+TEST_F(TypeIsHostShareableTest, Struct_NotHostShareable) {
+    auto* inner = ty.Struct(st.New(), tint::Vector{
+                                          Manager::StructMemberDesc{st.New(), ty.i32()},
+                                          Manager::StructMemberDesc{st.New(), ty.u32()},
+                                          Manager::StructMemberDesc{st.New(), ty.f32()},
+                                          Manager::StructMemberDesc{st.New(), ty.bool_()},
+                                          Manager::StructMemberDesc{st.New(), ty.vec3<f32>()},
+                                          Manager::StructMemberDesc{st.New(), ty.mat4x2<f32>()},
+                                          Manager::StructMemberDesc{st.New(), ty.array<f32, 4>()},
+                                      });
+    auto* outer = ty.Struct(st.New(), tint::Vector{
+                                          Manager::StructMemberDesc{st.New(), inner},
+                                      });
+    EXPECT_FALSE(inner->IsHostShareable());
+    EXPECT_FALSE(outer->IsHostShareable());
+}
+
+}  // namespace
+}  // namespace tint::core::type
diff --git a/src/tint/lang/core/type/matrix.cc b/src/tint/lang/core/type/matrix.cc
index a811a8f..b53395f 100644
--- a/src/tint/lang/core/type/matrix.cc
+++ b/src/tint/lang/core/type/matrix.cc
@@ -44,6 +44,7 @@
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }),
       subtype_(column_type->Type()),
       column_type_(column_type),
diff --git a/src/tint/lang/core/type/struct.cc b/src/tint/lang/core/type/struct.cc
index 3c481c9..6a8d872 100644
--- a/src/tint/lang/core/type/struct.cc
+++ b/src/tint/lang/core/type/struct.cc
@@ -51,6 +51,7 @@
         Flag::kConstructable,
         Flag::kCreationFixedFootprint,
         Flag::kFixedFootprint,
+        Flag::kHostShareable,
     };
     for (auto* member : members) {
         if (!member->Type()->IsConstructible()) {
@@ -62,6 +63,9 @@
         if (!member->Type()->HasCreationFixedFootprint()) {
             flags.Remove(Flag::kCreationFixedFootprint);
         }
+        if (!member->Type()->IsHostShareable()) {
+            flags.Remove(Flag::kHostShareable);
+        }
     }
     return flags;
 }
diff --git a/src/tint/lang/core/type/type.h b/src/tint/lang/core/type/type.h
index daa98f9..eef83fd 100644
--- a/src/tint/lang/core/type/type.h
+++ b/src/tint/lang/core/type/type.h
@@ -58,6 +58,9 @@
     /// Type has a fixed footprint.
     /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
     kFixedFootprint,
+    /// Type is host-shareable.
+    /// @see https://www.w3.org/TR/WGSL/#host-shareable
+    kHostShareable,
 };
 
 /// An alias to tint::EnumSet<Flag>
@@ -129,6 +132,10 @@
     /// @see https://www.w3.org/TR/WGSL/#fixed-footprint-types
     inline bool HasFixedFootprint() const { return flags_.Contains(Flag::kFixedFootprint); }
 
+    /// @returns true if type is host-shareable
+    /// https://www.w3.org/TR/WGSL/#host-shareable
+    inline bool IsHostShareable() const { return flags_.Contains(Flag::kHostShareable); }
+
     /// @returns true if the type is a scalar
     bool IsScalar() const;
     /// @returns true if this type is a float scalar
diff --git a/src/tint/lang/core/type/u32.cc b/src/tint/lang/core/type/u32.cc
index 409e1fb..c1b2910 100644
--- a/src/tint/lang/core/type/u32.cc
+++ b/src/tint/lang/core/type/u32.cc
@@ -39,6 +39,7 @@
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
+               Flag::kHostShareable,
            }) {}
 
 U32::~U32() = default;
diff --git a/src/tint/lang/core/type/vector.cc b/src/tint/lang/core/type/vector.cc
index a837c83..5662735 100644
--- a/src/tint/lang/core/type/vector.cc
+++ b/src/tint/lang/core/type/vector.cc
@@ -37,13 +37,24 @@
 
 namespace tint::core::type {
 
+namespace {
+
+core::type::Flags FlagsFrom(const Type* element) {
+    core::type::Flags flags{
+        Flag::kConstructable,
+        Flag::kCreationFixedFootprint,
+        Flag::kFixedFootprint,
+    };
+    if (element->IsHostShareable()) {
+        flags.Add(Flag::kHostShareable);
+    }
+    return flags;
+}
+
+}  // namespace
+
 Vector::Vector(type::Type const* subtype, uint32_t width, bool packed /* = false */)
-    : Base(Hash(tint::TypeCode::Of<Vector>().bits, width, subtype, packed),
-           core::type::Flags{
-               Flag::kConstructable,
-               Flag::kCreationFixedFootprint,
-               Flag::kFixedFootprint,
-           }),
+    : Base(Hash(tint::TypeCode::Of<Vector>().bits, width, subtype, packed), FlagsFrom(subtype)),
       subtype_(subtype),
       width_(width),
       packed_(packed) {
diff --git a/src/tint/lang/wgsl/resolver/BUILD.bazel b/src/tint/lang/wgsl/resolver/BUILD.bazel
index 720a77d..8899f2d 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.bazel
+++ b/src/tint/lang/wgsl/resolver/BUILD.bazel
@@ -133,7 +133,6 @@
     "increment_decrement_validation_test.cc",
     "inferred_type_test.cc",
     "input_attachments_extension_test.cc",
-    "is_host_shareable_test.cc",
     "is_storeable_test.cc",
     "language_features_test.cc",
     "load_test.cc",
diff --git a/src/tint/lang/wgsl/resolver/BUILD.cmake b/src/tint/lang/wgsl/resolver/BUILD.cmake
index bc4b6b7..863543b 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.cmake
+++ b/src/tint/lang/wgsl/resolver/BUILD.cmake
@@ -134,7 +134,6 @@
   lang/wgsl/resolver/increment_decrement_validation_test.cc
   lang/wgsl/resolver/inferred_type_test.cc
   lang/wgsl/resolver/input_attachments_extension_test.cc
-  lang/wgsl/resolver/is_host_shareable_test.cc
   lang/wgsl/resolver/is_storeable_test.cc
   lang/wgsl/resolver/language_features_test.cc
   lang/wgsl/resolver/load_test.cc
diff --git a/src/tint/lang/wgsl/resolver/BUILD.gn b/src/tint/lang/wgsl/resolver/BUILD.gn
index a69dcdf..592731e 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.gn
+++ b/src/tint/lang/wgsl/resolver/BUILD.gn
@@ -134,7 +134,6 @@
       "increment_decrement_validation_test.cc",
       "inferred_type_test.cc",
       "input_attachments_extension_test.cc",
-      "is_host_shareable_test.cc",
       "is_storeable_test.cc",
       "language_features_test.cc",
       "load_test.cc",
diff --git a/src/tint/lang/wgsl/resolver/is_host_shareable_test.cc b/src/tint/lang/wgsl/resolver/is_host_shareable_test.cc
deleted file mode 100644
index 1f3a603..0000000
--- a/src/tint/lang/wgsl/resolver/is_host_shareable_test.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2021 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-//    list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-//    contributors may be used to endorse or promote products derived from
-//    this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "src/tint/lang/wgsl/resolver/resolver.h"
-
-#include "gmock/gmock.h"
-#include "src/tint/lang/core/type/atomic.h"
-#include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"
-#include "src/tint/lang/wgsl/sem/array.h"
-
-namespace tint::resolver {
-namespace {
-
-using ResolverIsHostShareable = ResolverTest;
-
-TEST_F(ResolverIsHostShareable, Void) {
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Void>()));
-}
-
-TEST_F(ResolverIsHostShareable, Bool) {
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Bool>()));
-}
-
-TEST_F(ResolverIsHostShareable, NumericScalar) {
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::I32>()));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::U32>()));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::F32>()));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::F16>()));
-}
-
-TEST_F(ResolverIsHostShareable, NumericVector) {
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::I32>(), 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::I32>(), 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::I32>(), 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::U32>(), 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::U32>(), 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::U32>(), 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F32>(), 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F32>(), 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F32>(), 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F16>(), 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F16>(), 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::F16>(), 4u)));
-}
-
-TEST_F(ResolverIsHostShareable, BoolVector) {
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 2u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 3u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 4u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 2u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 3u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 4u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 2u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 3u)));
-    EXPECT_FALSE(r()->IsHostShareable(create<core::type::Vector>(create<core::type::Bool>(), 4u)));
-}
-
-TEST_F(ResolverIsHostShareable, Matrix) {
-    auto* vec2_f32 = create<core::type::Vector>(create<core::type::F32>(), 2u);
-    auto* vec3_f32 = create<core::type::Vector>(create<core::type::F32>(), 3u);
-    auto* vec4_f32 = create<core::type::Vector>(create<core::type::F32>(), 4u);
-    auto* vec2_f16 = create<core::type::Vector>(create<core::type::F16>(), 2u);
-    auto* vec3_f16 = create<core::type::Vector>(create<core::type::F16>(), 3u);
-    auto* vec4_f16 = create<core::type::Vector>(create<core::type::F16>(), 4u);
-
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f32, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f32, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f32, 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f32, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f32, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f32, 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f32, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f32, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f32, 4u)));
-
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f16, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f16, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec2_f16, 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f16, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f16, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec3_f16, 4u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f16, 2u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f16, 3u)));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Matrix>(vec4_f16, 4u)));
-}
-
-TEST_F(ResolverIsHostShareable, Pointer) {
-    auto* ptr = create<core::type::Pointer>(core::AddressSpace::kPrivate, create<core::type::I32>(),
-                                            core::Access::kReadWrite);
-    EXPECT_FALSE(r()->IsHostShareable(ptr));
-}
-
-TEST_F(ResolverIsHostShareable, Atomic) {
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Atomic>(create<core::type::I32>())));
-    EXPECT_TRUE(r()->IsHostShareable(create<core::type::Atomic>(create<core::type::U32>())));
-}
-
-TEST_F(ResolverIsHostShareable, ArraySizedOfHostShareable) {
-    auto* arr = create<sem::Array>(create<core::type::I32>(),
-                                   create<core::type::ConstantArrayCount>(5u), 4u, 20u, 4u, 4u);
-    EXPECT_TRUE(r()->IsHostShareable(arr));
-}
-
-TEST_F(ResolverIsHostShareable, ArrayUnsizedOfHostShareable) {
-    auto* arr = create<sem::Array>(create<core::type::I32>(),
-                                   create<core::type::RuntimeArrayCount>(), 4u, 4u, 4u, 4u);
-    EXPECT_TRUE(r()->IsHostShareable(arr));
-}
-
-// Note: Structure tests covered in host_shareable_validation_test.cc
-
-}  // namespace
-}  // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index d2edc57..e7f3631 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -5046,7 +5046,7 @@
         return false;
     }
 
-    if (core::IsHostShareable(address_space) && !validator_.IsHostShareable(ty)) {
+    if (core::IsHostShareable(address_space) && !ty->IsHostShareable()) {
         AddError(usage) << "type " << style::Type(sem_.TypeNameOf(ty))
                         << " cannot be used in address space " << style::Enum(address_space)
                         << " as it is non-host-shareable";
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index deb039e..9d031f9 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -129,12 +129,6 @@
     /// @returns true if the given type is storable
     bool IsStorable(const core::type::Type* type) const { return validator_.IsStorable(type); }
 
-    /// @param type the given type
-    /// @returns true if the given type is host-shareable
-    bool IsHostShareable(const core::type::Type* type) const {
-        return validator_.IsHostShareable(type);
-    }
-
     /// @returns the validator for testing
     const Validator* GetValidatorForTesting() const { return &validator_; }
 
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 4598a10..432c4d2 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -243,27 +243,6 @@
         [&](Default) { return type->Is<core::type::Scalar>(); });
 }
 
-// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
-bool Validator::IsHostShareable(const core::type::Type* type) const {
-    if (type->IsAnyOf<core::type::I32, core::type::U32, core::type::F32, core::type::F16>()) {
-        return true;
-    }
-    return Switch(
-        type,  //
-        [&](const core::type::Vector* vec) { return IsHostShareable(vec->Type()); },
-        [&](const core::type::Matrix* mat) { return IsHostShareable(mat->Type()); },
-        [&](const sem::Array* arr) { return IsHostShareable(arr->ElemType()); },
-        [&](const core::type::Struct* str) {
-            for (auto* member : str->Members()) {
-                if (!IsHostShareable(member->Type())) {
-                    return false;
-                }
-            }
-            return true;
-        },
-        [&](const core::type::Atomic* atomic) { return IsHostShareable(atomic->Type()); });
-}
-
 // https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
 bool Validator::IsStorable(const core::type::Type* type) const {
     return IsPlain(type) ||
diff --git a/src/tint/lang/wgsl/resolver/validator.h b/src/tint/lang/wgsl/resolver/validator.h
index 16c57c0..3955832 100644
--- a/src/tint/lang/wgsl/resolver/validator.h
+++ b/src/tint/lang/wgsl/resolver/validator.h
@@ -170,10 +170,6 @@
     /// @returns true if the given type is storable
     bool IsStorable(const core::type::Type* type) const;
 
-    /// @param type the given type
-    /// @returns true if the given type is host-shareable
-    bool IsHostShareable(const core::type::Type* type) const;
-
     /// Validates the enabled extensions
     /// @param enables the extension enables
     /// @returns true on success, false otherwise.