Add ArrayAccessor to output expressions.

This CL extends the WGSL writer to output ArrayAccessorExpression the
initializers are also output so we can test the array[5] syntax..

Bug: tint:4
Change-Id: I560ca6af4d714e13b136f6ded2fb3329e309c9ca
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/16820
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 09c20a3..46c6e65 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -16,10 +16,16 @@
 
 #include <cassert>
 
+#include "src/ast/array_accessor_expression.h"
 #include "src/ast/binding_decoration.h"
+#include "src/ast/bool_literal.h"
 #include "src/ast/builtin_decoration.h"
+#include "src/ast/const_initializer_expression.h"
 #include "src/ast/decorated_variable.h"
+#include "src/ast/float_literal.h"
 #include "src/ast/identifier_expression.h"
+#include "src/ast/initializer_expression.h"
+#include "src/ast/int_literal.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/set_decoration.h"
 #include "src/ast/struct.h"
@@ -30,6 +36,8 @@
 #include "src/ast/type/pointer_type.h"
 #include "src/ast/type/struct_type.h"
 #include "src/ast/type/vector_type.h"
+#include "src/ast/type_initializer_expression.h"
+#include "src/ast/uint_literal.h"
 
 namespace tint {
 namespace writer {
@@ -106,19 +114,100 @@
 }
 
 bool GeneratorImpl::EmitExpression(ast::Expression* expr) {
+  if (expr->IsArrayAccessor()) {
+    return EmitArrayAccessor(expr->AsArrayAccessor());
+  }
   if (expr->IsIdentifier()) {
-    bool first = true;
-    for (const auto& part : expr->AsIdentifier()->name()) {
-      if (!first) {
-        out_ << "::";
-      }
-      first = false;
-      out_ << part;
-    }
-  } else {
-    error_ = "unknown expression type";
+    return EmitIdentifier(expr->AsIdentifier());
+  }
+  if (expr->IsInitializer()) {
+    return EmitInitializer(expr->AsInitializer());
+  }
+
+  error_ = "unknown expression type";
+  return false;
+}
+
+bool GeneratorImpl::EmitArrayAccessor(ast::ArrayAccessorExpression* expr) {
+  if (!EmitExpression(expr->array())) {
     return false;
   }
+  out_ << "[";
+
+  if (!EmitExpression(expr->idx_expr())) {
+    return false;
+  }
+  out_ << "]";
+
+  return true;
+}
+
+bool GeneratorImpl::EmitInitializer(ast::InitializerExpression* expr) {
+  if (expr->IsConstInitializer()) {
+    return EmitConstInitializer(expr->AsConstInitializer());
+  }
+  return EmitTypeInitializer(expr->AsTypeInitializer());
+}
+
+bool GeneratorImpl::EmitTypeInitializer(ast::TypeInitializerExpression* expr) {
+  if (!EmitType(expr->type())) {
+    return false;
+  }
+
+  out_ << "(";
+
+  bool first = true;
+  for (const auto& e : expr->values()) {
+    if (!first) {
+      out_ << ", ";
+    }
+    first = false;
+
+    if (!EmitExpression(e.get())) {
+      return false;
+    }
+  }
+
+  out_ << ")";
+  return true;
+}
+
+bool GeneratorImpl::EmitConstInitializer(
+    ast::ConstInitializerExpression* expr) {
+  auto lit = expr->literal();
+  if (lit->IsBool()) {
+    out_ << (lit->AsBool()->IsTrue() ? "true" : "false");
+  } else if (lit->IsFloat()) {
+    auto flags = out_.flags();
+    auto precision = out_.precision();
+
+    out_.flags(flags | std::ios_base::showpoint);
+    out_.precision(std::numeric_limits<float>::max_digits10);
+
+    out_ << lit->AsFloat()->value();
+
+    out_.precision(precision);
+    out_.flags(flags);
+  } else if (lit->IsInt()) {
+    out_ << lit->AsInt()->value();
+  } else if (lit->IsUint()) {
+    out_ << lit->AsUint()->value() << "u";
+  } else {
+    error_ = "unknown literal type";
+    return false;
+  }
+  return true;
+}
+
+bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) {
+  bool first = true;
+  for (const auto& part : expr->AsIdentifier()->name()) {
+    if (!first) {
+      out_ << "::";
+    }
+    first = false;
+    out_ << part;
+  }
   return true;
 }
 
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 9d526a8..3ecc17c 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -18,11 +18,16 @@
 #include <sstream>
 #include <string>
 
+#include "src/ast/array_accessor_expression.h"
+#include "src/ast/const_initializer_expression.h"
 #include "src/ast/entry_point.h"
+#include "src/ast/identifier_expression.h"
 #include "src/ast/import.h"
+#include "src/ast/initializer_expression.h"
 #include "src/ast/module.h"
 #include "src/ast/type/alias_type.h"
 #include "src/ast/type/type.h"
+#include "src/ast/type_initializer_expression.h"
 #include "src/ast/variable.h"
 
 namespace tint {
@@ -65,6 +70,14 @@
   /// @param alias the alias to generate
   /// @returns true if the alias was emitted
   bool EmitAliasType(const ast::type::AliasType* alias);
+  /// Handles an array accessor expression
+  /// @param expr the expression to emit
+  /// @returns true if the array accessor was emitted
+  bool EmitArrayAccessor(ast::ArrayAccessorExpression* expr);
+  /// Handles generating a const initializer
+  /// @param expr the const initializer expression
+  /// @returns true if the initializer is emitted
+  bool EmitConstInitializer(ast::ConstInitializerExpression* expr);
   /// Handles generating an entry_point command
   /// @param ep the entry point
   /// @returns true if the entry point was emitted
@@ -73,14 +86,26 @@
   /// @param expr the expression
   /// @returns true if the expression was emitted
   bool EmitExpression(ast::Expression* expr);
+  /// Handles generating an identifier expression
+  /// @param expr the identifier expression
+  /// @returns true if the identifeir was emitted
+  bool EmitIdentifier(ast::IdentifierExpression* expr);
   /// Handles generating an import command
   /// @param import the import to generate
   /// @returns true if the import was emitted
   bool EmitImport(const ast::Import* import);
+  /// Handles generating initializer expressions
+  /// @param expr the initializer expression
+  /// @returns true if the expression was emitted
+  bool EmitInitializer(ast::InitializerExpression* expr);
   /// Handles generating type
   /// @param type the type to generate
   /// @returns true if the type is emitted
   bool EmitType(ast::type::Type* type);
+  /// Handles emitting a type initializer
+  /// @param expr the type initializer expression
+  /// @returns true if the initializer is emitted
+  bool EmitTypeInitializer(ast::TypeInitializerExpression* expr);
   /// Handles generating a variable
   /// @param var the variable to generate
   /// @returns true if the variable was emitted
diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc
index 813d71b..cb05e58 100644
--- a/src/writer/wgsl/generator_impl_test.cc
+++ b/src/writer/wgsl/generator_impl_test.cc
@@ -19,11 +19,15 @@
 #include <vector>
 
 #include "gtest/gtest.h"
+#include "src/ast/array_accessor_expression.h"
 #include "src/ast/binding_decoration.h"
+#include "src/ast/bool_literal.h"
 #include "src/ast/builtin.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/decorated_variable.h"
+#include "src/ast/float_literal.h"
 #include "src/ast/identifier_expression.h"
+#include "src/ast/int_literal.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/set_decoration.h"
 #include "src/ast/struct.h"
@@ -41,6 +45,7 @@
 #include "src/ast/type/u32_type.h"
 #include "src/ast/type/vector_type.h"
 #include "src/ast/type/void_type.h"
+#include "src/ast/uint_literal.h"
 #include "src/ast/variable.h"
 
 namespace tint {
@@ -57,12 +62,12 @@
   ast::type::AliasType alias("a", &f32);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitAliasType(&alias));
+  ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
   EXPECT_EQ(g.result(), R"(type a = f32;
 )");
 }
 
-TEST_F(GeneratorImplTest, DISABLED_EmitAliasType_Struct) {
+TEST_F(GeneratorImplTest, EmitAliasType_Struct) {
   ast::type::I32Type i32;
   ast::type::F32Type f32;
 
@@ -82,11 +87,11 @@
   ast::type::AliasType alias("a", &s);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitAliasType(&alias));
+  ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
   EXPECT_EQ(g.result(), R"(type a = struct {
   a : f32;
   [[offset 4]] b : i32;
-}
+};
 )");
 }
 
@@ -94,7 +99,7 @@
   ast::EntryPoint ep(ast::PipelineStage::kFragment, "", "frag_main");
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitEntryPoint(&ep));
+  ASSERT_TRUE(g.EmitEntryPoint(&ep)) << g.error();
   EXPECT_EQ(g.result(), R"(entry_point fragment = frag_main;
 )");
 }
@@ -103,7 +108,7 @@
   ast::EntryPoint ep(ast::PipelineStage::kFragment, "main", "frag_main");
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitEntryPoint(&ep));
+  ASSERT_TRUE(g.EmitEntryPoint(&ep)) << g.error();
   EXPECT_EQ(g.result(), R"(entry_point fragment as "main" = frag_main;
 )");
 }
@@ -112,7 +117,7 @@
   ast::Import import("GLSL.std.450", "std::glsl");
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitImport(&import));
+  ASSERT_TRUE(g.EmitImport(&import)) << g.error();
   EXPECT_EQ(g.result(), R"(import "GLSL.std.450" as std::glsl;
 )");
 }
@@ -122,7 +127,7 @@
   ast::type::AliasType alias("alias", &f32);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&alias));
+  ASSERT_TRUE(g.EmitType(&alias)) << g.error();
   EXPECT_EQ(g.result(), "alias");
 }
 
@@ -131,7 +136,7 @@
   ast::type::ArrayType a(&b, 4);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&a));
+  ASSERT_TRUE(g.EmitType(&a)) << g.error();
   EXPECT_EQ(g.result(), "array<bool, 4>");
 }
 
@@ -140,7 +145,7 @@
   ast::type::ArrayType a(&b);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&a));
+  ASSERT_TRUE(g.EmitType(&a)) << g.error();
   EXPECT_EQ(g.result(), "array<bool>");
 }
 
@@ -148,7 +153,7 @@
   ast::type::BoolType b;
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&b));
+  ASSERT_TRUE(g.EmitType(&b)) << g.error();
   EXPECT_EQ(g.result(), "bool");
 }
 
@@ -156,7 +161,7 @@
   ast::type::F32Type f32;
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&f32));
+  ASSERT_TRUE(g.EmitType(&f32)) << g.error();
   EXPECT_EQ(g.result(), "f32");
 }
 
@@ -164,7 +169,7 @@
   ast::type::I32Type i32;
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&i32));
+  ASSERT_TRUE(g.EmitType(&i32)) << g.error();
   EXPECT_EQ(g.result(), "i32");
 }
 
@@ -173,7 +178,7 @@
   ast::type::MatrixType m(&f32, 3, 2);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&m));
+  ASSERT_TRUE(g.EmitType(&m)) << g.error();
   EXPECT_EQ(g.result(), "mat2x3<f32>");
 }
 
@@ -182,7 +187,7 @@
   ast::type::PointerType p(&f32, ast::StorageClass::kWorkgroup);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&p));
+  ASSERT_TRUE(g.EmitType(&p)) << g.error();
   EXPECT_EQ(g.result(), "ptr<workgroup, f32>");
 }
 
@@ -205,7 +210,7 @@
   ast::type::StructType s(std::move(str));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&s));
+  ASSERT_TRUE(g.EmitType(&s)) << g.error();
   EXPECT_EQ(g.result(), R"(struct {
   a : i32;
   [[offset 4]] b : f32;
@@ -232,7 +237,7 @@
   ast::type::StructType s(std::move(str));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&s));
+  ASSERT_TRUE(g.EmitType(&s)) << g.error();
   EXPECT_EQ(g.result(), R"([[block]] struct {
   a : i32;
   [[offset 4]] b : f32;
@@ -243,7 +248,7 @@
   ast::type::U32Type u32;
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&u32));
+  ASSERT_TRUE(g.EmitType(&u32)) << g.error();
   EXPECT_EQ(g.result(), "u32");
 }
 
@@ -252,7 +257,7 @@
   ast::type::VectorType v(&f32, 3);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&v));
+  ASSERT_TRUE(g.EmitType(&v)) << g.error();
   EXPECT_EQ(g.result(), "vec3<f32>");
 }
 
@@ -260,7 +265,7 @@
   ast::type::VoidType v;
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitType(&v));
+  ASSERT_TRUE(g.EmitType(&v)) << g.error();
   EXPECT_EQ(g.result(), "void");
 }
 
@@ -269,7 +274,7 @@
   ast::Variable v("a", ast::StorageClass::kNone, &f32);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&v));
+  ASSERT_TRUE(g.EmitVariable(&v)) << g.error();
   EXPECT_EQ(g.result(), R"(var a : f32;
 )");
 }
@@ -279,7 +284,7 @@
   ast::Variable v("a", ast::StorageClass::kInput, &f32);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&v));
+  ASSERT_TRUE(g.EmitVariable(&v)) << g.error();
   EXPECT_EQ(g.result(), R"(var<in> a : f32;
 )");
 }
@@ -296,7 +301,7 @@
   dv.set_decorations(std::move(decos));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&dv));
+  ASSERT_TRUE(g.EmitVariable(&dv)) << g.error();
   EXPECT_EQ(g.result(), R"([[location 2]] var a : f32;
 )");
 }
@@ -317,7 +322,7 @@
   dv.set_decorations(std::move(decos));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&dv));
+  ASSERT_TRUE(g.EmitVariable(&dv)) << g.error();
   EXPECT_EQ(g.result(),
             R"([[builtin position, binding 0, set 1, location 2]] var a : f32;
 )");
@@ -331,7 +336,7 @@
   v.set_initializer(std::move(ident));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&v));
+  ASSERT_TRUE(g.EmitVariable(&v)) << g.error();
   EXPECT_EQ(g.result(), R"(var a : f32 = initializer;
 )");
 }
@@ -345,27 +350,242 @@
   v.set_is_const(true);
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitVariable(&v));
+  ASSERT_TRUE(g.EmitVariable(&v)) << g.error();
   EXPECT_EQ(g.result(), R"(const a : f32 = initializer;
 )");
 }
 
-TEST_F(GeneratorImplTest, EmitExpression_Identifier) {
-  ast::IdentifierExpression i("init");
+TEST_F(GeneratorImplTest, EmitExpression_ArrayAccessor) {
+  auto lit = std::make_unique<ast::IntLiteral>(5);
+  auto idx = std::make_unique<ast::ConstInitializerExpression>(std::move(lit));
+  auto ary = std::make_unique<ast::IdentifierExpression>("ary");
+
+  ast::ArrayAccessorExpression expr(std::move(ary), std::move(idx));
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitExpression(&i));
-  EXPECT_EQ(g.result(), "init");
+  ASSERT_TRUE(g.EmitExpression(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "ary[5]");
 }
 
-TEST_F(GeneratorImplTest, EmitExpression_Identifier_MultipleNames) {
+TEST_F(GeneratorImplTest, EmitExpression_Identifier) {
+  ast::IdentifierExpression i(std::vector<std::string>{"std", "glsl"});
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
+  EXPECT_EQ(g.result(), "std::glsl");
+}
+
+TEST_F(GeneratorImplTest, EmitArrayAccessor) {
+  auto ary = std::make_unique<ast::IdentifierExpression>("ary");
+  auto idx = std::make_unique<ast::IdentifierExpression>("idx");
+
+  ast::ArrayAccessorExpression expr(std::move(ary), std::move(idx));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitArrayAccessor(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "ary[idx]");
+}
+
+TEST_F(GeneratorImplTest, EmitIdentifierExpression_Single) {
+  ast::IdentifierExpression i("glsl");
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
+  EXPECT_EQ(g.result(), "glsl");
+}
+
+TEST_F(GeneratorImplTest, EmitIdentifierExpression_MultipleNames) {
   ast::IdentifierExpression i({"std", "glsl", "init"});
 
   GeneratorImpl g;
-  ASSERT_TRUE(g.EmitExpression(&i));
+  ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
   EXPECT_EQ(g.result(), "std::glsl::init");
 }
 
+TEST_F(GeneratorImplTest, EmitInitializer_Bool) {
+  auto lit = std::make_unique<ast::BoolLiteral>(false);
+  ast::ConstInitializerExpression expr(std::move(lit));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "false");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Int) {
+  auto lit = std::make_unique<ast::IntLiteral>(-12345);
+  ast::ConstInitializerExpression expr(std::move(lit));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "-12345");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_UInt) {
+  auto lit = std::make_unique<ast::UintLiteral>(56779);
+  ast::ConstInitializerExpression expr(std::move(lit));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "56779u");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Float) {
+  auto lit = std::make_unique<ast::FloatLiteral>(1.5e27);
+  ast::ConstInitializerExpression expr(std::move(lit));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "1.49999995e+27");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Float) {
+  ast::type::F32Type f32;
+
+  auto lit = std::make_unique<ast::FloatLiteral>(-1.2e-5);
+  std::vector<std::unique_ptr<ast::Expression>> values;
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit)));
+
+  ast::TypeInitializerExpression expr(&f32, std::move(values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "f32(-1.20000004e-05)");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Bool) {
+  ast::type::BoolType b;
+
+  auto lit = std::make_unique<ast::BoolLiteral>(true);
+  std::vector<std::unique_ptr<ast::Expression>> values;
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit)));
+
+  ast::TypeInitializerExpression expr(&b, std::move(values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "bool(true)");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Int) {
+  ast::type::I32Type i32;
+
+  auto lit = std::make_unique<ast::IntLiteral>(-12345);
+  std::vector<std::unique_ptr<ast::Expression>> values;
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit)));
+
+  ast::TypeInitializerExpression expr(&i32, std::move(values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "i32(-12345)");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Uint) {
+  ast::type::U32Type u32;
+
+  auto lit = std::make_unique<ast::UintLiteral>(12345);
+  std::vector<std::unique_ptr<ast::Expression>> values;
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit)));
+
+  ast::TypeInitializerExpression expr(&u32, std::move(values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "u32(12345u)");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Vec) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 3);
+
+  auto lit1 = std::make_unique<ast::FloatLiteral>(1.f);
+  auto lit2 = std::make_unique<ast::FloatLiteral>(2.f);
+  auto lit3 = std::make_unique<ast::FloatLiteral>(3.f);
+  std::vector<std::unique_ptr<ast::Expression>> values;
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit1)));
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit2)));
+  values.push_back(
+      std::make_unique<ast::ConstInitializerExpression>(std::move(lit3)));
+
+  ast::TypeInitializerExpression expr(&vec, std::move(values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), "vec3<f32>(1.00000000, 2.00000000, 3.00000000)");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Mat) {
+  ast::type::F32Type f32;
+  ast::type::MatrixType mat(&f32, 3, 2);
+
+  ast::type::VectorType vec(&f32, 2);
+
+  std::vector<std::unique_ptr<ast::Expression>> mat_values;
+
+  for (size_t i = 0; i < 3; i++) {
+    auto lit1 = std::make_unique<ast::FloatLiteral>(1.f + (i * 2));
+    auto lit2 = std::make_unique<ast::FloatLiteral>(2.f + (i * 2));
+
+    std::vector<std::unique_ptr<ast::Expression>> values;
+    values.push_back(
+        std::make_unique<ast::ConstInitializerExpression>(std::move(lit1)));
+    values.push_back(
+        std::make_unique<ast::ConstInitializerExpression>(std::move(lit2)));
+
+    mat_values.push_back(std::make_unique<ast::TypeInitializerExpression>(
+        &vec, std::move(values)));
+  }
+
+  ast::TypeInitializerExpression expr(&mat, std::move(mat_values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(),
+            std::string("mat2x3<f32>(vec2<f32>(1.00000000, 2.00000000), ") +
+                "vec2<f32>(3.00000000, 4.00000000), " +
+                "vec2<f32>(5.00000000, 6.00000000))");
+}
+
+TEST_F(GeneratorImplTest, EmitInitializer_Type_Array) {
+  ast::type::F32Type f32;
+  ast::type::VectorType vec(&f32, 3);
+  ast::type::ArrayType ary(&vec, 3);
+
+  std::vector<std::unique_ptr<ast::Expression>> ary_values;
+
+  for (size_t i = 0; i < 3; i++) {
+    auto lit1 = std::make_unique<ast::FloatLiteral>(1.f + (i * 3));
+    auto lit2 = std::make_unique<ast::FloatLiteral>(2.f + (i * 3));
+    auto lit3 = std::make_unique<ast::FloatLiteral>(3.f + (i * 3));
+
+    std::vector<std::unique_ptr<ast::Expression>> values;
+    values.push_back(
+        std::make_unique<ast::ConstInitializerExpression>(std::move(lit1)));
+    values.push_back(
+        std::make_unique<ast::ConstInitializerExpression>(std::move(lit2)));
+    values.push_back(
+        std::make_unique<ast::ConstInitializerExpression>(std::move(lit3)));
+
+    ary_values.push_back(std::make_unique<ast::TypeInitializerExpression>(
+        &vec, std::move(values)));
+  }
+
+  ast::TypeInitializerExpression expr(&ary, std::move(ary_values));
+
+  GeneratorImpl g;
+  ASSERT_TRUE(g.EmitInitializer(&expr)) << g.error();
+  EXPECT_EQ(g.result(), std::string("array<vec3<f32>, 3>(") +
+                            "vec3<f32>(1.00000000, 2.00000000, 3.00000000), " +
+                            "vec3<f32>(4.00000000, 5.00000000, 6.00000000), " +
+                            "vec3<f32>(7.00000000, 8.00000000, 9.00000000))");
+}
+
 }  // namespace
 }  // namespace wgsl
 }  // namespace writer