Have TypesBuilder::i32() return ast::I32

Bug: tint:724
Change-Id: I2b4abc1f128a1489a4023bd3b82fc7234d70449f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51485
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 62d95a7..23d6fac 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -567,7 +567,6 @@
     return nullptr;
   }
 
-
   /// Generates appropriate types for a Read-Only StorageTexture
   /// @param dim the texture dimension of the storage texture
   /// @param format the image format of the storage texture
@@ -2801,7 +2800,7 @@
   auto st_type = MakeStorageTextureTypes(dim, format, read_only);
   AddStorageTexture("st_var", st_type, 0, 0);
 
-  typ::Type dim_type = nullptr;
+  ast::Type* dim_type = nullptr;
   switch (dim) {
     case ast::TextureDimension::k1d:
       dim_type = ty.i32();
diff --git a/src/intrinsic_table_test.cc b/src/intrinsic_table_test.cc
index b84f1ab..7c11357 100644
--- a/src/intrinsic_table_test.cc
+++ b/src/intrinsic_table_test.cc
@@ -47,7 +47,8 @@
 }
 
 TEST_F(IntrinsicTableTest, MismatchF32) {
-  auto result = table->Lookup(*this, IntrinsicType::kCos, {ty.i32()}, Source{});
+  auto* i32 = create<sem::I32>();
+  auto result = table->Lookup(*this, IntrinsicType::kCos, {i32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
@@ -71,17 +72,18 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchI32) {
+  auto* i32 = create<sem::I32>();
   auto tex = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.i32(), ty.i32()}, Source{});
+                              {tex, i32, i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{ty.i32(), Parameter::Usage::kCoords},
-                          Parameter{ty.i32(), Parameter::Usage::kLevel}));
+                          Parameter{i32, Parameter::Usage::kCoords},
+                          Parameter{i32, Parameter::Usage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchI32) {
@@ -93,13 +95,14 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
+  auto* i32 = create<sem::I32>();
   auto result =
-      table->Lookup(*this, IntrinsicType::kCountOneBits, {ty.i32()}, Source{});
+      table->Lookup(*this, IntrinsicType::kCountOneBits, {i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCountOneBits);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.i32());
-  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.i32()}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), i32);
+  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{i32}));
 }
 
 TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
@@ -121,15 +124,15 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
-  auto result = table->Lookup(*this, IntrinsicType::kClamp,
-                              {ty.i32(), ty.i32(), ty.i32()}, Source{});
+  auto* i32 = create<sem::I32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kClamp, {i32, i32, i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.i32());
+  EXPECT_THAT(result.intrinsic->ReturnType(), i32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.i32()}, Parameter{ty.i32()},
-                          Parameter{ty.i32()}));
+              ElementsAre(Parameter{i32}, Parameter{i32}, Parameter{i32}));
 }
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
@@ -247,63 +250,72 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchSampledTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto tex = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.vec2<i32>(), ty.i32()}, Source{});
+                              {tex, vec2_i32, i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
-                          Parameter{ty.i32(), Parameter::Usage::kLevel}));
+                          Parameter{vec2_i32, Parameter::Usage::kCoords},
+                          Parameter{i32, Parameter::Usage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto* tex =
       create<sem::MultisampledTexture>(ast::TextureDimension::k2d, ty.f32());
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.vec2<i32>(), ty.i32()}, Source{});
+                              {tex, vec2_i32, i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
-                          Parameter{ty.i32(), Parameter::Usage::kSampleIndex}));
+                          Parameter{vec2_i32, Parameter::Usage::kCoords},
+                          Parameter{i32, Parameter::Usage::kSampleIndex}));
 }
 
 TEST_F(IntrinsicTableTest, MatchDepthTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto tex = ty.depth_texture(ast::TextureDimension::k2d);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.vec2<i32>(), ty.i32()}, Source{});
+                              {tex, vec2_i32, i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
-                          Parameter{ty.i32(), Parameter::Usage::kLevel}));
+                          Parameter{vec2_i32, Parameter::Usage::kCoords},
+                          Parameter{i32, Parameter::Usage::kLevel}));
 }
 
 TEST_F(IntrinsicTableTest, MatchExternalTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto* tex = create<sem::ExternalTexture>();
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.vec2<i32>()}, Source{});
+                              {tex, vec2_i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
-  EXPECT_THAT(
-      result.intrinsic->Parameters(),
-      ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                  Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
+  EXPECT_THAT(result.intrinsic->Parameters(),
+              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
+                          Parameter{vec2_i32, Parameter::Usage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchROStorageTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto* subtype =
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
   auto* tex = create<sem::StorageTexture>(
@@ -311,18 +323,19 @@
       ast::AccessControl::kReadOnly, subtype);
 
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.vec2<i32>()}, Source{});
+                              {tex, vec2_i32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureLoad);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
-  EXPECT_THAT(
-      result.intrinsic->Parameters(),
-      ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                  Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords}));
+  EXPECT_THAT(result.intrinsic->Parameters(),
+              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
+                          Parameter{vec2_i32, Parameter::Usage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto* subtype =
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
   auto* tex = create<sem::StorageTexture>(
@@ -330,20 +343,22 @@
       ast::AccessControl::kWriteOnly, subtype);
 
   auto result = table->Lookup(*this, IntrinsicType::kTextureStore,
-                              {tex, ty.vec2<i32>(), ty.vec4<f32>()}, Source{});
+                              {tex, vec2_i32, ty.vec4<f32>()}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureStore);
   EXPECT_THAT(result.intrinsic->ReturnType(), ty.void_());
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                          Parameter{ty.vec2<i32>(), Parameter::Usage::kCoords},
+                          Parameter{vec2_i32, Parameter::Usage::kCoords},
                           Parameter{ty.vec4<f32>(), Parameter::Usage::kValue}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchTexture) {
+  auto* i32 = create<sem::I32>();
+  auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {ty.f32(), ty.vec2<i32>()}, Source{});
+                              {ty.f32(), vec2_i32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
diff --git a/src/program_builder.h b/src/program_builder.h
index dddf340..f0975f9 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -377,14 +377,12 @@
     }
 
     /// @returns a i32 type
-    typ::I32 i32() const {
-      return {builder->create<ast::I32>(), builder->create<sem::I32>()};
-    }
+    typ::I32 i32() const { return {builder->create<ast::I32>()}; }
 
     /// @param source the Source of the node
     /// @returns a i32 type
     typ::I32 i32(const Source& source) const {
-      return {builder->create<ast::I32>(source), builder->create<sem::I32>()};
+      return {builder->create<ast::I32>(source)};
     }
 
     /// @returns a u32 type
diff --git a/src/resolver/intrinsic_test.cc b/src/resolver/intrinsic_test.cc
index eb704bf..dbb2ef5 100644
--- a/src/resolver/intrinsic_test.cc
+++ b/src/resolver/intrinsic_test.cc
@@ -1937,24 +1937,32 @@
       default:
         FAIL() << "invalid texture dimensions: " << param.texture_dimension;
       case ast::TextureDimension::k1d:
-        EXPECT_EQ(TypeOf(call)->type_name(), ty.i32()->type_name());
+        EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
         break;
       case ast::TextureDimension::k2d:
-      case ast::TextureDimension::k2dArray:
-        EXPECT_EQ(TypeOf(call)->type_name(), ty.vec2<i32>()->type_name());
+      case ast::TextureDimension::k2dArray: {
+        auto* vec = As<sem::Vector>(TypeOf(call));
+        ASSERT_NE(vec, nullptr);
+        EXPECT_EQ(vec->size(), 2u);
+        EXPECT_TRUE(vec->type()->Is<sem::I32>());
         break;
+      }
       case ast::TextureDimension::k3d:
       case ast::TextureDimension::kCube:
-      case ast::TextureDimension::kCubeArray:
-        EXPECT_EQ(TypeOf(call)->type_name(), ty.vec3<i32>()->type_name());
+      case ast::TextureDimension::kCubeArray: {
+        auto* vec = As<sem::Vector>(TypeOf(call));
+        ASSERT_NE(vec, nullptr);
+        EXPECT_EQ(vec->size(), 3u);
+        EXPECT_TRUE(vec->type()->Is<sem::I32>());
         break;
+      }
     }
   } else if (std::string(param.function) == "textureNumLayers") {
-    EXPECT_EQ(TypeOf(call), ty.i32());
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
   } else if (std::string(param.function) == "textureNumLevels") {
-    EXPECT_EQ(TypeOf(call), ty.i32());
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
   } else if (std::string(param.function) == "textureNumSamples") {
-    EXPECT_EQ(TypeOf(call), ty.i32());
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
   } else if (std::string(param.function) == "textureStore") {
     EXPECT_EQ(TypeOf(call), ty.void_());
   } else {
diff --git a/src/resolver/is_host_shareable_test.cc b/src/resolver/is_host_shareable_test.cc
index 9a434ef..f197768 100644
--- a/src/resolver/is_host_shareable_test.cc
+++ b/src/resolver/is_host_shareable_test.cc
@@ -32,15 +32,15 @@
 }
 
 TEST_F(ResolverIsHostShareable, NumericScalar) {
-  EXPECT_TRUE(r()->IsHostShareable(ty.i32()));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::I32>()));
   EXPECT_TRUE(r()->IsHostShareable(create<sem::U32>()));
   EXPECT_TRUE(r()->IsHostShareable(ty.f32()));
 }
 
 TEST_F(ResolverIsHostShareable, NumericVector) {
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec2<i32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec3<i32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec4<i32>()));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 2)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 3)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 4)));
   EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 2)));
   EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 3)));
   EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 4)));
diff --git a/src/resolver/is_storeable_test.cc b/src/resolver/is_storeable_test.cc
index 9b25f82..61ba656 100644
--- a/src/resolver/is_storeable_test.cc
+++ b/src/resolver/is_storeable_test.cc
@@ -29,15 +29,15 @@
 
 TEST_F(ResolverIsStorableTest, Scalar) {
   EXPECT_TRUE(r()->IsStorable(ty.bool_()));
-  EXPECT_TRUE(r()->IsStorable(ty.i32()));
+  EXPECT_TRUE(r()->IsStorable(create<sem::I32>()));
   EXPECT_TRUE(r()->IsStorable(create<sem::U32>()));
   EXPECT_TRUE(r()->IsStorable(ty.f32()));
 }
 
 TEST_F(ResolverIsStorableTest, Vector) {
-  EXPECT_TRUE(r()->IsStorable(ty.vec2<i32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.vec3<i32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.vec4<i32>()));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 2)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 3)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 4)));
   EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 2)));
   EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 3)));
   EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 4)));
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index 8d7a610..1b4b1c1 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -760,7 +760,7 @@
   ASSERT_NE(func_sem, nullptr);
   EXPECT_EQ(func_sem->Parameters().size(), 3u);
   EXPECT_EQ(func_sem->Parameters()[0]->Type(), ty.f32());
-  EXPECT_EQ(func_sem->Parameters()[1]->Type(), ty.i32());
+  EXPECT_TRUE(func_sem->Parameters()[1]->Type()->Is<sem::I32>());
   EXPECT_TRUE(func_sem->Parameters()[2]->Type()->Is<sem::U32>());
   EXPECT_EQ(func_sem->Parameters()[0]->Declaration(), param_a);
   EXPECT_EQ(func_sem->Parameters()[1]->Declaration(), param_b);
diff --git a/src/sem/pointer_type_test.cc b/src/sem/pointer_type_test.cc
index 441a96f..56cbe3a 100644
--- a/src/sem/pointer_type_test.cc
+++ b/src/sem/pointer_type_test.cc
@@ -33,12 +33,12 @@
 }
 
 TEST_F(PointerTest, FriendlyNameWithStorageClass) {
-  auto* r = create<Pointer>(ty.i32(), ast::StorageClass::kWorkgroup);
+  auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kWorkgroup);
   EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<workgroup, i32>");
 }
 
 TEST_F(PointerTest, FriendlyNameWithoutStorageClass) {
-  auto* r = create<Pointer>(ty.i32(), ast::StorageClass::kNone);
+  auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kNone);
   EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<i32>");
 }
 
diff --git a/src/sem/reference_type_test.cc b/src/sem/reference_type_test.cc
index 9084593..3b279f4 100644
--- a/src/sem/reference_type_test.cc
+++ b/src/sem/reference_type_test.cc
@@ -33,12 +33,12 @@
 }
 
 TEST_F(ReferenceTest, FriendlyNameWithStorageClass) {
-  auto* r = create<Reference>(ty.i32(), ast::StorageClass::kWorkgroup);
+  auto* r = create<Reference>(create<I32>(), ast::StorageClass::kWorkgroup);
   EXPECT_EQ(r->FriendlyName(Symbols()), "ref<workgroup, i32>");
 }
 
 TEST_F(ReferenceTest, FriendlyNameWithoutStorageClass) {
-  auto* r = create<Reference>(ty.i32(), ast::StorageClass::kNone);
+  auto* r = create<Reference>(create<I32>(), ast::StorageClass::kNone);
   EXPECT_EQ(r->FriendlyName(Symbols()), "ref<i32>");
 }
 
diff --git a/src/sem/sem_array_test.cc b/src/sem/sem_array_test.cc
index f0d2239..324fdd6 100644
--- a/src/sem/sem_array_test.cc
+++ b/src/sem/sem_array_test.cc
@@ -52,22 +52,22 @@
 }
 
 TEST_F(ArrayTest, FriendlyNameRuntimeSized) {
-  auto* arr = create<Array>(ty.i32(), 0, 0, 4, 4, true);
+  auto* arr = create<Array>(create<I32>(), 0, 0, 4, 4, true);
   EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
 }
 
 TEST_F(ArrayTest, FriendlyNameStaticSized) {
-  auto* arr = create<Array>(ty.i32(), 5, 4, 20, 4, true);
+  auto* arr = create<Array>(create<I32>(), 5, 4, 20, 4, true);
   EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
 }
 
 TEST_F(ArrayTest, FriendlyNameRuntimeSizedNonImplicitStride) {
-  auto* arr = create<Array>(ty.i32(), 0, 0, 4, 4, false);
+  auto* arr = create<Array>(create<I32>(), 0, 0, 4, 4, false);
   EXPECT_EQ(arr->FriendlyName(Symbols()), "[[stride(4)]] array<i32>");
 }
 
 TEST_F(ArrayTest, FriendlyNameStaticSizedNonImplicitStride) {
-  auto* arr = create<Array>(ty.i32(), 5, 4, 20, 4, false);
+  auto* arr = create<Array>(create<I32>(), 5, 4, 20, 4, false);
   EXPECT_EQ(arr->FriendlyName(Symbols()), "[[stride(4)]] array<i32, 5>");
 }
 
diff --git a/src/typepair.h b/src/typepair.h
index efe8acd..c1b7334 100644
--- a/src/typepair.h
+++ b/src/typepair.h
@@ -242,7 +242,6 @@
 using DepthTexture = TypePair<ast::DepthTexture, sem::DepthTexture>;
 using ExternalTexture = TypePair<ast::ExternalTexture, sem::ExternalTexture>;
 using F32 = TypePair<ast::F32, sem::F32>;
-using I32 = TypePair<ast::I32, sem::I32>;
 using Matrix = TypePair<ast::Matrix, sem::Matrix>;
 using MultisampledTexture =
     TypePair<ast::MultisampledTexture, sem::MultisampledTexture>;
@@ -256,6 +255,7 @@
 using Void = TypePair<ast::Void, sem::Void>;
 
 using U32 = Ptr<ast::U32>;
+using I32 = Ptr<ast::I32>;
 
 // Helpers
 
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 4994859..196d0b9 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -128,7 +128,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_I32) {
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index 7e5ea8a..29193b0 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -141,7 +141,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_I32) {
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index bccd360..a926a43 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -140,7 +140,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedBool) {
   auto bool_ = ty.bool_();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
 
@@ -168,7 +168,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedF32) {
   auto f32 = ty.f32();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
 
@@ -181,7 +181,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateI32) {
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
 
@@ -196,7 +196,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedI32) {
   auto f32 = ty.f32();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
 
@@ -225,8 +225,9 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) {
-  auto mat = ty.mat4x3<i32>();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
+  auto* col = create<sem::Vector>(i32, 4);
+  auto* mat = create<sem::Matrix>(col, 3);
 
   spirv::Builder& b = Build();
 
@@ -239,11 +240,12 @@
 }
 
 TEST_F(BuilderTest_Type, GeneratePtr) {
-  sem::Pointer ptr(ty.i32(), ast::StorageClass::kOutput);
+  auto* i32 = create<sem::I32>();
+  auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput);
 
   spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(&ptr);
+  auto id = b.GenerateTypeIfNeeded(ptr);
   ASSERT_FALSE(b.has_error()) << b.error();
   EXPECT_EQ(1u, id);
 
@@ -253,12 +255,13 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
-  sem::Pointer ptr(ty.i32(), ast::StorageClass::kOutput);
+  auto* i32 = create<sem::I32>();
+  auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput);
 
   spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(&ptr), 1u);
-  EXPECT_EQ(b.GenerateTypeIfNeeded(&ptr), 1u);
+  EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
+  EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
@@ -520,8 +523,8 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedVector) {
-  auto vec = ty.vec3<i32>();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
+  auto* vec = create<sem::Vector>(i32, 3);
 
   spirv::Builder& b = Build();
 
@@ -549,7 +552,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedVoid) {
   auto* void_ = create<sem::Void>();
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
 
@@ -656,7 +659,7 @@
 }
 
 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_i32) {
-  auto i32 = ty.i32();
+  auto* i32 = create<sem::I32>();
   auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, i32);
 
   spirv::Builder& b = Build();
@@ -697,7 +700,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_i32) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, ty.i32());
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d,
+                                        create<sem::I32>());
 
   spirv::Builder& b = Build();