resolver: Implement element inference of vecN and matNxM
Fixed: tint:1334
Change-Id: Idc94d49ecd41e37354bb93138348e3af3e733932
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/72143
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/docs/origin-trial-changes.md b/docs/origin-trial-changes.md
index 09f66a3..154c510 100644
--- a/docs/origin-trial-changes.md
+++ b/docs/origin-trial-changes.md
@@ -14,6 +14,7 @@
### New Features
+* Vector and matrix element type can now be inferred from constructor argument types. [tint:1334](https://crbug.com/tint/1334)
* New texture gather builtins: `textureGather()` and `textureGatherCompare()`. [tint:1330](https://crbug.com/tint/1330)
* Shadowing is now fully supported. [tint:819](https://crbug.com/tint/819)
* The `dot()` builtin now supports integer vector types.
diff --git a/src/ast/matrix.h b/src/ast/matrix.h
index 023adc6..1f24e96 100644
--- a/src/ast/matrix.h
+++ b/src/ast/matrix.h
@@ -28,7 +28,9 @@
/// Constructor
/// @param pid the identifier of the program that owns this node
/// @param src the source of this node
- /// @param subtype type matrix type
+ /// @param subtype the declared type of the matrix components. May be null for
+ /// matrix constructors, where the element type will be inferred from
+ /// the constructor arguments
/// @param rows the number of rows in the matrix
/// @param columns the number of columns in the matrix
Matrix(ProgramID pid,
@@ -50,7 +52,9 @@
/// @return the newly cloned type
const Matrix* Clone(CloneContext* ctx) const override;
- /// The type of the matrix
+ /// The declared type of the matrix components. May be null for matrix
+ /// constructors, where the element type will be inferred from the constructor
+ /// arguments
const Type* const type;
/// The number of rows in the matrix
diff --git a/src/ast/vector.cc b/src/ast/vector.cc
index bea0dc2..50b7712 100644
--- a/src/ast/vector.cc
+++ b/src/ast/vector.cc
@@ -37,7 +37,10 @@
std::string Vector::FriendlyName(const SymbolTable& symbols) const {
std::ostringstream out;
- out << "vec" << width << "<" << type->FriendlyName(symbols) << ">";
+ out << "vec" << width;
+ if (type) {
+ out << "<" << type->FriendlyName(symbols) << ">";
+ }
return out.str();
}
diff --git a/src/ast/vector.h b/src/ast/vector.h
index 956594d..1d64666 100644
--- a/src/ast/vector.h
+++ b/src/ast/vector.h
@@ -28,7 +28,9 @@
/// Constructor
/// @param pid the identifier of the program that owns this node
/// @param src the source of this node
- /// @param subtype the vector element type
+ /// @param subtype the declared type of the vector components. May be null
+ /// for vector constructors, where the element type will be inferred
+ /// from the constructor arguments
/// @param width the number of elements in the vector
Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t width);
/// Move constructor
@@ -45,7 +47,9 @@
/// @return the newly cloned type
const Vector* Clone(CloneContext* ctx) const override;
- /// The type of the vector elements
+ /// The declared type of the vector components. May be null for vector
+ /// constructors, where the element type will be inferred from the constructor
+ /// arguments
const Type* const type;
/// The number of elements in the vector
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index f1fca91..6845fbd 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1154,19 +1154,23 @@
Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
uint32_t count = 2;
- if (t.Is(Token::Type::kVec3))
+ if (t.Is(Token::Type::kVec3)) {
count = 3;
- else if (t.Is(Token::Type::kVec4))
+ } else if (t.Is(Token::Type::kVec4)) {
count = 4;
+ }
- const char* use = "vector";
+ const ast::Type* subtype = nullptr;
+ if (peek_is(Token::Type::kLessThan)) {
+ const char* use = "vector";
+ auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
+ if (ty.errored) {
+ return Failure::kErrored;
+ }
+ subtype = ty.value;
+ }
- auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
- if (subtype.errored)
- return Failure::kErrored;
-
- return builder_.ty.vec(make_source_range_from(t.source()), subtype.value,
- count);
+ return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
}
Expect<const ast::Type*> ParserImpl::expect_type_decl_array(
@@ -1217,14 +1221,18 @@
rows = 4;
}
- const char* use = "matrix";
+ const ast::Type* subtype = nullptr;
+ if (peek_is(Token::Type::kLessThan)) {
+ const char* use = "matrix";
+ auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
+ if (ty.errored) {
+ return Failure::kErrored;
+ }
+ subtype = ty.value;
+ }
- auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
- if (subtype.errored)
- return Failure::kErrored;
-
- return builder_.ty.mat(make_source_range_from(t.source()), subtype.value,
- columns, rows);
+ return builder_.ty.mat(make_source_range_from(t.source()), subtype, columns,
+ rows);
}
// storage_class
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index e30177b..79ab884 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -975,13 +975,6 @@
" ^\n");
}
-TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingLessThan) {
- EXPECT("var i : mat4x4;",
- "test.wgsl:1:15 error: expected '<' for matrix\n"
- "var i : mat4x4;\n"
- " ^\n");
-}
-
TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) {
EXPECT("var i : mat4x4<u32;",
"test.wgsl:1:19 error: expected '>' for matrix\n"
@@ -1066,13 +1059,6 @@
" ^\n");
}
-TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingLessThan) {
- EXPECT("var i : vec3;",
- "test.wgsl:1:13 error: expected '<' for vector\n"
- "var i : vec3;\n"
- " ^\n");
-}
-
TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingGreaterThan) {
EXPECT("var i : vec3<u32;",
"test.wgsl:1:17 error: expected '>' for vector\n"
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index d08a23d..f3cc52d 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -139,24 +139,6 @@
VecData{"vec3<f32", 3, {}},
VecData{"vec4<f32", 4, {}}));
-class VecMissingLessThanTest : public ParserImplTestWithParam<VecData> {};
-
-TEST_P(VecMissingLessThanTest, Handles_Missing_GreaterThan) {
- auto params = GetParam();
- auto p = parser(params.input);
- auto t = p->type_decl();
- EXPECT_TRUE(t.errored);
- EXPECT_FALSE(t.matched);
- ASSERT_EQ(t.value, nullptr);
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:5: expected '<' for vector");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
- VecMissingLessThanTest,
- testing::Values(VecData{"vec2", 2, {}},
- VecData{"vec3", 3, {}},
- VecData{"vec4", 4, {}}));
-
class VecMissingType : public ParserImplTestWithParam<VecData> {};
TEST_P(VecMissingType, Handles_Missing_Type) {
@@ -774,30 +756,6 @@
MatrixData{"mat4x3<f32", 4, 3, {}},
MatrixData{"mat4x4<f32", 4, 4, {}}));
-class MatrixMissingLessThanTest : public ParserImplTestWithParam<MatrixData> {};
-
-TEST_P(MatrixMissingLessThanTest, Handles_Missing_GreaterThan) {
- auto params = GetParam();
- auto p = parser(params.input);
- auto t = p->type_decl();
- EXPECT_TRUE(t.errored);
- EXPECT_FALSE(t.matched);
- ASSERT_EQ(t.value, nullptr);
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:8: expected '<' for matrix");
-}
-INSTANTIATE_TEST_SUITE_P(ParserImplTest,
- MatrixMissingLessThanTest,
- testing::Values(MatrixData{"mat2x2 f32>", 2, 2, {}},
- MatrixData{"mat2x3 f32>", 2, 3, {}},
- MatrixData{"mat2x4 f32>", 2, 4, {}},
- MatrixData{"mat3x2 f32>", 3, 2, {}},
- MatrixData{"mat3x3 f32>", 3, 3, {}},
- MatrixData{"mat3x4 f32>", 3, 4, {}},
- MatrixData{"mat4x2 f32>", 4, 2, {}},
- MatrixData{"mat4x3 f32>", 4, 3, {}},
- MatrixData{"mat4x4 f32>", 4, 4, {}}));
-
class MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
TEST_P(MatrixMissingType, Handles_Missing_Type) {
diff --git a/src/resolver/function_validation_test.cc b/src/resolver/function_validation_test.cc
index cd6bd6a..f2976de 100644
--- a/src/resolver/function_validation_test.cc
+++ b/src/resolver/function_validation_test.cc
@@ -766,6 +766,28 @@
"12:34 error: functions may declare at most 255 parameters");
}
+TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
+ // fn f(p : vec3) {}
+
+ Func(Source{{12, 34}}, "f",
+ {Param("p", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))},
+ ty.void_(), {});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
+ // fn f(p : vec3) {}
+
+ Func(Source{{12, 34}}, "f",
+ {Param("p", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))},
+ ty.void_(), {});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
struct TestParams {
ast::StorageClass storage_class;
bool should_pass;
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index abe47c4..d211dde 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -180,6 +180,10 @@
return builder_->create<sem::F32>();
}
if (auto* t = ty->As<ast::Vector>()) {
+ if (!t->type) {
+ AddError("missing vector element type", t->source.End());
+ return nullptr;
+ }
if (auto* el = Type(t->type)) {
if (auto* vector = builder_->create<sem::Vector>(el, t->width)) {
if (ValidateVector(vector, t->source)) {
@@ -190,6 +194,10 @@
return nullptr;
}
if (auto* t = ty->As<ast::Matrix>()) {
+ if (!t->type) {
+ AddError("missing matrix element type", t->source.End());
+ return nullptr;
+ }
if (auto* el = Type(t->type)) {
if (auto* column_type = builder_->create<sem::Vector>(el, t->rows)) {
if (auto* matrix =
@@ -1240,6 +1248,10 @@
std::vector<const sem::Type*> arg_tys(args.size());
sem::Behaviors arg_behaviors;
+ // The element type of all the arguments. Nullptr if argument types are
+ // different.
+ const sem::Type* arg_el_ty = nullptr;
+
for (size_t i = 0; i < expr->args.size(); i++) {
auto* arg = Sem(expr->args[i]);
if (!arg) {
@@ -1248,6 +1260,19 @@
args[i] = arg;
arg_tys[i] = args[i]->Type();
arg_behaviors.Add(arg->Behaviors());
+
+ // Determine the common argument element type
+ auto* el_ty = arg_tys[i]->UnwrapRef();
+ if (auto* vec = el_ty->As<sem::Vector>()) {
+ el_ty = vec->type();
+ } else if (auto* mat = el_ty->As<sem::Matrix>()) {
+ el_ty = mat->type();
+ }
+ if (i == 0) {
+ arg_el_ty = el_ty;
+ } else if (arg_el_ty != el_ty) {
+ arg_el_ty = nullptr;
+ }
}
arg_behaviors.Remove(sem::Behavior::kNext);
@@ -1273,10 +1298,71 @@
// Resolve the target of the CallExpression to determine whether this is a
// function call, cast or type constructor expression.
if (expr->target.type) {
- auto* ty = Type(expr->target.type);
- if (!ty) {
- return nullptr;
+ const sem::Type* ty = nullptr;
+
+ auto err_cannot_infer_el_ty = [&](std::string name) {
+ AddError(
+ "cannot infer " + name +
+ " element type, as constructor arguments have different types",
+ expr->source);
+ for (size_t i = 0; i < args.size(); i++) {
+ auto* arg = args[i];
+ AddNote("argument " + std::to_string(i) + " has type " +
+ arg->Type()->FriendlyName(builder_->Symbols()),
+ arg->Declaration()->source);
+ }
+ };
+
+ if (!expr->args.empty()) {
+ // vecN() without explicit element type?
+ // Try to infer element type from args
+ if (auto* vec = expr->target.type->As<ast::Vector>()) {
+ if (!vec->type) {
+ if (!arg_el_ty) {
+ err_cannot_infer_el_ty("vector");
+ return nullptr;
+ }
+
+ Mark(vec);
+ auto* v = builder_->create<sem::Vector>(
+ arg_el_ty, static_cast<uint32_t>(vec->width));
+ if (!ValidateVector(v, vec->source)) {
+ return nullptr;
+ }
+ builder_->Sem().Add(vec, v);
+ ty = v;
+ }
+ }
+
+ // matNxM() without explicit element type?
+ // Try to infer element type from args
+ if (auto* mat = expr->target.type->As<ast::Matrix>()) {
+ if (!mat->type) {
+ if (!arg_el_ty) {
+ err_cannot_infer_el_ty("matrix");
+ return nullptr;
+ }
+
+ Mark(mat);
+ auto* column_type =
+ builder_->create<sem::Vector>(arg_el_ty, mat->rows);
+ auto* m = builder_->create<sem::Matrix>(column_type, mat->columns);
+ if (!ValidateMatrix(m, mat->source)) {
+ return nullptr;
+ }
+ builder_->Sem().Add(mat, m);
+ ty = m;
+ }
+ }
}
+
+ if (ty == nullptr) {
+ ty = Type(expr->target.type);
+ if (!ty) {
+ return nullptr;
+ }
+ }
+
return type_ctor_or_conv(ty);
}
@@ -1393,16 +1479,16 @@
auto* call_target = utils::GetOrCreate(
type_conversions_, TypeConversionSig{target, source},
[&]() -> sem::TypeConversion* {
- // Now that the argument types have been determined, make sure that they
- // obey the conversion rules laid out in
+ // Now that the argument types have been determined, make sure that
+ // they obey the conversion rules laid out in
// https://gpuweb.github.io/gpuweb/wgsl/#conversion-expr.
bool ok = true;
if (auto* vec_type = target->As<sem::Vector>()) {
ok = ValidateVectorConstructorOrCast(expr, vec_type);
} else if (auto* mat_type = target->As<sem::Matrix>()) {
- // Note: Matrix types currently cannot be converted (the element type
- // must only be f32). We implement this for the day we support other
- // matrix element types.
+ // Note: Matrix types currently cannot be converted (the element
+ // type must only be f32). We implement this for the day we support
+ // other matrix element types.
ok = ValidateMatrixConstructorOrCast(expr, mat_type);
} else if (target->is_scalar()) {
ok = ValidateScalarConstructorOrCast(expr, target);
@@ -1452,8 +1538,8 @@
auto* call_target = utils::GetOrCreate(
type_ctors_, TypeConstructorSig{ty, arg_tys},
[&]() -> sem::TypeConstructor* {
- // Now that the argument types have been determined, make sure that they
- // obey the constructor type rules laid out in
+ // Now that the argument types have been determined, make sure that
+ // they obey the constructor type rules laid out in
// https://gpuweb.github.io/gpuweb/wgsl/#type-constructor-expr.
bool ok = true;
if (auto* vec_type = ty->As<sem::Vector>()) {
@@ -2359,8 +2445,8 @@
behaviors.Add(expr->Behaviors() - sem::Behavior::kNext);
}
- // Validate after processing the return value expression so that its type is
- // available for validation.
+ // Validate after processing the return value expression so that its type
+ // is available for validation.
return ValidateReturn(stmt);
});
}
diff --git a/src/resolver/resolver_validation.cc b/src/resolver/resolver_validation.cc
index b15aaf5..917c8db 100644
--- a/src/resolver/resolver_validation.cc
+++ b/src/resolver/resolver_validation.cc
@@ -1853,6 +1853,12 @@
return false;
}
+ std::vector<const sem::Type*> arg_tys;
+ arg_tys.reserve(values.size());
+ for (auto* value : values) {
+ arg_tys.emplace_back(TypeOf(value)->UnwrapRef());
+ }
+
auto* elem_type = matrix_ty->type();
auto num_elements = matrix_ty->columns() * matrix_ty->rows();
@@ -1864,7 +1870,14 @@
auto type_name = TypeNameOf(matrix_ty);
auto elem_type_name = TypeNameOf(elem_type);
std::stringstream ss;
- ss << "invalid constructor for " + type_name << std::endl << std::endl;
+ ss << "no matching constructor " + type_name << "(";
+ for (size_t i = 0; i < values.size(); i++) {
+ if (i > 0) {
+ ss << ", ";
+ }
+ ss << arg_tys[i]->FriendlyName(builder_->Symbols());
+ }
+ ss << ")" << std::endl << std::endl;
ss << "3 candidates available:" << std::endl;
ss << " " << type_name << "()" << std::endl;
ss << " " << type_name << "(" << elem_type_name << ",...,"
@@ -1893,8 +1906,8 @@
return false;
}
- for (auto* value : values) {
- if (TypeOf(value)->UnwrapRef() != expected_arg_type) {
+ for (auto* arg_ty : arg_tys) {
+ if (arg_ty != expected_arg_type) {
print_error();
return false;
}
diff --git a/src/resolver/type_constructor_validation_test.cc b/src/resolver/type_constructor_validation_test.cc
index 2c83801..1bd7775 100644
--- a/src/resolver/type_constructor_validation_test.cc
+++ b/src/resolver/type_constructor_validation_test.cc
@@ -1821,6 +1821,386 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
+TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromScalars) {
+ auto* vec2_bool =
+ Construct(create<ast::Vector>(nullptr, 2), Expr(true), Expr(false));
+ auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1), Expr(2));
+ auto* vec2_u32 =
+ Construct(create<ast::Vector>(nullptr, 2), Expr(1u), Expr(2u));
+ auto* vec2_f32 =
+ Construct(create<ast::Vector>(nullptr, 2), Expr(1.0f), Expr(2.0f));
+ WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
+ EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
+ EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
+ EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromVec2) {
+ auto* vec2_bool =
+ Construct(create<ast::Vector>(nullptr, 2), vec2<bool>(true, false));
+ auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), vec2<i32>(1, 2));
+ auto* vec2_u32 =
+ Construct(create<ast::Vector>(nullptr, 2), vec2<u32>(1u, 2u));
+ auto* vec2_f32 =
+ Construct(create<ast::Vector>(nullptr, 2), vec2<f32>(1.0f, 2.0f));
+ WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+ EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
+ EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
+ EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
+ EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalars) {
+ auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), Expr(true),
+ Expr(false), Expr(true));
+ auto* vec3_i32 =
+ Construct(create<ast::Vector>(nullptr, 3), Expr(1), Expr(2), Expr(3));
+ auto* vec3_u32 =
+ Construct(create<ast::Vector>(nullptr, 3), Expr(1u), Expr(2u), Expr(3u));
+ auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f),
+ Expr(2.0f), Expr(3.0f));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+ EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+ EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromVec3) {
+ auto* vec3_bool =
+ Construct(create<ast::Vector>(nullptr, 3), vec3<bool>(true, false, true));
+ auto* vec3_i32 =
+ Construct(create<ast::Vector>(nullptr, 3), vec3<i32>(1, 2, 3));
+ auto* vec3_u32 =
+ Construct(create<ast::Vector>(nullptr, 3), vec3<u32>(1u, 2u, 3u));
+ auto* vec3_f32 =
+ Construct(create<ast::Vector>(nullptr, 3), vec3<f32>(1.0f, 2.0f, 3.0f));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+ EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+ EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ InferVec3ElementTypeFromScalarAndVec2) {
+ auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), Expr(true),
+ vec2<bool>(false, true));
+ auto* vec3_i32 =
+ Construct(create<ast::Vector>(nullptr, 3), Expr(1), vec2<i32>(2, 3));
+ auto* vec3_u32 =
+ Construct(create<ast::Vector>(nullptr, 3), Expr(1u), vec2<u32>(2u, 3u));
+ auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f),
+ vec2<f32>(2.0f, 3.0f));
+ WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+ EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+ EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+ EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+ EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalars) {
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true),
+ Expr(false), Expr(true), Expr(false));
+ auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1), Expr(2),
+ Expr(3), Expr(4));
+ auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1u),
+ Expr(2u), Expr(3u), Expr(4u));
+ auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f),
+ Expr(2.0f), Expr(3.0f), Expr(4.0f));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+ EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+ EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec4) {
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4),
+ vec4<bool>(true, false, true, false));
+ auto* vec4_i32 =
+ Construct(create<ast::Vector>(nullptr, 4), vec4<i32>(1, 2, 3, 4));
+ auto* vec4_u32 =
+ Construct(create<ast::Vector>(nullptr, 4), vec4<u32>(1u, 2u, 3u, 4u));
+ auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4),
+ vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+ EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+ EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ InferVec4ElementTypeFromScalarAndVec3) {
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true),
+ vec3<bool>(false, true, false));
+ auto* vec4_i32 =
+ Construct(create<ast::Vector>(nullptr, 4), Expr(1), vec3<i32>(2, 3, 4));
+ auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1u),
+ vec3<u32>(2u, 3u, 4u));
+ auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f),
+ vec3<f32>(2.0f, 3.0f, 4.0f));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+ EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+ EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ InferVec4ElementTypeFromVec2AndVec2) {
+ auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4),
+ vec2<bool>(true, false), vec2<bool>(true, false));
+ auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), vec2<i32>(1, 2),
+ vec2<i32>(3, 4));
+ auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), vec2<u32>(1u, 2u),
+ vec2<u32>(3u, 4u));
+ auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4),
+ vec2<f32>(1.0f, 2.0f), vec2<f32>(3.0f, 4.0f));
+ WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+
+ ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+ ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+ EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+ EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+ EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+ EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+ EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+ EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+ EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+ EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+ EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVectorElementTypeWithoutArgs) {
+ WrapInFunction(Construct(create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec2ElementTypeFromScalarsMismatch) {
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 2),
+ Expr(Source{{1, 2}}, 1), //
+ Expr(Source{{1, 3}}, 2u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type i32
+1:3 note: argument 1 has type u32)");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec3ElementTypeFromScalarsMismatch) {
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+ Expr(Source{{1, 2}}, 1), //
+ Expr(Source{{1, 3}}, 2u), //
+ Expr(Source{{1, 4}}, 3)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type i32
+1:3 note: argument 1 has type u32
+1:4 note: argument 2 has type i32)");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
+ WrapInFunction(
+ Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+ Expr(Source{{1, 2}}, 1), //
+ Construct(Source{{1, 3}}, ty.vec2<f32>(), 2.0f, 3.0f)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type i32
+1:3 note: argument 1 has type vec2<f32>)");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec4ElementTypeFromScalarsMismatch) {
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ Expr(Source{{1, 2}}, 1), //
+ Expr(Source{{1, 3}}, 2), //
+ Expr(Source{{1, 4}}, 3.0f), //
+ Expr(Source{{1, 5}}, 4)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type i32
+1:3 note: argument 1 has type i32
+1:4 note: argument 2 has type f32
+1:5 note: argument 3 has type i32)");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
+ WrapInFunction(
+ Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ Expr(Source{{1, 2}}, 1), //
+ Construct(Source{{1, 3}}, ty.vec3<u32>(), 2u, 3u, 4u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type i32
+1:3 note: argument 1 has type vec3<u32>)");
+}
+
+TEST_F(ResolverTypeConstructorValidationTest,
+ CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
+ WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+ Construct(Source{{1, 2}}, ty.vec2<i32>(), 3, 4), //
+ Construct(Source{{1, 3}}, ty.vec2<u32>(), 3u, 4u)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+1:2 note: argument 0 has type vec2<i32>
+1:3 note: argument 1 has type vec2<u32>)");
+}
+
} // namespace VectorConstructor
namespace MatrixConstructor {
@@ -1841,10 +2221,15 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns - 1; i++) {
auto* vec_type = ty.vec<f32>(param.rows);
args.push_back(Construct(Source{{12, i}}, vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<f32>";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1852,9 +2237,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
@@ -1862,9 +2247,14 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns * param.rows - 1; i++) {
args.push_back(Construct(Source{{12, i}}, ty.f32()));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "f32";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1872,9 +2262,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
@@ -1882,10 +2272,15 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns + 1; i++) {
auto* vec_type = ty.vec<f32>(param.rows);
args.push_back(Construct(Source{{12, i}}, vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<f32>";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1893,9 +2288,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
@@ -1903,9 +2298,14 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns * param.rows + 1; i++) {
args.push_back(Construct(Source{{12, i}}, ty.f32()));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "f32";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1913,9 +2313,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest,
@@ -1924,10 +2324,15 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns; i++) {
auto* vec_type = ty.vec<u32>(param.rows);
args.push_back(Construct(Source{{12, i}}, vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<u32>";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1935,9 +2340,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest,
@@ -1946,9 +2351,14 @@
const auto param = GetParam();
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns; i++) {
args.push_back(Expr(Source{{12, i}}, 1u));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "u32";
}
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
@@ -1956,9 +2366,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest,
@@ -1972,23 +2382,29 @@
return;
}
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns - 1; i++) {
auto* valid_vec_type = ty.vec<f32>(param.rows);
args.push_back(Construct(Source{{12, i}}, valid_vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<f32>";
}
const size_t kInvalidLoc = 2 * (param.columns - 1);
auto* invalid_vec_type = ty.vec<f32>(param.rows - 1);
args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
+ args_tys << ", vec" << (param.rows - 1) << "<f32>";
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
auto* tc = Construct(Source{}, matrix_type, std::move(args));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest,
@@ -1997,28 +2413,34 @@
const auto param = GetParam();
- // Skip the test if parameters would have resuled in an invalid vec5 type.
+ // Skip the test if parameters would have resulted in an invalid vec5 type.
if (param.rows == 4) {
return;
}
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns - 1; i++) {
auto* valid_vec_type = ty.vec<f32>(param.rows);
args.push_back(Construct(Source{{12, i}}, valid_vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<f32>";
}
const size_t kInvalidLoc = 2 * (param.columns - 1);
auto* invalid_vec_type = ty.vec<f32>(param.rows + 1);
args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
+ args_tys << ", vec" << (param.rows + 1) << "<f32>";
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
auto* tc = Construct(Source{}, matrix_type, std::move(args));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) {
@@ -2073,10 +2495,15 @@
const auto param = GetParam();
auto* f32_alias = Alias("Float32", ty.f32());
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns; i++) {
auto* vec_type = ty.vec(ty.u32(), param.rows);
args.push_back(Construct(Source{{12, i}}, vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<u32>";
}
auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
@@ -2084,9 +2511,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
@@ -2116,8 +2543,9 @@
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(r()->error(),
- R"(12:34 error: invalid constructor for mat2x2<f32>
+ EXPECT_EQ(
+ r()->error(),
+ R"(12:34 error: no matching constructor mat2x2<f32>(vec2<u32>, vec2<f32>)
3 candidates available:
mat2x2<f32>()
@@ -2148,19 +2576,24 @@
auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
auto* f32_alias = Alias("UnsignedInt", ty.u32());
+ std::stringstream args_tys;
ast::ExpressionList args;
for (uint32_t i = 1; i <= param.columns; i++) {
auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
args.push_back(Construct(Source{{12, i}}, vec_type));
+ if (i > 1) {
+ args_tys << ", ";
+ }
+ args_tys << "vec" << param.rows << "<u32>";
}
auto* tc = Construct(Source{}, matrix_type, std::move(args));
WrapInFunction(tc);
EXPECT_FALSE(r()->Resolve());
- EXPECT_THAT(r()->error(),
- HasSubstr("12:1 error: invalid constructor for " +
- MatrixStr(param) + "\n\n3 candidates available:"));
+ EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
+ MatrixStr(param) + "(" + args_tys.str() +
+ ")\n\n3 candidates available:"));
}
TEST_P(MatrixConstructorTest,
@@ -2181,6 +2614,91 @@
ASSERT_TRUE(r()->Resolve()) << r()->error();
}
+TEST_P(MatrixConstructorTest, InferElementTypeFromVectors) {
+ const auto param = GetParam();
+
+ ast::ExpressionList args;
+ for (uint32_t i = 1; i <= param.columns; i++) {
+ args.push_back(Construct(ty.vec<f32>(param.rows)));
+ }
+
+ auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+ auto* tc = Construct(Source{}, matrix_type, std::move(args));
+ WrapInFunction(tc);
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_P(MatrixConstructorTest, InferElementTypeFromScalars) {
+ const auto param = GetParam();
+
+ ast::ExpressionList args;
+ for (uint32_t i = 0; i < param.rows * param.columns; i++) {
+ args.push_back(Expr(static_cast<f32>(i)));
+ }
+
+ auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+ WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+
+ ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
+ const auto param = GetParam();
+
+ std::stringstream err;
+ err << "12:34 error: cannot infer matrix element type, as constructor "
+ "arguments have different types";
+
+ ast::ExpressionList args;
+ for (uint32_t i = 0; i < param.columns; i++) {
+ err << "\n";
+ auto src = Source{{1, 10 + i}};
+ if (i == 1) {
+ // Odd one out
+ args.push_back(Construct(src, ty.vec<i32>(param.rows)));
+ err << src << " note: argument " << i << " has type vec" << param.rows
+ << "<i32>";
+ } else {
+ args.push_back(Construct(src, ty.vec<f32>(param.rows)));
+ err << src << " note: argument " << i << " has type vec" << param.rows
+ << "<f32>";
+ }
+ }
+
+ auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+ WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(r()->error(), err.str());
+}
+
+TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
+ const auto param = GetParam();
+
+ std::stringstream err;
+ err << "12:34 error: cannot infer matrix element type, as constructor "
+ "arguments have different types";
+ ast::ExpressionList args;
+ for (uint32_t i = 0; i < param.rows * param.columns; i++) {
+ err << "\n";
+ auto src = Source{{1, 10 + i}};
+ if (i == 3) {
+ args.push_back(Expr(src, static_cast<i32>(i))); // The odd one out
+ err << src << " note: argument " << i << " has type i32";
+ } else {
+ args.push_back(Expr(src, static_cast<f32>(i)));
+ err << src << " note: argument " << i << " has type f32";
+ }
+ }
+
+ auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+ WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_THAT(r()->error(), err.str());
+}
+
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
MatrixConstructorTest,
testing::Values(MatrixDimensions{2, 2},
diff --git a/src/resolver/type_validation_test.cc b/src/resolver/type_validation_test.cc
index 6c71d67..82037b3 100644
--- a/src/resolver/type_validation_test.cc
+++ b/src/resolver/type_validation_test.cc
@@ -416,6 +416,29 @@
"a struct");
}
+TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
+ // struct S {
+ // a: vec3;
+ // };
+
+ Structure("S",
+ {Member("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverTypeValidationTest, Struct_Member_MatrixNoType) {
+ // struct S {
+ // a: mat3x3;
+ // };
+ Structure(
+ "S", {Member("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
TEST_F(ResolverTypeValidationTest, Struct_TooBig) {
// struct Foo {
// a: array<f32, 0x20000000>;
@@ -795,9 +818,9 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
} else {
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- "12:34 error: cube dimensions for storage textures are not supported");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: cube dimensions for storage textures are not "
+ "supported");
}
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
@@ -1064,9 +1087,9 @@
Global("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve());
- EXPECT_EQ(
- r()->error(),
- "12:34 error: vector element type must be 'bool', 'f32', 'i32' or 'u32'");
+ EXPECT_EQ(r()->error(),
+ "12:34 error: vector element type must be 'bool', 'f32', 'i32' "
+ "or 'u32'");
}
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
InvalidVectorElementTypes,
diff --git a/src/resolver/var_let_validation_test.cc b/src/resolver/var_let_validation_test.cc
index 6326f3c..bc0377a 100644
--- a/src/resolver/var_let_validation_test.cc
+++ b/src/resolver/var_let_validation_test.cc
@@ -307,6 +307,42 @@
"storage classes 'private' and 'function'");
}
+TEST_F(ResolverVarLetValidationTest, VectorLetNoType) {
+ // let a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(Const("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3),
+ vec3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverVarLetValidationTest, VectorVarNoType) {
+ // var a : mat3x3;
+ WrapInFunction(Var("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+}
+
+TEST_F(ResolverVarLetValidationTest, MatrixLetNoType) {
+ // let a : mat3x3 = mat3x3<f32>();
+ WrapInFunction(Const("a",
+ create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3),
+ mat3x3<f32>()));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
+TEST_F(ResolverVarLetValidationTest, MatrixVarNoType) {
+ // var a : mat3x3;
+ WrapInFunction(
+ Var("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3)));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+}
+
} // namespace
} // namespace resolver
} // namespace tint
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 29ea3ef..0140fe7 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -393,11 +393,14 @@
} else if (ty->Is<ast::I32>()) {
out << "i32";
} else if (auto* mat = ty->As<ast::Matrix>()) {
- out << "mat" << mat->columns << "x" << mat->rows << "<";
- if (!EmitType(out, mat->type)) {
- return false;
+ out << "mat" << mat->columns << "x" << mat->rows;
+ if (auto* el_ty = mat->type) {
+ out << "<";
+ if (!EmitType(out, el_ty)) {
+ return false;
+ }
+ out << ">";
}
- out << ">";
} else if (auto* ptr = ty->As<ast::Pointer>()) {
out << "ptr<" << ptr->storage_class << ", ";
if (!EmitType(out, ptr->type)) {
@@ -493,11 +496,14 @@
} else if (ty->Is<ast::U32>()) {
out << "u32";
} else if (auto* vec = ty->As<ast::Vector>()) {
- out << "vec" << vec->width << "<";
- if (!EmitType(out, vec->type)) {
- return false;
+ out << "vec" << vec->width;
+ if (auto* el_ty = vec->type) {
+ out << "<";
+ if (!EmitType(out, el_ty)) {
+ return false;
+ }
+ out << ">";
}
- out << ">";
} else if (ty->Is<ast::Void>()) {
out << "void";
} else if (auto* tn = ty->As<ast::TypeName>()) {
diff --git a/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..0195661
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x2(0.0, 1.0,
+ 2.0, 3.0);
diff --git a/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..6dd93cf
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x2 m = float2x2(0.0f, 1.0f, 2.0f, 3.0f);
diff --git a/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..e33850f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
diff --git a/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..16c6345
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %m = OpConstantComposite %mat2v2float %6 %9
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %11
+ %14 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e4941d5
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x2(0.0, 1.0, 2.0, 3.0);
diff --git a/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..f802821
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x2(vec2<f32>(0.0, 1.0),
+ vec2<f32>(2.0, 3.0));
diff --git a/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..c2e0d31
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
diff --git a/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..e33850f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x2 m = float2x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f));
diff --git a/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..16c6345
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,27 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 15
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat2v2float = OpTypeMatrix %v2float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %m = OpConstantComposite %mat2v2float %6 %9
+ %void = OpTypeVoid
+ %11 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %11
+ %14 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..9a1f4c6
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x2/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x2(vec2<f32>(0.0, 1.0), vec2<f32>(2.0, 3.0));
diff --git a/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..dc7f65f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x3(0.0, 1.0, 2.0,
+ 3.0, 4.0, 5.0);
diff --git a/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..adc216f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x3 m = float2x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f);
diff --git a/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..86b17e2
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d99921c
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %m = OpConstantComposite %mat2v3float %7 %11
+ %void = OpTypeVoid
+ %13 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %13
+ %16 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..0be516f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x3(0.0, 1.0, 2.0, 3.0, 4.0, 5.0);
diff --git a/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..6819a81
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x3(vec3<f32>(0.0, 1.0, 2.0),
+ vec3<f32>(3.0, 4.0, 5.0));
diff --git a/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..fb12d01
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..86b17e2
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x3 m = float2x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d99921c
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,29 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat2v3float = OpTypeMatrix %v3float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %m = OpConstantComposite %mat2v3float %7 %11
+ %void = OpTypeVoid
+ %13 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %13
+ %16 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..092445a
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x3/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x3(vec3<f32>(0.0, 1.0, 2.0), vec3<f32>(3.0, 4.0, 5.0));
diff --git a/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..81abe9f
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x4(0.0, 1.0, 2.0, 3.0,
+ 4.0, 5.0, 6.0, 7.0);
diff --git a/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..7bcde85
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x4 m = float2x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f);
diff --git a/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..684918a
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..57110c5
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,31 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %m = OpConstantComposite %mat2v4float %8 %13
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %15
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..bcb4dfe
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
diff --git a/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..c57c2ed
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl
@@ -0,0 +1,2 @@
+let m = mat2x4(vec4<f32>(0.0, 1.0, 2.0, 3.0),
+ vec4<f32>(4.0, 5.0, 6.0, 7.0));
diff --git a/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..5ed2b1b
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..684918a
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2x4 m = float2x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..57110c5
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,31 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat2v4float = OpTypeMatrix %v4float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %m = OpConstantComposite %mat2v4float %8 %13
+ %void = OpTypeVoid
+ %15 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %15
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..f6335df
--- /dev/null
+++ b/test/expressions/type_ctor/mat2x4/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat2x4(vec4<f32>(0.0, 1.0, 2.0, 3.0), vec4<f32>(4.0, 5.0, 6.0, 7.0));
diff --git a/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..6fbe3b8
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x2(0.0, 1.0,
+ 2.0, 3.0,
+ 4.0, 5.0);
diff --git a/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..32160ad
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x2 m = float3x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f);
diff --git a/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..04aad8e
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ffaa504
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %12 = OpConstantComposite %v2float %float_4 %float_5
+ %m = OpConstantComposite %mat3v2float %6 %9 %12
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %14
+ %17 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..4d48f59
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x2(0.0, 1.0, 2.0, 3.0, 4.0, 5.0);
diff --git a/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..d9950ca
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x2(vec2<f32>(0.0, 1.0),
+ vec2<f32>(2.0, 3.0),
+ vec2<f32>(4.0, 5.0));
diff --git a/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..27568ed
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..04aad8e
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x2 m = float3x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f));
diff --git a/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..ffaa504
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,30 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 18
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat3v2float = OpTypeMatrix %v2float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %12 = OpConstantComposite %v2float %float_4 %float_5
+ %m = OpConstantComposite %mat3v2float %6 %9 %12
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %14
+ %17 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..70fc4e6
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x2/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x2(vec2<f32>(0.0, 1.0), vec2<f32>(2.0, 3.0), vec2<f32>(4.0, 5.0));
diff --git a/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..ecdafe7
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x3(0.0, 1.0, 2.0,
+ 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0);
diff --git a/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..513d8f8
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x3 m = float3x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
diff --git a/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..c8c096a
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
diff --git a/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8ec1da4
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+ %m = OpConstantComposite %mat3v3float %7 %11 %15
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %17
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..18ca6e3
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x3(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
diff --git a/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..5c2b614
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x3(vec3<f32>(0.0, 1.0, 2.0),
+ vec3<f32>(3.0, 4.0, 5.0),
+ vec3<f32>(6.0, 7.0, 8.0));
diff --git a/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..c35ca2a
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
diff --git a/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..c8c096a
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x3 m = float3x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f));
diff --git a/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8ec1da4
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+ %m = OpConstantComposite %mat3v3float %7 %11 %15
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %17
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..9fdc4c9
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x3/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x3(vec3<f32>(0.0, 1.0, 2.0), vec3<f32>(3.0, 4.0, 5.0), vec3<f32>(6.0, 7.0, 8.0));
diff --git a/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..cce8161
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x4(0.0, 1.0, 2.0, 3.0,
+ 4.0, 5.0, 6.0, 7.0,
+ 8.0, 9.0, 10.0, 11.0);
diff --git a/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..c76e3b8
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x4 m = float3x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f);
diff --git a/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..114cb09
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b6ff57d
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+ %m = OpConstantComposite %mat3v4float %8 %13 %18
+ %void = OpTypeVoid
+ %20 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %20
+ %23 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..5fce07f
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0);
diff --git a/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..eb6fad2
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl
@@ -0,0 +1,3 @@
+let m = mat3x4(vec4<f32>(0.0, 1.0, 2.0, 3.0),
+ vec4<f32>(4.0, 5.0, 6.0, 7.0),
+ vec4<f32>(8.0, 9.0, 10.0, 11.0));
diff --git a/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..fae68df
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..114cb09
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float3x4 m = float3x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..b6ff57d
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat3v4float = OpTypeMatrix %v4float 3
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+ %m = OpConstantComposite %mat3v4float %8 %13 %18
+ %void = OpTypeVoid
+ %20 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %20
+ %23 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..6d3960e
--- /dev/null
+++ b/test/expressions/type_ctor/mat3x4/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat3x4(vec4<f32>(0.0, 1.0, 2.0, 3.0), vec4<f32>(4.0, 5.0, 6.0, 7.0), vec4<f32>(8.0, 9.0, 10.0, 11.0));
diff --git a/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..f0946b9
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x2(0.0, 1.0,
+ 2.0, 3.0,
+ 4.0, 5.0,
+ 6.0, 7.0);
diff --git a/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..de86670
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x2 m = float4x2(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f);
diff --git a/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..0df65ff
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6a6c63
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %12 = OpConstantComposite %v2float %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %15 = OpConstantComposite %v2float %float_6 %float_7
+ %m = OpConstantComposite %mat4v2float %6 %9 %12 %15
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %17
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..8f69508
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x2(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
diff --git a/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..c1bd5ee
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x2(vec2<f32>(0.0, 1.0),
+ vec2<f32>(2.0, 3.0),
+ vec2<f32>(4.0, 5.0),
+ vec2<f32>(6.0, 7.0));
diff --git a/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..2acab36
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..0df65ff
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x2 m = float4x2(float2(0.0f, 1.0f), float2(2.0f, 3.0f), float2(4.0f, 5.0f), float2(6.0f, 7.0f));
diff --git a/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..c6a6c63
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,33 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 21
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+%mat4v2float = OpTypeMatrix %v2float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %6 = OpConstantComposite %v2float %float_0 %float_1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %9 = OpConstantComposite %v2float %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %12 = OpConstantComposite %v2float %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %15 = OpConstantComposite %v2float %float_6 %float_7
+ %m = OpConstantComposite %mat4v2float %6 %9 %12 %15
+ %void = OpTypeVoid
+ %17 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %17
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ca404bf
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x2/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x2(vec2<f32>(0.0, 1.0), vec2<f32>(2.0, 3.0), vec2<f32>(4.0, 5.0), vec2<f32>(6.0, 7.0));
diff --git a/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..32326a9
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x3(0.0, 1.0, 2.0,
+ 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0,
+ 9.0, 10.0, 11.0);
diff --git a/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..38a7333
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x3 m = float4x3(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f);
diff --git a/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..2a7c078
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d99b492
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %19 = OpConstantComposite %v3float %float_9 %float_10 %float_11
+ %m = OpConstantComposite %mat4v3float %7 %11 %15 %19
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %21
+ %24 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..209a376
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x3(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0);
diff --git a/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..a3ae9f2
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x3(vec3<f32>(0.0, 1.0, 2.0),
+ vec3<f32>(3.0, 4.0, 5.0),
+ vec3<f32>(6.0, 7.0, 8.0),
+ vec3<f32>(9.0, 10.0, 11.0));
diff --git a/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..254cc40
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..2a7c078
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x3 m = float4x3(float3(0.0f, 1.0f, 2.0f), float3(3.0f, 4.0f, 5.0f), float3(6.0f, 7.0f, 8.0f), float3(9.0f, 10.0f, 11.0f));
diff --git a/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d99b492
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,37 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v3float = OpTypeVector %float 3
+%mat4v3float = OpTypeMatrix %v3float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %7 = OpConstantComposite %v3float %float_0 %float_1 %float_2
+ %float_3 = OpConstant %float 3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %11 = OpConstantComposite %v3float %float_3 %float_4 %float_5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %float_8 = OpConstant %float 8
+ %15 = OpConstantComposite %v3float %float_6 %float_7 %float_8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %19 = OpConstantComposite %v3float %float_9 %float_10 %float_11
+ %m = OpConstantComposite %mat4v3float %7 %11 %15 %19
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %21
+ %24 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..ca7b45f
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x3/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x3(vec3<f32>(0.0, 1.0, 2.0), vec3<f32>(3.0, 4.0, 5.0), vec3<f32>(6.0, 7.0, 8.0), vec3<f32>(9.0, 10.0, 11.0));
diff --git a/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl
new file mode 100644
index 0000000..571610f
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x4(0.0, 1.0, 2.0, 3.0,
+ 4.0, 5.0, 6.0, 7.0,
+ 8.0, 9.0, 10.0, 11.0,
+ 12.0, 13.0, 14.0, 15.0);
diff --git a/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..3a70922
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x4 m = float4x4(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f);
diff --git a/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.msl
new file mode 100644
index 0000000..6fb51a2
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
diff --git a/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..84a8f89
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+ %float_12 = OpConstant %float 12
+ %float_13 = OpConstant %float 13
+ %float_14 = OpConstant %float 14
+ %float_15 = OpConstant %float 15
+ %23 = OpConstantComposite %v4float %float_12 %float_13 %float_14 %float_15
+ %m = OpConstantComposite %mat4v4float %8 %13 %18 %23
+ %void = OpTypeVoid
+ %25 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %25
+ %28 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..33b0598
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/scalars/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
diff --git a/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl
new file mode 100644
index 0000000..1e2c0d7
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl
@@ -0,0 +1,4 @@
+let m = mat4x4(vec4<f32>(0.0, 1.0, 2.0, 3.0),
+ vec4<f32>(4.0, 5.0, 6.0, 7.0),
+ vec4<f32>(8.0, 9.0, 10.0, 11.0),
+ vec4<f32>(12.0, 13.0, 14.0, 15.0));
diff --git a/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..2707999
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
diff --git a/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.msl b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.msl
new file mode 100644
index 0000000..6fb51a2
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float4x4 m = float4x4(float4(0.0f, 1.0f, 2.0f, 3.0f), float4(4.0f, 5.0f, 6.0f, 7.0f), float4(8.0f, 9.0f, 10.0f, 11.0f), float4(12.0f, 13.0f, 14.0f, 15.0f));
diff --git a/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..84a8f89
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %m "m"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%mat4v4float = OpTypeMatrix %v4float 4
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %float_2 = OpConstant %float 2
+ %float_3 = OpConstant %float 3
+ %8 = OpConstantComposite %v4float %float_0 %float_1 %float_2 %float_3
+ %float_4 = OpConstant %float 4
+ %float_5 = OpConstant %float 5
+ %float_6 = OpConstant %float 6
+ %float_7 = OpConstant %float 7
+ %13 = OpConstantComposite %v4float %float_4 %float_5 %float_6 %float_7
+ %float_8 = OpConstant %float 8
+ %float_9 = OpConstant %float 9
+ %float_10 = OpConstant %float 10
+ %float_11 = OpConstant %float 11
+ %18 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+ %float_12 = OpConstant %float 12
+ %float_13 = OpConstant %float 13
+ %float_14 = OpConstant %float 14
+ %float_15 = OpConstant %float 15
+ %23 = OpConstantComposite %v4float %float_12 %float_13 %float_14 %float_15
+ %m = OpConstantComposite %mat4v4float %8 %13 %18 %23
+ %void = OpTypeVoid
+ %25 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %25
+ %28 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..b022afe
--- /dev/null
+++ b/test/expressions/type_ctor/mat4x4/inferred/vectors/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let m = mat4x4(vec4<f32>(0.0, 1.0, 2.0, 3.0), vec4<f32>(4.0, 5.0, 6.0, 7.0), vec4<f32>(8.0, 9.0, 10.0, 11.0), vec4<f32>(12.0, 13.0, 14.0, 15.0));
diff --git a/test/expressions/type_ctor/vec2/inferred/bool.wgsl b/test/expressions/type_ctor/vec2/inferred/bool.wgsl
new file mode 100644
index 0000000..f5aced3
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/bool.wgsl
@@ -0,0 +1 @@
+let v = vec2(false, true);
diff --git a/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.hlsl b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.hlsl
new file mode 100644
index 0000000..0ba8ae6
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const bool2 v = bool2(false, true);
diff --git a/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.msl b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.msl
new file mode 100644
index 0000000..3103a85
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant bool2 v = bool2(false, true);
diff --git a/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.spvasm b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.spvasm
new file mode 100644
index 0000000..b982dbd
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %v "v"
+ OpName %unused_entry_point "unused_entry_point"
+ %bool = OpTypeBool
+ %v2bool = OpTypeVector %bool 2
+ %false = OpConstantFalse %bool
+ %true = OpConstantTrue %bool
+ %v = OpConstantComposite %v2bool %false %true
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %6
+ %9 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.wgsl b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.wgsl
new file mode 100644
index 0000000..f5aced3
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/bool.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let v = vec2(false, true);
diff --git a/test/expressions/type_ctor/vec2/inferred/f32.wgsl b/test/expressions/type_ctor/vec2/inferred/f32.wgsl
new file mode 100644
index 0000000..e0e5dc9
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/f32.wgsl
@@ -0,0 +1 @@
+let v = vec2(0.0, 1.0);
diff --git a/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.hlsl b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.hlsl
new file mode 100644
index 0000000..8802bbb
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const float2 v = float2(0.0f, 1.0f);
diff --git a/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.msl b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.msl
new file mode 100644
index 0000000..6e66829
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant float2 v = float2(0.0f, 1.0f);
diff --git a/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.spvasm b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.spvasm
new file mode 100644
index 0000000..d12bbf2
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %v "v"
+ OpName %unused_entry_point "unused_entry_point"
+ %float = OpTypeFloat 32
+ %v2float = OpTypeVector %float 2
+ %float_0 = OpConstant %float 0
+ %float_1 = OpConstant %float 1
+ %v = OpConstantComposite %v2float %float_0 %float_1
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %6
+ %9 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.wgsl
new file mode 100644
index 0000000..e0e5dc9
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/f32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let v = vec2(0.0, 1.0);
diff --git a/test/expressions/type_ctor/vec2/inferred/i32.wgsl b/test/expressions/type_ctor/vec2/inferred/i32.wgsl
new file mode 100644
index 0000000..de5642e
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/i32.wgsl
@@ -0,0 +1 @@
+let v = vec2(0, 1);
diff --git a/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.hlsl b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.hlsl
new file mode 100644
index 0000000..afa632e
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const int2 v = int2(0, 1);
diff --git a/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.msl b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.msl
new file mode 100644
index 0000000..2a0fc8d
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant int2 v = int2(0, 1);
diff --git a/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.spvasm b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.spvasm
new file mode 100644
index 0000000..2e021f9
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %v "v"
+ OpName %unused_entry_point "unused_entry_point"
+ %int = OpTypeInt 32 1
+ %v2int = OpTypeVector %int 2
+ %int_0 = OpConstant %int 0
+ %int_1 = OpConstant %int 1
+ %v = OpConstantComposite %v2int %int_0 %int_1
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %6
+ %9 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.wgsl
new file mode 100644
index 0000000..de5642e
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/i32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let v = vec2(0, 1);
diff --git a/test/expressions/type_ctor/vec2/inferred/u32.wgsl b/test/expressions/type_ctor/vec2/inferred/u32.wgsl
new file mode 100644
index 0000000..bd3e939
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/u32.wgsl
@@ -0,0 +1 @@
+let v = vec2(0u, 1u);
diff --git a/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.hlsl b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.hlsl
new file mode 100644
index 0000000..c298713
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.hlsl
@@ -0,0 +1,6 @@
+[numthreads(1, 1, 1)]
+void unused_entry_point() {
+ return;
+}
+
+static const uint2 v = uint2(0u, 1u);
diff --git a/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.msl b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.msl
new file mode 100644
index 0000000..132ee56
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.msl
@@ -0,0 +1,4 @@
+#include <metal_stdlib>
+
+using namespace metal;
+constant uint2 v = uint2(0u, 1u);
diff --git a/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.spvasm b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.spvasm
new file mode 100644
index 0000000..8c3ad8f
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.spvasm
@@ -0,0 +1,22 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 10
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %unused_entry_point "unused_entry_point"
+ OpExecutionMode %unused_entry_point LocalSize 1 1 1
+ OpName %v "v"
+ OpName %unused_entry_point "unused_entry_point"
+ %uint = OpTypeInt 32 0
+ %v2uint = OpTypeVector %uint 2
+ %uint_0 = OpConstant %uint 0
+ %uint_1 = OpConstant %uint 1
+ %v = OpConstantComposite %v2uint %uint_0 %uint_1
+ %void = OpTypeVoid
+ %6 = OpTypeFunction %void
+%unused_entry_point = OpFunction %void None %6
+ %9 = OpLabel
+ OpReturn
+ OpFunctionEnd
diff --git a/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.wgsl
new file mode 100644
index 0000000..bd3e939
--- /dev/null
+++ b/test/expressions/type_ctor/vec2/inferred/u32.wgsl.expected.wgsl
@@ -0,0 +1 @@
+let v = vec2(0u, 1u);
diff --git a/test/expressions/type_ctor/vec3/explicit/bool.wgsl b/test/expressions/type_ctor/vec3/explicit/bool.wgsl
index 0acf3bf..9f3a1f3 100644
--- a/test/expressions/type_ctor/vec3/explicit/bool.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/bool.wgsl
@@ -1 +1 @@
-let v = vec3<bool>(false, true, false);
+let v = vec3(false, true, false);
diff --git a/test/expressions/type_ctor/vec3/explicit/bool.wgsl.expected.wgsl b/test/expressions/type_ctor/vec3/explicit/bool.wgsl.expected.wgsl
index 0acf3bf..9f3a1f3 100644
--- a/test/expressions/type_ctor/vec3/explicit/bool.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/bool.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec3<bool>(false, true, false);
+let v = vec3(false, true, false);
diff --git a/test/expressions/type_ctor/vec3/explicit/f32.wgsl b/test/expressions/type_ctor/vec3/explicit/f32.wgsl
index 2164502..376f901 100644
--- a/test/expressions/type_ctor/vec3/explicit/f32.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/f32.wgsl
@@ -1 +1 @@
-let v = vec3<f32>(0.0, 1.0, 2.0);
+let v = vec3(0.0, 1.0, 2.0);
diff --git a/test/expressions/type_ctor/vec3/explicit/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec3/explicit/f32.wgsl.expected.wgsl
index 2164502..376f901 100644
--- a/test/expressions/type_ctor/vec3/explicit/f32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/f32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec3<f32>(0.0, 1.0, 2.0);
+let v = vec3(0.0, 1.0, 2.0);
diff --git a/test/expressions/type_ctor/vec3/explicit/i32.wgsl b/test/expressions/type_ctor/vec3/explicit/i32.wgsl
index 7d28b9e..7b9ebcb 100644
--- a/test/expressions/type_ctor/vec3/explicit/i32.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/i32.wgsl
@@ -1 +1 @@
-let v = vec3<i32>(0, 1, 2);
+let v = vec3(0, 1, 2);
diff --git a/test/expressions/type_ctor/vec3/explicit/i32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec3/explicit/i32.wgsl.expected.wgsl
index 7d28b9e..7b9ebcb 100644
--- a/test/expressions/type_ctor/vec3/explicit/i32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/i32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec3<i32>(0, 1, 2);
+let v = vec3(0, 1, 2);
diff --git a/test/expressions/type_ctor/vec3/explicit/u32.wgsl b/test/expressions/type_ctor/vec3/explicit/u32.wgsl
index 111a1d3..0040d27 100644
--- a/test/expressions/type_ctor/vec3/explicit/u32.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/u32.wgsl
@@ -1 +1 @@
-let v = vec3<u32>(0u, 1u, 2u);
+let v = vec3(0u, 1u, 2u);
diff --git a/test/expressions/type_ctor/vec3/explicit/u32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec3/explicit/u32.wgsl.expected.wgsl
index 111a1d3..0040d27 100644
--- a/test/expressions/type_ctor/vec3/explicit/u32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec3/explicit/u32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec3<u32>(0u, 1u, 2u);
+let v = vec3(0u, 1u, 2u);
diff --git a/test/expressions/type_ctor/vec4/explicit/bool.wgsl b/test/expressions/type_ctor/vec4/explicit/bool.wgsl
index 70cb499..baeff0f 100644
--- a/test/expressions/type_ctor/vec4/explicit/bool.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/bool.wgsl
@@ -1 +1 @@
-let v = vec4<bool>(false, true, false, true);
+let v = vec4(false, true, false, true);
diff --git a/test/expressions/type_ctor/vec4/explicit/bool.wgsl.expected.wgsl b/test/expressions/type_ctor/vec4/explicit/bool.wgsl.expected.wgsl
index 70cb499..baeff0f 100644
--- a/test/expressions/type_ctor/vec4/explicit/bool.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/bool.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec4<bool>(false, true, false, true);
+let v = vec4(false, true, false, true);
diff --git a/test/expressions/type_ctor/vec4/explicit/f32.wgsl b/test/expressions/type_ctor/vec4/explicit/f32.wgsl
index 3e7b8b6..bb1280e 100644
--- a/test/expressions/type_ctor/vec4/explicit/f32.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/f32.wgsl
@@ -1 +1 @@
-let v = vec4<f32>(0.0, 1.0, 2.0, 3.0);
+let v = vec4(0.0, 1.0, 2.0, 3.0);
diff --git a/test/expressions/type_ctor/vec4/explicit/f32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec4/explicit/f32.wgsl.expected.wgsl
index 3e7b8b6..bb1280e 100644
--- a/test/expressions/type_ctor/vec4/explicit/f32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/f32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec4<f32>(0.0, 1.0, 2.0, 3.0);
+let v = vec4(0.0, 1.0, 2.0, 3.0);
diff --git a/test/expressions/type_ctor/vec4/explicit/i32.wgsl b/test/expressions/type_ctor/vec4/explicit/i32.wgsl
index 9c86a2e..ab60e6e 100644
--- a/test/expressions/type_ctor/vec4/explicit/i32.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/i32.wgsl
@@ -1 +1 @@
-let v = vec4<i32>(0, 1, 2, 3);
+let v = vec4(0, 1, 2, 3);
diff --git a/test/expressions/type_ctor/vec4/explicit/i32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec4/explicit/i32.wgsl.expected.wgsl
index 9c86a2e..ab60e6e 100644
--- a/test/expressions/type_ctor/vec4/explicit/i32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/i32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec4<i32>(0, 1, 2, 3);
+let v = vec4(0, 1, 2, 3);
diff --git a/test/expressions/type_ctor/vec4/explicit/u32.wgsl b/test/expressions/type_ctor/vec4/explicit/u32.wgsl
index feaa000..ef7c766 100644
--- a/test/expressions/type_ctor/vec4/explicit/u32.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/u32.wgsl
@@ -1 +1 @@
-let v = vec4<u32>(0u, 1u, 2u, 3u);
+let v = vec4(0u, 1u, 2u, 3u);
diff --git a/test/expressions/type_ctor/vec4/explicit/u32.wgsl.expected.wgsl b/test/expressions/type_ctor/vec4/explicit/u32.wgsl.expected.wgsl
index feaa000..ef7c766 100644
--- a/test/expressions/type_ctor/vec4/explicit/u32.wgsl.expected.wgsl
+++ b/test/expressions/type_ctor/vec4/explicit/u32.wgsl.expected.wgsl
@@ -1 +1 @@
-let v = vec4<u32>(0u, 1u, 2u, 3u);
+let v = vec4(0u, 1u, 2u, 3u);