Support the zero initializer syntax.
This Cl updates the system to allow zero initializers. This allows:
```
var a : vec3<f32> = vec3<f32>();
```
Bug: tint:34
Change-Id: I84d6b431914c4ddf112ed375fae028d912f4a080
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/23660
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/type_constructor_expression.cc b/src/ast/type_constructor_expression.cc
index e53b87d..e29e620 100644
--- a/src/ast/type_constructor_expression.cc
+++ b/src/ast/type_constructor_expression.cc
@@ -40,7 +40,7 @@
bool TypeConstructorExpression::IsValid() const {
if (values_.empty()) {
- return false;
+ return true;
}
if (type_ == nullptr) {
return false;
diff --git a/src/ast/type_constructor_expression_test.cc b/src/ast/type_constructor_expression_test.cc
index 28b3608..c223fb5 100644
--- a/src/ast/type_constructor_expression_test.cc
+++ b/src/ast/type_constructor_expression_test.cc
@@ -66,6 +66,14 @@
EXPECT_TRUE(t.IsValid());
}
+TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) {
+ type::F32Type f32;
+ ExpressionList expr;
+
+ TypeConstructorExpression t(&f32, std::move(expr));
+ EXPECT_TRUE(t.IsValid());
+}
+
TEST_F(TypeConstructorExpressionTest, IsValid_NullType) {
ExpressionList expr;
expr.push_back(std::make_unique<IdentifierExpression>("expr"));
@@ -94,14 +102,6 @@
EXPECT_FALSE(t.IsValid());
}
-TEST_F(TypeConstructorExpressionTest, IsValid_EmptyValue) {
- type::F32Type f32;
- ExpressionList expr;
-
- TypeConstructorExpression t(&f32, std::move(expr));
- EXPECT_FALSE(t.IsValid());
-}
-
TEST_F(TypeConstructorExpressionTest, ToStr) {
type::F32Type f32;
type::VectorType vec(&f32, 3);
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 1886d62..63e426b 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1943,7 +1943,7 @@
// primary_expression
// : (IDENT NAMESPACE)* IDENT
-// | type_decl PAREN_LEFT argument_expression_list PAREN_RIGHT
+// | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT
// | const_literal
// | paren_rhs_stmt
// | CAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
@@ -2043,9 +2043,13 @@
return nullptr;
}
- auto params = argument_expression_list();
- if (has_error())
- return nullptr;
+ t = peek();
+ ast::ExpressionList params;
+ if (!t.IsParenRight() && !t.IsEof()) {
+ params = argument_expression_list();
+ if (has_error())
+ return nullptr;
+ }
t = next();
if (!t.IsParenRight()) {
diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc
index a5fd1d9..c2558e9 100644
--- a/src/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -98,6 +98,18 @@
EXPECT_EQ(ident->literal()->AsSint()->value(), 4);
}
+TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
+ auto* p = parser("vec4<i32>()");
+ auto e = p->primary_expression();
+ ASSERT_FALSE(p->has_error()) << p->error();
+ ASSERT_NE(e, nullptr);
+ ASSERT_TRUE(e->IsConstructor());
+ ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
+ auto* ty = e->AsConstructor()->AsTypeConstructor();
+
+ ASSERT_EQ(ty->values().size(), 0u);
+}
+
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
auto* p = parser("vec4<if>(2., 3., 4., 5.)");
auto e = p->primary_expression();
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 0157837..0a81e8e 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -940,6 +940,12 @@
return 0;
}
+ // Generate the zero initializer if there are no values provided.
+ if (init->values().empty()) {
+ ast::NullLiteral nl(init->type()->UnwrapPtrIfNeeded());
+ return GenerateLiteralIfNeeded(&nl);
+ }
+
auto* result_type = init->type()->UnwrapPtrIfNeeded();
if (result_type->IsVector()) {
result_type = result_type->AsVector()->type();
diff --git a/src/writer/spirv/builder_assign_test.cc b/src/writer/spirv/builder_assign_test.cc
index ad98cc3..d81af3b 100644
--- a/src/writer/spirv/builder_assign_test.cc
+++ b/src/writer/spirv/builder_assign_test.cc
@@ -78,6 +78,45 @@
)");
}
+TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec(&f32, 3);
+
+ ast::Variable v("var", ast::StorageClass::kOutput, &vec);
+
+ auto ident = std::make_unique<ast::IdentifierExpression>("var");
+ ast::ExpressionList vals;
+ auto val =
+ std::make_unique<ast::TypeConstructorExpression>(&vec, std::move(vals));
+
+ ast::AssignmentStatement assign(std::move(ident), std::move(val));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(&v);
+
+ ASSERT_TRUE(td.DetermineResultType(&assign)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_TRUE(b.GenerateAssignStatement(&assign)) << b.error();
+ EXPECT_FALSE(b.has_error());
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Output %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Output %5
+)");
+
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %1 %5
+)");
+}
+
TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) {
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc
index df0c219..3a16281 100644
--- a/src/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/writer/spirv/builder_constructor_expression_test.cc
@@ -82,6 +82,30 @@
)");
}
+TEST_F(BuilderTest, Constructor_Type_ZeroInit) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec(&f32, 2);
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&vec, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateConstructorExpression(&t, false), 3u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 2
+%3 = OpConstantNull %1
+)");
+}
+
TEST_F(BuilderTest, Constructor_Type_NonConstructorParam) {
ast::type::F32Type f32;
ast::type::VectorType vec(&f32, 2);
diff --git a/test/simple.wgsl b/test/simple.wgsl
index da941a2..e60ec1d 100644
--- a/test/simple.wgsl
+++ b/test/simple.wgsl
@@ -15,6 +15,7 @@
[[location 0]] var<out> gl_FragColor : vec4<f32>;
fn main() -> void {
+ var a : vec2<f32> = vec2<f32>();
gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
return;
}