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;
 }