[val] Add missing IR validator tests 2/5

This CL adds missing testing coverage to branches related to to
functions and built-in/attributes validation, e.g. "root block for
function is undefined" or "instruction for @workgroup_size param is
not defined".

Bug: 502244655

Skip-Clang-Tidy-Checks: readability-trailing-comma

Change-Id: I72fab6e66d2e80d38f64153a39310e270849e968
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/302915
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index a0ee08f..5bf90ed 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -2651,10 +2651,10 @@
         return;
     }
 
-    if (!func->Block()) {
-        AddError(func) << "root block for function is undefined";
-        return;
-    }
+    // Note: This is not a validator error because Function::SetBlock() asserts that the block is
+    // not null, and the disassembler will crash if this is not null. This should only be hit due
+    // to some sort of corruption, not a bad shader/programmer error.
+    TINT_ASSERT(func->Block()) << "root block for function is undefined";
 
     if (func->Block()->Is<ir::MultiInBlock>()) {
         AddError(func) << "root block for function cannot be a multi-in block";
diff --git a/src/tint/lang/core/ir/validator_builtin_test.cc b/src/tint/lang/core/ir/validator_builtin_test.cc
index 9cb5bd6..ee09e851 100644
--- a/src/tint/lang/core/ir/validator_builtin_test.cc
+++ b/src/tint/lang/core/ir/validator_builtin_test.cc
@@ -1332,6 +1332,23 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, InputAttachmentIndex_NonEntryPoint_InvalidIOKind) {
+    auto* f = b.Function("my_func", ty.void_());
+    auto* p = b.FunctionParam("p", ty.input_attachment(ty.f32()));
+    p->SetAttributes(IOAttributes{.input_attachment_index = 0u});
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(input attachment index IO attributes cannot be declared on a input param. They can only be used on a module scope variable.)"))
+        << res.Failure();
+}
+
 namespace {
 template <typename T>
 static const core::type::Type* TypeBuilder(core::type::Manager& m) {
diff --git a/src/tint/lang/core/ir/validator_function_test.cc b/src/tint/lang/core/ir/validator_function_test.cc
index 8ad32b1..116f393 100644
--- a/src/tint/lang/core/ir/validator_function_test.cc
+++ b/src/tint/lang/core/ir/validator_function_test.cc
@@ -35,6 +35,7 @@
 #include "src/tint/lang/core/number.h"
 #include "src/tint/lang/core/type/abstract_float.h"
 #include "src/tint/lang/core/type/abstract_int.h"
+#include "src/tint/lang/core/type/function.h"
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/matrix.h"
 #include "src/tint/lang/core/type/memory_view.h"
@@ -480,6 +481,41 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, ValidateShaderIOAnnotations_Location_NonNumeric) {
+    auto* f = FragmentEntryPoint("my_func");
+    auto* p = b.FunctionParam("p", ty.bool_());
+    p->SetAttributes(IOAttributes{.location = 0u});
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr("error: input param with a location attribute must be a numeric "
+                                   "scalar or vector, but has type bool"))
+        << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, ValidateShaderIOAnnotations_StructMember_Location_NonNumeric) {
+    auto* str_ty = ty.Struct(mod.symbols.New("MyStruct"),
+                             {
+                                 {mod.symbols.New("a"), ty.bool_(), IOAttributes{.location = 0u}},
+                             });
+    auto* f = FragmentEntryPoint("my_func");
+    auto* p = b.FunctionParam("p", str_ty);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr("error: input param struct member with a location attribute "
+                                   "must be a numeric scalar or vector, but has type bool"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, EntryPoint_InputLocation_Duplicate_InParams) {
     auto* f = FragmentEntryPoint("my_func");
 
@@ -1387,6 +1423,27 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_Interpolate_WithoutLocation_LoosenValidation) {
+    auto* f = FragmentEntryPoint("my_func");
+
+    auto* p = b.FunctionParam("p", ty.f32());
+    p->SetInterpolation(Interpolation{.type = InterpolationType::kLinear,
+                                      .sampling = InterpolationSampling::kCenter});
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kLoosenValidationForShaderIO});
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(:1:27 error: interpolation attribute requires a location attribute (or location-like shader I/O annotation)
+%my_func = @fragment func(%p:f32):void {
+                          ^^^^^^
+)")) << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_Interpolate_Struct_WithLocation) {
     auto* f = FragmentEntryPoint("my_func");
 
@@ -1890,6 +1947,66 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_Param_BindingPointWithoutCapability) {
+    auto* f = b.Function("my_func", ty.void_());
+    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
+    p->SetBindingPoint(0, 0);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr(
+                    R"(:1:17 error: input param to non-entry point function has a binding point set
+%my_func = func(%my_param:ptr<uniform, i32, read> [@binding_point(0, 0)]):void {
+                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+)")) << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Function_EntryPointParam_BindingPointWithoutCapability) {
+    auto* f = ComputeEntryPoint("my_func");
+    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
+    p->SetBindingPoint(0, 0);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr(
+                    R"(:1:54 error: binding_points are only valid on resource variables
+%my_func = @compute @workgroup_size(1u, 1u, 1u) func(%my_param:ptr<uniform, i32, read> [@binding_point(0, 0)]):void {
+                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+)")) << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Function_EntryPointParam_BindingPointWithCapability) {
+    auto* f = ComputeEntryPoint("my_func");
+    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
+    p->SetBindingPoint(0, 0);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kMslAllowEntryPointInterface});
+    ASSERT_EQ(res, Success) << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Function_Param_Color_F16) {
+    auto* f = FragmentEntryPoint("my_func");
+    auto* p = b.FunctionParam("my_param", ty.f16());
+    p->SetColor(0);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kAllowNonCoreTypes});
+    EXPECT_EQ(res, Success);
+}
+
 TEST_F(IR_ValidatorTest, Function_Param_Color_NonFragment) {
     auto* f = b.ComputeFunction("my_func");
     auto* p = b.FunctionParam("my_param", ty.vec4f());
@@ -1935,104 +2052,6 @@
 )")) << res.Failure();
 }
 
-TEST_F(IR_ValidatorTest, Function_Return_Color) {
-    auto* f = FragmentEntryPoint("my_func");
-    f->SetReturnType(ty.vec4f());
-
-    IOAttributes attr;
-    attr.color = 0;
-    f->SetReturnAttributes(attr);
-
-    b.Append(f->Block(), [&] { b.Return(f, b.Zero(ty.vec4f())); });
-
-    auto res = ir::Validate(mod);
-    ASSERT_NE(res, Success);
-    EXPECT_THAT(
-        res.Failure().reason,
-        testing::HasSubstr(
-            R"(:1:1 error: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
-%my_func = @fragment func():vec4<f32> {
-^^^^^^^^
-)")) << res.Failure();
-}
-
-TEST_F(IR_ValidatorTest, Function_Return_Struct_Color) {
-    IOAttributes attr;
-    attr.color = 0;
-
-    auto* str_ty =
-        ty.Struct(mod.symbols.New("MyStruct"), {
-                                                   {mod.symbols.New("pos"), ty.vec4f(), attr},
-                                               });
-
-    auto* f = FragmentEntryPoint("my_func");
-    f->SetReturnType(str_ty);
-
-    b.Append(f->Block(), [&] { b.Return(f, b.Zero(str_ty)); });
-
-    auto res = ir::Validate(mod);
-    ASSERT_NE(res, Success);
-    EXPECT_THAT(
-        res.Failure().reason,
-        testing::HasSubstr(
-            R"(:5:1 error: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
-%my_func = @fragment func():MyStruct {
-^^^^^^^^
-)")) << res.Failure();
-}
-
-TEST_F(IR_ValidatorTest, Function_MSV_Color_Output) {
-    auto* f = FragmentEntryPoint("my_func");
-
-    auto* v = b.Var("v", AddressSpace::kOut, ty.vec4f());
-    v->SetColor(0);
-    mod.root_block->Append(v);
-
-    b.Append(f->Block(), [&] {
-        b.Store(v, b.Zero(ty.vec4f()));
-        b.Return(f);
-    });
-
-    auto res = ir::Validate(mod);
-    ASSERT_NE(res, Success);
-    EXPECT_THAT(
-        res.Failure().reason,
-        testing::HasSubstr(
-            R"(:2:42 error: var: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
-  %v:ptr<__out, vec4<f32>, read_write> = var undef
-                                         ^^^
-)")) << res.Failure();
-}
-
-TEST_F(IR_ValidatorTest, Function_MSV_Struct_Color_Output) {
-    auto* f = FragmentEntryPoint("my_func");
-
-    IOAttributes attr;
-    attr.color = 0;
-    auto* str_ty =
-        ty.Struct(mod.symbols.New("MyStruct"), {
-                                                   {mod.symbols.New("col"), ty.vec4f(), attr},
-                                               });
-
-    auto* v = b.Var("v", AddressSpace::kOut, str_ty);
-    mod.root_block->Append(v);
-
-    b.Append(f->Block(), [&] {
-        b.Store(v, b.Zero(str_ty));
-        b.Return(f);
-    });
-
-    auto res = ir::Validate(mod);
-    ASSERT_NE(res, Success);
-    EXPECT_THAT(
-        res.Failure().reason,
-        testing::HasSubstr(
-            R"(:6:41 error: var: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
-  %v:ptr<__out, MyStruct, read_write> = var undef
-                                        ^^^
-)")) << res.Failure();
-}
-
 TEST_F(IR_ValidatorTest, Function_MSV_Color_Input_Fragment) {
     auto* f = FragmentEntryPoint("my_func");
 
@@ -2122,52 +2141,100 @@
 )")) << res.Failure();
 }
 
-TEST_F(IR_ValidatorTest, Function_Param_BindingPointWithoutCapability) {
-    auto* f = b.Function("my_func", ty.void_());
-    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
-    p->SetBindingPoint(0, 0);
-    f->SetParams({p});
+TEST_F(IR_ValidatorTest, Function_Return_Color) {
+    auto* f = FragmentEntryPoint("my_func");
+    f->SetReturnType(ty.vec4f());
 
-    b.Append(f->Block(), [&] { b.Return(f); });
+    IOAttributes attr;
+    attr.color = 0;
+    f->SetReturnAttributes(attr);
+
+    b.Append(f->Block(), [&] { b.Return(f, b.Zero(ty.vec4f())); });
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_THAT(res.Failure().reason,
-                testing::HasSubstr(
-                    R"(:1:17 error: input param to non-entry point function has a binding point set
-%my_func = func(%my_param:ptr<uniform, i32, read> [@binding_point(0, 0)]):void {
-                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(:1:1 error: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
+%my_func = @fragment func():vec4<f32> {
+^^^^^^^^
 )")) << res.Failure();
 }
 
-TEST_F(IR_ValidatorTest, Function_EntryPointParam_BindingPointWithoutCapability) {
-    auto* f = ComputeEntryPoint("my_func");
-    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
-    p->SetBindingPoint(0, 0);
-    f->SetParams({p});
+TEST_F(IR_ValidatorTest, Function_Return_Struct_Color) {
+    IOAttributes attr;
+    attr.color = 0;
 
-    b.Append(f->Block(), [&] { b.Return(f); });
+    auto* str_ty =
+        ty.Struct(mod.symbols.New("MyStruct"), {
+                                                   {mod.symbols.New("pos"), ty.vec4f(), attr},
+                                               });
+
+    auto* f = FragmentEntryPoint("my_func");
+    f->SetReturnType(str_ty);
+
+    b.Append(f->Block(), [&] { b.Return(f, b.Zero(str_ty)); });
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_THAT(res.Failure().reason,
-                testing::HasSubstr(
-                    R"(:1:54 error: binding_points are only valid on resource variables
-%my_func = @compute @workgroup_size(1u, 1u, 1u) func(%my_param:ptr<uniform, i32, read> [@binding_point(0, 0)]):void {
-                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(:5:1 error: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
+%my_func = @fragment func():MyStruct {
+^^^^^^^^
 )")) << res.Failure();
 }
 
-TEST_F(IR_ValidatorTest, Function_EntryPointParam_BindingPointWithCapability) {
-    auto* f = ComputeEntryPoint("my_func");
-    auto* p = b.FunctionParam("my_param", ty.ptr<uniform, i32>());
-    p->SetBindingPoint(0, 0);
-    f->SetParams({p});
+TEST_F(IR_ValidatorTest, Function_MSV_Color_Output) {
+    auto* f = FragmentEntryPoint("my_func");
 
-    b.Append(f->Block(), [&] { b.Return(f); });
+    auto* v = b.Var("v", AddressSpace::kOut, ty.vec4f());
+    v->SetColor(0);
+    mod.root_block->Append(v);
 
-    auto res = ir::Validate(mod, Capabilities{Capability::kMslAllowEntryPointInterface});
-    ASSERT_EQ(res, Success) << res.Failure();
+    b.Append(f->Block(), [&] {
+        b.Store(v, b.Zero(ty.vec4f()));
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(error: var: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.)"))
+        << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Function_MSV_Struct_Color_Output) {
+    auto* f = FragmentEntryPoint("my_func");
+
+    IOAttributes attr;
+    attr.color = 0;
+    auto* str_ty =
+        ty.Struct(mod.symbols.New("MyStruct"), {
+                                                   {mod.symbols.New("col"), ty.vec4f(), attr},
+                                               });
+
+    auto* v = b.Var("v", AddressSpace::kOut, str_ty);
+    mod.root_block->Append(v);
+
+    b.Append(f->Block(), [&] {
+        b.Store(v, b.Zero(str_ty));
+        b.Return(f);
+    });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr(
+            R"(:6:41 error: var: color IO attributes cannot be declared for a fragment shader output. They can only be used for a fragment shader input.
+  %v:ptr<__out, MyStruct, read_write> = var undef
+                                        ^^^
+)")) << res.Failure();
 }
 
 TEST_F(IR_ValidatorTest, Function_Param_Color_InvalidType) {
@@ -2188,6 +2255,23 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_Param_Color_Bool) {
+    auto* f = FragmentEntryPoint("my_func");
+    auto* p = b.FunctionParam("my_param", ty.bool_());
+    p->SetColor(0);
+    f->SetParams({p});
+
+    b.Append(f->Block(), [&] { b.Return(f); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason, testing::HasSubstr(
+                                          R"(:1:27 error: color must be a numeric scalar or vector
+%my_func = @fragment func(%my_param:bool [@color(0)]):void {
+                          ^^^^^^^^^^^^^^
+)")) << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_Param_InputIndexAttachment) {
     auto* f = FragmentEntryPoint("my_func");
 
@@ -2623,6 +2707,19 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_WorkgroupSize_InstructionNotDefined) {
+    auto* ep = b.ComputeFunction("ep");
+    auto* res_val = mod.CreateValue<ir::InstructionResult>(ty.u32());
+    ep->SetWorkgroupSize({res_val, b.Constant(1_u), b.Constant(1_u)});
+    b.Append(ep->Block(), [&] { b.Return(ep); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kAllowOverrides});
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr("error: instruction for @workgroup_size param is not defined"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_WorkgroupSize_ParamWrongType) {
     auto* f = ComputeEntryPoint();
     f->SetWorkgroupSize({b.Constant(1_f), b.Constant(2_u), b.Constant(3_u)});
@@ -2655,6 +2752,19 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_WorkgroupSize_InvalidValue) {
+    auto* ep = b.ComputeFunction("ep");
+    ep->SetWorkgroupSize({b.FunctionParam(ty.u32()), b.Constant(1_u), b.Constant(1_u)});
+    b.Append(ep->Block(), [&] { b.Return(ep); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kAllowOverrides});
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr("error: @workgroup_size must be an InstructionResult or a Constant"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_WorkgroupSize_InvalidValueKind) {
     auto* f = ComputeEntryPoint();
     f->SetWorkgroupSize({b.Constant(1_u), b.FunctionParam("p", ty.u32()), b.Constant(3_u)});
@@ -2826,6 +2936,33 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_SubgroupSize_MissingType) {
+    auto* ep = b.ComputeFunction("ep");
+    auto* val = b.Constant(1_u);
+    val->SetType(nullptr);
+    ep->SetSubgroupSize(val);
+    b.Append(ep->Block(), [&] { b.Return(ep); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr("error: a @subgroup_size param is missing a type"))
+        << res.Failure();
+}
+
+TEST_F(IR_ValidatorTest, Function_SubgroupSize_InstructionNotDefined) {
+    auto* ep = b.ComputeFunction("ep");
+    auto* res_val = mod.CreateValue<ir::InstructionResult>(ty.u32());
+    ep->SetSubgroupSize(res_val);
+    b.Append(ep->Block(), [&] { b.Return(ep); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kAllowOverrides});
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(res.Failure().reason,
+                testing::HasSubstr("error: instruction for @subgroup_size param is not defined"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_SubgroupSize_ParamWrongType) {
     auto* f = ComputeEntryPoint();
     f->SetWorkgroupSize({b.Constant(1_u), b.Constant(2_u), b.Constant(3_u)});
@@ -2875,6 +3012,19 @@
 )")) << res.Failure();
 }
 
+TEST_F(IR_ValidatorTest, Function_SubgroupSize_InvalidValue) {
+    auto* ep = b.ComputeFunction("ep");
+    ep->SetSubgroupSize(b.FunctionParam(ty.u32()));
+    b.Append(ep->Block(), [&] { b.Return(ep); });
+
+    auto res = ir::Validate(mod, Capabilities{Capability::kAllowOverrides});
+    ASSERT_NE(res, Success);
+    EXPECT_THAT(
+        res.Failure().reason,
+        testing::HasSubstr("error: @subgroup_size must be an InstructionResult or a Constant"))
+        << res.Failure();
+}
+
 TEST_F(IR_ValidatorTest, Function_SubgroupSize_ParamNonPowerOfTwo) {
     auto* f = ComputeEntryPoint();
     f->SetWorkgroupSize({b.Constant(1_u), b.Constant(2_u), b.Constant(3_u)});
@@ -3239,33 +3389,4 @@
 )")) << res.Failure();
 }
 
-TEST_F(IR_ValidatorTest, Function_Param_Color_F16) {
-    auto* f = FragmentEntryPoint("my_func");
-    auto* p = b.FunctionParam("my_param", ty.f16());
-    p->SetColor(0);
-    f->SetParams({p});
-
-    b.Append(f->Block(), [&] { b.Return(f); });
-
-    auto res = ir::Validate(mod, Capabilities{Capability::kAllowNonCoreTypes});
-    EXPECT_EQ(res, Success);
-}
-
-TEST_F(IR_ValidatorTest, Function_Param_Color_Bool) {
-    auto* f = FragmentEntryPoint("my_func");
-    auto* p = b.FunctionParam("my_param", ty.bool_());
-    p->SetColor(0);
-    f->SetParams({p});
-
-    b.Append(f->Block(), [&] { b.Return(f); });
-
-    auto res = ir::Validate(mod);
-    ASSERT_NE(res, Success);
-    EXPECT_THAT(res.Failure().reason, testing::HasSubstr(
-                                          R"(:1:27 error: color must be a numeric scalar or vector
-%my_func = @fragment func(%my_param:bool [@color(0)]):void {
-                          ^^^^^^^^^^^^^^
-)")) << res.Failure();
-}
-
 }  // namespace tint::core::ir