[ir] Validate construct for array types
Other composite types will need more special-case logic.
Change-Id: I2bcd1cbcb63918c9c1b73edfab8f52011e77c1cb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/249235
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
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 3989869..772b3d6 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -3091,7 +3091,32 @@
return;
}
- if (auto* str = As<core::type::Struct>(construct->Result()->Type())) {
+ auto* result_type = construct->Result()->Type();
+
+ auto check_args_match_elements = [&] {
+ // Check that type type of each argument matches the expected element type of the composite.
+ for (size_t i = 0; i < args.Length(); i++) {
+ if (args[i]->Is<ir::Unused>()) {
+ continue;
+ }
+ auto* expected_type = result_type->Element(static_cast<uint32_t>(i));
+ if (args[i]->Type() != expected_type) {
+ AddError(construct, Construct::kArgsOperandOffset + i)
+ << "type " << NameOf(args[i]->Type()) << " of argument " << i
+ << " does not match expected type " << NameOf(expected_type);
+ }
+ }
+ };
+
+ if (result_type->Is<core::type::Scalar>()) {
+ // TODO(crbug.com/427964608): This needs special handling as Element() produces nullptr.
+ } else if (result_type->Is<core::type::Vector>()) {
+ // TODO(crbug.com/427964205): This needs special handling as there are many cases.
+ } else if (result_type->Is<core::type::Matrix>()) {
+ // TODO(crbug.com/427965903): This needs special handling as there are many cases.
+ } else if (result_type->Is<core::type::Array>()) {
+ check_args_match_elements();
+ } else if (auto* str = As<core::type::Struct>(result_type)) {
auto members = str->Members();
if (args.Length() != str->Members().Length()) {
AddError(construct) << "structure has " << members.Length()
@@ -3099,16 +3124,7 @@
<< " arguments";
return;
}
- for (size_t i = 0; i < args.Length(); i++) {
- if (args[i]->Is<ir::Unused>()) {
- continue;
- }
- if (args[i]->Type() != members[i]->Type()) {
- AddError(construct, Construct::kArgsOperandOffset + i)
- << "type " << NameOf(args[i]->Type()) << " of argument " << i
- << " does not match type " << NameOf(members[i]->Type()) << " of struct member";
- }
- }
+ check_args_match_elements();
}
}
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 20ce4db..90e708b 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -191,6 +191,24 @@
)")) << res.Failure();
}
+TEST_F(IR_ValidatorTest, Construct_Array_WrongArgType) {
+ auto* f = b.Function("f", ty.void_());
+ b.Append(f->Block(), [&] {
+ b.Construct<array<u32, 4>>(1_u, 2_u, 3_i, 4_u);
+ b.Return(f);
+ });
+
+ auto res = ir::Validate(mod);
+ ASSERT_NE(res, Success);
+ EXPECT_THAT(
+ res.Failure().reason,
+ testing::HasSubstr(
+ R"(:3:42 error: construct: type 'i32' of argument 2 does not match expected type 'u32'
+ %2:array<u32, 4> = construct 1u, 2u, 3i, 4u
+ ^^
+)")) << res.Failure();
+}
+
TEST_F(IR_ValidatorTest, Construct_Struct_ZeroValue) {
auto* str_ty = ty.Struct(mod.symbols.New("MyStruct"), {
{mod.symbols.New("a"), ty.i32()},
@@ -302,7 +320,7 @@
EXPECT_THAT(
res.Failure().reason,
testing::HasSubstr(
- R"(:8:33 error: construct: type 'i32' of argument 1 does not match type 'u32' of struct member
+ R"(:8:33 error: construct: type 'i32' of argument 1 does not match expected type 'u32'
%2:MyStruct = construct 1i, 2i
^^
)")) << res.Failure();