Have TypesBuilder::F32() return ast::F32

Also contains a UBSAN fix for tests that didn't quite all migrate to ast::I32.

Bug: tint:724
Change-Id: I2a3ad6d6a69595b7da6bb502a87fb655a7f5961a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51486
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/intrinsic_table_test.cc b/src/intrinsic_table_test.cc
index 7c11357..d689681 100644
--- a/src/intrinsic_table_test.cc
+++ b/src/intrinsic_table_test.cc
@@ -38,12 +38,13 @@
 };
 
 TEST_F(IntrinsicTableTest, MatchF32) {
-  auto result = table->Lookup(*this, IntrinsicType::kCos, {ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto result = table->Lookup(*this, IntrinsicType::kCos, {f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
-  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
+  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{f32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchF32) {
@@ -54,32 +55,37 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchU32) {
+  auto* f32 = create<sem::F32>();
   auto* u32 = create<sem::U32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
   auto result =
       table->Lookup(*this, IntrinsicType::kUnpack2x16Float, {u32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kUnpack2x16Float);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec2<f32>());
+  EXPECT_THAT(result.intrinsic->ReturnType(), vec2_f32);
   EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{u32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchU32) {
-  auto result = table->Lookup(*this, IntrinsicType::kUnpack2x16Float,
-                              {ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kUnpack2x16Float, {f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchI32) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
-  auto tex = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
+  auto tex = ty.sampled_texture(ast::TextureDimension::k1d, f32);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
                               {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->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{i32, Parameter::Usage::kCoords},
@@ -87,9 +93,10 @@
 }
 
 TEST_F(IntrinsicTableTest, MismatchI32) {
-  auto tex = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {tex, ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto tex = ty.sampled_texture(ast::TextureDimension::k1d, f32);
+  auto result =
+      table->Lookup(*this, IntrinsicType::kTextureLoad, {tex, f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
@@ -117,8 +124,9 @@
 }
 
 TEST_F(IntrinsicTableTest, MismatchIU32) {
+  auto* f32 = create<sem::F32>();
   auto result =
-      table->Lookup(*this, IntrinsicType::kCountOneBits, {ty.f32()}, Source{});
+      table->Lookup(*this, IntrinsicType::kCountOneBits, {f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
@@ -148,15 +156,15 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
-  auto result = table->Lookup(*this, IntrinsicType::kClamp,
-                              {ty.f32(), ty.f32(), ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kClamp, {f32, f32, f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
-                          Parameter{ty.f32()}));
+              ElementsAre(Parameter{f32}, Parameter{f32}, Parameter{f32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchFIU32) {
@@ -167,41 +175,43 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchBool) {
+  auto* f32 = create<sem::F32>();
   auto result = table->Lookup(*this, IntrinsicType::kSelect,
-                              {ty.f32(), ty.f32(), ty.bool_()}, Source{});
+                              {f32, f32, ty.bool_()}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kSelect);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
-  EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
-                          Parameter{ty.bool_()}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
+  EXPECT_THAT(
+      result.intrinsic->Parameters(),
+      ElementsAre(Parameter{f32}, Parameter{f32}, Parameter{ty.bool_()}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchBool) {
-  auto result = table->Lookup(*this, IntrinsicType::kSelect,
-                              {ty.f32(), ty.f32(), ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kSelect, {f32, f32, f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchPointer) {
-  auto result = table->Lookup(
-      *this, IntrinsicType::kModf,
-      {ty.f32(), ty.pointer<f32>(ast::StorageClass::kNone)}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto* ptr = create<sem::Pointer>(f32, ast::StorageClass::kNone);
+  auto result =
+      table->Lookup(*this, IntrinsicType::kModf, {f32, ptr}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kModf);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
-  EXPECT_THAT(
-      result.intrinsic->Parameters(),
-      ElementsAre(Parameter{ty.f32()},
-                  Parameter{ty.pointer<f32>(ast::StorageClass::kNone)}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
+  EXPECT_THAT(result.intrinsic->Parameters(),
+              ElementsAre(Parameter{f32}, Parameter{ptr}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchPointer) {
-  auto result = table->Lookup(*this, IntrinsicType::kModf, {ty.f32(), ty.f32()},
-                              Source{});
+  auto* f32 = create<sem::F32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kModf, {f32, f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
@@ -219,46 +229,53 @@
 }
 
 TEST_F(IntrinsicTableTest, MismatchArray) {
+  auto* f32 = create<sem::F32>();
   auto result =
-      table->Lookup(*this, IntrinsicType::kArrayLength, {ty.f32()}, Source{});
+      table->Lookup(*this, IntrinsicType::kArrayLength, {f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchSampler) {
-  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
+  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, f32);
   auto sampler = ty.sampler(ast::SamplerKind::kSampler);
   auto result = table->Lookup(*this, IntrinsicType::kTextureSample,
-                              {tex, sampler, ty.vec2<f32>()}, Source{});
+                              {tex, sampler, vec2_f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureSample);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec4<f32>());
-  EXPECT_THAT(
-      result.intrinsic->Parameters(),
-      ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
-                  Parameter{sampler, Parameter::Usage::kSampler},
-                  Parameter{ty.vec2<f32>(), Parameter::Usage::kCoords}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), vec4_f32);
+  EXPECT_THAT(result.intrinsic->Parameters(),
+              ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
+                          Parameter{sampler, Parameter::Usage::kSampler},
+                          Parameter{vec2_f32, Parameter::Usage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchSampler) {
-  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
+  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, f32);
   auto result = table->Lookup(*this, IntrinsicType::kTextureSample,
-                              {tex, ty.f32(), ty.vec2<f32>()}, Source{});
+                              {tex, f32, vec2_f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchSampledTexture) {
   auto* i32 = create<sem::I32>();
+  auto* f32 = create<sem::F32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
-  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
+  auto tex = ty.sampled_texture(ast::TextureDimension::k2d, f32);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
                               {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->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords},
@@ -267,15 +284,16 @@
 
 TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
   auto* i32 = create<sem::I32>();
+  auto* f32 = create<sem::F32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
-  auto* tex =
-      create<sem::MultisampledTexture>(ast::TextureDimension::k2d, ty.f32());
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
+  auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
                               {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->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords},
@@ -283,6 +301,7 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchDepthTexture) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto tex = ty.depth_texture(ast::TextureDimension::k2d);
@@ -291,7 +310,7 @@
   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->ReturnType(), f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords},
@@ -299,23 +318,27 @@
 }
 
 TEST_F(IntrinsicTableTest, MatchExternalTexture) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
   auto* tex = create<sem::ExternalTexture>();
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
                               {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->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchROStorageTexture) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
   auto* subtype =
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
   auto* tex = create<sem::StorageTexture>(
@@ -327,15 +350,17 @@
   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->ReturnType(), vec4_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords}));
 }
 
 TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
+  auto* vec4_f32 = create<sem::Vector>(f32, 4);
   auto* subtype =
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR16Float, Types());
   auto* tex = create<sem::StorageTexture>(
@@ -343,7 +368,7 @@
       ast::AccessControl::kWriteOnly, subtype);
 
   auto result = table->Lookup(*this, IntrinsicType::kTextureStore,
-                              {tex, vec2_i32, ty.vec4<f32>()}, Source{});
+                              {tex, vec2_i32, vec4_f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kTextureStore);
@@ -351,85 +376,95 @@
   EXPECT_THAT(result.intrinsic->Parameters(),
               ElementsAre(Parameter{tex, Parameter::Usage::kTexture},
                           Parameter{vec2_i32, Parameter::Usage::kCoords},
-                          Parameter{ty.vec4<f32>(), Parameter::Usage::kValue}));
+                          Parameter{vec4_f32, Parameter::Usage::kValue}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchTexture) {
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
   auto* vec2_i32 = create<sem::Vector>(i32, 2);
   auto result = table->Lookup(*this, IntrinsicType::kTextureLoad,
-                              {ty.f32(), vec2_i32}, Source{});
+                              {f32, vec2_i32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
+  auto* f32 = create<sem::F32>();
   auto result = table->Lookup(
       *this, IntrinsicType::kCos,
-      {create<sem::Reference>(create<sem::F32>(), ast::StorageClass::kNone)},
-      Source{});
+      {create<sem::Reference>(f32, ast::StorageClass::kNone)}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kCos);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
-  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{ty.f32()}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
+  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{f32}));
 }
 
 TEST_F(IntrinsicTableTest, MatchOpenType) {
-  auto result = table->Lookup(*this, IntrinsicType::kClamp,
-                              {ty.f32(), ty.f32(), ty.f32()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto result =
+      table->Lookup(*this, IntrinsicType::kClamp, {f32, f32, f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.f32()}, Parameter{ty.f32()},
-                          Parameter{ty.f32()}));
+              ElementsAre(Parameter{f32}, Parameter{f32}, Parameter{f32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchOpenType) {
+  auto* f32 = create<sem::F32>();
   auto* u32 = create<sem::U32>();
-  auto result = table->Lookup(*this, IntrinsicType::kClamp,
-                              {ty.f32(), u32, ty.f32()}, Source{});
+  auto result =
+      table->Lookup(*this, IntrinsicType::kClamp, {f32, u32, f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
-  auto result =
-      table->Lookup(*this, IntrinsicType::kClamp,
-                    {ty.vec2<f32>(), ty.vec2<f32>(), ty.vec2<f32>()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
+  auto result = table->Lookup(*this, IntrinsicType::kClamp,
+                              {vec2_f32, vec2_f32, vec2_f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kClamp);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.vec2<f32>());
+  EXPECT_THAT(result.intrinsic->ReturnType(), vec2_f32);
   EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.vec2<f32>()}, Parameter{ty.vec2<f32>()},
-                          Parameter{ty.vec2<f32>()}));
+              ElementsAre(Parameter{vec2_f32}, Parameter{vec2_f32},
+                          Parameter{vec2_f32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
+  auto* f32 = create<sem::F32>();
   auto* u32 = create<sem::U32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
   auto result = table->Lookup(*this, IntrinsicType::kClamp,
-                              {ty.vec2<f32>(), u32, ty.vec2<f32>()}, Source{});
+                              {vec2_f32, u32, vec2_f32}, Source{});
   ASSERT_EQ(result.intrinsic, nullptr);
   ASSERT_THAT(result.diagnostics.str(), HasSubstr("no matching call"));
 }
 
 TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) {
-  auto result = table->Lookup(*this, IntrinsicType::kDeterminant,
-                              {ty.mat3x3<f32>()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto* vec3_f32 = create<sem::Vector>(f32, 3);
+  auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3);
+  auto result =
+      table->Lookup(*this, IntrinsicType::kDeterminant, {mat3_f32}, Source{});
   ASSERT_NE(result.intrinsic, nullptr);
   ASSERT_EQ(result.diagnostics.str(), "");
   EXPECT_THAT(result.intrinsic->Type(), IntrinsicType::kDeterminant);
-  EXPECT_THAT(result.intrinsic->ReturnType(), ty.f32());
-  EXPECT_THAT(result.intrinsic->Parameters(),
-              ElementsAre(Parameter{ty.mat3x3<f32>()}));
+  EXPECT_THAT(result.intrinsic->ReturnType(), f32);
+  EXPECT_THAT(result.intrinsic->Parameters(), ElementsAre(Parameter{mat3_f32}));
 }
 
 TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
-  auto result = table->Lookup(*this, IntrinsicType::kDeterminant,
-                              {ty.mat3x2<f32>()}, Source{});
+  auto* f32 = create<sem::F32>();
+  auto* vec2_f32 = create<sem::Vector>(f32, 2);
+  auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3);
+  auto result =
+      table->Lookup(*this, IntrinsicType::kDeterminant, {mat3x2_f32}, 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 f0975f9..a808356 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -366,14 +366,12 @@
     }
 
     /// @returns a f32 type
-    typ::F32 f32() const {
-      return {builder->create<ast::F32>(), builder->create<sem::F32>()};
-    }
+    typ::F32 f32() const { return {builder->create<ast::F32>()}; }
 
     /// @param source the Source of the node
     /// @returns a f32 type
     typ::F32 f32(const Source& source) const {
-      return {builder->create<ast::F32>(source), builder->create<sem::F32>()};
+      return {builder->create<ast::F32>(source)};
     }
 
     /// @returns a i32 type
diff --git a/src/resolver/intrinsic_test.cc b/src/resolver/intrinsic_test.cc
index dbb2ef5..cbcc1fc 100644
--- a/src/resolver/intrinsic_test.cc
+++ b/src/resolver/intrinsic_test.cc
@@ -1986,7 +1986,7 @@
         break;
       }
       case ast::intrinsic::test::TextureKind::kDepth: {
-        EXPECT_EQ(TypeOf(call), ty.f32());
+        EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
         break;
       }
     }
diff --git a/src/resolver/is_host_shareable_test.cc b/src/resolver/is_host_shareable_test.cc
index f197768..5ef5f48 100644
--- a/src/resolver/is_host_shareable_test.cc
+++ b/src/resolver/is_host_shareable_test.cc
@@ -34,7 +34,7 @@
 TEST_F(ResolverIsHostShareable, NumericScalar) {
   EXPECT_TRUE(r()->IsHostShareable(create<sem::I32>()));
   EXPECT_TRUE(r()->IsHostShareable(create<sem::U32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.f32()));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::F32>()));
 }
 
 TEST_F(ResolverIsHostShareable, NumericVector) {
@@ -44,9 +44,9 @@
   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)));
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec2<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec3<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.vec4<f32>()));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 2)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 3)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 4)));
 }
 
 TEST_F(ResolverIsHostShareable, BoolVector) {
@@ -62,20 +62,25 @@
 }
 
 TEST_F(ResolverIsHostShareable, Matrix) {
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat2x2<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat2x3<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat2x4<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat3x2<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat3x3<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat3x4<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat4x2<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat4x3<f32>()));
-  EXPECT_TRUE(r()->IsHostShareable(ty.mat4x4<f32>()));
+  auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2);
+  auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3);
+  auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4);
+
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 2)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 3)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 4)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 2)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 3)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 4)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 2)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 3)));
+  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 4)));
 }
 
 TEST_F(ResolverIsHostShareable, Pointer) {
-  EXPECT_FALSE(
-      r()->IsHostShareable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
+  auto* ptr =
+      create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate);
+  EXPECT_FALSE(r()->IsHostShareable(ptr));
 }
 
 TEST_F(ResolverIsHostShareable, ArraySizedOfHostShareable) {
diff --git a/src/resolver/is_storeable_test.cc b/src/resolver/is_storeable_test.cc
index 61ba656..064c28a 100644
--- a/src/resolver/is_storeable_test.cc
+++ b/src/resolver/is_storeable_test.cc
@@ -31,7 +31,7 @@
   EXPECT_TRUE(r()->IsStorable(ty.bool_()));
   EXPECT_TRUE(r()->IsStorable(create<sem::I32>()));
   EXPECT_TRUE(r()->IsStorable(create<sem::U32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.f32()));
+  EXPECT_TRUE(r()->IsStorable(create<sem::F32>()));
 }
 
 TEST_F(ResolverIsStorableTest, Vector) {
@@ -41,25 +41,30 @@
   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)));
-  EXPECT_TRUE(r()->IsStorable(ty.vec2<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.vec3<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.vec4<f32>()));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4)));
 }
 
 TEST_F(ResolverIsStorableTest, Matrix) {
-  EXPECT_TRUE(r()->IsStorable(ty.mat2x2<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat2x3<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat2x4<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat3x2<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat3x3<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat3x4<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat4x2<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat4x3<f32>()));
-  EXPECT_TRUE(r()->IsStorable(ty.mat4x4<f32>()));
+  auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2);
+  auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3);
+  auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4);
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 2)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 3)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 4)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 2)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 3)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 4)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 2)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 3)));
+  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 4)));
 }
 
 TEST_F(ResolverIsStorableTest, Pointer) {
-  EXPECT_FALSE(r()->IsStorable(ty.pointer<i32>(ast::StorageClass::kPrivate)));
+  auto* ptr =
+      create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate);
+  EXPECT_FALSE(r()->IsStorable(ptr));
 }
 
 TEST_F(ResolverIsStorableTest, ArraySizedOfStorable) {
@@ -82,10 +87,9 @@
 }
 
 TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
-  auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
   Structure("S", {
                      Member("a", ty.i32()),
-                     Member("b", ptr_ty),
+                     Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
                  });
 
   EXPECT_FALSE(r()->Resolve());
@@ -108,11 +112,12 @@
 }
 
 TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
-  auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
-  auto* non_storable = Structure("nonstorable", {
-                                                    Member("a", ty.i32()),
-                                                    Member("b", ptr_ty),
-                                                });
+  auto* non_storable =
+      Structure("nonstorable",
+                {
+                    Member("a", ty.i32()),
+                    Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+                });
   Structure("S", {
                      Member("a", ty.i32()),
                      Member("b", non_storable),
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index 1b4b1c1..8e5631b 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -759,7 +759,7 @@
   auto* func_sem = Sem().Get(func);
   ASSERT_NE(func_sem, nullptr);
   EXPECT_EQ(func_sem->Parameters().size(), 3u);
-  EXPECT_EQ(func_sem->Parameters()[0]->Type(), ty.f32());
+  EXPECT_TRUE(func_sem->Parameters()[0]->Type()->Is<sem::F32>());
   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);
@@ -1072,7 +1072,7 @@
   EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
   auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
   ASSERT_NE(sma, nullptr);
-  EXPECT_EQ(sma->Member()->Type(), ty.f32());
+  EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
   EXPECT_EQ(sma->Member()->Index(), 1u);
   EXPECT_EQ(sma->Member()->Declaration()->symbol(),
             Symbols().Get("second_member"));
@@ -1097,7 +1097,7 @@
   EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
   auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
   ASSERT_NE(sma, nullptr);
-  EXPECT_EQ(sma->Member()->Type(), ty.f32());
+  EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
   EXPECT_EQ(sma->Member()->Index(), 1u);
 }
 
@@ -1515,20 +1515,20 @@
   uint32_t mat_rows = std::get<2>(GetParam());
   uint32_t mat_cols = std::get<3>(GetParam());
 
-  typ::Type lhs_type;
-  typ::Type rhs_type;
-  typ::Type result_type;
+  ast::Type* lhs_type;
+  ast::Type* rhs_type;
+  sem::Type* result_type;
   bool is_valid_expr;
 
   if (vec_by_mat) {
     lhs_type = ty.vec<f32>(vec_size);
     rhs_type = ty.mat<f32>(mat_cols, mat_rows);
-    result_type = ty.vec<f32>(mat_cols);
+    result_type = create<sem::Vector>(create<sem::F32>(), mat_cols);
     is_valid_expr = vec_size == mat_rows;
   } else {
     lhs_type = ty.mat<f32>(mat_cols, mat_rows);
     rhs_type = ty.vec<f32>(vec_size);
-    result_type = ty.vec<f32>(mat_rows);
+    result_type = create<sem::Vector>(create<sem::F32>(), mat_rows);
     is_valid_expr = vec_size == mat_cols;
   }
 
@@ -1568,7 +1568,10 @@
 
   auto lhs_type = ty.mat<f32>(lhs_mat_cols, lhs_mat_rows);
   auto rhs_type = ty.mat<f32>(rhs_mat_cols, rhs_mat_rows);
-  auto result_type = ty.mat<f32>(rhs_mat_cols, lhs_mat_rows);
+
+  auto* f32 = create<sem::F32>();
+  auto* col = create<sem::Vector>(f32, lhs_mat_rows);
+  auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
 
   Global("lhs", lhs_type, ast::StorageClass::kInput);
   Global("rhs", rhs_type, ast::StorageClass::kInput);
diff --git a/src/sem/multisampled_texture_type_test.cc b/src/sem/multisampled_texture_type_test.cc
index 3b44246..97d0b38 100644
--- a/src/sem/multisampled_texture_type_test.cc
+++ b/src/sem/multisampled_texture_type_test.cc
@@ -56,7 +56,8 @@
 }
 
 TEST_F(MultisampledTextureTest, FriendlyName) {
-  MultisampledTexture s(ast::TextureDimension::k3d, ty.f32());
+  F32 f32;
+  MultisampledTexture s(ast::TextureDimension::k3d, &f32);
   EXPECT_EQ(s.FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
 }
 
diff --git a/src/sem/sampled_texture_type_test.cc b/src/sem/sampled_texture_type_test.cc
index 222dd70..a1ee7bc 100644
--- a/src/sem/sampled_texture_type_test.cc
+++ b/src/sem/sampled_texture_type_test.cc
@@ -25,7 +25,6 @@
 
 using SampledTextureTest = TestHelper;
 
-
 TEST_F(SampledTextureTest, IsTexture) {
   F32 f32;
   SampledTexture s(ast::TextureDimension::kCube, &f32);
@@ -55,7 +54,8 @@
 }
 
 TEST_F(SampledTextureTest, FriendlyName) {
-  SampledTexture s(ast::TextureDimension::k3d, ty.f32());
+  F32 f32;
+  SampledTexture s(ast::TextureDimension::k3d, &f32);
   EXPECT_EQ(s.FriendlyName(Symbols()), "texture_3d<f32>");
 }
 
diff --git a/src/typepair.h b/src/typepair.h
index c1b7334..52f0065 100644
--- a/src/typepair.h
+++ b/src/typepair.h
@@ -241,7 +241,6 @@
 using Bool = TypePair<ast::Bool, sem::Bool>;
 using DepthTexture = TypePair<ast::DepthTexture, sem::DepthTexture>;
 using ExternalTexture = TypePair<ast::ExternalTexture, sem::ExternalTexture>;
-using F32 = TypePair<ast::F32, sem::F32>;
 using Matrix = TypePair<ast::Matrix, sem::Matrix>;
 using MultisampledTexture =
     TypePair<ast::MultisampledTexture, sem::MultisampledTexture>;
@@ -256,6 +255,7 @@
 
 using U32 = Ptr<ast::U32>;
 using I32 = Ptr<ast::I32>;
+using F32 = Ptr<ast::F32>;
 
 // Helpers
 
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 196d0b9..b57fe5b 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -117,7 +117,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_F32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
 
   GeneratorImpl& gen = Build();
 
@@ -139,7 +139,9 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
-  auto mat2x3 = ty.mat2x3<f32>();
+  auto* f32 = create<sem::F32>();
+  auto* vec3 = create<sem::Vector>(f32, 3);
+  auto* mat2x3 = create<sem::Matrix>(vec3, 2);
 
   GeneratorImpl& gen = Build();
 
@@ -151,11 +153,12 @@
 
 // TODO(dsinclair): How to annotate as workgroup?
 TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
-  sem::Pointer p(ty.f32(), ast::StorageClass::kWorkgroup);
+  auto* f32 = create<sem::F32>();
+  auto* p = create<sem::Pointer>(f32, ast::StorageClass::kWorkgroup);
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(out, &p, ast::StorageClass::kNone,
+  ASSERT_TRUE(gen.EmitType(out, p, ast::StorageClass::kNone,
                            ast::AccessControl::kInvalid, ""))
       << gen.error();
   EXPECT_EQ(result(), "float*");
@@ -293,7 +296,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Vector) {
-  auto vec3 = ty.vec3<f32>();
+  auto* f32 = create<sem::F32>();
+  auto* vec3 = create<sem::Vector>(f32, 3);
 
   GeneratorImpl& gen = Build();
 
@@ -522,11 +526,12 @@
         }));
 
 TEST_F(HlslGeneratorImplTest_Type, EmitMultisampledTexture) {
-  sem::MultisampledTexture s(ast::TextureDimension::k2d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(out, &s, ast::StorageClass::kNone,
+  ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone,
                            ast::AccessControl::kInvalid, ""))
       << gen.error();
   EXPECT_EQ(result(), "Texture2DMS<float4>");
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index 29193b0..340eb27 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -132,7 +132,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_F32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
 
   GeneratorImpl& gen = Build();
 
@@ -150,7 +150,9 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Matrix) {
-  auto mat2x3 = ty.mat2x3<f32>();
+  auto* f32 = create<sem::F32>();
+  auto* vec3 = create<sem::Vector>(f32, 3);
+  auto* mat2x3 = create<sem::Matrix>(vec3, 2);
 
   GeneratorImpl& gen = Build();
 
@@ -160,11 +162,12 @@
 
 // TODO(dsinclair): How to annotate as workgroup?
 TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Pointer) {
-  sem::Pointer p(ty.f32(), ast::StorageClass::kWorkgroup);
+  auto* f32 = create<sem::F32>();
+  auto* p = create<sem::Pointer>(f32, ast::StorageClass::kWorkgroup);
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&p, "")) << gen.error();
+  ASSERT_TRUE(gen.EmitType(p, "")) << gen.error();
   EXPECT_EQ(gen.result(), "float*");
 }
 
@@ -634,7 +637,8 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Vector) {
-  auto vec3 = ty.vec3<f32>();
+  auto* f32 = create<sem::F32>();
+  auto* vec3 = create<sem::Vector>(f32, 3);
 
   GeneratorImpl& gen = Build();
 
@@ -713,11 +717,12 @@
 TEST_P(MslSampledtexturesTest, Emit) {
   auto params = GetParam();
 
-  sem::SampledTexture s(params.dim, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(params.dim, f32);
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&s, "")) << gen.error();
+  ASSERT_TRUE(gen.EmitType(s, "")) << gen.error();
   EXPECT_EQ(gen.result(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index a926a43..8da9b7a 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -153,7 +153,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateF32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
 
   spirv::Builder& b = Build();
 
@@ -167,7 +167,7 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedF32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
@@ -195,7 +195,7 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedI32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
   auto* i32 = create<sem::I32>();
 
   spirv::Builder& b = Build();
@@ -209,7 +209,9 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateMatrix) {
-  auto mat2x3 = ty.mat2x3<f32>();
+  auto* f32 = create<sem::F32>();
+  auto* vec3 = create<sem::Vector>(f32, 3);
+  auto* mat2x3 = create<sem::Matrix>(vec3, 2);
 
   spirv::Builder& b = Build();
 
@@ -495,7 +497,7 @@
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedU32) {
   auto* u32 = create<sem::U32>();
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
 
   spirv::Builder& b = Build();
 
@@ -686,7 +688,7 @@
 }
 
 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_f32) {
-  auto f32 = ty.f32();
+  auto* f32 = create<sem::F32>();
   auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
 
   spirv::Builder& b = Build();
@@ -736,7 +738,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_f32) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
 
   spirv::Builder& b = Build();
 
@@ -753,7 +756,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
 
   spirv::Builder& b = Build();
 
@@ -766,8 +770,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d_array) {
-  auto* s =
-      create<sem::SampledTexture>(ast::TextureDimension::k2dArray, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2dArray, f32);
 
   spirv::Builder& b = Build();
 
@@ -780,7 +784,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_3d) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k3d, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k3d, f32);
 
   spirv::Builder& b = Build();
 
@@ -793,7 +798,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_Cube) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCube, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCube, f32);
 
   spirv::Builder& b = Build();
 
@@ -807,8 +813,8 @@
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_CubeArray) {
-  auto* s =
-      create<sem::SampledTexture>(ast::TextureDimension::kCubeArray, ty.f32());
+  auto* f32 = create<sem::F32>();
+  auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCubeArray, f32);
 
   spirv::Builder& b = Build();