[tint] Migrate to 'fluent types'

Replace the ProgramBuilder and type::Manager over to using a common set
of templated types for type construction.

Allows for arbitrarily-deep templated type declarations instead of the
one-level declarations that were offered previously.

Change-Id: I4744417cdbbb531c6b9958d92f45d3dd5bebddac
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/137061
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 2b450fb..b975fc1 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -201,8 +201,6 @@
 
 libtint_source_set("libtint_symbols_src") {
   sources = [
-    "number.cc",
-    "number.h",
     "program_id.cc",
     "program_id.h",
     "reflection.h",
@@ -812,6 +810,7 @@
     "builtin/diagnostic_severity.h",
     "builtin/extension.cc",
     "builtin/extension.h",
+    "builtin/fluent_types.h",
     "builtin/function.cc",
     "builtin/function.h",
     "builtin/interpolation.h",
@@ -819,6 +818,8 @@
     "builtin/interpolation_sampling.h",
     "builtin/interpolation_type.cc",
     "builtin/interpolation_type.h",
+    "builtin/number.cc",
+    "builtin/number.h",
     "builtin/texel_format.cc",
     "builtin/texel_format.h",
   ]
@@ -920,6 +921,7 @@
     "constant/value.h",
   ]
   deps = [
+    ":libtint_builtins_src",
     ":libtint_symbols_src",
     ":libtint_type_src",
     ":libtint_utils_src",
@@ -1604,6 +1606,7 @@
       "builtin/extension_test.cc",
       "builtin/interpolation_sampling_test.cc",
       "builtin/interpolation_type_test.cc",
+      "builtin/number_test.cc",
       "builtin/texel_format_test.cc",
     ]
     deps = [ ":libtint_builtins_src" ]
@@ -2256,6 +2259,7 @@
 
     deps = [
       ":libtint_ast_transform_src",
+      ":libtint_builtins_src",
       ":libtint_glsl_writer_src",
       ":libtint_symbols_src",
       ":libtint_transform_manager_src",
@@ -2266,7 +2270,6 @@
 
   tint_unittests_source_set("tint_unittests_symbols_src") {
     sources = [
-      "number_test.cc",
       "reflection_test.cc",
       "scope_stack_test.cc",
       "symbol_table_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 6e6d760..3345626 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -58,14 +58,14 @@
 add_library(tint_diagnostic_utils
   debug.cc
   debug.h
-  source.h
-  source.cc
   diagnostic/diagnostic.cc
   diagnostic/diagnostic.h
   diagnostic/formatter.cc
   diagnostic/formatter.h
   diagnostic/printer.cc
   diagnostic/printer.h
+  source.cc
+  source.h
   utils/debugger.cc
   utils/debugger.h
   utils/unicode.cc
@@ -232,6 +232,9 @@
   ast/while_statement.h
   ast/workgroup_attribute.cc
   ast/workgroup_attribute.h
+  builtin/fluent_types.h
+  builtin/number.cc
+  builtin/number.h
   clone_context.cc
   clone_context.h
   constant/clone_context.h
@@ -255,8 +258,6 @@
   inspector/resource_binding.h
   inspector/scalar.cc
   inspector/scalar.h
-  number.cc
-  number.h
   program_builder.cc
   program_builder.h
   program_id.cc
@@ -955,6 +956,7 @@
     ast/variable_test.cc
     ast/while_statement_test.cc
     ast/workgroup_attribute_test.cc
+    builtin/number_test.cc
     clone_context_test.cc
     constant/composite_test.cc
     constant/manager_test.cc
@@ -965,7 +967,6 @@
     diagnostic/diagnostic_test.cc
     diagnostic/formatter_test.cc
     diagnostic/printer_test.cc
-    number_test.cc
     program_builder_test.cc
     program_test.cc
     reflection_test.cc
diff --git a/src/tint/ast/builtin_texture_helper_test.cc b/src/tint/ast/builtin_texture_helper_test.cc
index 3231081a..7f1e91a 100644
--- a/src/tint/ast/builtin_texture_helper_test.cc
+++ b/src/tint/ast/builtin_texture_helper_test.cc
@@ -20,7 +20,8 @@
 #include "src/tint/type/sampled_texture.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::test {
 namespace {
@@ -492,10 +493,10 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_i,                      // component
-                                   kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f));  // coords
+                return b->ExprList(0_i,                            // component
+                                   kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f));  // coords
             },
             /* returns value */ true,
         },
@@ -512,11 +513,11 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_u,                      // component
-                                   kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<i32>(3_i, 4_i));  // offset
+                return b->ExprList(0_u,                            // component
+                                   kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<i32>>(3_i, 4_i));  // offset
             },
             /* returns value */ true,
         },
@@ -533,11 +534,11 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_i,                     // component
-                                   kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i);                    // array index
+                return b->ExprList(0_i,                           // component
+                                   kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i);                          // array index
             },
             /* returns value */ true,
         },
@@ -555,12 +556,12 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_u,                      // component
-                                   kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_u,                      // array_index
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(0_u,                            // component
+                                   kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_u,                            // array_index
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -576,10 +577,10 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_i,                           // component
-                                   kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f));  // coords
+                return b->ExprList(0_i,                                 // component
+                                   kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f));  // coords
             },
             /* returns value */ true,
         },
@@ -596,11 +597,11 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(0_u,                          // component
-                                   kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_u);                         // array_index
+                return b->ExprList(0_u,                                // component
+                                   kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_u);                               // array_index
             },
             /* returns value */ true,
         },
@@ -615,9 +616,9 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f));  // coords
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f));  // coords
             },
             /* returns value */ true,
         },
@@ -633,10 +634,10 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<i32>(3_i, 4_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<i32>>(3_i, 4_i));  // offset
             },
             /* returns value */ true,
         },
@@ -652,10 +653,10 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_u);                    // array_index
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_u);                          // array_index
             },
             /* returns value */ true,
         },
@@ -672,11 +673,11 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -691,9 +692,9 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f));  // coords
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f));  // coords
             },
             /* returns value */ true,
         },
@@ -709,10 +710,10 @@
             TextureDataType::kF32,
             "textureGather",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_u);                         // array_index
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_u);                               // array_index
             },
             /* returns value */ true,
         },
@@ -728,10 +729,10 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -748,11 +749,11 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_f,                      // depth_ref
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -769,11 +770,11 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i,                     // array_index
-                                   4_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i,                           // array_index
+                                   4_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -791,12 +792,12 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   4_f,                      // depth_ref
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   4_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -812,10 +813,10 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -832,11 +833,11 @@
             TextureDataType::kF32,
             "textureGatherCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_u,                          // array_index
-                                   5_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_u,                                // array_index
+                                   5_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -1044,9 +1045,9 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f));  // coords
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f));  // coords
             },
             /* returns value */ true,
         },
@@ -1062,10 +1063,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<i32>(3_i, 4_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<i32>>(3_i, 4_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1081,10 +1082,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i);                    // array_index
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i);                          // array_index
             },
             /* returns value */ true,
         },
@@ -1101,11 +1102,11 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_u,                      // array_index
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_u,                            // array_index
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1120,9 +1121,9 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f));  // coords
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f));  // coords
             },
             /* returns value */ true,
         },
@@ -1138,10 +1139,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   b->vec3<i32>(4_i, 5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   b->Call<vec3<i32>>(4_i, 5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1156,9 +1157,9 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f));  // coords
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f));  // coords
             },
             /* returns value */ true,
         },
@@ -1174,10 +1175,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i);                         // array_index
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i);                               // array_index
             },
             /* returns value */ true,
         },
@@ -1192,9 +1193,9 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f));  // coords
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f));  // coords
             },
             /* returns value */ true,
         },
@@ -1210,10 +1211,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<i32>(3_i, 4_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<i32>>(3_i, 4_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1229,10 +1230,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i);                    // array_index
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i);                          // array_index
             },
             /* returns value */ true,
         },
@@ -1249,11 +1250,11 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1268,9 +1269,9 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f));  // coords
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f));  // coords
             },
             /* returns value */ true,
         },
@@ -1286,10 +1287,10 @@
             TextureDataType::kF32,
             "textureSample",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_u);                         // array_index
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_u);                               // array_index
             },
             /* returns value */ true,
         },
@@ -1305,10 +1306,10 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_f);                    // bias
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_f);                          // bias
             },
             /* returns value */ true,
         },
@@ -1325,11 +1326,11 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_f,                      // bias
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_f,                            // bias
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1346,11 +1347,11 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   4_u,                     // array_index
-                                   3_f);                    // bias
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   4_u,                           // array_index
+                                   3_f);                          // bias
             },
             /* returns value */ true,
         },
@@ -1368,12 +1369,12 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   4_f,                      // bias
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   4_f,                            // bias
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1389,10 +1390,10 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // bias
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // bias
             },
             /* returns value */ true,
         },
@@ -1409,11 +1410,11 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   4_f,                           // bias
-                                   b->vec3<i32>(5_i, 6_i, 7_i));  // offset
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   4_f,                                 // bias
+                                   b->Call<vec3<i32>>(5_i, 6_i, 7_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1429,10 +1430,10 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // bias
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // bias
             },
             /* returns value */ true,
         },
@@ -1449,11 +1450,11 @@
             TextureDataType::kF32,
             "textureSampleBias",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   3_i,                          // array_index
-                                   4_f);                         // bias
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   3_i,                                // array_index
+                                   4_f);                               // bias
             },
             /* returns value */ true,
         },
@@ -1469,10 +1470,10 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_f);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_f);                          // level
             },
             /* returns value */ true,
         },
@@ -1489,11 +1490,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_f,                      // level
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_f,                            // level
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1510,11 +1511,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i,                     // array_index
-                                   4_f);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i,                           // array_index
+                                   4_f);                          // level
             },
             /* returns value */ true,
         },
@@ -1532,12 +1533,12 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   4_f,                      // level
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   4_f,                            // level
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1553,10 +1554,10 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // level
             },
             /* returns value */ true,
         },
@@ -1573,11 +1574,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   4_f,                           // level
-                                   b->vec3<i32>(5_i, 6_i, 7_i));  // offset
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   4_f,                                 // level
+                                   b->Call<vec3<i32>>(5_i, 6_i, 7_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1593,10 +1594,10 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // level
             },
             /* returns value */ true,
         },
@@ -1613,11 +1614,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i,                          // array_index
-                                   5_f);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i,                                // array_index
+                                   5_f);                               // level
             },
             /* returns value */ true,
         },
@@ -1633,10 +1634,10 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_u);                          // level
             },
             /* returns value */ true,
         },
@@ -1653,11 +1654,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // level
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // level
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1674,11 +1675,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_u,                     // array_index
-                                   4_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_u,                           // array_index
+                                   4_u);                          // level
             },
             /* returns value */ true,
         },
@@ -1696,12 +1697,12 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_u,                      // array_index
-                                   4_u,                      // level
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_u,                            // array_index
+                                   4_u,                            // level
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1717,10 +1718,10 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i);                               // level
             },
             /* returns value */ true,
         },
@@ -1737,11 +1738,11 @@
             TextureDataType::kF32,
             "textureSampleLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i,                          // array_index
-                                   5_i);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i,                                // array_index
+                                   5_i);                               // level
             },
             /* returns value */ true,
         },
@@ -1758,11 +1759,11 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<f32>(3_f, 4_f),   // ddx
-                                   b->vec2<f32>(5_f, 6_f));  // ddy
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<f32>>(3_f, 4_f),   // ddx
+                                   b->Call<vec2<f32>>(5_f, 6_f));  // ddy
             },
             /* returns value */ true,
         },
@@ -1780,12 +1781,12 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   b->vec2<f32>(3_f, 4_f),   // ddx
-                                   b->vec2<f32>(5_f, 6_f),   // ddy
-                                   b->vec2<i32>(7_i, 7_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   b->Call<vec2<f32>>(3_f, 4_f),   // ddx
+                                   b->Call<vec2<f32>>(5_f, 6_f),   // ddy
+                                   b->Call<vec2<i32>>(7_i, 7_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1803,12 +1804,12 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   b->vec2<f32>(4_f, 5_f),   // ddx
-                                   b->vec2<f32>(6_f, 7_f));  // ddy
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   b->Call<vec2<f32>>(4_f, 5_f),   // ddx
+                                   b->Call<vec2<f32>>(6_f, 7_f));  // ddy
             },
             /* returns value */ true,
         },
@@ -1827,13 +1828,13 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_u,                      // array_index
-                                   b->vec2<f32>(4_f, 5_f),   // ddx
-                                   b->vec2<f32>(6_f, 7_f),   // ddy
-                                   b->vec2<i32>(6_i, 7_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_u,                            // array_index
+                                   b->Call<vec2<f32>>(4_f, 5_f),   // ddx
+                                   b->Call<vec2<f32>>(6_f, 7_f),   // ddy
+                                   b->Call<vec2<i32>>(6_i, 7_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1850,11 +1851,11 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   b->vec3<f32>(4_f, 5_f, 6_f),   // ddx
-                                   b->vec3<f32>(7_f, 8_f, 9_f));  // ddy
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   b->Call<vec3<f32>>(4_f, 5_f, 6_f),   // ddx
+                                   b->Call<vec3<f32>>(7_f, 8_f, 9_f));  // ddy
             },
             /* returns value */ true,
         },
@@ -1872,12 +1873,12 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   b->vec3<f32>(4_f, 5_f, 6_f),   // ddx
-                                   b->vec3<f32>(7_f, 8_f, 9_f),   // ddy
-                                   b->vec3<i32>(0_i, 1_i, 2_i));  // offset
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   b->Call<vec3<f32>>(4_f, 5_f, 6_f),   // ddx
+                                   b->Call<vec3<f32>>(7_f, 8_f, 9_f),   // ddy
+                                   b->Call<vec3<i32>>(0_i, 1_i, 2_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1894,11 +1895,11 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                  // t
-                                   kSamplerName,                  // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),   // coords
-                                   b->vec3<f32>(4_f, 5_f, 6_f),   // ddx
-                                   b->vec3<f32>(7_f, 8_f, 9_f));  // ddy
+                return b->ExprList(kTextureName,                        // t
+                                   kSamplerName,                        // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),   // coords
+                                   b->Call<vec3<f32>>(4_f, 5_f, 6_f),   // ddx
+                                   b->Call<vec3<f32>>(7_f, 8_f, 9_f));  // ddy
             },
             /* returns value */ true,
         },
@@ -1916,12 +1917,12 @@
             TextureDataType::kF32,
             "textureSampleGrad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                   // t
-                                   kSamplerName,                   // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),    // coords
-                                   4_u,                            // array_index
-                                   b->vec3<f32>(5_f, 6_f, 7_f),    // ddx
-                                   b->vec3<f32>(8_f, 9_f, 10_f));  // ddy
+                return b->ExprList(kTextureName,                         // t
+                                   kSamplerName,                         // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),    // coords
+                                   4_u,                                  // array_index
+                                   b->Call<vec3<f32>>(5_f, 6_f, 7_f),    // ddx
+                                   b->Call<vec3<f32>>(8_f, 9_f, 10_f));  // ddy
             },
             /* returns value */ true,
         },
@@ -1937,10 +1938,10 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -1957,11 +1958,11 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_f,                      // depth_ref
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -1978,11 +1979,11 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   4_i,                     // array_index
-                                   3_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   4_i,                           // array_index
+                                   3_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -2000,12 +2001,12 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   4_u,                      // array_index
-                                   3_f,                      // depth_ref
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   4_u,                            // array_index
+                                   3_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -2021,10 +2022,10 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -2041,11 +2042,11 @@
             TextureDataType::kF32,
             "textureSampleCompare",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i,                          // array_index
-                                   5_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i,                                // array_index
+                                   5_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -2061,10 +2062,10 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -2081,11 +2082,11 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_f,                      // depth_ref
-                                   b->vec2<i32>(4_i, 5_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(4_i, 5_i));  // offset
             },
             /* returns value */ true,
         },
@@ -2102,11 +2103,11 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   kSamplerName,            // s
-                                   b->vec2<f32>(1_f, 2_f),  // coords
-                                   3_i,                     // array_index
-                                   4_f);                    // depth_ref
+                return b->ExprList(kTextureName,                  // t
+                                   kSamplerName,                  // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),  // coords
+                                   3_i,                           // array_index
+                                   4_f);                          // depth_ref
             },
             /* returns value */ true,
         },
@@ -2124,12 +2125,12 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,             // t
-                                   kSamplerName,             // s
-                                   b->vec2<f32>(1_f, 2_f),   // coords
-                                   3_i,                      // array_index
-                                   4_f,                      // depth_ref
-                                   b->vec2<i32>(5_i, 6_i));  // offset
+                return b->ExprList(kTextureName,                   // t
+                                   kSamplerName,                   // s
+                                   b->Call<vec2<f32>>(1_f, 2_f),   // coords
+                                   3_i,                            // array_index
+                                   4_f,                            // depth_ref
+                                   b->Call<vec2<i32>>(5_i, 6_i));  // offset
             },
             /* returns value */ true,
         },
@@ -2145,10 +2146,10 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -2165,11 +2166,11 @@
             TextureDataType::kF32,
             "textureSampleCompareLevel",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   kSamplerName,                 // s
-                                   b->vec3<f32>(1_f, 2_f, 3_f),  // coords
-                                   4_i,                          // array_index
-                                   5_f);                         // depth_ref
+                return b->ExprList(kTextureName,                       // t
+                                   kSamplerName,                       // s
+                                   b->Call<vec3<f32>>(1_f, 2_f, 3_f),  // coords
+                                   4_i,                                // array_index
+                                   5_f);                               // depth_ref
             },
             /* returns value */ true,
         },
@@ -2231,9 +2232,9 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u);                          // level
             },
             /* returns value */ true,
         },
@@ -2247,9 +2248,9 @@
             TextureDataType::kU32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i);                          // level
             },
             /* returns value */ true,
         },
@@ -2263,9 +2264,9 @@
             TextureDataType::kI32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u);                          // level
             },
             /* returns value */ true,
         },
@@ -2280,10 +2281,10 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i,                     // array_index
-                                   4_i);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i,                           // array_index
+                                   4_i);                          // level
             },
             /* returns value */ true,
         },
@@ -2298,10 +2299,10 @@
             TextureDataType::kU32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i,                     // array_index
-                                   4_i);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i,                           // array_index
+                                   4_i);                          // level
             },
             /* returns value */ true,
         },
@@ -2316,10 +2317,10 @@
             TextureDataType::kI32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u,                     // array_index
-                                   4_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u,                           // array_index
+                                   4_u);                          // level
             },
             /* returns value */ true,
         },
@@ -2333,9 +2334,9 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   b->vec3<i32>(1_i, 2_i, 3_i),  // coords
-                                   4_i);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   b->Call<vec3<i32>>(1_i, 2_i, 3_i),  // coords
+                                   4_i);                               // level
             },
             /* returns value */ true,
         },
@@ -2349,9 +2350,9 @@
             TextureDataType::kU32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   b->vec3<i32>(1_i, 2_i, 3_i),  // coords
-                                   4_i);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   b->Call<vec3<i32>>(1_i, 2_i, 3_i),  // coords
+                                   4_i);                               // level
             },
             /* returns value */ true,
         },
@@ -2365,9 +2366,9 @@
             TextureDataType::kI32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                 // t
-                                   b->vec3<u32>(1_u, 2_u, 3_u),  // coords
-                                   4_u);                         // level
+                return b->ExprList(kTextureName,                       // t
+                                   b->Call<vec3<u32>>(1_u, 2_u, 3_u),  // coords
+                                   4_u);                               // level
             },
             /* returns value */ true,
         },
@@ -2381,9 +2382,9 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i);                    // sample_index
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i);                          // sample_index
             },
             /* returns value */ true,
         },
@@ -2397,9 +2398,9 @@
             TextureDataType::kU32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i);                    // sample_index
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i);                          // sample_index
             },
             /* returns value */ true,
         },
@@ -2413,9 +2414,9 @@
             TextureDataType::kI32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u);                    // sample_index
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u);                          // sample_index
             },
             /* returns value */ true,
         },
@@ -2429,9 +2430,9 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<i32>(1_i, 2_i),  // coords
-                                   3_i);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),  // coords
+                                   3_i);                          // level
             },
             /* returns value */ true,
         },
@@ -2446,10 +2447,10 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u,                     // array_index
-                                   4_u);                    // level
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u,                           // array_index
+                                   4_u);                          // level
             },
             /* returns value */ true,
         },
@@ -2463,9 +2464,9 @@
             TextureDataType::kF32,
             "textureLoad",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,            // t
-                                   b->vec2<u32>(1_u, 2_u),  // coords
-                                   3_u);                    // sample_index
+                return b->ExprList(kTextureName,                  // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),  // coords
+                                   3_u);                          // sample_index
             },
             /* returns value */ true,
         },
@@ -2480,9 +2481,9 @@
             TextureDataType::kF32,
             "textureStore",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                       // t
-                                   1_i,                                // coords
-                                   b->vec4<f32>(2_f, 3_f, 4_f, 5_f));  // value
+                return b->ExprList(kTextureName,                             // t
+                                   1_i,                                      // coords
+                                   b->Call<vec4<f32>>(2_f, 3_f, 4_f, 5_f));  // value
             },
             /* returns value */ false,
         },
@@ -2497,9 +2498,9 @@
             TextureDataType::kF32,
             "textureStore",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                       // t
-                                   b->vec2<i32>(1_i, 2_i),             // coords
-                                   b->vec4<f32>(3_f, 4_f, 5_f, 6_f));  // value
+                return b->ExprList(kTextureName,                             // t
+                                   b->Call<vec2<i32>>(1_i, 2_i),             // coords
+                                   b->Call<vec4<f32>>(3_f, 4_f, 5_f, 6_f));  // value
             },
             /* returns value */ false,
         },
@@ -2515,10 +2516,10 @@
             TextureDataType::kF32,
             "textureStore",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                       // t
-                                   b->vec2<u32>(1_u, 2_u),             // coords
-                                   3_u,                                // array_index
-                                   b->vec4<f32>(4_f, 5_f, 6_f, 7_f));  // value
+                return b->ExprList(kTextureName,                             // t
+                                   b->Call<vec2<u32>>(1_u, 2_u),             // coords
+                                   3_u,                                      // array_index
+                                   b->Call<vec4<f32>>(4_f, 5_f, 6_f, 7_f));  // value
             },
             /* returns value */ false,
         },
@@ -2533,9 +2534,9 @@
             TextureDataType::kF32,
             "textureStore",
             [](ProgramBuilder* b) {
-                return b->ExprList(kTextureName,                       // t
-                                   b->vec3<u32>(1_u, 2_u, 3_u),        // coords
-                                   b->vec4<f32>(4_f, 5_f, 6_f, 7_f));  // value
+                return b->ExprList(kTextureName,                             // t
+                                   b->Call<vec3<u32>>(1_u, 2_u, 3_u),        // coords
+                                   b->Call<vec4<f32>>(4_f, 5_f, 6_f, 7_f));  // value
             },
             /* returns value */ false,
         },
diff --git a/src/tint/ast/transform/builtin_polyfill.cc b/src/tint/ast/transform/builtin_polyfill.cc
index 05f5da9..75d91b3 100644
--- a/src/tint/ast/transform/builtin_polyfill.cc
+++ b/src/tint/ast/transform/builtin_polyfill.cc
@@ -29,7 +29,8 @@
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/map.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BuiltinPolyfill);
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BuiltinPolyfill::Config);
@@ -767,7 +768,7 @@
         auto name = b.Symbols().New("tint_textureSampleBaseClampToEdge");
         auto body = utils::Vector{
             b.Decl(b.Let("dims", b.Call(b.ty.vec2<f32>(), b.Call("textureDimensions", "t", 0_a)))),
-            b.Decl(b.Let("half_texel", b.Div(b.vec2<f32>(0.5_a), "dims"))),
+            b.Decl(b.Let("half_texel", b.Div(b.Call<vec2<f32>>(0.5_a), "dims"))),
             b.Decl(
                 b.Let("clamped", b.Call("clamp", "coord", "half_texel", b.Sub(1_a, "half_texel")))),
             b.Return(b.Call("textureSampleLevel", "t", "s", "clamped", 0_a)),
@@ -814,7 +815,7 @@
         auto name = b.Symbols().New("tint_workgroupUniformLoad");
         b.Func(name,
                utils::Vector{
-                   b.Param("p", b.ty.ptr(builtin::AddressSpace::kWorkgroup, T(type))),
+                   b.Param("p", b.ty.ptr<workgroup>(T(type))),
                },
                T(type),
                utils::Vector{
diff --git a/src/tint/ast/transform/calculate_array_length.cc b/src/tint/ast/transform/calculate_array_length.cc
index 0e11ad4..4a1c0c8 100644
--- a/src/tint/ast/transform/calculate_array_length.cc
+++ b/src/tint/ast/transform/calculate_array_length.cc
@@ -35,7 +35,8 @@
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CalculateArrayLength);
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CalculateArrayLength::BufferSizeIntrinsic);
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 
@@ -112,7 +113,7 @@
                        b.Param("buffer",
                                b.ty.ptr(buffer_type->AddressSpace(), type, buffer_type->Access()),
                                utils::Vector{disable_validation}),
-                       b.Param("result", b.ty.ptr(builtin::AddressSpace::kFunction, b.ty.u32())),
+                       b.Param("result", b.ty.ptr<function, u32>()),
                    },
                    b.ty.void_(), nullptr,
                    utils::Vector{
diff --git a/src/tint/ast/transform/decompose_strided_matrix_test.cc b/src/tint/ast/transform/decompose_strided_matrix_test.cc
index 4fa8017..bc1d416 100644
--- a/src/tint/ast/transform/decompose_strided_matrix_test.cc
+++ b/src/tint/ast/transform/decompose_strided_matrix_test.cc
@@ -24,7 +24,8 @@
 #include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/program_builder.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 namespace {
@@ -356,15 +357,16 @@
                          });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
-    b.Func("f", utils::Empty, b.ty.void_(),
-           utils::Vector{
-               b.Assign(b.MemberAccessor("s", "m"),
-                        b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
-           },
-           utils::Vector{
-               b.Stage(PipelineStage::kCompute),
-               b.WorkgroupSize(1_i),
-           });
+    b.Func(
+        "f", utils::Empty, b.ty.void_(),
+        utils::Vector{
+            b.Assign(b.MemberAccessor("s", "m"),
+                     b.Call<mat2x2<f32>>(b.Call<vec2<f32>>(1_f, 2_f), b.Call<vec2<f32>>(3_f, 4_f))),
+        },
+        utils::Vector{
+            b.Stage(PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
     auto* expect = R"(
 struct S {
@@ -415,14 +417,15 @@
                          });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
-    b.Func("f", utils::Empty, b.ty.void_(),
-           utils::Vector{
-               b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i), b.vec2<f32>(1_f, 2_f)),
-           },
-           utils::Vector{
-               b.Stage(PipelineStage::kCompute),
-               b.WorkgroupSize(1_i),
-           });
+    b.Func(
+        "f", utils::Empty, b.ty.void_(),
+        utils::Vector{
+            b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i), b.Call<vec2<f32>>(1_f, 2_f)),
+        },
+        utils::Vector{
+            b.Stage(PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
     auto* expect = R"(
 struct S {
@@ -482,8 +485,9 @@
                b.Decl(b.Let("x", b.Deref("b"))),
                b.Decl(b.Let("y", b.IndexAccessor(b.Deref("b"), 1_i))),
                b.Decl(b.Let("z", b.IndexAccessor("x", 1_i))),
-               b.Assign(b.Deref("b"), b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
-               b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), b.vec2<f32>(5_f, 6_f)),
+               b.Assign(b.Deref("b"), b.Call<mat2x2<f32>>(b.Call<vec2<f32>>(1_f, 2_f),
+                                                          b.Call<vec2<f32>>(3_f, 4_f))),
+               b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), b.Call<vec2<f32>>(5_f, 6_f)),
            },
            utils::Vector{
                b.Stage(PipelineStage::kCompute),
@@ -600,15 +604,16 @@
                                       }),
                          });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kPrivate);
-    b.Func("f", utils::Empty, b.ty.void_(),
-           utils::Vector{
-               b.Assign(b.MemberAccessor("s", "m"),
-                        b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
-           },
-           utils::Vector{
-               b.Stage(PipelineStage::kCompute),
-               b.WorkgroupSize(1_i),
-           });
+    b.Func(
+        "f", utils::Empty, b.ty.void_(),
+        utils::Vector{
+            b.Assign(b.MemberAccessor("s", "m"),
+                     b.Call<mat2x2<f32>>(b.Call<vec2<f32>>(1_f, 2_f), b.Call<vec2<f32>>(3_f, 4_f))),
+        },
+        utils::Vector{
+            b.Stage(PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
     auto* expect = R"(
 struct S {
diff --git a/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc b/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
index db06414..14112f0 100644
--- a/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
@@ -30,6 +30,8 @@
 
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ModuleScopeVarToEntryPointParam);
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+
 namespace tint::ast::transform {
 namespace {
 
@@ -183,9 +185,7 @@
                     auto* member_ptr = ctx.dst->AddressOf(
                         ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
                     auto* local_var = ctx.dst->Let(
-                        new_var_symbol,
-                        ctx.dst->ty.ptr(builtin::AddressSpace::kWorkgroup, store_type()),
-                        member_ptr);
+                        new_var_symbol, ctx.dst->ty.ptr<workgroup>(store_type()), member_ptr);
                     ctx.InsertFront(func->body->statements, ctx.dst->Decl(local_var));
                     is_pointer = true;
                 } else {
@@ -427,8 +427,7 @@
                     }
                 } else {
                     // Create a parameter that is a pointer to the private variable struct.
-                    auto ptr = ctx.dst->ty.ptr(builtin::AddressSpace::kPrivate,
-                                               ctx.dst->ty(PrivateStructName()));
+                    auto ptr = ctx.dst->ty.ptr<private_>(ctx.dst->ty(PrivateStructName()));
                     auto* param = ctx.dst->Param(PrivateStructVariableName(), ptr);
                     ctx.InsertBack(func_ast->params, param);
                 }
@@ -489,8 +488,7 @@
                 // The parameter is a struct that contains members for each workgroup variable.
                 auto* str =
                     ctx.dst->Structure(ctx.dst->Sym(), std::move(workgroup_parameter_members));
-                auto param_type =
-                    ctx.dst->ty.ptr(builtin::AddressSpace::kWorkgroup, ctx.dst->ty.Of(str));
+                auto param_type = ctx.dst->ty.ptr(workgroup, ctx.dst->ty.Of(str));
                 auto* param =
                     ctx.dst->Param(workgroup_param(), param_type,
                                    utils::Vector{
diff --git a/src/tint/ast/transform/multiplanar_external_texture.cc b/src/tint/ast/transform/multiplanar_external_texture.cc
index 87844f8..9c4c62c 100644
--- a/src/tint/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/ast/transform/multiplanar_external_texture.cc
@@ -27,7 +27,8 @@
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::MultiplanarExternalTexture);
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::MultiplanarExternalTexture::NewBindingPoints);
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 namespace {
@@ -270,34 +271,35 @@
     void createGammaCorrectionFn() {
         gamma_correction_sym = b.Symbols().New("gammaCorrection");
 
-        b.Func(
-            gamma_correction_sym,
-            utils::Vector{
-                b.Param("v", b.ty.vec3<f32>()),
-                b.Param("params", b.ty(gamma_transfer_struct_sym)),
-            },
-            b.ty.vec3<f32>(),
-            utils::Vector{
-                // let cond = abs(v) < vec3(params.D);
-                b.Decl(b.Let("cond", b.LessThan(b.Call("abs", "v"),
-                                                b.vec3<f32>(b.MemberAccessor("params", "D"))))),
-                // let t = sign(v) * ((params.C * abs(v)) + params.F);
-                b.Decl(b.Let("t",
-                             b.Mul(b.Call("sign", "v"),
-                                   b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
-                                         b.MemberAccessor("params", "F"))))),
-                // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
-                // vec3(params.G))) + params.E;
-                b.Decl(b.Let("f", b.Mul(b.Call("sign", "v"),
-                                        b.Add(b.Call("pow",
-                                                     b.Add(b.Mul(b.MemberAccessor("params", "A"),
-                                                                 b.Call("abs", "v")),
-                                                           b.MemberAccessor("params", "B")),
-                                                     b.vec3<f32>(b.MemberAccessor("params", "G"))),
-                                              b.MemberAccessor("params", "E"))))),
-                // return select(f, t, cond);
-                b.Return(b.Call("select", "f", "t", "cond")),
-            });
+        b.Func(gamma_correction_sym,
+               utils::Vector{
+                   b.Param("v", b.ty.vec3<f32>()),
+                   b.Param("params", b.ty(gamma_transfer_struct_sym)),
+               },
+               b.ty.vec3<f32>(),
+               utils::Vector{
+                   // let cond = abs(v) < vec3(params.D);
+                   b.Decl(b.Let("cond",
+                                b.LessThan(b.Call("abs", "v"),
+                                           b.Call<vec3<f32>>(b.MemberAccessor("params", "D"))))),
+                   // let t = sign(v) * ((params.C * abs(v)) + params.F);
+                   b.Decl(b.Let(
+                       "t", b.Mul(b.Call("sign", "v"),
+                                  b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
+                                        b.MemberAccessor("params", "F"))))),
+                   // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
+                   // vec3(params.G))) + params.E;
+                   b.Decl(b.Let(
+                       "f", b.Mul(b.Call("sign", "v"),
+                                  b.Add(b.Call("pow",
+                                               b.Add(b.Mul(b.MemberAccessor("params", "A"),
+                                                           b.Call("abs", "v")),
+                                                     b.MemberAccessor("params", "B")),
+                                               b.Call<vec3<f32>>(b.MemberAccessor("params", "G"))),
+                                        b.MemberAccessor("params", "E"))))),
+                   // return select(f, t, cond);
+                   b.Return(b.Call("select", "f", "t", "cond")),
+               });
     }
 
     /// Constructs a StatementList containing all the statements making up the body of the texture
@@ -313,21 +315,21 @@
             case builtin::Function::kTextureSampleBaseClampToEdge:
                 stmts.Push(b.Decl(b.Let(
                     "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
-                                            b.vec3<f32>("coord", 1_a)))));
+                                            b.Call<vec3<f32>>("coord", 1_a)))));
 
                 stmts.Push(b.Decl(
                     b.Let("plane0_dims",
                           b.Call(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane0", 0_a)))));
-                stmts.Push(
-                    b.Decl(b.Let("plane0_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane0_dims"))));
+                stmts.Push(b.Decl(
+                    b.Let("plane0_half_texel", b.Div(b.Call<vec2<f32>>(0.5_a), "plane0_dims"))));
                 stmts.Push(b.Decl(
                     b.Let("plane0_clamped", b.Call("clamp", "modifiedCoords", "plane0_half_texel",
                                                    b.Sub(1_a, "plane0_half_texel")))));
                 stmts.Push(b.Decl(
                     b.Let("plane1_dims",
                           b.Call(b.ty.vec2<f32>(), b.Call("textureDimensions", "plane1", 0_a)))));
-                stmts.Push(
-                    b.Decl(b.Let("plane1_half_texel", b.Div(b.vec2<f32>(0.5_a), "plane1_dims"))));
+                stmts.Push(b.Decl(
+                    b.Let("plane1_half_texel", b.Div(b.Call<vec2<f32>>(0.5_a), "plane1_dims"))));
                 stmts.Push(b.Decl(
                     b.Let("plane1_clamped", b.Call("clamp", "modifiedCoords", "plane1_half_texel",
                                                    b.Sub(1_a, "plane1_half_texel")))));
@@ -346,7 +348,7 @@
                 // textureLoad(plane0, coord, 0);
                 plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_a);
                 // let coord1 = coord >> 1;
-                stmts.Push(b.Decl(b.Let("coord1", b.Shr("coord", b.vec2<u32>(1_a)))));
+                stmts.Push(b.Decl(b.Let("coord1", b.Shr("coord", b.Call<vec2<u32>>(1_a)))));
                 // textureLoad(plane1, coord1, 0);
                 plane_1_call = b.Call("textureLoad", "plane1", "coord1", 0_a);
                 break;
@@ -367,8 +369,8 @@
                      // color = vec4<f32>(plane_0_call.r, plane_1_call.rg, 1.0) *
                      //         params.yuvToRgbConversionMatrix;
                      b.Assign("color",
-                              b.Mul(b.vec4<f32>(b.MemberAccessor(plane_0_call, "r"),
-                                                b.MemberAccessor(plane_1_call, "rg"), 1_a),
+                              b.Mul(b.Call<vec4<f32>>(b.MemberAccessor(plane_0_call, "r"),
+                                                      b.MemberAccessor(plane_1_call, "rg"), 1_a),
                                     b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))));
 
         // if (params.doYuvToRgbConversionOnly == 0u)
@@ -386,7 +388,7 @@
                                               b.MemberAccessor("params", "gammaEncodeParams"))))));
 
         // return vec4<f32>(color, 1.f);
-        stmts.Push(b.Return(b.vec4<f32>("color", 1_a)));
+        stmts.Push(b.Return(b.Call<vec4<f32>>("color", 1_a)));
 
         return stmts;
     }
diff --git a/src/tint/ast/transform/preserve_padding.cc b/src/tint/ast/transform/preserve_padding.cc
index 7d9143c..69e6d25 100644
--- a/src/tint/ast/transform/preserve_padding.cc
+++ b/src/tint/ast/transform/preserve_padding.cc
@@ -26,7 +26,8 @@
 
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PreservePadding);
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 
@@ -122,8 +123,7 @@
                 auto helper_name = b.Symbols().New("assign_and_preserve_padding");
                 utils::Vector<const Parameter*, 2> params = {
                     b.Param(kDestParamName,
-                            b.ty.ptr(builtin::AddressSpace::kStorage, CreateASTTypeFor(ctx, ty),
-                                     builtin::Access::kReadWrite)),
+                            b.ty.ptr<storage, read_write>(CreateASTTypeFor(ctx, ty))),
                     b.Param(kValueParamName, CreateASTTypeFor(ctx, ty)),
                 };
                 b.Func(helper_name, params, b.ty.void_(), body());
diff --git a/src/tint/ast/transform/robustness.cc b/src/tint/ast/transform/robustness.cc
index aa94748..e0be9e5 100644
--- a/src/tint/ast/transform/robustness.cc
+++ b/src/tint/ast/transform/robustness.cc
@@ -35,7 +35,8 @@
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Robustness);
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Robustness::Config);
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 
diff --git a/src/tint/ast/transform/vertex_pulling.cc b/src/tint/ast/transform/vertex_pulling.cc
index c2a543e..375bfc3 100644
--- a/src/tint/ast/transform/vertex_pulling.cc
+++ b/src/tint/ast/transform/vertex_pulling.cc
@@ -32,7 +32,8 @@
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VertexPulling);
 TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VertexPulling::Config);
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::ast::transform {
 
@@ -576,71 +577,71 @@
 
             case VertexFormat::kUint8x2: {
                 // yyxx0000, yyxx0000
-                auto* u16s = b.vec2<u32>(load_u16_h());
+                auto* u16s = b.Call<vec2<u32>>(load_u16_h());
                 // xx000000, yyxx0000
-                auto* shl = b.Shl(u16s, b.vec2<u32>(8_u, 0_u));
+                auto* shl = b.Shl(u16s, b.Call<vec2<u32>>(8_u, 0_u));
                 // 000000xx, 000000yy
-                return b.Shr(shl, b.vec2<u32>(24_u));
+                return b.Shr(shl, b.Call<vec2<u32>>(24_u));
             }
             case VertexFormat::kUint8x4: {
                 // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
-                auto* u32s = b.vec4<u32>(load_u32());
+                auto* u32s = b.Call<vec4<u32>>(load_u32());
                 // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
-                auto* shl = b.Shl(u32s, b.vec4<u32>(24_u, 16_u, 8_u, 0_u));
+                auto* shl = b.Shl(u32s, b.Call<vec4<u32>>(24_u, 16_u, 8_u, 0_u));
                 // 000000xx, 000000yy, 000000zz, 000000ww
-                return b.Shr(shl, b.vec4<u32>(24_u));
+                return b.Shr(shl, b.Call<vec4<u32>>(24_u));
             }
             case VertexFormat::kUint16x2: {
                 // yyyyxxxx, yyyyxxxx
-                auto* u32s = b.vec2<u32>(load_u32());
+                auto* u32s = b.Call<vec2<u32>>(load_u32());
                 // xxxx0000, yyyyxxxx
-                auto* shl = b.Shl(u32s, b.vec2<u32>(16_u, 0_u));
+                auto* shl = b.Shl(u32s, b.Call<vec2<u32>>(16_u, 0_u));
                 // 0000xxxx, 0000yyyy
-                return b.Shr(shl, b.vec2<u32>(16_u));
+                return b.Shr(shl, b.Call<vec2<u32>>(16_u));
             }
             case VertexFormat::kUint16x4: {
                 // yyyyxxxx, wwwwzzzz
-                auto* u32s = b.vec2<u32>(load_u32(), load_next_u32());
+                auto* u32s = b.Call<vec2<u32>>(load_u32(), load_next_u32());
                 // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
                 auto* xxyy = b.MemberAccessor(u32s, "xxyy");
                 // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
-                auto* shl = b.Shl(xxyy, b.vec4<u32>(16_u, 0_u, 16_u, 0_u));
+                auto* shl = b.Shl(xxyy, b.Call<vec4<u32>>(16_u, 0_u, 16_u, 0_u));
                 // 0000xxxx, 0000yyyy, 0000zzzz, 0000wwww
-                return b.Shr(shl, b.vec4<u32>(16_u));
+                return b.Shr(shl, b.Call<vec4<u32>>(16_u));
             }
             case VertexFormat::kSint8x2: {
                 // yyxx0000, yyxx0000
-                auto* i16s = b.vec2<i32>(load_i16_h());
+                auto* i16s = b.Call<vec2<i32>>(load_i16_h());
                 // xx000000, yyxx0000
-                auto* shl = b.Shl(i16s, b.vec2<u32>(8_u, 0_u));
+                auto* shl = b.Shl(i16s, b.Call<vec2<u32>>(8_u, 0_u));
                 // ssssssxx, ssssssyy
-                return b.Shr(shl, b.vec2<u32>(24_u));
+                return b.Shr(shl, b.Call<vec2<u32>>(24_u));
             }
             case VertexFormat::kSint8x4: {
                 // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
-                auto* i32s = b.vec4<i32>(load_i32());
+                auto* i32s = b.Call<vec4<i32>>(load_i32());
                 // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
-                auto* shl = b.Shl(i32s, b.vec4<u32>(24_u, 16_u, 8_u, 0_u));
+                auto* shl = b.Shl(i32s, b.Call<vec4<u32>>(24_u, 16_u, 8_u, 0_u));
                 // ssssssxx, ssssssyy, sssssszz, ssssssww
-                return b.Shr(shl, b.vec4<u32>(24_u));
+                return b.Shr(shl, b.Call<vec4<u32>>(24_u));
             }
             case VertexFormat::kSint16x2: {
                 // yyyyxxxx, yyyyxxxx
-                auto* i32s = b.vec2<i32>(load_i32());
+                auto* i32s = b.Call<vec2<i32>>(load_i32());
                 // xxxx0000, yyyyxxxx
-                auto* shl = b.Shl(i32s, b.vec2<u32>(16_u, 0_u));
+                auto* shl = b.Shl(i32s, b.Call<vec2<u32>>(16_u, 0_u));
                 // ssssxxxx, ssssyyyy
-                return b.Shr(shl, b.vec2<u32>(16_u));
+                return b.Shr(shl, b.Call<vec2<u32>>(16_u));
             }
             case VertexFormat::kSint16x4: {
                 // yyyyxxxx, wwwwzzzz
-                auto* i32s = b.vec2<i32>(load_i32(), load_next_i32());
+                auto* i32s = b.Call<vec2<i32>>(load_i32(), load_next_i32());
                 // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
                 auto* xxyy = b.MemberAccessor(i32s, "xxyy");
                 // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
-                auto* shl = b.Shl(xxyy, b.vec4<u32>(16_u, 0_u, 16_u, 0_u));
+                auto* shl = b.Shl(xxyy, b.Call<vec4<u32>>(16_u, 0_u, 16_u, 0_u));
                 // ssssxxxx, ssssyyyy, sssszzzz, sssswwww
-                return b.Shr(shl, b.vec4<u32>(16_u));
+                return b.Shr(shl, b.Call<vec4<u32>>(16_u));
             }
             case VertexFormat::kUnorm8x2:
                 return b.MemberAccessor(b.Call("unpack4x8unorm", load_u16_l()), "xy");
@@ -657,14 +658,14 @@
             case VertexFormat::kFloat16x2:
                 return b.Call("unpack2x16float", load_u32());
             case VertexFormat::kUnorm16x4:
-                return b.vec4<f32>(b.Call("unpack2x16unorm", load_u32()),
-                                   b.Call("unpack2x16unorm", load_next_u32()));
+                return b.Call<vec4<f32>>(b.Call("unpack2x16unorm", load_u32()),
+                                         b.Call("unpack2x16unorm", load_next_u32()));
             case VertexFormat::kSnorm16x4:
-                return b.vec4<f32>(b.Call("unpack2x16snorm", load_u32()),
-                                   b.Call("unpack2x16snorm", load_next_u32()));
+                return b.Call<vec4<f32>>(b.Call("unpack2x16snorm", load_u32()),
+                                         b.Call("unpack2x16snorm", load_next_u32()));
             case VertexFormat::kFloat16x4:
-                return b.vec4<f32>(b.Call("unpack2x16float", load_u32()),
-                                   b.Call("unpack2x16float", load_next_u32()));
+                return b.Call<vec4<f32>>(b.Call("unpack2x16float", load_u32()),
+                                         b.Call("unpack2x16float", load_next_u32()));
         }
 
         TINT_UNREACHABLE(Transform, b.Diagnostics()) << "format " << static_cast<int>(format);
diff --git a/src/tint/builtin/fluent_types.h b/src/tint/builtin/fluent_types.h
new file mode 100644
index 0000000..925b54e
--- /dev/null
+++ b/src/tint/builtin/fluent_types.h
@@ -0,0 +1,237 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_BUILTIN_FLUENT_TYPES_H_
+#define SRC_TINT_BUILTIN_FLUENT_TYPES_H_
+
+#include <stdint.h>
+
+#include "src/tint/builtin/access.h"
+#include "src/tint/builtin/address_space.h"
+#include "src/tint/builtin/number.h"
+
+namespace tint::builtin::fluent_types {
+
+// A sentinel type used by some template arguments to signal that the a type should be inferred.
+struct Infer {};
+
+/// A 'fluent' type helper used to construct an ast::Array or type::Array.
+/// @tparam T the array element type
+/// @tparam N the array length. 0 represents a runtime-sized array.
+/// @see https://www.w3.org/TR/WGSL/#array-types
+template <typename T = Infer, uint32_t N = 0>
+struct array {
+    /// the array element type
+    using type = T;
+    /// the array length. 0 represents a runtime-sized array.
+    static constexpr uint32_t length = N;
+};
+
+/// A 'fluent' type helper used to construct an ast::Atomic or type::Atomic.
+/// @tparam T the atomic element type
+/// @see https://www.w3.org/TR/WGSL/#atomic-types
+template <typename T>
+struct atomic {
+    /// the atomic element type
+    using type = T;
+};
+
+/// A 'fluent' type helper used to construct an ast::Vector or type::Vector.
+/// @tparam N the vector width
+/// @tparam T the vector element type
+template <uint32_t N, typename T = Infer>
+struct vec {
+    /// the vector width
+    static constexpr uint32_t width = N;
+    /// the vector element type
+    using type = T;
+};
+
+/// A 'fluent' type helper used to construct an ast::Matrix or type::Matrix.
+/// @tparam C the number of columns of the matrix
+/// @tparam R the number of rows of the matrix
+/// @tparam T the matrix element type
+/// @see https://www.w3.org/TR/WGSL/#matrix-types
+template <uint32_t C, uint32_t R, typename T = Infer>
+struct mat {
+    /// the number of columns of the matrix
+    static constexpr uint32_t columns = C;
+    /// the number of rows of the matrix
+    static constexpr uint32_t rows = R;
+    /// the matrix element type
+    using type = T;
+    /// the column vector type
+    using column = vec<R, T>;
+};
+
+/// A 'fluent' type helper used to construct an ast::Pointer or type::Pointer.
+/// @tparam ADDRESS the pointer address space
+/// @tparam T the pointer storage type
+/// @tparam ACCESS the pointer access control
+template <builtin::AddressSpace ADDRESS,
+          typename T,
+          builtin::Access ACCESS = builtin::Access::kUndefined>
+struct ptr {
+    /// the pointer address space
+    static constexpr builtin::AddressSpace address = ADDRESS;
+    /// the pointer storage type
+    using type = T;
+    /// the pointer access control
+    static constexpr builtin::Access access = ACCESS;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Aliases
+//
+// Shorthand aliases for the types declared above
+////////////////////////////////////////////////////////////////////////////////
+
+//! @cond Doxygen_Suppress
+template <typename T>
+using mat2x2 = mat<2, 2, T>;
+
+template <typename T>
+using mat2x3 = mat<2, 3, T>;
+
+template <typename T>
+using mat2x4 = mat<2, 4, T>;
+
+template <typename T>
+using mat3x2 = mat<3, 2, T>;
+
+template <typename T>
+using mat3x3 = mat<3, 3, T>;
+
+template <typename T>
+using mat3x4 = mat<3, 4, T>;
+
+template <typename T>
+using mat4x2 = mat<4, 2, T>;
+
+template <typename T>
+using mat4x3 = mat<4, 3, T>;
+
+template <typename T>
+using mat4x4 = mat<4, 4, T>;
+
+template <typename T>
+using vec2 = vec<2, T>;
+
+template <typename T>
+using vec3 = vec<3, T>;
+
+template <typename T>
+using vec4 = vec<4, T>;
+
+//! @endcond
+
+////////////////////////////////////////////////////////////////////////////////
+// Address space aliases
+////////////////////////////////////////////////////////////////////////////////
+static constexpr builtin::AddressSpace function = builtin::AddressSpace::kFunction;
+static constexpr builtin::AddressSpace private_ = builtin::AddressSpace::kPrivate;
+static constexpr builtin::AddressSpace push_constant = builtin::AddressSpace::kPushConstant;
+static constexpr builtin::AddressSpace storage = builtin::AddressSpace::kStorage;
+static constexpr builtin::AddressSpace uniform = builtin::AddressSpace::kUniform;
+static constexpr builtin::AddressSpace workgroup = builtin::AddressSpace::kWorkgroup;
+
+////////////////////////////////////////////////////////////////////////////////
+// Access control aliases
+////////////////////////////////////////////////////////////////////////////////
+static constexpr builtin::Access read = builtin::Access::kRead;
+static constexpr builtin::Access read_write = builtin::Access::kReadWrite;
+static constexpr builtin::Access write = builtin::Access::kWrite;
+
+////////////////////////////////////////////////////////////////////////////////
+// Traits
+////////////////////////////////////////////////////////////////////////////////
+namespace detail {
+
+//! @cond Doxygen_Suppress
+template <typename T>
+struct IsArray {
+    static constexpr bool value = false;
+};
+
+template <typename T, uint32_t N>
+struct IsArray<array<T, N>> {
+    static constexpr bool value = true;
+};
+
+template <typename T>
+struct IsAtomic {
+    static constexpr bool value = false;
+};
+
+template <typename T>
+struct IsAtomic<atomic<T>> {
+    static constexpr bool value = true;
+};
+
+template <typename T>
+struct IsMatrix {
+    static constexpr bool value = false;
+};
+
+template <uint32_t C, uint32_t R, typename T>
+struct IsMatrix<mat<C, R, T>> {
+    static constexpr bool value = true;
+};
+
+template <typename T>
+struct IsVector {
+    static constexpr bool value = false;
+};
+
+template <uint32_t N, typename T>
+struct IsVector<vec<N, T>> {
+    static constexpr bool value = true;
+};
+
+template <typename T>
+struct IsPointer {
+    static constexpr bool value = false;
+};
+
+template <builtin::AddressSpace ADDRESS, typename T, builtin::Access ACCESS>
+struct IsPointer<ptr<ADDRESS, T, ACCESS>> {
+    static constexpr bool value = true;
+};
+//! @endcond
+
+}  // namespace detail
+
+/// Evaluates to true if `T` is a array
+template <typename T>
+static constexpr bool IsArray = fluent_types::detail::IsArray<T>::value;
+
+/// Evaluates to true if `T` is a atomic
+template <typename T>
+static constexpr bool IsAtomic = fluent_types::detail::IsAtomic<T>::value;
+
+/// Evaluates to true if `T` is a mat
+template <typename T>
+static constexpr bool IsMatrix = fluent_types::detail::IsMatrix<T>::value;
+
+/// Evaluates to true if `T` is a vec
+template <typename T>
+static constexpr bool IsVector = fluent_types::detail::IsVector<T>::value;
+
+/// Evaluates to true if `T` is a ptr
+template <typename T>
+static constexpr bool IsPointer = fluent_types::detail::IsPointer<T>::value;
+
+}  // namespace tint::builtin::fluent_types
+
+#endif  // SRC_TINT_BUILTIN_FLUENT_TYPES_H_
diff --git a/src/tint/number.cc b/src/tint/builtin/number.cc
similarity index 99%
rename from src/tint/number.cc
rename to src/tint/builtin/number.cc
index 8b85670..bf15fef 100644
--- a/src/tint/number.cc
+++ b/src/tint/builtin/number.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/number.h"
+#include "src/tint/builtin/number.h"
 
 #include <algorithm>
 #include <cmath>
@@ -345,7 +345,7 @@
 }
 
 // static
-Number<detail::NumberKindF16> f16::FromBits(uint16_t bits) {
+Number<tint::detail::NumberKindF16> f16::FromBits(uint16_t bits) {
     // Assert we use binary32 (i.e. float) as underlying type, which has 4 bytes.
     static_assert(std::is_same<f16::type, float>());
 
diff --git a/src/tint/number.h b/src/tint/builtin/number.h
similarity index 96%
rename from src/tint/number.h
rename to src/tint/builtin/number.h
index 06ab7fd..accc5e2 100644
--- a/src/tint/number.h
+++ b/src/tint/builtin/number.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_NUMBER_H_
-#define SRC_TINT_NUMBER_H_
+#ifndef SRC_TINT_BUILTIN_NUMBER_H_
+#define SRC_TINT_BUILTIN_NUMBER_H_
 
 #include <stdint.h>
 #include <cmath>
@@ -66,16 +66,16 @@
 
 /// Evaluates to true iff T is a Number
 template <typename T>
-constexpr bool IsNumber = detail::IsNumber<T>::value;
+constexpr bool IsNumber = tint::detail::IsNumber<T>::value;
 
 /// Resolves to the underlying type for a Number.
 template <typename T>
-using UnwrapNumber = typename detail::NumberUnwrapper<T>::type;
+using UnwrapNumber = typename tint::detail::NumberUnwrapper<T>::type;
 
 /// Evaluates to true iff T or Number<T> is a floating-point type or is NumberKindF16.
 template <typename T>
 constexpr bool IsFloatingPoint = std::is_floating_point_v<UnwrapNumber<T>> ||
-                                 std::is_same_v<UnwrapNumber<T>, detail::NumberKindF16>;
+                                 std::is_same_v<UnwrapNumber<T>, tint::detail::NumberKindF16>;
 
 /// Evaluates to true iff T or Number<T> is an integral type.
 template <typename T>
@@ -186,7 +186,7 @@
 /// The partial specification of Number for f16 type, storing the f16 value as float,
 /// and enforcing proper explicit casting.
 template <>
-struct Number<detail::NumberKindF16> : NumberBase<Number<detail::NumberKindF16>> {
+struct Number<tint::detail::NumberKindF16> : NumberBase<Number<tint::detail::NumberKindF16>> {
     /// C++ does not have a native float16 type, so we use a 32-bit float instead.
     using type = float;
 
@@ -226,7 +226,7 @@
 
     /// Negation operator
     /// @returns the negative value of the number
-    Number operator-() const { return Number<detail::NumberKindF16>(-value); }
+    Number operator-() const { return Number<tint::detail::NumberKindF16>(-value); }
 
     /// Assignment operator with parameter as native floating point type
     /// @param v the new value
@@ -246,7 +246,7 @@
     /// Creates an f16 value from the uint16_t bit representation.
     /// @param bits the bits to convert from
     /// @returns the binary16 value based off the provided bit pattern.
-    static Number<detail::NumberKindF16> FromBits(uint16_t bits);
+    static Number<tint::detail::NumberKindF16> FromBits(uint16_t bits);
 
     /// @param value the input float32 value
     /// @returns the float32 value quantized to the smaller float16 value, through truncation of the
@@ -272,7 +272,7 @@
 using f32 = Number<float>;
 /// `f16` is a type alias to `Number<detail::NumberKindF16>`, which should be IEEE 754 binary16.
 /// However since C++ don't have native binary16 type, the value is stored as float.
-using f16 = Number<detail::NumberKindF16>;
+using f16 = Number<tint::detail::NumberKindF16>;
 
 template <typename T, utils::traits::EnableIf<IsFloatingPoint<T>>* = nullptr>
 inline const auto kPi = T(UnwrapNumber<T>(3.14159265358979323846));
@@ -576,7 +576,7 @@
         return {};
     }
 
-    return AInt{detail::Mod(a.value, b.value)};
+    return AInt{tint::detail::Mod(a.value, b.value)};
 }
 
 /// @returns the remainder of a / b, or an empty optional if the resulting value overflowed the
@@ -587,7 +587,7 @@
     if (b == FloatingPointT{0.0} || b == FloatingPointT{-0.0}) {
         return {};
     }
-    auto result = FloatingPointT{detail::Mod(a.value, b.value)};
+    auto result = FloatingPointT{tint::detail::Mod(a.value, b.value)};
     if (!std::isfinite(result.value)) {
         return {};
     }
@@ -681,4 +681,4 @@
 
 }  // namespace std
 
-#endif  // SRC_TINT_NUMBER_H_
+#endif  // SRC_TINT_BUILTIN_NUMBER_H_
diff --git a/src/tint/number_test.cc b/src/tint/builtin/number_test.cc
similarity index 100%
rename from src/tint/number_test.cc
rename to src/tint/builtin/number_test.cc
diff --git a/src/tint/constant/composite.h b/src/tint/constant/composite.h
index 23367a5..c2f264c 100644
--- a/src/tint/constant/composite.h
+++ b/src/tint/constant/composite.h
@@ -15,8 +15,8 @@
 #ifndef SRC_TINT_CONSTANT_COMPOSITE_H_
 #define SRC_TINT_CONSTANT_COMPOSITE_H_
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/value.h"
-#include "src/tint/number.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/castable.h"
 #include "src/tint/utils/hash.h"
diff --git a/src/tint/constant/manager.h b/src/tint/constant/manager.h
index d356988..43d50496 100644
--- a/src/tint/constant/manager.h
+++ b/src/tint/constant/manager.h
@@ -17,8 +17,8 @@
 
 #include <utility>
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/value.h"
-#include "src/tint/number.h"
 #include "src/tint/type/manager.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/unique_allocator.h"
diff --git a/src/tint/constant/scalar.h b/src/tint/constant/scalar.h
index 23684ec..442bc59 100644
--- a/src/tint/constant/scalar.h
+++ b/src/tint/constant/scalar.h
@@ -15,9 +15,9 @@
 #ifndef SRC_TINT_CONSTANT_SCALAR_H_
 #define SRC_TINT_CONSTANT_SCALAR_H_
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/manager.h"
 #include "src/tint/constant/value.h"
-#include "src/tint/number.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/castable.h"
 #include "src/tint/utils/hash.h"
diff --git a/src/tint/constant/value.h b/src/tint/constant/value.h
index baf1171..34ca335 100644
--- a/src/tint/constant/value.h
+++ b/src/tint/constant/value.h
@@ -17,9 +17,9 @@
 
 #include <variant>
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/clone_context.h"
 #include "src/tint/constant/node.h"
-#include "src/tint/number.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/castable.h"
 
diff --git a/src/tint/ir/access_test.cc b/src/tint/ir/access_test.cc
index 1f0e947..9d461b1 100644
--- a/src/tint/ir/access_test.cc
+++ b/src/tint/ir/access_test.cc
@@ -18,6 +18,8 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ir/ir_test_helper.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+
 namespace tint::ir {
 namespace {
 
diff --git a/src/tint/ir/from_program_accessor_test.cc b/src/tint/ir/from_program_accessor_test.cc
index d8e6601..3628f10 100644
--- a/src/tint/ir/from_program_accessor_test.cc
+++ b/src/tint/ir/from_program_accessor_test.cc
@@ -24,7 +24,8 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using IR_FromProgramAccessorTest = ProgramTestHelper;
 
@@ -348,7 +349,7 @@
     // let a: mat3x4<f32> = mat3x4<u32>()
     // let b = a[2][3]
 
-    auto* a = Let("a", ty.mat3x4<f32>(), mat3x4<f32>());
+    auto* a = Let("a", ty.mat3x4<f32>(), Call<mat3x4<f32>>());
     auto* expr = Decl(Let("b", IndexAccessor(IndexAccessor(a, 2_u), 3_u)));
     WrapInFunction(Block(utils::Vector{Decl(a), expr}));
 
@@ -448,7 +449,7 @@
                                          Member("a", ty.i32()),
                                          Member("foo", ty.array(ty.Of(inner), 4_u)),
                                      });
-    auto* a = Let("a", ty.array(ty.Of(outer), 4_u), array(ty.Of(outer), 4_u));
+    auto* a = Let("a", ty.array(ty.Of(outer), 4_u), Call(ty.array(ty.Of(outer), 4_u)));
     auto* expr = Decl(Let(
         "b",
         MemberAccessor(IndexAccessor(MemberAccessor(IndexAccessor(a, 0_u), "foo"), 1_u), "bar")));
diff --git a/src/tint/ir/from_program_call_test.cc b/src/tint/ir/from_program_call_test.cc
index ce89975..1148f56 100644
--- a/src/tint/ir/from_program_call_test.cc
+++ b/src/tint/ir/from_program_call_test.cc
@@ -21,7 +21,8 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using IR_FromProgramCallTest = ProgramTestHelper;
 
@@ -92,7 +93,7 @@
 
 TEST_F(IR_FromProgramCallTest, EmitExpression_Convert) {
     auto i = GlobalVar("i", builtin::AddressSpace::kPrivate, Expr(1_i));
-    auto* expr = Call(ty.f32(), i);
+    auto* expr = Call<f32>(i);
     WrapInFunction(expr);
 
     auto m = Build();
@@ -114,7 +115,7 @@
 }
 
 TEST_F(IR_FromProgramCallTest, EmitExpression_ConstructEmpty) {
-    auto* expr = vec3(ty.f32());
+    auto* expr = Call<vec3<f32>>();
     GlobalVar("i", builtin::AddressSpace::kPrivate, expr);
 
     auto m = Build();
@@ -130,7 +131,7 @@
 
 TEST_F(IR_FromProgramCallTest, EmitExpression_Construct) {
     auto i = GlobalVar("i", builtin::AddressSpace::kPrivate, Expr(1_f));
-    auto* expr = vec3(ty.f32(), 2_f, 3_f, i);
+    auto* expr = Call<vec3<f32>>(2_f, 3_f, i);
     WrapInFunction(expr);
 
     auto m = Build();
diff --git a/src/tint/ir/from_program_function_test.cc b/src/tint/ir/from_program_function_test.cc
index c467f28..2fce0e7 100644
--- a/src/tint/ir/from_program_function_test.cc
+++ b/src/tint/ir/from_program_function_test.cc
@@ -21,12 +21,14 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using IR_FromProgramFunctionTest = ProgramTestHelper;
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_Vertex) {
-    Func("test", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(vec4<f32>(0_f, 0_f, 0_f, 0_f))},
+    Func("test", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{Return(Call<vec4<f32>>(0_f, 0_f, 0_f, 0_f))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
 
@@ -73,8 +75,8 @@
 }
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_Return) {
-    Func("test", utils::Empty, ty.vec3<f32>(), utils::Vector{Return(vec3<f32>(0_f, 0_f, 0_f))},
-         utils::Empty);
+    Func("test", utils::Empty, ty.vec3<f32>(),
+         utils::Vector{Return(Call<vec3<f32>>(0_f, 0_f, 0_f))}, utils::Empty);
 
     auto m = Build();
     ASSERT_TRUE(m) << (!m ? m.Failure() : "");
@@ -88,7 +90,8 @@
 }
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_ReturnPosition) {
-    Func("test", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(vec4<f32>(1_f, 2_f, 3_f, 4_f))},
+    Func("test", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{Return(Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
 
@@ -104,7 +107,8 @@
 }
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_ReturnPositionInvariant) {
-    Func("test", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(vec4<f32>(1_f, 2_f, 3_f, 4_f))},
+    Func("test", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{Return(Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(builtin::BuiltinValue::kPosition), Invariant()});
 
@@ -121,7 +125,8 @@
 }
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_ReturnLocation) {
-    Func("test", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(vec4<f32>(1_f, 2_f, 3_f, 4_f))},
+    Func("test", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{Return(Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))},
          utils::Vector{Stage(ast::PipelineStage::kFragment)}, utils::Vector{Location(1_i)});
 
     auto m = Build();
@@ -137,7 +142,8 @@
 }
 
 TEST_F(IR_FromProgramFunctionTest, EmitFunction_ReturnLocation_Interpolate) {
-    Func("test", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(vec4<f32>(1_f, 2_f, 3_f, 4_f))},
+    Func("test", utils::Empty, ty.vec4<f32>(),
+         utils::Vector{Return(Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))},
          utils::Vector{Stage(ast::PipelineStage::kFragment)},
          utils::Vector{Location(1_i), Interpolate(builtin::InterpolationType::kLinear,
                                                   builtin::InterpolationSampling::kCentroid)});
diff --git a/src/tint/ir/ir_test_helper.h b/src/tint/ir/ir_test_helper.h
index 737a596..0406606 100644
--- a/src/tint/ir/ir_test_helper.h
+++ b/src/tint/ir/ir_test_helper.h
@@ -34,15 +34,6 @@
     Builder b{mod};
     /// The type manager
     type::Manager& ty{mod.Types()};
-
-    /// Alias to builtin::AddressSpace::kStorage
-    static constexpr auto storage = builtin::AddressSpace::kStorage;
-    /// Alias to builtin::AddressSpace::kUniform
-    static constexpr auto uniform = builtin::AddressSpace::kUniform;
-    /// Alias to builtin::AddressSpace::kPrivate
-    static constexpr auto private_ = builtin::AddressSpace::kPrivate;
-    /// Alias to builtin::AddressSpace::kFunction
-    static constexpr auto function = builtin::AddressSpace::kFunction;
 };
 
 using IRTestHelper = IRTestHelperBase<testing::Test>;
diff --git a/src/tint/ir/load_test.cc b/src/tint/ir/load_test.cc
index 0cfba85..6f9ddb1 100644
--- a/src/tint/ir/load_test.cc
+++ b/src/tint/ir/load_test.cc
@@ -21,14 +21,14 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using IR_LoadTest = IRTestHelper;
 
 TEST_F(IR_LoadTest, Create) {
     auto* store_type = ty.i32();
-    auto* var =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, store_type, builtin::Access::kReadWrite));
+    auto* var = b.Var(ty.ptr<function, i32>());
     auto* inst = b.Load(var);
 
     ASSERT_TRUE(inst->Is<Load>());
@@ -41,9 +41,7 @@
 }
 
 TEST_F(IR_LoadTest, Usage) {
-    auto* store_type = ty.i32();
-    auto* var =
-        b.Var(ty.ptr(builtin::AddressSpace::kFunction, store_type, builtin::Access::kReadWrite));
+    auto* var = b.Var(ty.ptr<function, i32>());
     auto* inst = b.Load(var);
 
     ASSERT_NE(inst->From(), nullptr);
@@ -71,13 +69,7 @@
 }
 
 TEST_F(IR_LoadTest, Fail_NullValue) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-            Load l(nullptr);
-        },
-        "");
+    EXPECT_FATAL_FAILURE({ Load l(nullptr); }, "");
 }
 
 }  // namespace
diff --git a/src/tint/ir/module_test.cc b/src/tint/ir/module_test.cc
index 61cd5d4..d2621aa 100644
--- a/src/tint/ir/module_test.cc
+++ b/src/tint/ir/module_test.cc
@@ -19,37 +19,33 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
-class IR_ModuleTest : public IRTestHelper {
-  protected:
-    const type::Pointer* ptr(const type::Type* elem) {
-        return ty.ptr(builtin::AddressSpace::kFunction, elem, builtin::Access::kReadWrite);
-    }
-};
+using IR_ModuleTest = IRTestHelper;
 
 TEST_F(IR_ModuleTest, NameOfUnnamed) {
-    auto* v = mod.values.Create<ir::Var>(ptr(ty.i32()));
+    auto* v = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
     EXPECT_FALSE(mod.NameOf(v).IsValid());
 }
 
 TEST_F(IR_ModuleTest, SetName) {
-    auto* v = mod.values.Create<ir::Var>(ptr(ty.i32()));
+    auto* v = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
     EXPECT_EQ(mod.SetName(v, "a").Name(), "a");
     EXPECT_EQ(mod.NameOf(v).Name(), "a");
 }
 
 TEST_F(IR_ModuleTest, SetNameRename) {
-    auto* v = mod.values.Create<ir::Var>(ptr(ty.i32()));
+    auto* v = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
     EXPECT_EQ(mod.SetName(v, "a").Name(), "a");
     EXPECT_EQ(mod.SetName(v, "b").Name(), "b");
     EXPECT_EQ(mod.NameOf(v).Name(), "b");
 }
 
 TEST_F(IR_ModuleTest, SetNameCollision) {
-    auto* a = mod.values.Create<ir::Var>(ptr(ty.i32()));
-    auto* b = mod.values.Create<ir::Var>(ptr(ty.i32()));
-    auto* c = mod.values.Create<ir::Var>(ptr(ty.i32()));
+    auto* a = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
+    auto* b = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
+    auto* c = mod.values.Create<ir::Var>(ty.ptr<function, i32>());
     EXPECT_EQ(mod.SetName(a, "x").Name(), "x");
     EXPECT_EQ(mod.SetName(b, "x_1").Name(), "x_1");
     EXPECT_EQ(mod.SetName(c, "x").Name(), "x_2");
diff --git a/src/tint/ir/program_test_helper.h b/src/tint/ir/program_test_helper.h
index 3ce88f0..d982366 100644
--- a/src/tint/ir/program_test_helper.h
+++ b/src/tint/ir/program_test_helper.h
@@ -20,9 +20,9 @@
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/ir/disassembler.h"
 #include "src/tint/ir/from_program.h"
-#include "src/tint/number.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/string_stream.h"
 
diff --git a/src/tint/ir/store_test.cc b/src/tint/ir/store_test.cc
index 5578005..5582eb4 100644
--- a/src/tint/ir/store_test.cc
+++ b/src/tint/ir/store_test.cc
@@ -21,13 +21,13 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using IR_StoreTest = IRTestHelper;
 
 TEST_F(IR_StoreTest, CreateStore) {
-    auto* to = b.Var(mod.Types().ptr(builtin::AddressSpace::kPrivate, mod.Types().i32(),
-                                     builtin::Access::kReadWrite));
+    auto* to = b.Var(ty.ptr<private_, i32>());
     auto* inst = b.Store(to, 4_i);
 
     ASSERT_TRUE(inst->Is<Store>());
@@ -65,8 +65,7 @@
         {
             Module mod;
             Builder b{mod};
-            auto* to = b.Var(mod.Types().ptr(builtin::AddressSpace::kPrivate, mod.Types().i32(),
-                                             builtin::Access::kReadWrite));
+            auto* to = b.Var(mod.Types().ptr<private_, i32>());
             b.Store(to, nullptr);
         },
         "");
diff --git a/src/tint/ir/swizzle_test.cc b/src/tint/ir/swizzle_test.cc
index ada269d4..58df467 100644
--- a/src/tint/ir/swizzle_test.cc
+++ b/src/tint/ir/swizzle_test.cc
@@ -18,6 +18,8 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ir/ir_test_helper.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+
 namespace tint::ir {
 namespace {
 
diff --git a/src/tint/ir/transform/block_decorated_structs_test.cc b/src/tint/ir/transform/block_decorated_structs_test.cc
index e86c563..a333894 100644
--- a/src/tint/ir/transform/block_decorated_structs_test.cc
+++ b/src/tint/ir/transform/block_decorated_structs_test.cc
@@ -21,13 +21,14 @@
 #include "src/tint/type/pointer.h"
 #include "src/tint/type/struct.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 namespace tint::ir::transform {
 namespace {
 
 using IR_BlockDecoratedStructsTest = TransformTest;
 
-using namespace tint::number_suffixes;  // NOLINT
-
 TEST_F(IR_BlockDecoratedStructsTest, NoRootBlock) {
     auto* func = b.Function("foo", ty.void_());
     func->StartTarget()->Append(b.Return(func));
@@ -116,7 +117,7 @@
 }
 
 TEST_F(IR_BlockDecoratedStructsTest, RuntimeArray) {
-    auto* buffer = b.Var(ty.ptr(storage, ty.runtime_array(ty.i32()), builtin::Access::kReadWrite));
+    auto* buffer = b.Var(ty.ptr<storage, array<i32>>());
     buffer->SetBindingPoint(0, 0);
     b.RootBlock()->Append(buffer);
 
@@ -219,8 +220,7 @@
     buffer->SetBindingPoint(0, 0);
     b.RootBlock()->Append(buffer);
 
-    auto* private_var =
-        b.Var(ty.ptr(builtin::AddressSpace::kPrivate, structure, builtin::Access::kReadWrite));
+    auto* private_var = b.Var(ty.ptr<private_, read_write>(structure));
     b.RootBlock()->Append(private_var);
 
     auto* func = b.Function("foo", ty.void_());
diff --git a/src/tint/ir/transform/test_helper.h b/src/tint/ir/transform/test_helper.h
index ea75fcf..83ff8c2 100644
--- a/src/tint/ir/transform/test_helper.h
+++ b/src/tint/ir/transform/test_helper.h
@@ -60,15 +60,6 @@
     /// The type manager.
     type::Manager& ty{mod.Types()};
 
-    /// Alias to builtin::AddressSpace::kStorage
-    static constexpr auto storage = builtin::AddressSpace::kStorage;
-    /// Alias to builtin::AddressSpace::kUniform
-    static constexpr auto uniform = builtin::AddressSpace::kUniform;
-    /// Alias to builtin::AddressSpace::kPrivate
-    static constexpr auto private_ = builtin::AddressSpace::kPrivate;
-    /// Alias to builtin::AddressSpace::kFunction
-    static constexpr auto function = builtin::AddressSpace::kFunction;
-
   private:
     std::vector<std::unique_ptr<Source::File>> files_;
 };
diff --git a/src/tint/ir/transform/var_for_dynamic_index_test.cc b/src/tint/ir/transform/var_for_dynamic_index_test.cc
index 6b64025..d9b7b8c 100644
--- a/src/tint/ir/transform/var_for_dynamic_index_test.cc
+++ b/src/tint/ir/transform/var_for_dynamic_index_test.cc
@@ -21,17 +21,13 @@
 #include "src/tint/type/matrix.h"
 #include "src/tint/type/struct.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 namespace tint::ir::transform {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
-
-class IR_VarForDynamicIndexTest : public TransformTest {
-  protected:
-    const type::Type* ptr(const type::Type* elem) {
-        return ty.ptr(builtin::AddressSpace::kFunction, elem, builtin::Access::kReadWrite);
-    }
-};
+using IR_VarForDynamicIndexTest = TransformTest;
 
 TEST_F(IR_VarForDynamicIndexTest, NoModify_ConstantIndex_ArrayValue) {
     auto* arr = b.FunctionParam(ty.array<i32, 4u>());
@@ -82,13 +78,13 @@
 }
 
 TEST_F(IR_VarForDynamicIndexTest, NoModify_DynamicIndex_ArrayPointer) {
-    auto* arr = b.FunctionParam(ptr(ty.array<i32, 4u>()));
+    auto* arr = b.FunctionParam(ty.ptr<function, array<i32, 4u>>());
     auto* idx = b.FunctionParam(ty.i32());
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arr, idx});
 
     auto* block = func->StartTarget();
-    auto* access = block->Append(b.Access(ptr(ty.i32()), arr, idx));
+    auto* access = block->Append(b.Access(ty.ptr<function, i32>(), arr, idx));
     auto* load = block->Append(b.Load(access));
     block->Append(b.Return(func, load));
     mod.functions.Push(func);
@@ -109,13 +105,13 @@
 }
 
 TEST_F(IR_VarForDynamicIndexTest, NoModify_DynamicIndex_MatrixPointer) {
-    auto* mat = b.FunctionParam(ptr(ty.mat2x2<f32>()));
+    auto* mat = b.FunctionParam(ty.ptr<function, mat2x2<f32>>());
     auto* idx = b.FunctionParam(ty.i32());
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({mat, idx});
 
     auto* block = func->StartTarget();
-    auto* access = block->Append(b.Access(ptr(ty.f32()), mat, idx, idx));
+    auto* access = block->Append(b.Access(ty.ptr<function, f32>(), mat, idx, idx));
     auto* load = block->Append(b.Load(access));
     block->Append(b.Return(func, load));
     mod.functions.Push(func);
diff --git a/src/tint/ir/validate_test.cc b/src/tint/ir/validate_test.cc
index d49b0dd..b24843e 100644
--- a/src/tint/ir/validate_test.cc
+++ b/src/tint/ir/validate_test.cc
@@ -22,17 +22,17 @@
 #include "src/tint/type/pointer.h"
 #include "src/tint/type/struct.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
-
 using IR_ValidateTest = IRTestHelper;
 
 TEST_F(IR_ValidateTest, RootBlock_Var) {
     mod.root_block = b.RootBlock();
-    mod.root_block->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite)));
+    mod.root_block->Append(b.Var(ty.ptr<private_, i32>()));
     auto res = ir::Validate(mod);
     EXPECT_TRUE(res) << res.Failure().str();
 }
@@ -113,8 +113,7 @@
 
 TEST_F(IR_ValidateTest, Valid_Access_Ptr) {
     auto* f = b.Function("my_func", ty.void_());
-    auto* obj = b.FunctionParam(
-        ty.ptr(builtin::AddressSpace::kPrivate, ty.mat3x2<f32>(), builtin::Access::kReadWrite));
+    auto* obj = b.FunctionParam(ty.ptr<private_, mat3x2<f32>>());
     f->SetParams({obj});
     mod.functions.Push(f);
 
@@ -192,8 +191,7 @@
 
 TEST_F(IR_ValidateTest, Access_OOB_Index_Ptr) {
     auto* f = b.Function("my_func", ty.void_());
-    auto* obj = b.FunctionParam(
-        ty.ptr(builtin::AddressSpace::kPrivate, ty.mat3x2<f32>(), builtin::Access::kReadWrite));
+    auto* obj = b.FunctionParam(ty.ptr<private_, mat3x2<f32>>());
     f->SetParams({obj});
     mod.functions.Push(f);
 
@@ -341,8 +339,7 @@
     auto* str_ty = ty.Get<type::Struct>(mod.symbols.New(), std::move(members), 4u, 8u, 8u);
 
     auto* f = b.Function("my_func", ty.void_());
-    auto* obj = b.FunctionParam(
-        ty.ptr(builtin::AddressSpace::kPrivate, str_ty, builtin::Access::kReadWrite));
+    auto* obj = b.FunctionParam(ty.ptr<private_, read_write>(str_ty));
     auto* idx = b.FunctionParam(ty.i32());
     f->SetParams({obj, idx});
     mod.functions.Push(f);
@@ -410,8 +407,7 @@
 
 TEST_F(IR_ValidateTest, Access_Incorrect_Type_Ptr_Ptr) {
     auto* f = b.Function("my_func", ty.void_());
-    auto* obj = b.FunctionParam(
-        ty.ptr(builtin::AddressSpace::kPrivate, ty.mat3x2<f32>(), builtin::Access::kReadWrite));
+    auto* obj = b.FunctionParam(ty.ptr<private_, mat3x2<f32>>());
     f->SetParams({obj});
     mod.functions.Push(f);
 
@@ -443,8 +439,7 @@
 
 TEST_F(IR_ValidateTest, Access_Incorrect_Type_Ptr_Value) {
     auto* f = b.Function("my_func", ty.void_());
-    auto* obj = b.FunctionParam(
-        ty.ptr(builtin::AddressSpace::kPrivate, ty.mat3x2<f32>(), builtin::Access::kReadWrite));
+    auto* obj = b.FunctionParam(ty.ptr<private_, mat3x2<f32>>());
     f->SetParams({obj});
     mod.functions.Push(f);
 
diff --git a/src/tint/ir/var_test.cc b/src/tint/ir/var_test.cc
index 7173237..1896e05 100644
--- a/src/tint/ir/var_test.cc
+++ b/src/tint/ir/var_test.cc
@@ -23,7 +23,9 @@
 namespace tint::ir {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using IR_VarTest = IRTestHelper;
 
 TEST_F(IR_VarTest, Fail_NullType) {
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 52a73b3..4f4788f 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -76,10 +76,11 @@
 #include "src/tint/ast/while_statement.h"
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/builtin/extension.h"
+#include "src/tint/builtin/fluent_types.h"
 #include "src/tint/builtin/interpolation_sampling.h"
 #include "src/tint/builtin/interpolation_type.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/manager.h"
-#include "src/tint/number.h"
 #include "src/tint/program.h"
 #include "src/tint/program_id.h"
 #include "src/tint/sem/array_count.h"
@@ -117,13 +118,10 @@
 
 namespace tint {
 
-// A sentinel type used by some template arguments to signal that the a type should be inferred.
-struct Infer {};
-
 /// Evaluates to true if T is a Infer, AInt or AFloat.
 template <typename T>
 static constexpr const bool IsInferOrAbstract =
-    std::is_same_v<std::decay_t<T>, Infer> || IsAbstract<std::decay_t<T>>;
+    std::is_same_v<std::decay_t<T>, builtin::fluent_types::Infer> || IsAbstract<std::decay_t<T>>;
 
 // Forward declare metafunction that evaluates to true iff T can be wrapped in a statement.
 template <typename T, typename = void>
@@ -1007,17 +1005,6 @@
             return array(builder->source_, subtype, std::move(attrs));
         }
 
-        /// @param subtype the array element type
-        /// @param n the array size. nullptr represents a runtime-array
-        /// @param attrs the optional attributes for the array
-        /// @return an array of size `n` of type `T`
-        template <typename COUNT, typename = DisableIfVectorLike<COUNT>>
-        ast::Type array(ast::Type subtype,
-                        COUNT&& n,
-                        utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            return array(builder->source_, subtype, std::forward<COUNT>(n), std::move(attrs));
-        }
-
         /// @param source the Source of the node
         /// @param subtype the array element type
         /// @param attrs the optional attributes for the array
@@ -1033,6 +1020,17 @@
                                                           std::move(attrs)))};
         }
 
+        /// @param subtype the array element type
+        /// @param n the array size. nullptr represents a runtime-array
+        /// @param attrs the optional attributes for the array
+        /// @return an array of size `n` of type `T`
+        template <typename COUNT, typename = DisableIfVectorLike<COUNT>>
+        ast::Type array(ast::Type subtype,
+                        COUNT&& n,
+                        utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
+            return array(builder->source_, subtype, std::forward<COUNT>(n), std::move(attrs));
+        }
+
         /// @param source the Source of the node
         /// @param subtype the array element type
         /// @param n the array size. nullptr represents a runtime-array
@@ -1054,53 +1052,47 @@
 
         /// @param source the Source of the node
         /// @return a inferred-size or runtime-sized array of type `T`
-        template <typename T, typename = EnableIfInferOrAbstract<T>>
+        template <typename T, int N = 0, typename = EnableIfInferOrAbstract<T>>
         ast::Type array(const Source& source) const {
+            static_assert(N == 0, "arrays with a count cannot be inferred");
             return (*this)(source, "array");
         }
 
         /// @return a inferred-size or runtime-sized array of type `T`
-        template <typename T, typename = EnableIfInferOrAbstract<T>>
+        template <typename T, int N = 0, typename = EnableIfInferOrAbstract<T>>
         ast::Type array() const {
+            static_assert(N == 0, "arrays with a count cannot be inferred");
             return array<T>(builder->source_);
         }
 
         /// @param source the Source of the node
         /// @param attrs the optional attributes for the array
         /// @return a inferred-size or runtime-sized array of type `T`
-        template <typename T, typename = DisableIfInferOrAbstract<T>>
+        template <typename T, int N = 0, typename = DisableIfInferOrAbstract<T>>
         ast::Type array(const Source& source,
                         utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            return ast::Type{builder->Expr(
-                builder->create<ast::TemplatedIdentifier>(source, builder->Sym("array"),
-                                                          utils::Vector<const ast::Expression*, 1>{
-                                                              Of<T>().expr,
-                                                          },
-                                                          std::move(attrs)))};
-        }
-
-        /// @param attrs the optional attributes for the array
-        /// @return a inferred-size or runtime-sized array of type `T`
-        template <typename T, typename = DisableIfInferOrAbstract<T>>
-        ast::Type array(utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            return array<T>(builder->source_, std::move(attrs));
-        }
-
-        /// @param source the Source of the node
-        /// @param attrs the optional attributes for the array
-        /// @return an array of size `N` of type `T`
-        template <typename T, int N>
-        ast::Type array(const Source& source,
-                        utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            static_assert(!IsInferOrAbstract<T>, "arrays with a count cannot be inferred");
-            return array(source, Of<T>(), tint::u32(N), std::move(attrs));
+            if constexpr (N == 0) {
+                return ast::Type{builder->Expr(builder->create<ast::TemplatedIdentifier>(
+                    source, builder->Sym("array"),
+                    utils::Vector<const ast::Expression*, 1>{
+                        Of<T>().expr,
+                    },
+                    std::move(attrs)))};
+            } else {
+                return ast::Type{builder->Expr(builder->create<ast::TemplatedIdentifier>(
+                    source, builder->Sym("array"),
+                    utils::Vector{
+                        Of<T>().expr,
+                        builder->Expr(builder->source_, tint::u32(N)),
+                    },
+                    std::move(attrs)))};
+            }
         }
 
         /// @param attrs the optional attributes for the array
         /// @return an array of size `N` of type `T`
-        template <typename T, int N>
+        template <typename T, int N = 0, typename = DisableIfInferOrAbstract<T>>
         ast::Type array(utils::VectorRef<const ast::Attribute*> attrs = utils::Empty) const {
-            static_assert(!IsInferOrAbstract<T>, "arrays with a count cannot be inferred");
             return array<T, N>(builder->source_, std::move(attrs));
         }
 
@@ -1160,9 +1152,48 @@
         }
 
         /// @param source the Source of the node
+        /// @return the pointer to type `T` with the builtin::AddressSpace `ADDRESS` and access
+        /// control `ACCESS`.
+        template <builtin::AddressSpace ADDRESS,
+                  typename T,
+                  builtin::Access ACCESS = builtin::Access::kUndefined>
+        ast::Type ptr(const Source& source) const {
+            return ptr<T>(source, ADDRESS, ACCESS);
+        }
+
+        /// @param type the type of the pointer
+        /// @return the pointer to the given type with the builtin::AddressSpace `ADDRESS` and
+        /// access control `ACCESS`.
+        template <builtin::AddressSpace ADDRESS,
+                  builtin::Access ACCESS = builtin::Access::kUndefined>
+        ast::Type ptr(ast::Type type) const {
+            return ptr(builder->source_, ADDRESS, type, ACCESS);
+        }
+
+        /// @param source the Source of the node
+        /// @param type the type of the pointer
+        /// @return the pointer to the given type with the builtin::AddressSpace `ADDRESS` and
+        /// access control `ACCESS`.
+        template <builtin::AddressSpace ADDRESS,
+                  builtin::Access ACCESS = builtin::Access::kUndefined>
+        ast::Type ptr(const Source& source, ast::Type type) const {
+            return ptr(source, ADDRESS, type, ACCESS);
+        }
+
+        /// @return the pointer to type `T` with the builtin::AddressSpace `ADDRESS` and access
+        /// control `ACCESS`.
+        template <builtin::AddressSpace ADDRESS,
+                  typename T,
+                  builtin::Access ACCESS = builtin::Access::kUndefined>
+        ast::Type ptr() const {
+            return ptr<T>(builder->source_, ADDRESS, ACCESS);
+        }
+
+        /// @param source the Source of the node
         /// @param address_space the address space of the pointer
         /// @param access the optional access control of the pointer
-        /// @return the pointer to type `T` with the given builtin::AddressSpace.
+        /// @return the pointer to type `T` the builtin::AddressSpace `ADDRESS` and access control
+        /// `ACCESS`.
         template <typename T>
         ast::Type ptr(const Source& source,
                       builtin::AddressSpace address_space,
@@ -1654,325 +1685,6 @@
         return Call(source, ty.vec(type, size), std::forward<ARGS>(args)...);
     }
 
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 2-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* vec2(ARGS&&... args) {
-        return vec2<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 2-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* vec2(const Source& source, ARGS&&... args) {
-        return Call(source, ty.vec2<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 2-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec2(ast::Type type, ARGS&&... args) {
-        return vec2(source_, type, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 2-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec2(const Source& source, ast::Type type, ARGS&&... args) {
-        return Call(source, ty.vec2(type), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 3-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* vec3(ARGS&&... args) {
-        return vec3<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 3-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* vec3(const Source& source, ARGS&&... args) {
-        return Call(source, ty.vec3<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 3-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec3(ast::Type type, ARGS&&... args) {
-        return vec3(source_, type, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 3-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec3(const Source& source, ast::Type type, ARGS&&... args) {
-        return Call(source, ty.vec3(type), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 4-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* vec4(ARGS&&... args) {
-        return vec4<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 4-element vector of type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* vec4(const Source& source, ARGS&&... args) {
-        return Call(source, ty.vec4<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 4-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec4(ast::Type type, ARGS&&... args) {
-        return vec4(source_, type, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the vector source
-    /// @param type the element type of the vector
-    /// @param args the arguments for the vector constructor
-    /// @return an `ast::CallExpression` of a 4-element vector of type @p type, constructed with the
-    /// values @p args.
-    template <typename... ARGS>
-    const ast::CallExpression* vec4(const Source& source, ast::Type type, ARGS&&... args) {
-        return Call(source, ty.vec4(type), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat2x2(ARGS&&... args) {
-        return mat2x2<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat2x2(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat2x2<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat2x3(ARGS&&... args) {
-        return mat2x3<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat2x3(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat2x3<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat2x4(ARGS&&... args) {
-        return mat2x4<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 2x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat2x4(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat2x4<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat3x2(ARGS&&... args) {
-        return mat3x2<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat3x2(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat3x2<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat3x3(ARGS&&... args) {
-        return mat3x3<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat3x3(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat3x3<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat3x4(ARGS&&... args) {
-        return mat3x4<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 3x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat3x4(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat3x4<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat4x2(ARGS&&... args) {
-        return mat4x2<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x2 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat4x2(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat4x2<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat4x3(ARGS&&... args) {
-        return mat4x3<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x3 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat4x3(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat4x3<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* mat4x4(ARGS&&... args) {
-        return mat4x4<T>(source_, std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the matrix source
-    /// @param args the arguments for the matrix constructor
-    /// @return an `ast::CallExpression` of a 4x4 matrix of type
-    /// `T`, constructed with the values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* mat4x4(const Source& source, ARGS&&... args) {
-        return Call(source, ty.mat4x4<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* array(ARGS&&... args) {
-        return Call(ty.array<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the array source
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type `T`, constructed with the
-    /// values @p args.
-    template <typename T, typename... ARGS>
-    const ast::CallExpression* array(const Source& source, ARGS&&... args) {
-        return Call(source, ty.array<T>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type `T` and size `N`, constructed
-    /// with the values @p args.
-    template <typename T, int N, typename... ARGS, typename = DisableIfSource<ARGS...>>
-    const ast::CallExpression* array(ARGS&&... args) {
-        return Call(ty.array<T, N>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the array source
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type `T` and size `N`, constructed
-    /// with the values @p args.
-    template <typename T, int N, typename... ARGS>
-    const ast::CallExpression* array(const Source& source, ARGS&&... args) {
-        return Call(source, ty.array<T, N>(), std::forward<ARGS>(args)...);
-    }
-
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array.
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type
-    /// `subtype`, constructed with the values @p args.
-    template <typename EXPR, typename... ARGS>
-    const ast::CallExpression* array(ast::Type subtype, EXPR&& n, ARGS&&... args) {
-        return Call(ty.array(subtype, std::forward<EXPR>(n)), std::forward<ARGS>(args)...);
-    }
-
-    /// @param source the array source
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array.
-    /// @param args the arguments for the array constructor
-    /// @return an `ast::CallExpression` of an array with element type
-    /// `subtype`, constructed with the values @p args.
-    template <typename EXPR, typename... ARGS>
-    const ast::CallExpression* array(const Source& source,
-                                     ast::Type subtype,
-                                     EXPR&& n,
-                                     ARGS&&... args) {
-        return Call(source, ty.array(subtype, std::forward<EXPR>(n)), std::forward<ARGS>(args)...);
-    }
-
     /// Adds the extension to the list of enable directives at the top of the module.
     /// @param extension the extension to enable
     /// @return an `ast::Enable` enabling the given extension.
@@ -3933,6 +3645,28 @@
 struct ProgramBuilder::TypesBuilder::CToAST<bool> {
     static ast::Type get(const ProgramBuilder::TypesBuilder* t) { return t->bool_(); }
 };
+template <typename T, uint32_t N>
+struct ProgramBuilder::TypesBuilder::CToAST<tint::builtin::fluent_types::array<T, N>> {
+    static ast::Type get(const ProgramBuilder::TypesBuilder* t) { return t->array<T, N>(); }
+};
+template <typename T>
+struct ProgramBuilder::TypesBuilder::CToAST<tint::builtin::fluent_types::atomic<T>> {
+    static ast::Type get(const ProgramBuilder::TypesBuilder* t) { return t->atomic<T>(); }
+};
+template <uint32_t C, uint32_t R, typename T>
+struct ProgramBuilder::TypesBuilder::CToAST<tint::builtin::fluent_types::mat<C, R, T>> {
+    static ast::Type get(const ProgramBuilder::TypesBuilder* t) { return t->mat<T>(C, R); }
+};
+template <uint32_t N, typename T>
+struct ProgramBuilder::TypesBuilder::CToAST<tint::builtin::fluent_types::vec<N, T>> {
+    static ast::Type get(const ProgramBuilder::TypesBuilder* t) { return t->vec<T, N>(); }
+};
+template <builtin::AddressSpace ADDRESS, typename T, builtin::Access ACCESS>
+struct ProgramBuilder::TypesBuilder::CToAST<tint::builtin::fluent_types::ptr<ADDRESS, T, ACCESS>> {
+    static ast::Type get(const ProgramBuilder::TypesBuilder* t) {
+        return t->ptr<ADDRESS, T, ACCESS>();
+    }
+};
 //! @endcond
 
 /// @param builder the ProgramBuilder
diff --git a/src/tint/program_id.h b/src/tint/program_id.h
index 4169ba1..35ab476 100644
--- a/src/tint/program_id.h
+++ b/src/tint/program_id.h
@@ -103,11 +103,11 @@
 /// valid program identifiers.
 #if TINT_CHECK_FOR_CROSS_PROGRAM_LEAKS
 #define TINT_ASSERT_PROGRAM_IDS_EQUAL(system, a, b)                        \
-    detail::AssertProgramIDsEqual(                                         \
+    tint::detail::AssertProgramIDsEqual(                                   \
         ProgramIDOf(a), ProgramIDOf(b), false, tint::diag::System::system, \
         "TINT_ASSERT_PROGRAM_IDS_EQUAL(" #system "," #a ", " #b ")", __FILE__, __LINE__)
 #define TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(system, a, b)              \
-    detail::AssertProgramIDsEqual(                                        \
+    tint::detail::AssertProgramIDsEqual(                                  \
         ProgramIDOf(a), ProgramIDOf(b), true, tint::diag::System::system, \
         "TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(" #system ", " #a ", " #b ")", __FILE__, __LINE__)
 #else
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 304a545..ac42988 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -25,8 +25,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/debug.h"
-#include "src/tint/number.h"
 #include "src/tint/utils/parse_num.h"
 #include "src/tint/utils/unicode.h"
 
diff --git a/src/tint/reader/wgsl/lexer_test.cc b/src/tint/reader/wgsl/lexer_test.cc
index 8d49bf8..a705de0 100644
--- a/src/tint/reader/wgsl/lexer_test.cc
+++ b/src/tint/reader/wgsl/lexer_test.cc
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "gtest/gtest.h"
-#include "src/tint/number.h"
+#include "src/tint/builtin/number.h"
 
 namespace tint::reader::wgsl {
 namespace {
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index b167f56..1151fc4 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -121,9 +121,9 @@
         /// std::unique_ptr, operator->() automatically dereferences so that the
         /// return type will always be a pointer to a non-pointer type. #errored
         /// must be false to call.
-        inline typename detail::OperatorArrow<T>::type operator->() {
+        inline typename wgsl::detail::OperatorArrow<T>::type operator->() {
             TINT_ASSERT(Reader, !errored);
-            return detail::OperatorArrow<T>::ptr(value);
+            return wgsl::detail::OperatorArrow<T>::ptr(value);
         }
 
         /// The expected value of a successful parse.
@@ -183,9 +183,9 @@
         /// std::unique_ptr, operator->() automatically dereferences so that the
         /// return type will always be a pointer to a non-pointer type. #errored
         /// must be false to call.
-        inline typename detail::OperatorArrow<T>::type operator->() {
+        inline typename wgsl::detail::OperatorArrow<T>::type operator->() {
             TINT_ASSERT(Reader, !errored);
-            return detail::OperatorArrow<T>::ptr(value);
+            return wgsl::detail::OperatorArrow<T>::ptr(value);
         }
 
         /// The value of a successful parse.
diff --git a/src/tint/reflection.h b/src/tint/reflection.h
index d341f98..e965200 100644
--- a/src/tint/reflection.h
+++ b/src/tint/reflection.h
@@ -36,7 +36,7 @@
 
 /// Is true if the class T has reflected its fields with TINT_REFLECT()
 template <typename T>
-static constexpr bool HasReflection = detail::HasReflection<T>::value;
+static constexpr bool HasReflection = tint::detail::HasReflection<T>::value;
 
 /// Calls @p callback with each field of @p object
 /// @param object the object
diff --git a/src/tint/resolver/address_space_layout_validation_test.cc b/src/tint/resolver/address_space_layout_validation_test.cc
index 9a621e3..1006120 100644
--- a/src/tint/resolver/address_space_layout_validation_test.cc
+++ b/src/tint/resolver/address_space_layout_validation_test.cc
@@ -17,11 +17,12 @@
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverAddressSpaceLayoutValidationTest = ResolverTest;
 
 // Detect unaligned member for storage buffers
@@ -430,7 +431,7 @@
     // @group(0) @binding(0)
     // var<uniform> a : Outer;
 
-    Alias("Inner", ty.array(ty.vec2<f32>(), 10_u));
+    Alias("Inner", ty.array<vec2<f32>, 10>());
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
@@ -739,7 +740,7 @@
 
     Structure(Source{{12, 34}}, "Outer",
               utils::Vector{
-                  Member("arr", ty.array(ty.vec3<f16>(), 10_u)),
+                  Member("arr", ty.array<vec3<f16>, 10>()),
               });
 
     GlobalVar(Source{{78, 90}}, "a", ty("Outer"), builtin::AddressSpace::kUniform, Group(0_a),
diff --git a/src/tint/resolver/address_space_validation_test.cc b/src/tint/resolver/address_space_validation_test.cc
index fae4a25..a5bd21e 100644
--- a/src/tint/resolver/address_space_validation_test.cc
+++ b/src/tint/resolver/address_space_validation_test.cc
@@ -18,11 +18,12 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/struct.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ::testing::HasSubstr;
 
 using ResolverAddressSpaceValidationTest = ResolverTest;
@@ -67,8 +68,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Private_RuntimeArray) {
     // type t : ptr<private, array<i32>>;
-    Alias("t", ty.ptr(Source{{56, 78}}, builtin::AddressSpace::kPrivate,
-                      ty.array(Source{{12, 34}}, ty.i32())));
+    Alias("t", ty.ptr<private_>(Source{{56, 78}}, ty.array(Source{{12, 34}}, ty.i32())));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -93,7 +93,7 @@
     // struct S { m : array<i32> };
     // type t = ptr<private, S>;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    Alias("t", ty.ptr(builtin::AddressSpace::kPrivate, ty("S")));
+    Alias("t", ty.ptr<private_>(ty("S")));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -115,7 +115,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Workgroup_RuntimeArray) {
     // type t = ptr<workgroup, array<i32>>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kWorkgroup, ty.array(Source{{12, 34}}, ty.i32())));
+    Alias("t", ty.ptr<workgroup>(ty.array(Source{{12, 34}}, ty.i32())));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -140,7 +140,7 @@
     // struct S { m : array<i32> };
     // type t = ptr<workgroup, S>;
     Structure("S", utils::Vector{Member(Source{{12, 34}}, "m", ty.array(ty.i32()))});
-    Alias(Source{{56, 78}}, "t", ty.ptr(builtin::AddressSpace::kWorkgroup, ty("S")));
+    Alias(Source{{56, 78}}, "t", ty.ptr<workgroup>(ty("S")));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -164,8 +164,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_Bool) {
     // type t = ptr<storage, bool>;
-    Alias(Source{{56, 78}}, "t",
-          ty.ptr(builtin::AddressSpace::kStorage, ty.bool_(Source{{12, 34}})));
+    Alias(Source{{56, 78}}, "t", ty.ptr<storage>(ty.bool_(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -194,8 +193,7 @@
     // type a = bool;
     // type t = ptr<storage, a>;
     Alias("a", ty.bool_());
-    Alias(Source{{56, 78}}, "t",
-          ty.ptr(builtin::AddressSpace::kStorage, ty(Source{{12, 34}}, "a")));
+    Alias(Source{{56, 78}}, "t", ty.ptr<storage>(ty(Source{{12, 34}}, "a")));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -207,8 +205,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_Storage_Pointer) {
     // var<storage> g : ptr<private, f32>;
-    GlobalVar(Source{{56, 78}}, "g",
-              ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32()),
+    GlobalVar(Source{{56, 78}}, "g", ty.ptr<private_, f32>(Source{{12, 34}}),
               builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -221,8 +218,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_Pointer) {
     // type t = ptr<storage, ptr<private, f32>>;
-    Alias("t", ty.ptr(Source{{56, 78}}, builtin::AddressSpace::kStorage,
-                      ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32())));
+    Alias("t", ty.ptr<storage>(Source{{56, 78}}, ty.ptr<private_, f32>(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -241,7 +237,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_IntScalar) {
     // type t = ptr<storage, i32;
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.i32()));
+    Alias("t", ty.ptr<storage, i32>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -261,7 +257,7 @@
     // type t = ptr<storage, f16>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.f16()));
+    Alias("t", ty.ptr<storage, f16>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -285,7 +281,7 @@
     Enable(builtin::Extension::kF16);
 
     Alias("a", ty.f16());
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty("a")));
+    Alias("t", ty.ptr<storage>(ty("a")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -299,7 +295,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF32) {
     // type t = ptr<storage, vec4<f32>>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.vec4<f32>()));
+    Alias("t", ty.ptr<storage, vec4<f32>>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -315,7 +311,7 @@
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_VectorF16) {
     // type t = ptr<storage, vec4<f16>>;
     Enable(builtin::Extension::kF16);
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.vec(ty.f16(), 4u)));
+    Alias("t", ty.ptr<storage, vec4<f32>>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -334,7 +330,7 @@
     // struct S{ a : f32 };
     // type t = ptr<storage, array<S, 3u>>;
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.array(ty("S"), 3_u)));
+    Alias("t", ty.ptr<storage>(ty.array(ty("S"), 3_u)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -359,8 +355,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16())});
-    Alias("t",
-          ty.ptr(builtin::AddressSpace::kStorage, ty.array(ty("S"), 3_u), builtin::Access::kRead));
+    Alias("t", ty.ptr<storage, read>(ty.array(ty("S"), 3_u)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -379,7 +374,7 @@
     // struct S { x : i32 };
     // type t = ptr<storage, S, read>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty("S"), builtin::Access::kRead));
+    Alias("t", ty.ptr<storage, read>(ty("S")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -404,7 +399,7 @@
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty("a2"), builtin::Access::kRead));
+    Alias("t", ty.ptr<storage, read>(ty("a2")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -427,7 +422,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty("S"), builtin::Access::kRead));
+    Alias("t", ty.ptr<storage, read>(ty("S")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -456,7 +451,7 @@
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
     Alias("a2", ty("a1"));
-    Alias("g", ty.ptr(builtin::AddressSpace::kStorage, ty("a2"), builtin::Access::kRead));
+    Alias("g", ty.ptr<storage, read>(ty("a2")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -475,8 +470,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_NotStorage_AccessMode) {
     // type t = ptr<private, i32, read>;
-    Alias("t", ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.i32(),
-                      builtin::Access::kRead));
+    Alias("t", ty.ptr<private_, i32, read>(Source{{12, 34}}));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -495,7 +489,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadAccessMode) {
     // type t = ptr<storage, i32, read>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kRead));
+    Alias("t", ty.ptr<storage, i32, read>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -510,7 +504,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_ReadWriteAccessMode) {
     // type t = ptr<storage, i32, read_write>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
+    Alias("t", ty.ptr<storage, i32, read_write>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -527,9 +521,8 @@
 }
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_Storage_WriteAccessMode) {
-    // type t = ptr<storage, i32, read_write>;
-    Alias("t", ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kStorage, ty.i32(),
-                      builtin::Access::kWrite));
+    // type t = ptr<storage, i32, write>;
+    Alias("t", ty.ptr<storage, i32, write>(Source{{12, 34}}));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -561,7 +554,7 @@
     Structure("S",
               utils::Vector{Member(Source{{56, 78}}, "m", ty.array(Source{{12, 34}}, ty.i32()))});
 
-    Alias("t", ty.ptr(Source{{90, 12}}, builtin::AddressSpace::kUniform, ty("S")));
+    Alias("t", ty.ptr<uniform>(Source{{90, 12}}, ty("S")));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -589,8 +582,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferBool) {
     // type t = ptr<uniform, bool>;
-    Alias("t",
-          ty.ptr(Source{{56, 78}}, builtin::AddressSpace::kUniform, ty.bool_(Source{{12, 34}})));
+    Alias("t", ty.ptr<uniform>(Source{{56, 78}}, ty.bool_(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -619,8 +611,7 @@
     // type a = bool;
     // type t = ptr<uniform, a>;
     Alias("a", ty.bool_());
-    Alias("t",
-          ty.ptr(Source{{56, 78}}, builtin::AddressSpace::kUniform, ty(Source{{12, 34}}, "a")));
+    Alias("t", ty.ptr<uniform>(Source{{56, 78}}, ty(Source{{12, 34}}, "a")));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -632,8 +623,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, GlobalVariable_UniformPointer) {
     // var<uniform> g : ptr<private, f32>;
-    GlobalVar(Source{{56, 78}}, "g",
-              ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32()),
+    GlobalVar(Source{{56, 78}}, "g", ty.ptr<private_, f32>(Source{{12, 34}}),
               builtin::AddressSpace::kUniform, Binding(0_a), Group(0_a));
 
     ASSERT_FALSE(r()->Resolve());
@@ -646,8 +636,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformPointer) {
     // type t = ptr<uniform, ptr<private, f32>>;
-    Alias("t", ty.ptr(Source{{56, 78}}, builtin::AddressSpace::kUniform,
-                      ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32())));
+    Alias("t", ty.ptr<uniform>(Source{{56, 78}}, ty.ptr<private_, f32>(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
 
@@ -667,7 +656,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferIntScalar) {
     // type t = ptr<uniform, i32>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.i32()));
+    Alias("t", ty.ptr<uniform, i32>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -687,7 +676,7 @@
     // type t = ptr<uniform, f16>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.f16()));
+    Alias("t", ty.ptr<uniform, f16>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -701,7 +690,7 @@
 
 TEST_F(ResolverAddressSpaceValidationTest, PointerAlias_UniformBufferVectorF32) {
     // type t = ptr<uniform, vec4<f32>>;
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.vec4<f32>()));
+    Alias("t", ty.ptr<uniform, vec4<f32>>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -721,7 +710,7 @@
     // type t = ptr<uniform, vec4<f16>>;
     Enable(builtin::Extension::kF16);
 
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.vec4<f16>()));
+    Alias("t", ty.ptr<uniform, f16>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -744,7 +733,7 @@
     // }
     // type t = ptr<uniform, array<S, 3u>>;
     Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{MemberSize(16_a)})});
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.array(ty("S"), 3_u)));
+    Alias("t", ty.ptr<uniform>(ty.array(ty("S"), 3_u)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -773,7 +762,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("a", ty.f16(), utils::Vector{MemberSize(16_a)})});
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty.array(ty("S"), 3_u)));
+    Alias("t", ty.ptr<uniform>(ty.array(ty("S"), 3_u)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -791,7 +780,7 @@
     // struct S { x : i32 };
     // type t = ptr<uniform, S>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty("S")));
+    Alias("t", ty.ptr<uniform>(ty("S")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -813,7 +802,7 @@
     // type t = ptr<uniform, a1>;
     Structure("S", utils::Vector{Member("x", ty.i32())});
     Alias("a1", ty("S"));
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty("a1")));
+    Alias("t", ty.ptr<uniform>(ty("a1")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -837,7 +826,7 @@
     Enable(builtin::Extension::kF16);
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty("S")));
+    Alias("t", ty.ptr<uniform>(ty("S")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -865,7 +854,7 @@
 
     Structure("S", utils::Vector{Member("x", ty.f16())});
     Alias("a1", ty("S"));
-    Alias("t", ty.ptr(builtin::AddressSpace::kUniform, ty("a1")));
+    Alias("t", ty.ptr<uniform>(ty("a1")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -888,8 +877,7 @@
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, bool>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias(Source{{56, 78}}, "t",
-          ty.ptr(builtin::AddressSpace::kPushConstant, ty.bool_(Source{{12, 34}})));
+    Alias(Source{{56, 78}}, "t", ty.ptr<push_constant>(ty.bool_(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -917,7 +905,7 @@
     // type t = ptr<push_constant, f16>;
     Enable(builtin::Extension::kF16);
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.ptr(builtin::AddressSpace::kPushConstant, ty.f16(Source{{56, 78}})));
+    Alias("t", ty.ptr<push_constant>(ty.f16(Source{{56, 78}})));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -928,8 +916,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : ptr<private, f32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar(Source{{56, 78}}, "g",
-              ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32()),
+    GlobalVar(Source{{56, 78}}, "g", ty.ptr<private_, f32>(Source{{12, 34}}),
               builtin::AddressSpace::kPushConstant);
 
     ASSERT_FALSE(r()->Resolve());
@@ -943,9 +930,7 @@
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, ptr<private, f32>>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias(Source{{56, 78}}, "t",
-          ty.ptr(builtin::AddressSpace::kPushConstant,
-                 ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kPrivate, ty.f32())));
+    Alias(Source{{56, 78}}, "t", ty.ptr<push_constant>(ty.ptr<private_, f32>(Source{{12, 34}})));
 
     ASSERT_FALSE(r()->Resolve());
     EXPECT_EQ(
@@ -967,7 +952,7 @@
     // enable chromium_experimental_push_constant;
     // type t = ptr<push_constant, i32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.ptr(builtin::AddressSpace::kPushConstant, ty.i32()));
+    Alias("t", ty.ptr<push_constant, i32>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -985,7 +970,7 @@
     // enable chromium_experimental_push_constant;
     // var<push_constant> g : vec4<f32>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
-    Alias("t", ty.ptr(builtin::AddressSpace::kPushConstant, ty.vec4<f32>()));
+    Alias("t", ty.ptr<push_constant, vec4<f32>>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -1007,7 +992,7 @@
     // type t = ptr<push_constant, array<S, 3u>>;
     Enable(builtin::Extension::kChromiumExperimentalPushConstant);
     Structure("S", utils::Vector{Member("a", ty.f32())});
-    Alias("t", ty.ptr(builtin::AddressSpace::kPushConstant, ty.array(ty("S"), 3_u)));
+    Alias("t", ty.ptr<push_constant>(ty.array(ty("S"), 3_u)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/alias_analysis_test.cc b/src/tint/resolver/alias_analysis_test.cc
index 7eab9bc..21d8758 100644
--- a/src/tint/resolver/alias_analysis_test.cc
+++ b/src/tint/resolver/alias_analysis_test.cc
@@ -18,7 +18,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -726,8 +727,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
-             Param("p2", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
+             Param("p1", ty.ptr<function>(ty("S"))),
+             Param("p2", ty.ptr<function>(ty("S"))),
          },
          ty.void_(),
          utils::Vector{
@@ -755,8 +756,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
-             Param("p2", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
+             Param("p1", ty.ptr<function>(ty("S"))),
+             Param("p2", ty.ptr<function>(ty("S"))),
          },
          ty.void_(),
          utils::Vector{
@@ -787,8 +788,8 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
-             Param("p2", ty.ptr(builtin::AddressSpace::kFunction, ty("S"))),
+             Param("p1", ty.ptr<function>(ty("S"))),
+             Param("p2", ty.ptr<function>(ty("S"))),
          },
          ty.void_(),
          utils::Vector{
@@ -818,13 +819,13 @@
     Structure("S", utils::Vector{Member("a", ty.i32())});
     Func("f2",
          utils::Vector{
-             Param("p1", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>())),
-             Param("p2", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>())),
+             Param("p1", ty.ptr<function, vec4<f32>>()),
+             Param("p2", ty.ptr<function, vec4<f32>>()),
          },
          ty.void_(),
          utils::Vector{
              Assign(Phony(), MemberAccessor(Deref("p2"), "zy")),
-             Assign(Deref("p1"), Call(ty.vec4<f32>())),
+             Assign(Deref("p1"), Call<vec4<f32>>()),
          });
     Func("f1", utils::Empty, ty.void_(),
          utils::Vector{
diff --git a/src/tint/resolver/array_accessor_test.cc b/src/tint/resolver/array_accessor_test.cc
index 118bcff..f9bc250 100644
--- a/src/tint/resolver/array_accessor_test.cc
+++ b/src/tint/resolver/array_accessor_test.cc
@@ -19,7 +19,8 @@
 #include "src/tint/sem/index_accessor_expression.h"
 #include "src/tint/type/reference.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -65,7 +66,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic) {
-    GlobalConst("my_const", ty.mat2x3<f32>(), Call(ty.mat2x3<f32>()));
+    GlobalConst("my_const", ty.mat2x3<f32>(), Call<mat2x3<f32>>());
     auto* idx = Var("idx", ty.i32(), Call<i32>());
     auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
     WrapInFunction(Decl(idx), acc);
@@ -80,7 +81,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
-    GlobalConst("my_const", ty.mat4x4<f32>(), Call(ty.mat4x4<f32>()));
+    GlobalConst("my_const", ty.mat4x4<f32>(), Call<mat4x4<f32>>());
     auto* idx = Var("idx", ty.u32(), Expr(3_u));
     auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
     WrapInFunction(Decl(idx), acc);
@@ -90,7 +91,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
-    GlobalConst("my_const", ty.mat4x4<f32>(), Call(ty.mat4x4<f32>()));
+    GlobalConst("my_const", ty.mat4x4<f32>(), Call<mat4x4<f32>>());
     auto* idx = Var("idy", ty.u32(), Expr(2_u));
     auto* acc = IndexAccessor(IndexAccessor("my_const", Expr(Source{{12, 34}}, idx)), 1_i);
     WrapInFunction(Decl(idx), acc);
@@ -158,7 +159,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic) {
-    GlobalConst("my_const", ty.vec3<f32>(), Call(ty.vec3<f32>()));
+    GlobalConst("my_const", ty.vec3<f32>(), Call<vec3<f32>>());
     auto* idx = Var("idx", ty.i32(), Expr(2_i));
     auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
     WrapInFunction(Decl(idx), acc);
@@ -242,7 +243,7 @@
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Constant) {
-    GlobalConst("my_const", ty.array<f32, 3>(), array<f32, 3>());
+    GlobalConst("my_const", ty.array<f32, 3>(), Call<array<f32, 3>>());
 
     auto* acc = IndexAccessor("my_const", 2_i);
     WrapInFunction(acc);
@@ -257,7 +258,7 @@
     // let a : array<f32, 3> = 0;
     // var idx : i32 = 0;
     // var f : f32 = a[idx];
-    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* a = Let("a", ty.array<f32, 3>(), Call<array<f32, 3>>());
     auto* idx = Var("idx", ty.i32(), Call<i32>());
     auto* acc = IndexAccessor("a", Expr(Source{{12, 34}}, idx));
     auto* f = Var("f", ty.f32(), acc);
@@ -280,7 +281,7 @@
 TEST_F(ResolverIndexAccessorTest, Array_Literal_F32) {
     // let a : array<f32, 3>;
     // var f : f32 = a[2.0f];
-    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* a = Let("a", ty.array<f32, 3>(), Call<array<f32, 3>>());
     auto* f = Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2_f)));
     Func("my_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -294,7 +295,7 @@
 TEST_F(ResolverIndexAccessorTest, Array_Literal_I32) {
     // let a : array<f32, 3>;
     // var f : f32 = a[2i];
-    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* a = Let("a", ty.array<f32, 3>(), Call<array<f32, 3>>());
     auto* acc = IndexAccessor("a", 2_i);
     auto* f = Var("a_2", ty.f32(), acc);
     Func("my_func", utils::Empty, ty.void_(),
@@ -316,7 +317,7 @@
     //     let x: f32 = (*p)[idx];
     //     return x;
     // }
-    auto* p = Param("p", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()));
+    auto* p = Param("p", ty.ptr<function, vec4<f32>>());
     auto* idx = Let("idx", ty.u32(), Call<u32>());
     auto* star_p = Deref(p);
     auto* acc = IndexAccessor(Source{{12, 34}}, star_p, idx);
@@ -337,7 +338,7 @@
     //     let x: f32 = *p[idx];
     //     return x;
     // }
-    auto* p = Param("p", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()));
+    auto* p = Param("p", ty.ptr<function, vec4<f32>>());
     auto* idx = Let("idx", ty.u32(), Call<u32>());
     auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
     auto* star_p = Deref(accessor_expr);
diff --git a/src/tint/resolver/assignment_validation_test.cc b/src/tint/resolver/assignment_validation_test.cc
index bd4cd71..f1251cb 100644
--- a/src/tint/resolver/assignment_validation_test.cc
+++ b/src/tint/resolver/assignment_validation_test.cc
@@ -19,11 +19,12 @@
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverAssignmentValidationTest = ResolverTest;
 
 TEST_F(ResolverAssignmentValidationTest, ReadOnlyBuffer) {
@@ -182,9 +183,8 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b = 2i;
-    const auto func = builtin::AddressSpace::kFunction;
-    WrapInFunction(Var("a", ty.i32(), func, Expr(2_i)),                //
-                   Let("b", ty.ptr<i32>(func), AddressOf(Expr("a"))),  //
+    WrapInFunction(Var("a", ty.i32(), builtin::AddressSpace::kFunction, Expr(2_i)),  //
+                   Let("b", ty.ptr<function, i32>(), AddressOf(Expr("a"))),          //
                    Assign(Deref("b"), 2_i));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -194,9 +194,8 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b = 2;
-    const auto func = builtin::AddressSpace::kFunction;
-    auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
-    auto* var_b = Let("b", ty.ptr<i32>(func), AddressOf(Expr("a")));
+    auto* var_a = Var("a", ty.i32(), builtin::AddressSpace::kFunction, Expr(2_i));
+    auto* var_b = Let("b", ty.ptr<function, i32>(), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b, Assign(Deref("b"), 2_a));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -433,9 +432,9 @@
                    Assign(Phony(), 3_f),                                    //
                    Assign(Phony(), 4_a),                                    //
                    Assign(Phony(), 5.0_a),                                  //
-                   Assign(Phony(), vec2<Infer>(6_a)),                       //
-                   Assign(Phony(), vec3<Infer>(7.0_a)),                     //
-                   Assign(Phony(), vec4<bool>()),                           //
+                   Assign(Phony(), Call<vec2<Infer>>(6_a)),                 //
+                   Assign(Phony(), Call<vec3<Infer>>(7.0_a)),               //
+                   Assign(Phony(), Call<vec4<bool>>()),                     //
                    Assign(Phony(), "tex"),                                  //
                    Assign(Phony(), "smp"),                                  //
                    Assign(Phony(), AddressOf("s")),                         //
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 97af866..741641e 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -22,25 +22,14 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 
 // Helpers and typedefs
 template <typename T>
 using DataType = builder::DataType<T>;
-template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
 template <typename T, int ID = 0>
 using alias = builder::alias<T, ID>;
 template <typename T>
@@ -353,7 +342,7 @@
     auto* p = Param("a", ty.vec4<f32>(), attrs);
     Func("vertex_main", utils::Vector{p}, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
@@ -404,7 +393,7 @@
     auto& params = GetParam();
     Func("main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>(), 1_f)),
+             Return(Call<vec4<f32>>(1_f)),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kCompute),
@@ -456,7 +445,7 @@
     auto& params = GetParam();
     auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
     attrs.Push(Location(Source{{34, 56}}, 2_a));
-    Func("frag_main", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(Call(ty.vec4<f32>()))},
+    Func("frag_main", utils::Empty, ty.vec4<f32>(), utils::Vector{Return(Call<vec4<f32>>())},
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
          },
@@ -513,7 +502,7 @@
     }
     Func("vertex_main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
@@ -1602,8 +1591,10 @@
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Var("a", ty.vec4<f32>(), Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
-             Decl(Var("b", ty.vec4<f32>(), Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
+             Decl(Var("a", ty.vec4<f32>(),
+                      Call("textureLoad", "A", Call<vec2<i32>>(1_i, 2_i), 0_i))),
+             Decl(Var("b", ty.vec4<f32>(),
+                      Call("textureLoad", "B", Call<vec2<i32>>(1_i, 2_i), 0_i))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1624,14 +1615,16 @@
 
     Func("F_A", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Var("a", ty.vec4<f32>(), Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
+             Decl(Var("a", ty.vec4<f32>(),
+                      Call("textureLoad", "A", Call<vec2<i32>>(1_i, 2_i), 0_i))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
          });
     Func("F_B", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Var("b", ty.vec4<f32>(), Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
+             Decl(Var("b", ty.vec4<f32>(),
+                      Call("textureLoad", "B", Call<vec2<i32>>(1_i, 2_i), 0_i))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1663,7 +1656,7 @@
                         });
     Func("main", utils::Vector{param}, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1682,7 +1675,7 @@
                         });
     Func("main", utils::Vector{param}, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -1705,7 +1698,7 @@
 TEST_F(MustUseAttributeTests, MustUse) {
     Func("main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              MustUse(Source{{12, 34}}),
@@ -1964,7 +1957,7 @@
 TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
     Func("main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
diff --git a/src/tint/resolver/bitcast_validation_test.cc b/src/tint/resolver/bitcast_validation_test.cc
index fb0b960..c979c55 100644
--- a/src/tint/resolver/bitcast_validation_test.cc
+++ b/src/tint/resolver/bitcast_validation_test.cc
@@ -21,6 +21,8 @@
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+
 struct Type {
     template <typename T>
     static constexpr Type Create() {
@@ -39,36 +41,36 @@
     Type::Create<u32>(),
 };
 static constexpr Type kVec2NumericScalars[] = {
-    Type::Create<builder::vec2<f32>>(),
-    Type::Create<builder::vec2<i32>>(),
-    Type::Create<builder::vec2<u32>>(),
+    Type::Create<vec2<f32>>(),
+    Type::Create<vec2<i32>>(),
+    Type::Create<vec2<u32>>(),
 };
 static constexpr Type kVec3NumericScalars[] = {
-    Type::Create<builder::vec3<f32>>(),
-    Type::Create<builder::vec3<i32>>(),
-    Type::Create<builder::vec3<u32>>(),
+    Type::Create<vec3<f32>>(),
+    Type::Create<vec3<i32>>(),
+    Type::Create<vec3<u32>>(),
 };
 static constexpr Type kVec4NumericScalars[] = {
-    Type::Create<builder::vec4<f32>>(),
-    Type::Create<builder::vec4<i32>>(),
-    Type::Create<builder::vec4<u32>>(),
+    Type::Create<vec4<f32>>(),
+    Type::Create<vec4<i32>>(),
+    Type::Create<vec4<u32>>(),
 };
 static constexpr Type kInvalid[] = {
     // A non-exhaustive selection of uncastable types
     Type::Create<bool>(),
-    Type::Create<builder::vec2<bool>>(),
-    Type::Create<builder::vec3<bool>>(),
-    Type::Create<builder::vec4<bool>>(),
-    Type::Create<builder::array<2, i32>>(),
-    Type::Create<builder::array<3, u32>>(),
-    Type::Create<builder::array<4, f32>>(),
-    Type::Create<builder::array<5, bool>>(),
-    Type::Create<builder::mat2x2<f32>>(),
-    Type::Create<builder::mat3x3<f32>>(),
-    Type::Create<builder::mat4x4<f32>>(),
-    Type::Create<builder::ptr<i32>>(),
-    Type::Create<builder::ptr<builder::array<2, i32>>>(),
-    Type::Create<builder::ptr<builder::mat2x2<f32>>>(),
+    Type::Create<vec2<bool>>(),
+    Type::Create<vec3<bool>>(),
+    Type::Create<vec4<bool>>(),
+    Type::Create<array<i32, 2>>(),
+    Type::Create<array<u32, 3>>(),
+    Type::Create<array<f32, 4>>(),
+    Type::Create<array<bool, 5>>(),
+    Type::Create<mat2x2<f32>>(),
+    Type::Create<mat3x3<f32>>(),
+    Type::Create<mat4x4<f32>>(),
+    Type::Create<ptr<private_, i32>>(),
+    Type::Create<ptr<private_, array<i32, 2>>>(),
+    Type::Create<ptr<private_, mat2x2<f32>>>(),
 };
 
 using ResolverBitcastValidationTest = ResolverTestWithParam<std::tuple<Type, Type>>;
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 5a23354..5d23b39 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -43,7 +43,8 @@
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -156,8 +157,9 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_Matrix) {
-    auto* expr = Call("select", mat2x2<f32>(vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f)),
-                      mat2x2<f32>(vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f)), Expr(true));
+    auto* expr =
+        Call("select", Call<mat2x2<f32>>(Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f)),
+             Call<mat2x2<f32>>(Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f)), Expr(true));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve());
@@ -173,7 +175,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_MismatchTypes) {
-    auto* expr = Call("select", 1_f, vec2<f32>(2_f, 3_f), Expr(true));
+    auto* expr = Call("select", 1_f, Call<vec2<f32>>(2_f, 3_f), Expr(true));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve());
@@ -189,7 +191,7 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_MismatchVectorSize) {
-    auto* expr = Call("select", vec2<f32>(1_f, 2_f), vec3<f32>(3_f, 4_f, 5_f), Expr(true));
+    auto* expr = Call("select", Call<vec2<f32>>(1_f, 2_f), Call<vec3<f32>>(3_f, 4_f, 5_f), true);
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve());
@@ -304,8 +306,8 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, OneParam_Vector_f32) {
     auto param = GetParam();
 
-    auto val = param.name == std::string("acosh") ? vec3<f32>(1.0_f, 2.0_f, 3.0_f)
-                                                  : vec3<f32>(0.5_f, 0.5_f, 0.8_f);
+    auto val = param.name == std::string("acosh") ? Call<vec3<f32>>(1.0_f, 2.0_f, 3.0_f)
+                                                  : Call<vec3<f32>>(0.5_f, 0.5_f, 0.8_f);
 
     auto* call = Call(param.name, val);
     WrapInFunction(call);
@@ -352,7 +354,7 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, TwoParams_Vector_f32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call(param.name, Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     if (param.args_number == 2u) {
@@ -397,8 +399,8 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, ThreeParams_Vector_f32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<f32>(0_f, 0_f, 0_f), vec3<f32>(1_f, 1_f, 1_f),
-                      vec3<f32>(2_f, 2_f, 2_f));
+    auto* call = Call(param.name, Call<vec3<f32>>(0_f, 0_f, 0_f), Call<vec3<f32>>(1_f, 1_f, 1_f),
+                      Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -444,8 +446,8 @@
 TEST_P(ResolverBuiltinTest_FloatBuiltin_IdenticalType, FourParams_Vector_f32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
-                      vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call(param.name, Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f),
+                      Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     if (param.args_number == 4u) {
@@ -500,8 +502,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto val = param.name == std::string("acosh") ? vec3<f16>(1.0_h, 2.0_h, 3.0_h)
-                                                  : vec3<f16>(0.5_h, 0.5_h, 0.8_h);
+    auto val = param.name == std::string("acosh") ? Call<vec3<f16>>(1.0_h, 2.0_h, 3.0_h)
+                                                  : Call<vec3<f16>>(0.5_h, 0.5_h, 0.8_h);
 
     auto* call = Call(param.name, val);
     WrapInFunction(call);
@@ -552,7 +554,7 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call(param.name, Call<vec3<f16>>(1_h, 1_h, 3_h), Call<vec3<f16>>(1_h, 1_h, 3_h));
     WrapInFunction(call);
 
     if (param.args_number == 2u) {
@@ -601,8 +603,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call(param.name, vec3<f16>(0_h, 0_h, 0_h), vec3<f16>(1_h, 1_h, 1_h),
-                      vec3<f16>(2_h, 2_h, 2_h));
+    auto* call = Call(param.name, Call<vec3<f16>>(0_h, 0_h, 0_h), Call<vec3<f16>>(1_h, 1_h, 1_h),
+                      Call<vec3<f16>>(2_h, 2_h, 2_h));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -652,8 +654,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call(param.name, vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h),
-                      vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call(param.name, Call<vec3<f16>>(1_h, 1_h, 3_h), Call<vec3<f16>>(1_h, 1_h, 3_h),
+                      Call<vec3<f16>>(1_h, 1_h, 3_h), Call<vec3<f16>>(1_h, 1_h, 3_h));
     WrapInFunction(call);
 
     if (param.args_number == 4u) {
@@ -732,7 +734,7 @@
 
 // cross: (vec3<T>, vec3<T>) -> vec3<T>
 TEST_F(ResolverBuiltinFloatTest, Cross_f32) {
-    auto* call = Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
+    auto* call = Call("cross", Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(1_f, 2_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -746,7 +748,7 @@
 TEST_F(ResolverBuiltinFloatTest, Cross_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("cross", vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(1_h, 2_h, 3_h));
+    auto* call = Call("cross", Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(1_h, 2_h, 3_h));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -784,7 +786,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Cross_Error_Vec3Int) {
-    auto* call = Call("cross", vec3<i32>(1_i, 2_i, 3_i), vec3<i32>(1_i, 2_i, 3_i));
+    auto* call = Call("cross", Call<vec3<i32>>(1_i, 2_i, 3_i), Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -798,7 +800,8 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Cross_Error_Vec4) {
-    auto* call = Call("cross", vec4<f32>(1_f, 2_f, 3_f, 4_f), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+    auto* call =
+        Call("cross", Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
 
     WrapInFunction(call);
 
@@ -813,8 +816,8 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Cross_Error_TooManyParams) {
-    auto* call =
-        Call("cross", vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
+    auto* call = Call("cross", Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(1_f, 2_f, 3_f),
+                      Call<vec3<f32>>(1_f, 2_f, 3_f));
 
     WrapInFunction(call);
 
@@ -852,7 +855,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Distance_Vector_f32) {
-    auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call("distance", Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -864,7 +867,7 @@
 TEST_F(ResolverBuiltinFloatTest, Distance_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("distance", vec3<f16>(1_h, 1_h, 3_h), vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call("distance", Call<vec3<f16>>(1_h, 1_h, 3_h), Call<vec3<f16>>(1_h, 1_h, 3_h));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -874,8 +877,8 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Distance_TooManyParams) {
-    auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f),
-                      vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call("distance", Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f),
+                      Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -889,7 +892,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Distance_TooFewParams) {
-    auto* call = Call("distance", vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call("distance", Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -979,7 +982,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, FrexpVector_f32) {
-    auto* call = Call("frexp", vec3<f32>());
+    auto* call = Call("frexp", Call<vec3<f32>>());
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1014,7 +1017,7 @@
 TEST_F(ResolverBuiltinFloatTest, FrexpVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("frexp", vec3<f16>());
+    auto* call = Call("frexp", Call<vec3<f16>>());
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1086,7 +1089,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, Length_FloatVector_f32) {
-    auto* call = Call("length", vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call("length", Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1098,7 +1101,7 @@
 TEST_F(ResolverBuiltinFloatTest, Length_FloatVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("length", vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call("length", Call<vec3<f16>>(1_h, 1_h, 3_h));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1138,7 +1141,7 @@
 // mix(vecN<T>, vecN<T>, T) -> vecN<T>. Other overloads are tested in
 // ResolverBuiltinTest_FloatBuiltin_IdenticalType above.
 TEST_F(ResolverBuiltinFloatTest, Mix_VectorScalar_f32) {
-    auto* call = Call("mix", vec3<f32>(1_f, 1_f, 3_f), vec3<f32>(1_f, 1_f, 3_f), 4_f);
+    auto* call = Call("mix", Call<vec3<f32>>(1_f, 1_f, 3_f), Call<vec3<f32>>(1_f, 1_f, 3_f), 4_f);
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1153,7 +1156,7 @@
 TEST_F(ResolverBuiltinFloatTest, Mix_VectorScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("mix", vec3<f16>(1_h, 1_h, 1_h), vec3<f16>(1_h, 1_h, 1_h), 4_h);
+    auto* call = Call("mix", Call<vec3<f16>>(1_h, 1_h, 1_h), Call<vec3<f16>>(1_h, 1_h, 1_h), 4_h);
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1228,7 +1231,7 @@
 }
 
 TEST_F(ResolverBuiltinFloatTest, ModfVector_f32) {
-    auto* call = Call("modf", vec3<f32>());
+    auto* call = Call("modf", Call<vec3<f32>>());
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1263,7 +1266,7 @@
 TEST_F(ResolverBuiltinFloatTest, ModfVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("modf", vec3<f16>());
+    auto* call = Call("modf", Call<vec3<f16>>());
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1343,7 +1346,7 @@
 
 TEST_F(ResolverBuiltinFloatTest, Modf_Error_VectorSizesDontMatch) {
     GlobalVar("whole", ty.vec4<f32>(), builtin::AddressSpace::kWorkgroup);
-    auto* call = Call("modf", vec2<f32>(1_f, 2_f), AddressOf("whole"));
+    auto* call = Call("modf", Call<vec2<f32>>(1_f, 2_f), AddressOf("whole"));
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -1359,7 +1362,7 @@
 
 // normalize: (vecN<T>) -> vecN<T>
 TEST_F(ResolverBuiltinFloatTest, Normalize_Vector_f32) {
-    auto* call = Call("normalize", vec3<f32>(1_f, 1_f, 3_f));
+    auto* call = Call("normalize", Call<vec3<f32>>(1_f, 1_f, 3_f));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1373,7 +1376,7 @@
 TEST_F(ResolverBuiltinFloatTest, Normalize_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* call = Call("normalize", vec3<f16>(1_h, 1_h, 3_h));
+    auto* call = Call("normalize", Call<vec3<f16>>(1_h, 1_h, 3_h));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1455,7 +1458,7 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Vector_i32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
+    auto* call = Call(param.name, Call<vec3<i32>>(1_i, 1_i, 3_i));
     WrapInFunction(call);
 
     if (param.args_number == 1u) {
@@ -1500,7 +1503,7 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, OneParams_Vector_u32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u));
+    auto* call = Call(param.name, Call<vec3<u32>>(1_u, 1_u, 3_u));
     WrapInFunction(call);
 
     if (param.args_number == 1u) {
@@ -1545,7 +1548,7 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Vector_i32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
+    auto* call = Call(param.name, Call<vec3<i32>>(1_i, 1_i, 3_i), Call<vec3<i32>>(1_i, 1_i, 3_i));
     WrapInFunction(call);
 
     if (param.args_number == 2u) {
@@ -1590,7 +1593,7 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, TwoParams_Vector_u32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
+    auto* call = Call(param.name, Call<vec3<u32>>(1_u, 1_u, 3_u), Call<vec3<u32>>(1_u, 1_u, 3_u));
     WrapInFunction(call);
 
     if (param.args_number == 2u) {
@@ -1635,8 +1638,8 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Vector_i32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
-                      vec3<i32>(1_i, 1_i, 3_i));
+    auto* call = Call(param.name, Call<vec3<i32>>(1_i, 1_i, 3_i), Call<vec3<i32>>(1_i, 1_i, 3_i),
+                      Call<vec3<i32>>(1_i, 1_i, 3_i));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -1682,8 +1685,8 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, ThreeParams_Vector_u32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
-                      vec3<u32>(1_u, 1_u, 3_u));
+    auto* call = Call(param.name, Call<vec3<u32>>(1_u, 1_u, 3_u), Call<vec3<u32>>(1_u, 1_u, 3_u),
+                      Call<vec3<u32>>(1_u, 1_u, 3_u));
     WrapInFunction(call);
 
     if (param.args_number == 3u) {
@@ -1729,8 +1732,8 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Vector_i32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
-                      vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
+    auto* call = Call(param.name, Call<vec3<i32>>(1_i, 1_i, 3_i), Call<vec3<i32>>(1_i, 1_i, 3_i),
+                      Call<vec3<i32>>(1_i, 1_i, 3_i), Call<vec3<i32>>(1_i, 1_i, 3_i));
     WrapInFunction(call);
 
     if (param.args_number == 4u) {
@@ -1776,8 +1779,8 @@
 TEST_P(ResolverBuiltinTest_IntegerBuiltin_IdenticalType, FourParams_Vector_u32) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
-                      vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
+    auto* call = Call(param.name, Call<vec3<u32>>(1_u, 1_u, 3_u), Call<vec3<u32>>(1_u, 1_u, 3_u),
+                      Call<vec3<u32>>(1_u, 1_u, 3_u), Call<vec3<u32>>(1_u, 1_u, 3_u));
     WrapInFunction(call);
 
     if (param.args_number == 4u) {
@@ -2188,10 +2191,9 @@
                          ResolverBuiltinTest_Texture,
                          testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
-static std::string to_str(const std::string& function,
-                          utils::VectorRef<const sem::Parameter*> params) {
+static std::string to_str(const std::string& func, utils::VectorRef<const sem::Parameter*> params) {
     utils::StringStream out;
-    out << function << "(";
+    out << func << "(";
     bool first = true;
     for (auto* param : params) {
         if (!first) {
@@ -2556,8 +2558,8 @@
     bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
                  param.builtin == builtin::Function::kPack4X8Unorm;
 
-    auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f))
-                       : Call(param.name, vec2<f32>(1_f, 2_f));
+    auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))
+                       : Call(param.name, Call<vec2<f32>>(1_f, 2_f));
     WrapInFunction(call);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -2571,8 +2573,8 @@
     bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
                  param.builtin == builtin::Function::kPack4X8Unorm;
 
-    auto* call = pack4 ? Call(param.name, vec4<i32>(1_i, 2_i, 3_i, 4_i))
-                       : Call(param.name, vec2<i32>(1_i, 2_i));
+    auto* call = pack4 ? Call(param.name, Call<vec4<i32>>(1_i, 2_i, 3_i, 4_i))
+                       : Call(param.name, Call<vec2<i32>>(1_i, 2_i));
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -2597,8 +2599,8 @@
     bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
                  param.builtin == builtin::Function::kPack4X8Unorm;
 
-    auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f)
-                       : Call(param.name, vec2<f32>(1_f, 2_f), 1_f);
+    auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f), 1_f)
+                       : Call(param.name, Call<vec2<f32>>(1_f, 2_f), 1_f);
     WrapInFunction(call);
 
     EXPECT_FALSE(r()->Resolve());
@@ -2669,7 +2671,7 @@
 TEST_P(ResolverBuiltinTest_Barrier, Error_TooManyParams) {
     auto param = GetParam();
 
-    auto* call = Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f);
+    auto* call = Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f), 1_f);
     WrapInFunction(CallStmt(call));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index fbe5a5f..f24fc4b 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -19,7 +19,8 @@
 #include "src/tint/sem/value_constructor.h"
 #include "src/tint/utils/string_stream.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -250,10 +251,10 @@
                               i32(values[2]));
             case Kind::kVec3_Scalar_Vec2:
                 return b.Call(src, b.ty.vec3<i32>(), i32(values[0]),
-                              b.vec2<i32>(i32(values[1]), i32(values[2])));
+                              b.Call<vec2<i32>>(i32(values[1]), i32(values[2])));
             case Kind::kVec3_Vec2_Scalar:
-                return b.Call(src, b.ty.vec3<i32>(), b.vec2<i32>(i32(values[0]), i32(values[1])),
-                              i32(values[2]));
+                return b.Call(src, b.ty.vec3<i32>(),
+                              b.Call<vec2<i32>>(i32(values[0]), i32(values[1])), i32(values[2]));
             case Kind::kEmptyVec2:
                 return b.Call(src, b.ty.vec2<i32>());
             case Kind::kEmptyVec3:
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index d5f8c4f..a1cc2e2 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -17,20 +17,14 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/utils/string_stream.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 template <typename T>
 using DataType = builder::DataType<T>;
-template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-
 class ResolverBuiltinsValidationTest : public resolver::TestHelper, public testing::Test {};
 namespace StageTest {
 struct Params {
@@ -870,21 +864,21 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec2) {
-    auto* builtin = Call("length", vec2<f32>(1_f, 1_f));
+    auto* builtin = Call("length", Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec3) {
-    auto* builtin = Call("length", vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin = Call("length", Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec4) {
-    auto* builtin = Call("length", vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin = Call("length", Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -898,46 +892,50 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec2) {
-    auto* builtin = Call("distance", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
+    auto* builtin = Call("distance", Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec3) {
-    auto* builtin = Call("distance", vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin =
+        Call("distance", Call<vec3<f32>>(1_f, 1_f, 1_f), Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec4) {
-    auto* builtin = Call("distance", vec4<f32>(1_f, 1_f, 1_f, 1_f), vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin =
+        Call("distance", Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f), Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat2x2) {
-    auto* builtin = Call("determinant", mat2x2<f32>(vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f)));
+    auto* builtin = Call("determinant",
+                         Call<mat2x2<f32>>(Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f)));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat3x3) {
-    auto* builtin = Call(
-        "determinant",
-        mat3x3<f32>(vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f)));
+    auto* builtin = Call("determinant", Call<mat3x3<f32>>(Call<vec3<f32>>(1_f, 1_f, 1_f),
+                                                          Call<vec3<f32>>(1_f, 1_f, 1_f),
+                                                          Call<vec3<f32>>(1_f, 1_f, 1_f)));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat4x4) {
-    auto* builtin = Call("determinant",
-                         mat4x4<f32>(vec4<f32>(1_f, 1_f, 1_f, 1_f), vec4<f32>(1_f, 1_f, 1_f, 1_f),
-                                     vec4<f32>(1_f, 1_f, 1_f, 1_f), vec4<f32>(1_f, 1_f, 1_f, 1_f)));
+    auto* builtin = Call("determinant", Call<mat4x4<f32>>(Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f),
+                                                          Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f),
+                                                          Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f),
+                                                          Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f)));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -957,7 +955,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec2) {
-    auto* builtin = Call("frexp", vec2<f32>(1_f, 1_f));
+    auto* builtin = Call("frexp", Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -974,7 +972,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec3) {
-    auto* builtin = Call("frexp", vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin = Call("frexp", Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -991,7 +989,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec4) {
-    auto* builtin = Call("frexp", vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin = Call("frexp", Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1021,7 +1019,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec2) {
-    auto* builtin = Call("modf", vec2<f32>(1_f, 1_f));
+    auto* builtin = Call("modf", Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1038,7 +1036,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec3) {
-    auto* builtin = Call("modf", vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin = Call("modf", Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1055,7 +1053,7 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec4) {
-    auto* builtin = Call("modf", vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin = Call("modf", Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1072,28 +1070,29 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Cross_Float_Vec3) {
-    auto* builtin = Call("cross", vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin = Call("cross", Call<vec3<f32>>(1_f, 1_f, 1_f), Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec2) {
-    auto* builtin = Call("dot", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f));
+    auto* builtin = Call("dot", Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec3) {
-    auto* builtin = Call("dot", vec3<f32>(1_f, 1_f, 1_f), vec3<f32>(1_f, 1_f, 1_f));
+    auto* builtin = Call("dot", Call<vec3<f32>>(1_f, 1_f, 1_f), Call<vec3<f32>>(1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec4) {
-    auto* builtin = Call("dot", vec4<f32>(1_f, 1_f, 1_f, 1_f), vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin =
+        Call("dot", Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f), Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1121,24 +1120,24 @@
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Float_Vec2) {
-    auto* builtin =
-        Call("select", vec2<f32>(1_f, 1_f), vec2<f32>(1_f, 1_f), vec2<bool>(true, true));
+    auto* builtin = Call("select", Call<vec2<f32>>(1_f, 1_f), Call<vec2<f32>>(1_f, 1_f),
+                         Call<vec2<bool>>(true, true));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Integer_Vec2) {
-    auto* builtin =
-        Call("select", vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i), vec2<bool>(true, true));
+    auto* builtin = Call("select", Call<vec2<i32>>(1_i, 1_i), Call<vec2<i32>>(1_i, 1_i),
+                         Call<vec2<bool>>(true, true));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Boolean_Vec2) {
-    auto* builtin =
-        Call("select", vec2<bool>(true, true), vec2<bool>(true, true), vec2<bool>(true, true));
+    auto* builtin = Call("select", Call<vec2<bool>>(true, true), Call<vec2<bool>>(true, true),
+                         Call<vec2<bool>>(true, true));
     WrapInFunction(builtin);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1178,7 +1177,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec2<f32>(f32(i + 1), f32(i + 1)));
+        params.Push(Call<vec2<f32>>(f32(i + 1), f32(i + 1)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1199,7 +1198,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec3<f32>(f32(i + 1), f32(i + 1), f32(i + 1)));
+        params.Push(Call<vec3<f32>>(f32(i + 1), f32(i + 1), f32(i + 1)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1220,7 +1219,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec4<f32>(f32(i + 1), f32(i + 1), f32(i + 1), f32(i + 1)));
+        params.Push(Call<vec4<f32>>(f32(i + 1), f32(i + 1), f32(i + 1), f32(i + 1)));
     }
     auto* builtin = Call(name, params);
     Func("func", utils::Empty, ty.void_(),
@@ -1302,7 +1301,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec2<u32>(1_u, 1_u));
+        params.Push(Call<vec2<u32>>(1_u, 1_u));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1317,7 +1316,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec3<u32>(1_u, 1_u, 1_u));
+        params.Push(Call<vec3<u32>>(1_u, 1_u, 1_u));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1332,7 +1331,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec4<u32>(1_u, 1_u, 1_u, 1_u));
+        params.Push(Call<vec4<u32>>(1_u, 1_u, 1_u, 1_u));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1362,7 +1361,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec2<i32>(1_i, 1_i));
+        params.Push(Call<vec2<i32>>(1_i, 1_i));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1377,7 +1376,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec3<i32>(1_i, 1_i, 1_i));
+        params.Push(Call<vec3<i32>>(1_i, 1_i, 1_i));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1392,7 +1391,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec4<i32>(1_i, 1_i, 1_i, 1_i));
+        params.Push(Call<vec4<i32>>(1_i, 1_i, 1_i, 1_i));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1419,7 +1418,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec2<bool>(true, true));
+        params.Push(Call<vec2<bool>>(true, true));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1433,7 +1432,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec3<bool>(true, true, true));
+        params.Push(Call<vec3<bool>>(true, true, true));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1447,7 +1446,7 @@
 
     utils::Vector<const ast::Expression*, 8> params;
     for (uint32_t i = 0; i < num_params; ++i) {
-        params.Push(vec4<bool>(true, true, true, true));
+        params.Push(Call<vec4<bool>>(true, true, true, true));
     }
     auto* builtin = Call(name, params);
     WrapInFunction(builtin);
@@ -1463,7 +1462,7 @@
 
 TEST_P(DataPacking4x8, Float_Vec4) {
     auto name = GetParam();
-    auto* builtin = Call(name, vec4<f32>(1_f, 1_f, 1_f, 1_f));
+    auto* builtin = Call(name, Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f));
     WrapInFunction(builtin);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -1476,7 +1475,7 @@
 
 TEST_P(DataPacking2x16, Float_Vec2) {
     auto name = GetParam();
-    auto* builtin = Call(name, vec2<f32>(1_f, 1_f));
+    auto* builtin = Call(name, Call<vec2<f32>>(1_f, 1_f));
     WrapInFunction(builtin);
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
diff --git a/src/tint/resolver/call_test.cc b/src/tint/resolver/call_test.cc
index 25f4814..6ebd629 100644
--- a/src/tint/resolver/call_test.cc
+++ b/src/tint/resolver/call_test.cc
@@ -18,39 +18,21 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
-// Helpers and typedefs
-template <typename T>
-using DataType = builder::DataType<T>;
-template <int N, typename T>
-using vec = builder::vec<N, T>;
-template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <int N, int M, typename T>
-using mat = builder::mat<N, M, T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat2x3 = builder::mat2x3<T>;
-template <typename T>
-using mat3x2 = builder::mat3x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
+
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 template <typename T, int ID = 0>
 using alias = builder::alias<T, ID>;
+
 template <typename T>
 using alias1 = builder::alias1<T>;
+
 template <typename T>
 using alias2 = builder::alias2<T>;
+
 template <typename T>
 using alias3 = builder::alias3<T>;
 
@@ -63,7 +45,7 @@
 
 template <typename T>
 constexpr Params ParamsFor() {
-    return Params{DataType<T>::ExprFromDouble, DataType<T>::AST};
+    return Params{builder::DataType<T>::ExprFromDouble, builder::DataType<T>::AST};
 }
 
 static constexpr Params all_param_types[] = {
diff --git a/src/tint/resolver/call_validation_test.cc b/src/tint/resolver/call_validation_test.cc
index bf533cc..571dd07 100644
--- a/src/tint/resolver/call_validation_test.cc
+++ b/src/tint/resolver/call_validation_test.cc
@@ -18,7 +18,8 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -103,7 +104,7 @@
     //   var z: i32 = 1i;
     //   foo(&z);
     // }
-    auto* param = Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction));
+    auto* param = Param("p", ty.ptr<function, i32>());
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -120,7 +121,7 @@
     //   let z: i32 = 1i;
     //   foo(&z);
     // }
-    auto* param = Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction));
+    auto* param = Param("p", ty.ptr<function, i32>());
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -142,7 +143,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction));
+    auto* param = Param("p", ty.ptr<function, i32>());
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -169,7 +170,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction));
+    auto* param = Param("p", ty.ptr<function, i32>());
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -189,7 +190,7 @@
     auto* S = Structure("S", utils::Vector{
                                  Member("m", ty.i32()),
                              });
-    auto* param = Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction));
+    auto* param = Param("p", ty.ptr<function, i32>());
     Func("foo", utils::Vector{param}, ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -208,12 +209,12 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("bar",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(),
          utils::Vector{
@@ -235,12 +236,12 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("bar",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(),
          utils::Vector{
@@ -268,13 +269,13 @@
     // }
     Func("x",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.i32())),
-             Decl(Let("p", ty.ptr(builtin::AddressSpace::kFunction, ty.i32()), AddressOf("v"))),
+             Decl(Let("p", ty.ptr<function, i32>(), AddressOf("v"))),
              CallStmt(Call("x", "p")),
          },
          utils::Vector{
@@ -293,13 +294,13 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kPrivate)),
+             Param("p", ty.ptr<private_, i32>()),
          },
          ty.void_(), utils::Empty);
     GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Let("p", ty.ptr(builtin::AddressSpace::kPrivate, ty.i32()), AddressOf("v"))),
+             Decl(Let("p", ty.ptr<private_, i32>(), AddressOf("v"))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
          utils::Vector{
@@ -318,14 +319,13 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.array<i32, 4>())),
-             Decl(Let("p", ty.ptr(builtin::AddressSpace::kFunction, ty.i32()),
-                      AddressOf(IndexAccessor("v", 0_a)))),
+             Decl(Let("p", ty.ptr<function, i32>(), AddressOf(IndexAccessor("v", 0_a)))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
          utils::Vector{
@@ -349,14 +349,13 @@
     Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Var("v", ty.array<i32, 4>())),
-             Decl(Let("p", ty.ptr(builtin::AddressSpace::kFunction, ty.i32()),
-                      AddressOf(IndexAccessor("v", 0_a)))),
+             Decl(Let("p", ty.ptr<function, i32>(), AddressOf(IndexAccessor("v", 0_a)))),
              CallStmt(Call("foo", Expr(Source{{12, 34}}, "p"))),
          },
          utils::Vector{
@@ -377,7 +376,7 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr(builtin::AddressSpace::kFunction, ty.array<i32, 4>())),
+             Param("p", ty.ptr<function, array<i32, 4>>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
@@ -406,7 +405,7 @@
     // }
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
@@ -440,7 +439,7 @@
     Enable(builtin::Extension::kChromiumExperimentalFullPtrParameters);
     Func("foo",
          utils::Vector{
-             Param("p", ty.ptr<i32>(builtin::AddressSpace::kFunction)),
+             Param("p", ty.ptr<function, i32>()),
          },
          ty.void_(), utils::Empty);
     Func("main", utils::Empty, ty.void_(),
diff --git a/src/tint/resolver/compound_assignment_validation_test.cc b/src/tint/resolver/compound_assignment_validation_test.cc
index 0343f08..0acf993 100644
--- a/src/tint/resolver/compound_assignment_validation_test.cc
+++ b/src/tint/resolver/compound_assignment_validation_test.cc
@@ -18,13 +18,13 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/type/storage_texture.h"
 
-using ::testing::HasSubstr;
-
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverCompoundAssignmentValidationTest = ResolverTest;
 
 TEST_F(ResolverCompoundAssignmentValidationTest, CompatibleTypes) {
@@ -51,9 +51,8 @@
     // var a : i32;
     // let b : ptr<function,i32> = &a;
     // *b += 2;
-    const auto func = builtin::AddressSpace::kFunction;
-    auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
-    auto* var_b = Let("b", ty.ptr<i32>(func), AddressOf(Expr("a")));
+    auto* var_a = Var("a", ty.i32(), builtin::AddressSpace::kFunction, Expr(2_i));
+    auto* var_b = Let("b", ty.ptr<function, i32>(), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b,
                    CompoundAssign(Source{{12, 34}}, Deref("b"), 2_i, ast::BinaryOp::kAdd));
 
@@ -116,7 +115,7 @@
 
     auto* var = Var("a", ty.f32());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(), ast::BinaryOp::kAdd);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", Call<vec4<f32>>(), ast::BinaryOp::kAdd);
     WrapInFunction(var, assign);
 
     ASSERT_FALSE(r()->Resolve());
@@ -146,7 +145,8 @@
 
     auto* var = Var("a", ty.f32());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(), ast::BinaryOp::kMultiply);
+    auto* assign =
+        CompoundAssign(Source{{12, 34}}, "a", Call<mat4x4<f32>>(), ast::BinaryOp::kMultiply);
     WrapInFunction(var, assign);
 
     ASSERT_FALSE(r()->Resolve());
@@ -162,7 +162,8 @@
 
     auto* var = Var("a", ty.vec4<f32>());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(), ast::BinaryOp::kMultiply);
+    auto* assign =
+        CompoundAssign(Source{{12, 34}}, "a", Call<mat4x4<f32>>(), ast::BinaryOp::kMultiply);
     WrapInFunction(var, assign);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -176,7 +177,8 @@
 
     auto* var = Var("a", ty.vec4<f32>());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x2<f32>(), ast::BinaryOp::kMultiply);
+    auto* assign =
+        CompoundAssign(Source{{12, 34}}, "a", Call<mat4x2<f32>>(), ast::BinaryOp::kMultiply);
     WrapInFunction(var, assign);
 
     ASSERT_FALSE(r()->Resolve());
@@ -194,7 +196,8 @@
 
     auto* var = Var("a", ty.vec4<f32>());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat2x4<f32>(), ast::BinaryOp::kMultiply);
+    auto* assign =
+        CompoundAssign(Source{{12, 34}}, "a", Call<mat2x4<f32>>(), ast::BinaryOp::kMultiply);
     WrapInFunction(var, assign);
 
     ASSERT_FALSE(r()->Resolve());
@@ -210,7 +213,8 @@
 
     auto* var = Var("a", ty.mat4x4<f32>());
 
-    auto* assign = CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(), ast::BinaryOp::kMultiply);
+    auto* assign =
+        CompoundAssign(Source{{12, 34}}, "a", Call<vec4<f32>>(), ast::BinaryOp::kMultiply);
     WrapInFunction(var, assign);
 
     ASSERT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/const_eval.cc b/src/tint/resolver/const_eval.cc
index 3fa71cd..73e274b 100644
--- a/src/tint/resolver/const_eval.cc
+++ b/src/tint/resolver/const_eval.cc
@@ -22,11 +22,11 @@
 #include <type_traits>
 #include <utility>
 
+#include "src/tint/builtin/number.h"
 #include "src/tint/constant/composite.h"
 #include "src/tint/constant/scalar.h"
 #include "src/tint/constant/splat.h"
 #include "src/tint/constant/value.h"
-#include "src/tint/number.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/value_constructor.h"
diff --git a/src/tint/resolver/const_eval.h b/src/tint/resolver/const_eval.h
index 9303656..0253d30 100644
--- a/src/tint/resolver/const_eval.h
+++ b/src/tint/resolver/const_eval.h
@@ -18,7 +18,7 @@
 #include <stddef.h>
 #include <string>
 
-#include "src/tint/number.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/type/type.h"
 #include "src/tint/utils/result.h"
 #include "src/tint/utils/vector.h"
diff --git a/src/tint/resolver/const_eval_binary_op_test.cc b/src/tint/resolver/const_eval_binary_op_test.cc
index e61599f..dac78ce 100644
--- a/src/tint/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/resolver/const_eval_binary_op_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/reader/wgsl/parser.h"
 #include "src/tint/utils/result.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 using ::testing::HasSubstr;
 
 namespace tint::resolver {
@@ -1690,7 +1691,7 @@
     // const i = 4;
     // const result = (one == 0) && (a[i] == 0);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(4_a));
     auto* lhs = Equal("one", 0_a);
     auto* rhs = Equal(IndexAccessor("a", "i"), 0_a);
@@ -1707,7 +1708,7 @@
     // const i = 3;
     // const result = (one == 1) && (a[i] == 0);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(3_a));
     auto* lhs = Equal("one", 1_a);
     auto* rhs = Equal(IndexAccessor("a", Expr(Source{{12, 34}}, "i")), 0_a);
@@ -1724,7 +1725,7 @@
     // const i = 3;
     // const result = (one == 0) && (a[i] == 0.0f);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(3_a));
     auto* lhs = Equal("one", 0_a);
     auto* rhs = Equal(Source{{12, 34}}, IndexAccessor("a", "i"), 0.0_f);
@@ -1747,7 +1748,7 @@
     // const i = 4;
     // const result = (one == 1) || (a[i] == 0);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(4_a));
     auto* lhs = Equal("one", 1_a);
     auto* rhs = Equal(IndexAccessor("a", "i"), 0_a);
@@ -1764,7 +1765,7 @@
     // const i = 3;
     // const result = (one == 0) || (a[i] == 0);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(3_a));
     auto* lhs = Equal("one", 0_a);
     auto* rhs = Equal(IndexAccessor("a", Expr(Source{{12, 34}}, "i")), 0_a);
@@ -1781,7 +1782,7 @@
     // const i = 3;
     // const result = (one == 1) || (a[i] == 0.0f);
     GlobalConst("one", Expr(1_a));
-    GlobalConst("a", array<i32, 3>(1_i, 2_i, 3_i));
+    GlobalConst("a", Call<array<i32, 3>>(1_i, 2_i, 3_i));
     GlobalConst("i", Expr(3_a));
     auto* lhs = Equal("one", 1_a);
     auto* rhs = Equal(Source{{12, 34}}, IndexAccessor("a", "i"), 0.0_f);
@@ -1914,7 +1915,8 @@
     // const result = (one == 0) && (vec2<f32>(1.0, true).x == 0.0);
     GlobalConst("one", Expr(1_a));
     auto* lhs = Equal("one", 0_a);
-    auto* rhs = Equal(MemberAccessor(vec2<f32>(Source{{12, 34}}, 1.0_a, Expr(true)), "x"), 0.0_a);
+    auto* rhs =
+        Equal(MemberAccessor(Call<vec2<f32>>(Source{{12, 34}}, 1.0_a, Expr(true)), "x"), 0.0_a);
     GlobalConst("result", LogicalAnd(lhs, rhs));
 
     EXPECT_FALSE(r()->Resolve());
@@ -1942,7 +1944,8 @@
     // const result = (one == 1) || (vec2<f32>(1.0, true).x == 0.0);
     GlobalConst("one", Expr(1_a));
     auto* lhs = Equal("one", 0_a);
-    auto* rhs = Equal(MemberAccessor(vec2<f32>(Source{{12, 34}}, 1.0_a, Expr(true)), "x"), 0.0_a);
+    auto* rhs =
+        Equal(MemberAccessor(Call<vec2<f32>>(Source{{12, 34}}, 1.0_a, Expr(true)), "x"), 0.0_a);
     GlobalConst("result", LogicalOr(lhs, rhs));
 
     EXPECT_FALSE(r()->Resolve());
@@ -2328,7 +2331,8 @@
     // const result = (one == 0) && (vec2(1, 2).z == 0);
     GlobalConst("one", Expr(1_a));
     auto* lhs = Equal("one", 0_a);
-    auto* rhs = Equal(MemberAccessor(vec2<Infer>(1_a, 2_a), Ident(Source{{12, 34}}, "z")), 0_a);
+    auto* rhs =
+        Equal(MemberAccessor(Call<vec2<Infer>>(1_a, 2_a), Ident(Source{{12, 34}}, "z")), 0_a);
     GlobalConst("result", LogicalAnd(lhs, rhs));
 
     EXPECT_FALSE(r()->Resolve());
@@ -2340,7 +2344,8 @@
     // const result = (one == 1) || (vec2(1, 2).z == 0);
     GlobalConst("one", Expr(1_a));
     auto* lhs = Equal("one", 1_a);
-    auto* rhs = Equal(MemberAccessor(vec2<Infer>(1_a, 2_a), Ident(Source{{12, 34}}, "z")), 0_a);
+    auto* rhs =
+        Equal(MemberAccessor(Call<vec2<Infer>>(1_a, 2_a), Ident(Source{{12, 34}}, "z")), 0_a);
     GlobalConst("result", LogicalOr(lhs, rhs));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/const_eval_bitcast_test.cc b/src/tint/resolver/const_eval_bitcast_test.cc
index cbb09d5..c52e2e3 100644
--- a/src/tint/resolver/const_eval_bitcast_test.cc
+++ b/src/tint/resolver/const_eval_bitcast_test.cc
@@ -14,11 +14,12 @@
 
 #include "src/tint/resolver/const_eval_test.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 struct Case {
     Value input;
     struct Success {
@@ -169,24 +170,24 @@
                                      Vec(0_i, 0x3F800000_i, 0x42F60000_i)),
 
                              // Unrepresentable
-                             Failure<f32>(Val(nan_as_u32)),                          //
-                             Failure<f32>(Val(nan_as_i32)),                          //
-                             Failure<f32>(Val(inf_as_u32)),                          //
-                             Failure<f32>(Val(inf_as_i32)),                          //
-                             Failure<f32>(Val(neg_inf_as_u32)),                      //
-                             Failure<f32>(Val(neg_inf_as_i32)),                      //
-                             Failure<builder::vec2<f32>>(Vec(nan_as_u32, 0_u)),      //
-                             Failure<builder::vec2<f32>>(Vec(nan_as_i32, 0_i)),      //
-                             Failure<builder::vec2<f32>>(Vec(inf_as_u32, 0_u)),      //
-                             Failure<builder::vec2<f32>>(Vec(inf_as_i32, 0_i)),      //
-                             Failure<builder::vec2<f32>>(Vec(neg_inf_as_u32, 0_u)),  //
-                             Failure<builder::vec2<f32>>(Vec(neg_inf_as_i32, 0_i)),  //
-                             Failure<builder::vec2<f32>>(Vec(0_u, nan_as_u32)),      //
-                             Failure<builder::vec2<f32>>(Vec(0_i, nan_as_i32)),      //
-                             Failure<builder::vec2<f32>>(Vec(0_u, inf_as_u32)),      //
-                             Failure<builder::vec2<f32>>(Vec(0_i, inf_as_i32)),      //
-                             Failure<builder::vec2<f32>>(Vec(0_u, neg_inf_as_u32)),  //
-                             Failure<builder::vec2<f32>>(Vec(0_i, neg_inf_as_i32)),  //
+                             Failure<f32>(Val(nan_as_u32)),                 //
+                             Failure<f32>(Val(nan_as_i32)),                 //
+                             Failure<f32>(Val(inf_as_u32)),                 //
+                             Failure<f32>(Val(inf_as_i32)),                 //
+                             Failure<f32>(Val(neg_inf_as_u32)),             //
+                             Failure<f32>(Val(neg_inf_as_i32)),             //
+                             Failure<vec2<f32>>(Vec(nan_as_u32, 0_u)),      //
+                             Failure<vec2<f32>>(Vec(nan_as_i32, 0_i)),      //
+                             Failure<vec2<f32>>(Vec(inf_as_u32, 0_u)),      //
+                             Failure<vec2<f32>>(Vec(inf_as_i32, 0_i)),      //
+                             Failure<vec2<f32>>(Vec(neg_inf_as_u32, 0_u)),  //
+                             Failure<vec2<f32>>(Vec(neg_inf_as_i32, 0_i)),  //
+                             Failure<vec2<f32>>(Vec(0_u, nan_as_u32)),      //
+                             Failure<vec2<f32>>(Vec(0_i, nan_as_i32)),      //
+                             Failure<vec2<f32>>(Vec(0_u, inf_as_u32)),      //
+                             Failure<vec2<f32>>(Vec(0_i, inf_as_i32)),      //
+                             Failure<vec2<f32>>(Vec(0_u, neg_inf_as_u32)),  //
+                             Failure<vec2<f32>>(Vec(0_i, neg_inf_as_i32)),  //
                          }));
 
 }  // namespace
diff --git a/src/tint/resolver/const_eval_construction_test.cc b/src/tint/resolver/const_eval_construction_test.cc
index 3d595140..4ecca7f 100644
--- a/src/tint/resolver/const_eval_construction_test.cc
+++ b/src/tint/resolver/const_eval_construction_test.cc
@@ -14,11 +14,12 @@
 
 #include "src/tint/resolver/const_eval_test.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 TEST_F(ResolverConstEvalTest, Scalar_AFloat) {
     auto* expr = Expr(99.0_a);
     auto* a = Const("a", expr);
@@ -189,26 +190,26 @@
                              C<f32>(),
                              C<f16>(),
                              C<bool>(),
-                             C<builder::vec2<AInt>>(),
-                             C<builder::vec3<AInt>>(),
-                             C<builder::vec4<AInt>>(),
-                             C<builder::vec3<u32>>(),
-                             C<builder::vec3<i32>>(),
-                             C<builder::vec3<f32>>(),
-                             C<builder::vec3<f16>>(),
-                             C<builder::mat2x2<f32>>(),
-                             C<builder::mat2x2<f16>>(),
-                             C<builder::array<3, u32>>(),
-                             C<builder::array<3, i32>>(),
-                             C<builder::array<3, f32>>(),
-                             C<builder::array<3, f16>>(),
-                             C<builder::array<3, bool>>(),
+                             C<vec2<AInt>>(),
+                             C<vec3<AInt>>(),
+                             C<vec4<AInt>>(),
+                             C<vec3<u32>>(),
+                             C<vec3<i32>>(),
+                             C<vec3<f32>>(),
+                             C<vec3<f16>>(),
+                             C<mat2x2<f32>>(),
+                             C<mat2x2<f16>>(),
+                             C<array<u32, 3>>(),
+                             C<array<i32, 3>>(),
+                             C<array<f32, 3>>(),
+                             C<array<f16, 3>>(),
+                             C<array<bool, 3>>(),
                          }));
 
 }  // namespace ZeroInit
 
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_i32) {
-    auto* expr = vec3<i32>();
+    auto* expr = Call<vec3<i32>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -237,7 +238,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_u32) {
-    auto* expr = vec3<u32>();
+    auto* expr = Call<vec3<u32>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -266,7 +267,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_f32) {
-    auto* expr = vec3<f32>();
+    auto* expr = Call<vec3<f32>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -297,7 +298,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>();
+    auto* expr = Call<vec3<f16>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -326,7 +327,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_ZeroInit_bool) {
-    auto* expr = vec3<bool>();
+    auto* expr = Call<vec3<bool>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -355,7 +356,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Splat_i32) {
-    auto* expr = vec3<i32>(99_i);
+    auto* expr = Call<vec3<i32>>(99_i);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -384,7 +385,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Splat_u32) {
-    auto* expr = vec3<u32>(99_u);
+    auto* expr = Call<vec3<u32>>(99_u);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -413,7 +414,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Splat_f32) {
-    auto* expr = vec3<f32>(9.9_f);
+    auto* expr = Call<vec3<f32>>(9.9_f);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -444,7 +445,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_Splat_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(9.9_h);
+    auto* expr = Call<vec3<f16>>(9.9_h);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -474,7 +475,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Splat_bool) {
-    auto* expr = vec3<bool>(true);
+    auto* expr = Call<vec3<bool>>(true);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -503,7 +504,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_AInt) {
-    auto* expr = vec3<Infer>(1_a, 2_a, 3_a);
+    auto* expr = Call<vec3<Infer>>(1_a, 2_a, 3_a);
     auto* a = Const("a", expr);
     WrapInFunction(a);
 
@@ -533,7 +534,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_AFloat) {
-    auto* expr = vec3<Infer>(1.0_a, 2.0_a, 3.0_a);
+    auto* expr = Call<vec3<Infer>>(1.0_a, 2.0_a, 3.0_a);
     auto* a = Const("a", expr);
     WrapInFunction(a);
 
@@ -563,7 +564,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_i32) {
-    auto* expr = vec3<i32>(1_i, 2_i, 3_i);
+    auto* expr = Call<vec3<i32>>(1_i, 2_i, 3_i);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -592,7 +593,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_u32) {
-    auto* expr = vec3<u32>(1_u, 2_u, 3_u);
+    auto* expr = Call<vec3<u32>>(1_u, 2_u, 3_u);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -621,7 +622,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_f32) {
-    auto* expr = vec3<f32>(1_f, 2_f, 3_f);
+    auto* expr = Call<vec3<f32>>(1_f, 2_f, 3_f);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -652,7 +653,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(1_h, 2_h, 3_h);
+    auto* expr = Call<vec3<f16>>(1_h, 2_h, 3_h);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -681,7 +682,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_FullConstruct_bool) {
-    auto* expr = vec3<bool>(true, false, true);
+    auto* expr = Call<vec3<bool>>(true, false, true);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -710,7 +711,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_i32) {
-    auto* expr = vec3<i32>(1_i, vec2<i32>(2_i, 3_i));
+    auto* expr = Call<vec3<i32>>(1_i, Call<vec2<i32>>(2_i, 3_i));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -739,7 +740,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_u32) {
-    auto* expr = vec3<u32>(vec2<u32>(1_u, 2_u), 3_u);
+    auto* expr = Call<vec3<u32>>(Call<vec2<u32>>(1_u, 2_u), 3_u);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -768,7 +769,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32) {
-    auto* expr = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
+    auto* expr = Call<vec3<f32>>(1_f, Call<vec2<f32>>(2_f, 3_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -797,7 +798,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_10) {
-    auto* expr = vec3<f32>(10_f, vec2<f32>(10_f, 10_f));
+    auto* expr = Call<vec3<f32>>(10_f, Call<vec2<f32>>(10_f, 10_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -826,7 +827,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_positive_0) {
-    auto* expr = vec3<f32>(0_f, vec2<f32>(0_f, 0_f));
+    auto* expr = Call<vec3<f32>>(0_f, Call<vec2<f32>>(0_f, 0_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -855,7 +856,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_all_negative_0) {
-    auto* expr = vec3<f32>(vec2<f32>(-0_f, -0_f), -0_f);
+    auto* expr = Call<vec3<f32>>(Call<vec2<f32>>(-0_f, -0_f), -0_f);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -884,7 +885,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f32_mixed_sign_0) {
-    auto* expr = vec3<f32>(0_f, vec2<f32>(-0_f, 0_f));
+    auto* expr = Call<vec3<f32>>(0_f, Call<vec2<f32>>(-0_f, 0_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -915,7 +916,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
+    auto* expr = Call<vec3<f16>>(1_h, Call<vec2<f16>>(2_h, 3_h));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -946,7 +947,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_10) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(10_h, vec2<f16>(10_h, 10_h));
+    auto* expr = Call<vec3<f16>>(10_h, Call<vec2<f16>>(10_h, 10_h));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -977,7 +978,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_positive_0) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(0_h, vec2<f16>(0_h, 0_h));
+    auto* expr = Call<vec3<f16>>(0_h, Call<vec2<f16>>(0_h, 0_h));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1008,7 +1009,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_all_negative_0) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(vec2<f16>(-0_h, -0_h), -0_h);
+    auto* expr = Call<vec3<f16>>(Call<vec2<f16>>(-0_h, -0_h), -0_h);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1039,7 +1040,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_f16_mixed_sign_0) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(0_h, vec2<f16>(-0_h, 0_h));
+    auto* expr = Call<vec3<f16>>(0_h, Call<vec2<f16>>(-0_h, 0_h));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1068,7 +1069,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_bool) {
-    auto* expr = vec3<bool>(vec2<bool>(true, false), true);
+    auto* expr = Call<vec3<bool>>(Call<vec2<bool>>(true, false), true);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1097,7 +1098,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_all_true) {
-    auto* expr = vec3<bool>(true, vec2<bool>(true, true));
+    auto* expr = Call<vec3<bool>>(true, Call<vec2<bool>>(true, true));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1126,7 +1127,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_MixConstruct_all_false) {
-    auto* expr = vec3<bool>(false, vec2<bool>(false, false));
+    auto* expr = Call<vec3<bool>>(false, Call<vec2<bool>>(false, false));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1155,7 +1156,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat2x3_ZeroInit_f32) {
-    auto* expr = mat2x3<f32>();
+    auto* expr = Call<mat2x3<f32>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1199,7 +1200,7 @@
 TEST_F(ResolverConstEvalTest, Mat2x3_ZeroInit_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = mat2x3<f16>();
+    auto* expr = Call<mat2x3<f16>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1241,7 +1242,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat3x2_Construct_Scalars_af) {
-    auto* expr = Call(ty.mat3x2<Infer>(), 1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a);
+    auto* expr = Call<mat3x2<Infer>>(1.0_a, 2.0_a, 3.0_a, 4.0_a, 5.0_a, 6.0_a);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1283,10 +1284,10 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat3x2_Construct_Columns_af) {
-    auto* expr = Call(ty.mat<Infer>(3, 2),        //
-                      vec2<Infer>(1.0_a, 2.0_a),  //
-                      vec2<Infer>(3.0_a, 4.0_a),  //
-                      vec2<Infer>(5.0_a, 6.0_a));
+    auto* expr = Call<mat<3, 2, Infer>>(  //
+        Call<vec2<Infer>>(1.0_a, 2.0_a),  //
+        Call<vec2<Infer>>(3.0_a, 4.0_a),  //
+        Call<vec2<Infer>>(5.0_a, 6.0_a));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1328,7 +1329,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_i32_Zero) {
-    auto* expr = Call(ty.array<i32, 4>());
+    auto* expr = Call<array<i32, 4>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1360,7 +1361,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_f32_Zero) {
-    auto* expr = Call(ty.array<f32, 4>());
+    auto* expr = Call<array<f32, 4>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1392,7 +1393,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_vec3_f32_Zero) {
-    auto* expr = Call(ty.array(ty.vec3<f32>(), 2_u));
+    auto* expr = Call<array<vec3<f32>, 2>>();
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1468,7 +1469,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_i32_Elements) {
-    auto* expr = Call(ty.array<i32, 4>(), 10_i, 20_i, 30_i, 40_i);
+    auto* expr = Call<array<i32, 4>>(10_i, 20_i, 30_i, 40_i);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1592,7 +1593,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_f32_Elements) {
-    auto* expr = Call(ty.array<f32, 4>(), 10_f, 20_f, 30_f, 40_f);
+    auto* expr = Call<array<f32, 4>>(10_f, 20_f, 30_f, 40_f);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -1624,8 +1625,8 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_vec3_f32_Elements) {
-    auto* expr = Call(ty.array(ty.vec3<f32>(), 2_u),  //
-                      vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f));
+    auto* expr =
+        Call<array<vec3<f32>, 2>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -2083,8 +2084,8 @@
                        Member("m4", ty.vec3<f16>()),
                        Member("m5", ty.vec2<bool>()),
                    });
-    auto* expr = Call("S", vec2<i32>(1_i), vec3<u32>(2_u), vec4<f32>(3_f), vec3<f16>(4_h),
-                      vec2<bool>(false));
+    auto* expr = Call("S", Call<vec2<i32>>(1_i), Call<vec3<u32>>(2_u), Call<vec4<f32>>(3_f),
+                      Call<vec3<f16>>(4_h), Call<vec2<bool>>(false));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -2192,7 +2193,7 @@
                        Member("m2", ty.array<f32, 3>()),
                    });
     auto* expr = Call("S",  //
-                      Call(ty.array<i32, 2>(), 1_i, 2_i), Call(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+                      Call<array<i32, 2>>(1_i, 2_i), Call<array<f32, 3>>(1_f, 2_f, 3_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/const_eval_conversion_test.cc b/src/tint/resolver/const_eval_conversion_test.cc
index 468d2b4..582ce19 100644
--- a/src/tint/resolver/const_eval_conversion_test.cc
+++ b/src/tint/resolver/const_eval_conversion_test.cc
@@ -16,7 +16,8 @@
 #include "src/tint/resolver/const_eval_test.h"
 #include "src/tint/sem/materialize.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -75,7 +76,7 @@
     auto* input_val = input.Expr(*this);
     auto* expr = Call(type.ast(*this), input_val);
     if (kind == Kind::kVector) {
-        expr = Call(ty.vec<Infer>(3), expr);
+        expr = Call<vec3<Infer>>(expr);
     }
     WrapInFunction(expr);
 
@@ -225,7 +226,7 @@
                                           })));
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_f32_to_i32) {
-    auto* expr = vec3<i32>(vec3<f32>(1.1_f, 2.2_f, 3.3_f));
+    auto* expr = Call<vec3<i32>>(Call<vec3<f32>>(1.1_f, 2.2_f, 3.3_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -254,7 +255,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_u32_to_f32) {
-    auto* expr = vec3<f32>(vec3<u32>(10_u, 20_u, 30_u));
+    auto* expr = Call<vec3<f32>>(Call<vec3<u32>>(10_u, 20_u, 30_u));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -285,7 +286,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_Convert_f16_to_i32) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<i32>(vec3<f16>(1.1_h, 2.2_h, 3.3_h));
+    auto* expr = Call<vec3<i32>>(Call<vec3<f16>>(1.1_h, 2.2_h, 3.3_h));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -316,7 +317,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_Convert_u32_to_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(vec3<u32>(10_u, 20_u, 30_u));
+    auto* expr = Call<vec3<f16>>(Call<vec3<u32>>(10_u, 20_u, 30_u));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -345,7 +346,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_i32) {
-    auto* expr = vec3<i32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
+    auto* expr = Call<vec3<i32>>(Call<vec3<f32>>(1e10_f, -1e20_f, 1e30_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -374,7 +375,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_u32) {
-    auto* expr = vec3<u32>(vec3<f32>(1e10_f, -1e20_f, 1e30_f));
+    auto* expr = Call<vec3<u32>>(Call<vec3<f32>>(1e10_f, -1e20_f, 1e30_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -405,7 +406,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Large_f32_to_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(Source{{12, 34}}, vec3<f32>(1e10_f, 0_f, 0_f));
+    auto* expr = Call<vec3<f16>>(Source{{12, 34}}, Call<vec3<f32>>(1e10_f, 0_f, 0_f));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve());
@@ -415,7 +416,7 @@
 TEST_F(ResolverConstEvalTest, Vec3_Convert_Small_f32_to_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = vec3<f16>(vec3<f32>(1e-20_f, -2e-30_f, 3e-40_f));
+    auto* expr = Call<vec3<f16>>(Call<vec3<f32>>(1e-20_f, -2e-30_f, 3e-40_f));
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/const_eval_indexing_test.cc b/src/tint/resolver/const_eval_indexing_test.cc
index d311d30..0358d5a 100644
--- a/src/tint/resolver/const_eval_indexing_test.cc
+++ b/src/tint/resolver/const_eval_indexing_test.cc
@@ -14,13 +14,14 @@
 
 #include "src/tint/resolver/const_eval_test.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
 
 TEST_F(ResolverConstEvalTest, Vec3_Index) {
-    auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), 2_i);
+    auto* expr = IndexAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), 2_i);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -35,7 +36,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_High) {
-    auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, 3_i));
+    auto* expr = IndexAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, 3_i));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -43,7 +44,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Index_OOB_Low) {
-    auto* expr = IndexAccessor(vec3<i32>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, -3_i));
+    auto* expr = IndexAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), Expr(Source{{12, 34}}, -3_i));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -123,7 +124,7 @@
 }  // namespace Swizzle
 
 TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Scalar) {
-    auto* expr = MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "y");
+    auto* expr = MemberAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), "y");
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -138,7 +139,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Vector) {
-    auto* expr = MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "zx");
+    auto* expr = MemberAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), "zx");
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -161,7 +162,8 @@
 
 TEST_F(ResolverConstEvalTest, Vec3_Swizzle_Chain) {
     auto* expr =  // (1, 2, 3) -> (2, 3, 1) -> (3, 2) -> 2
-        MemberAccessor(MemberAccessor(MemberAccessor(vec3<i32>(1_i, 2_i, 3_i), "gbr"), "yx"), "y");
+        MemberAccessor(MemberAccessor(MemberAccessor(Call<vec3<i32>>(1_i, 2_i, 3_i), "gbr"), "yx"),
+                       "y");
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -176,8 +178,10 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat3x2_Index) {
-    auto* expr = IndexAccessor(
-        mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)), 2_i);
+    auto* expr =
+        IndexAccessor(Call<mat3x2<f32>>(Call<vec2<f32>>(1._a, 2._a), Call<vec2<f32>>(3._a, 4._a),
+                                        Call<vec2<f32>>(5._a, 6._a)),
+                      2_i);
     WrapInFunction(expr);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -199,9 +203,10 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_High) {
-    auto* expr = IndexAccessor(
-        mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)),
-        Expr(Source{{12, 34}}, 3_i));
+    auto* expr =
+        IndexAccessor(Call<mat3x2<f32>>(Call<vec2<f32>>(1._a, 2._a), Call<vec2<f32>>(3._a, 4._a),
+                                        Call<vec2<f32>>(5._a, 6._a)),
+                      Expr(Source{{12, 34}}, 3_i));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -209,9 +214,10 @@
 }
 
 TEST_F(ResolverConstEvalTest, Mat3x2_Index_OOB_Low) {
-    auto* expr = IndexAccessor(
-        mat3x2<f32>(vec2<f32>(1._a, 2._a), vec2<f32>(3._a, 4._a), vec2<f32>(5._a, 6._a)),
-        Expr(Source{{12, 34}}, -3_i));
+    auto* expr =
+        IndexAccessor(Call<mat3x2<f32>>(Call<vec2<f32>>(1._a, 2._a), Call<vec2<f32>>(3._a, 4._a),
+                                        Call<vec2<f32>>(5._a, 6._a)),
+                      Expr(Source{{12, 34}}, -3_i));
     WrapInFunction(expr);
 
     EXPECT_FALSE(r()->Resolve()) << r()->error();
@@ -219,8 +225,9 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index) {
-    auto* expr = IndexAccessor(Call(ty.array(ty.vec3<f32>(), 2_u),  //
-                                    vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+    auto* expr = IndexAccessor(Call<array<vec3<f32>, 2>>(           //
+                                   Call<vec3<f32>>(1_f, 2_f, 3_f),  //
+                                   Call<vec3<f32>>(4_f, 5_f, 6_f)),
                                1_i);
     WrapInFunction(expr);
 
@@ -248,8 +255,9 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_High) {
-    auto* expr = IndexAccessor(Call(ty.array(ty.vec3<f32>(), 2_u),  //
-                                    vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+    auto* expr = IndexAccessor(Call<array<vec3<f32>, 2>>(           //
+                                   Call<vec3<f32>>(1_f, 2_f, 3_f),  //
+                                   Call<vec3<f32>>(4_f, 5_f, 6_f)),
                                Expr(Source{{12, 34}}, 2_i));
     WrapInFunction(expr);
 
@@ -258,8 +266,9 @@
 }
 
 TEST_F(ResolverConstEvalTest, Array_vec3_f32_Index_OOB_Low) {
-    auto* expr = IndexAccessor(Call(ty.array(ty.vec3<f32>(), 2_u),  //
-                                    vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f)),
+    auto* expr = IndexAccessor(Call<array<vec3<f32>, 2>>(           //
+                                   Call<vec3<f32>>(1_f, 2_f, 3_f),  //
+                                   Call<vec3<f32>>(4_f, 5_f, 6_f)),
                                Expr(Source{{12, 34}}, -2_i));
     WrapInFunction(expr);
 
@@ -268,7 +277,7 @@
 }
 
 TEST_F(ResolverConstEvalTest, RuntimeArray_vec3_f32_Index_OOB_Low) {
-    auto* sb = GlobalVar("sb", ty.array(ty.vec3<f32>()), Group(0_a), Binding(0_a),
+    auto* sb = GlobalVar("sb", ty.array<vec3<f32>>(), Group(0_a), Binding(0_a),
                          builtin::AddressSpace::kStorage);
     auto* expr = IndexAccessor(sb, Expr(Source{{12, 34}}, -2_i));
     WrapInFunction(expr);
@@ -278,11 +287,11 @@
 }
 
 TEST_F(ResolverConstEvalTest, ChainedIndex) {
-    auto* arr_expr = Call(ty.array(ty.mat2x3<f32>(), 2_u),        // array<mat2x3<f32>, 2u>
-                          mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f),   //
-                                      vec3<f32>(4_f, 5_f, 6_f)),  //
-                          mat2x3<f32>(vec3<f32>(7_f, 0_f, 9_f),   //
-                                      vec3<f32>(10_f, 11_f, 12_f)));
+    auto* arr_expr = Call<array<mat2x3<f32>, 2>>(           //
+        Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f),   //
+                          Call<vec3<f32>>(4_f, 5_f, 6_f)),  //
+        Call<mat2x3<f32>>(Call<vec3<f32>>(7_f, 0_f, 9_f),   //
+                          Call<vec3<f32>>(10_f, 11_f, 12_f)));
 
     auto* mat_expr = IndexAccessor(arr_expr, 1_i);  // arr[1]
     auto* vec_expr = IndexAccessor(mat_expr, 0_i);  // arr[1][0]
diff --git a/src/tint/resolver/const_eval_member_access_test.cc b/src/tint/resolver/const_eval_member_access_test.cc
index ee92714..49b8e8c 100644
--- a/src/tint/resolver/const_eval_member_access_test.cc
+++ b/src/tint/resolver/const_eval_member_access_test.cc
@@ -14,7 +14,8 @@
 
 #include "src/tint/resolver/const_eval_test.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -68,9 +69,9 @@
 }
 
 TEST_F(ResolverConstEvalTest, Matrix_AFloat_Construct_From_AInt_Vectors) {
-    auto* c = Const("a", Call(ty.mat2x2<Infer>(),  //
-                              Call(ty.vec<Infer>(2), Expr(1_a), Expr(2_a)),
-                              Call(ty.vec<Infer>(2), Expr(3_a), Expr(4_a))));
+    auto* c = Const("a", Call<mat2x2<Infer>>(              //
+                             Call<vec2<Infer>>(1_a, 2_a),  //
+                             Call<vec2<Infer>>(3_a, 4_a)));
     WrapInFunction(c);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -93,18 +94,18 @@
 }
 
 TEST_F(ResolverConstEvalTest, MatrixMemberAccess_AFloat) {
-    auto* c = Const("a", Call(ty.mat2x3<Infer>(),  //
-                              Call(ty.vec3<Infer>(), Expr(1.0_a), Expr(2.0_a), Expr(3.0_a)),
-                              Call(ty.vec3<Infer>(), Expr(4.0_a), Expr(5.0_a), Expr(6.0_a))));
+    auto* c = Const("a", Call<mat2x3<Infer>>(                         //
+                             Call<vec3<Infer>>(1.0_a, 2.0_a, 3.0_a),  //
+                             Call<vec3<Infer>>(4.0_a, 5.0_a, 6.0_a)));
 
-    auto* col_0 = Const("col_0", IndexAccessor("a", Expr(0_i)));
-    auto* col_1 = Const("col_1", IndexAccessor("a", Expr(1_i)));
-    auto* e00 = Const("e00", IndexAccessor("col_0", Expr(0_i)));
-    auto* e01 = Const("e01", IndexAccessor("col_0", Expr(1_i)));
-    auto* e02 = Const("e02", IndexAccessor("col_0", Expr(2_i)));
-    auto* e10 = Const("e10", IndexAccessor("col_1", Expr(0_i)));
-    auto* e11 = Const("e11", IndexAccessor("col_1", Expr(1_i)));
-    auto* e12 = Const("e12", IndexAccessor("col_1", Expr(2_i)));
+    auto* col_0 = Const("col_0", IndexAccessor("a", 0_i));
+    auto* col_1 = Const("col_1", IndexAccessor("a", 1_i));
+    auto* e00 = Const("e00", IndexAccessor("col_0", 0_i));
+    auto* e01 = Const("e01", IndexAccessor("col_0", 1_i));
+    auto* e02 = Const("e02", IndexAccessor("col_0", 2_i));
+    auto* e10 = Const("e10", IndexAccessor("col_1", 0_i));
+    auto* e11 = Const("e11", IndexAccessor("col_1", 1_i));
+    auto* e12 = Const("e12", IndexAccessor("col_1", 2_i));
 
     (void)col_0;
     (void)col_1;
@@ -169,18 +170,18 @@
 }
 
 TEST_F(ResolverConstEvalTest, MatrixMemberAccess_f32) {
-    auto* c = Const("a", Call(ty.mat2x3<Infer>(),  //
-                              Call(ty.vec3<Infer>(), Expr(1.0_f), Expr(2.0_f), Expr(3.0_f)),
-                              Call(ty.vec3<Infer>(), Expr(4.0_f), Expr(5.0_f), Expr(6.0_f))));
+    auto* c = Const("a", Call<mat2x3<Infer>>(                         //
+                             Call<vec3<Infer>>(1.0_f, 2.0_f, 3.0_f),  //
+                             Call<vec3<Infer>>(4.0_f, 5.0_f, 6.0_f)));
 
-    auto* col_0 = Const("col_0", IndexAccessor("a", Expr(0_i)));
-    auto* col_1 = Const("col_1", IndexAccessor("a", Expr(1_i)));
-    auto* e00 = Const("e00", IndexAccessor("col_0", Expr(0_i)));
-    auto* e01 = Const("e01", IndexAccessor("col_0", Expr(1_i)));
-    auto* e02 = Const("e02", IndexAccessor("col_0", Expr(2_i)));
-    auto* e10 = Const("e10", IndexAccessor("col_1", Expr(0_i)));
-    auto* e11 = Const("e11", IndexAccessor("col_1", Expr(1_i)));
-    auto* e12 = Const("e12", IndexAccessor("col_1", Expr(2_i)));
+    auto* col_0 = Const("col_0", IndexAccessor("a", 0_i));
+    auto* col_1 = Const("col_1", IndexAccessor("a", 1_i));
+    auto* e00 = Const("e00", IndexAccessor("col_0", 0_i));
+    auto* e01 = Const("e01", IndexAccessor("col_0", 1_i));
+    auto* e02 = Const("e02", IndexAccessor("col_0", 2_i));
+    auto* e10 = Const("e10", IndexAccessor("col_1", 0_i));
+    auto* e11 = Const("e11", IndexAccessor("col_1", 1_i));
+    auto* e12 = Const("e12", IndexAccessor("col_1", 2_i));
 
     (void)col_0;
     (void)col_1;
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index ee509a7..49856fd 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -23,7 +23,8 @@
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/transform.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -1732,7 +1733,7 @@
     GlobalVar(Sym(), ty.array(T, V));
     GlobalVar(Sym(), ty.vec3(T));
     GlobalVar(Sym(), ty.mat3x2(T));
-    GlobalVar(Sym(), ty.ptr(builtin::AddressSpace::kPrivate, T));
+    GlobalVar(Sym(), ty.ptr<private_>(T));
     GlobalVar(Sym(), ty.sampled_texture(type::TextureDimension::k2d, T));
     GlobalVar(Sym(), ty.depth_texture(type::TextureDimension::k2d));
     GlobalVar(Sym(), ty.depth_multisampled_texture(type::TextureDimension::k2d));
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index eb2d779..4da98db 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -22,27 +22,16 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 // Helpers and typedefs
 template <typename T>
 using DataType = builder::DataType<T>;
 template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
-template <typename T>
 using alias = builder::alias<T>;
 
 class ResolverEntryPointValidationTest : public TestHelper, public testing::Test {};
@@ -69,7 +58,7 @@
     // fn main() -> @builtin(position) vec4<f32> { return vec4<f32>(); }
     Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
@@ -88,7 +77,7 @@
     // }
     Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
@@ -105,7 +94,7 @@
     // }
     Func(Source{{12, 34}}, "main", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
@@ -793,7 +782,7 @@
 
     Func(Source{{12, 34}}, "frag_main", utils::Empty, ty.array<f32, 2>(),
          utils::Vector{
-             Return(Call(ty.array<f32, 2>())),
+             Return(Call<array<f32, 2>>()),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
diff --git a/src/tint/resolver/evaluation_stage_test.cc b/src/tint/resolver/evaluation_stage_test.cc
index 2e148e5..c9c9e97 100644
--- a/src/tint/resolver/evaluation_stage_test.cc
+++ b/src/tint/resolver/evaluation_stage_test.cc
@@ -17,11 +17,12 @@
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverEvaluationStageTest = ResolverTest;
 
 TEST_F(ResolverEvaluationStageTest, Literal_i32) {
@@ -41,7 +42,7 @@
 }
 
 TEST_F(ResolverEvaluationStageTest, Vector_Init) {
-    auto* expr = vec3<f32>();
+    auto* expr = Call<vec3<f32>>();
     WrapInFunction(expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -52,7 +53,7 @@
     // const f = 1.f;
     // vec2<f32>(f, f);
     auto* f = Const("f", Expr(1_f));
-    auto* expr = vec2<f32>(f, f);
+    auto* expr = Call<vec2<f32>>(f, f);
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -64,7 +65,7 @@
     // var f = 1.f;
     // vec2<f32>(f, f);
     auto* f = Var("f", Expr(1_f));
-    auto* expr = vec2<f32>(f, f);
+    auto* expr = Call<vec2<f32>>(f, f);
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -76,7 +77,7 @@
     // const f = 1.f;
     // vec2<u32>(vec2<f32>(f));
     auto* f = Const("f", Expr(1_f));
-    auto* expr = vec2<u32>(vec2<f32>(f));
+    auto* expr = Call<vec2<u32>>(Call<vec2<f32>>(f));
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -88,7 +89,7 @@
     // var f = 1.f;
     // vec2<u32>(vec2<f32>(f));
     auto* f = Var("f", Expr(1_f));
-    auto* expr = vec2<u32>(vec2<f32>(f));
+    auto* expr = Call<vec2<u32>>(Call<vec2<f32>>(f));
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -97,7 +98,7 @@
 }
 
 TEST_F(ResolverEvaluationStageTest, Matrix_Init) {
-    auto* expr = mat2x2<f32>();
+    auto* expr = Call<mat2x2<f32>>();
     WrapInFunction(expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -105,7 +106,7 @@
 }
 
 TEST_F(ResolverEvaluationStageTest, Array_Init) {
-    auto* expr = array<f32, 3>();
+    auto* expr = Call<array<f32, 3>>();
     WrapInFunction(expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -116,7 +117,7 @@
     // const f = 1.f;
     // array<f32, 2>(f, f);
     auto* f = Const("f", Expr(1_f));
-    auto* expr = Call(ty.array<f32, 2>(), f, f);
+    auto* expr = Call<array<f32, 2>>(f, f);
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -130,7 +131,7 @@
     // array<f32, 2>(f1, f2);
     auto* f1 = Const("f1", Expr(1_f));
     auto* f2 = Override("f2", Expr(2_f));
-    auto* expr = Call(ty.array<f32, 2>(), f1, f2);
+    auto* expr = Call<array<f32, 2>>(f1, f2);
     WrapInFunction(f1, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -145,7 +146,7 @@
     // array<f32, 2>(f1, f2);
     auto* f1 = Override("f1", Expr(1_f));
     auto* f2 = Var("f2", Expr(2_f));
-    auto* expr = Call(ty.array<f32, 2>(), f1, f2);
+    auto* expr = Call<array<f32, 2>>(f1, f2);
     WrapInFunction(f2, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -160,7 +161,7 @@
     // array<f32, 2>(f1, f2);
     auto* f1 = Const("f1", Expr(1_f));
     auto* f2 = Var("f2", Expr(2_f));
-    auto* expr = Call(ty.array<f32, 2>(), f1, f2);
+    auto* expr = Call<array<f32, 2>>(f1, f2);
     WrapInFunction(f1, f2, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -173,7 +174,7 @@
     // var f = 1.f;
     // array<f32, 2>(f, f);
     auto* f = Var("f", Expr(1_f));
-    auto* expr = Call(ty.array<f32, 2>(), f, f);
+    auto* expr = Call<array<f32, 2>>(f, f);
     WrapInFunction(f, expr);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -185,7 +186,7 @@
     // const vec = vec4<f32>();
     // const idx = 1_i;
     // vec[idx]
-    auto* vec = Const("vec", vec4<f32>());
+    auto* vec = Const("vec", Call<vec4<f32>>());
     auto* idx = Const("idx", Expr(1_i));
     auto* expr = IndexAccessor(vec, idx);
     WrapInFunction(vec, idx, expr);
@@ -200,7 +201,7 @@
     // var vec = vec4<f32>();
     // const idx = 1_i;
     // vec[idx]
-    auto* vec = Var("vec", vec4<f32>());
+    auto* vec = Var("vec", Call<vec4<f32>>());
     auto* idx = Const("idx", Expr(1_i));
     auto* expr = IndexAccessor(vec, idx);
     WrapInFunction(vec, idx, expr);
@@ -215,7 +216,7 @@
     // const vec = vec4<f32>();
     // override idx = 1_i;
     // vec[idx]
-    auto* vec = Const("vec", vec4<f32>());
+    auto* vec = Const("vec", Call<vec4<f32>>());
     auto* idx = Override("idx", Expr(1_i));
     auto* expr = IndexAccessor(vec, idx);
     WrapInFunction(vec, expr);
@@ -230,7 +231,7 @@
     // const vec = vec4<f32>();
     // let idx = 1_i;
     // vec[idx]
-    auto* vec = Const("vec", vec4<f32>());
+    auto* vec = Const("vec", Call<vec4<f32>>());
     auto* idx = Let("idx", Expr(1_i));
     auto* expr = IndexAccessor(vec, idx);
     WrapInFunction(vec, idx, expr);
@@ -244,7 +245,7 @@
 TEST_F(ResolverEvaluationStageTest, Swizzle_Const) {
     // const vec = S();
     // vec.m
-    auto* vec = Const("vec", vec4<f32>());
+    auto* vec = Const("vec", Call<vec4<f32>>());
     auto* expr = MemberAccessor(vec, "xz");
     WrapInFunction(vec, expr);
 
@@ -256,7 +257,7 @@
 TEST_F(ResolverEvaluationStageTest, Swizzle_Runtime) {
     // var vec = S();
     // vec.m
-    auto* vec = Var("vec", vec4<f32>());
+    auto* vec = Var("vec", Call<vec4<f32>>());
     auto* expr = MemberAccessor(vec, "rg");
     WrapInFunction(vec, expr);
 
diff --git a/src/tint/resolver/f16_extension_test.cc b/src/tint/resolver/f16_extension_test.cc
index 0868208..8e4ad02 100644
--- a/src/tint/resolver/f16_extension_test.cc
+++ b/src/tint/resolver/f16_extension_test.cc
@@ -17,11 +17,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverF16ExtensionTest = ResolverTest;
 
 TEST_F(ResolverF16ExtensionTest, TypeUsedWithExtension) {
@@ -65,7 +66,7 @@
     // var<private> v = vec2<f16>();
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", vec2<f16>(), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec2<f16>>(), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -83,14 +84,15 @@
     // var<private> v = vec2<f16>(vec2<f32>());
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("v", vec2<f16>(vec2<f32>()), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec2<f16>>(Call<vec2<f32>>()), builtin::AddressSpace::kPrivate);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverF16ExtensionTest, Vec2TypeConvUsedWithoutExtension) {
     // var<private> v = vec2<f16>(vec2<f32>());
-    GlobalVar("v", vec2(ty.f16(Source{{12, 34}}), vec2<f32>()), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call(ty.vec2(ty.f16(Source{{12, 34}})), Call<vec2<f32>>()),
+              builtin::AddressSpace::kPrivate);
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: f16 type used without 'f16' extension enabled");
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index b97e7f3..cc5f746 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -22,7 +22,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -187,7 +188,7 @@
     Func(Source{{1, 2}}, "func", utils::Empty, ty.vec4<f32>(),
          utils::Vector{
              Discard(Source{{12, 34}}),
-             Return(Call(ty.vec4<f32>())),
+             Return(Call<vec4<f32>>()),
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
@@ -926,7 +927,7 @@
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
-    auto ret_type = ty.ptr(Source{{12, 34}}, builtin::AddressSpace::kFunction, ty.i32());
+    auto ret_type = ty.ptr<function, i32>(Source{{12, 34}});
     Func("f", utils::Empty, ret_type, utils::Empty);
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/increment_decrement_validation_test.cc b/src/tint/resolver/increment_decrement_validation_test.cc
index c3a0c78..b0ce2e3 100644
--- a/src/tint/resolver/increment_decrement_validation_test.cc
+++ b/src/tint/resolver/increment_decrement_validation_test.cc
@@ -17,11 +17,12 @@
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverIncrementDecrementValidationTest = ResolverTest;
 
 TEST_F(ResolverIncrementDecrementValidationTest, Increment_Signed) {
@@ -65,7 +66,7 @@
     // let b : ptr<function,i32> = &a;
     // *b++;
     auto* var_a = Var("a", ty.i32(), builtin::AddressSpace::kFunction);
-    auto* var_b = Let("b", ty.ptr<i32>(builtin::AddressSpace::kFunction), AddressOf(Expr("a")));
+    auto* var_b = Let("b", ty.ptr<function, i32>(), AddressOf(Expr("a")));
     WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index 4545419..b6b5481 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -17,27 +17,16 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 // Helpers and typedefs
 template <typename T>
 using DataType = builder::DataType<T>;
 template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
-template <typename T>
 using alias = builder::alias<T>;
 
 struct ResolverInferredTypeTest : public resolver::TestHelper, public testing::Test {};
diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc
index 1d5627c..7b658ad8 100644
--- a/src/tint/resolver/intrinsic_table_test.cc
+++ b/src/tint/resolver/intrinsic_table_test.cc
@@ -36,15 +36,16 @@
 namespace {
 
 using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
 
 using Parameter = sem::Parameter;
 using ParameterUsage = sem::ParameterUsage;
 
-using AFloatV = builder::vec<3, AFloat>;
-using AIntV = builder::vec<3, AInt>;
-using f32V = builder::vec<3, f32>;
-using i32V = builder::vec<3, i32>;
-using u32V = builder::vec<3, u32>;
+using AFloatV = vec3<AFloat>;
+using AIntV = vec3<AInt>;
+using f32V = vec3<f32>;
+using i32V = vec3<i32>;
+using u32V = vec3<u32>;
 
 class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
   public:
diff --git a/src/tint/resolver/is_storeable_test.cc b/src/tint/resolver/is_storeable_test.cc
index 65c1ab9..b7fa0e8 100644
--- a/src/tint/resolver/is_storeable_test.cc
+++ b/src/tint/resolver/is_storeable_test.cc
@@ -18,6 +18,8 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/type/atomic.h"
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -112,7 +114,7 @@
 TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
     Structure("S", utils::Vector{
                        Member("a", ty.i32()),
-                       Member("b", ty.ptr<i32>(builtin::AddressSpace::kPrivate)),
+                       Member("b", ty.ptr<private_, i32>()),
                    });
 
     EXPECT_FALSE(r()->Resolve());
@@ -135,11 +137,10 @@
 }
 
 TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
-    auto* non_storable =
-        Structure("nonstorable", utils::Vector{
-                                     Member("a", ty.i32()),
-                                     Member("b", ty.ptr<i32>(builtin::AddressSpace::kPrivate)),
-                                 });
+    auto* non_storable = Structure("nonstorable", utils::Vector{
+                                                      Member("a", ty.i32()),
+                                                      Member("b", ty.ptr<private_, i32>()),
+                                                  });
     Structure("S", utils::Vector{
                        Member("a", ty.i32()),
                        Member("b", ty.Of(non_storable)),
diff --git a/src/tint/resolver/load_test.cc b/src/tint/resolver/load_test.cc
index 2334227..48b9886 100644
--- a/src/tint/resolver/load_test.cc
+++ b/src/tint/resolver/load_test.cc
@@ -20,11 +20,12 @@
 #include "src/tint/type/reference.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverLoadTest = ResolverTest;
 
 TEST_F(ResolverLoadTest, VarInitializer) {
@@ -140,7 +141,7 @@
     // var v = array<i32, 3>(1i, 2i, 3i)[ref];
     auto* ident = Expr("ref");
     WrapInFunction(Var("ref", Expr(1_i)),  //
-                   IndexAccessor(array<i32, 3>(1_i, 2_i, 3_i), ident));
+                   IndexAccessor(Call<array<i32, 3>>(1_i, 2_i, 3_i), ident));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* load = Sem().Get<sem::Load>(ident);
@@ -154,7 +155,7 @@
     // var ref = vec4(1);
     // var v = ref.xyz;
     auto* ident = Expr("ref");
-    WrapInFunction(Var("ref", vec4<i32>(1_i)),  //
+    WrapInFunction(Var("ref", Call<vec4<i32>>(1_i)),  //
                    Var("v", MemberAccessor(ident, "xyz")));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -230,7 +231,7 @@
          },
          ty.vec4<f32>(),
          utils::Vector{
-             Return(Call("textureSampleLevel", "tp", "sp", vec2<f32>(), 0_a)),
+             Return(Call("textureSampleLevel", "tp", "sp", Call<vec2<f32>>(), 0_a)),
          });
     auto* t_ident = Expr("t");
     auto* s_ident = Expr("s");
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index cf67c93..7a45bf8 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -21,26 +21,27 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
-using AFloatV = builder::vec<3, AFloat>;
-using AFloatM = builder::mat<3, 2, AFloat>;
-using AFloatA = builder::array<3, AFloat>;
-using AIntV = builder::vec<3, AInt>;
-using AIntA = builder::array<3, AInt>;
-using f32V = builder::vec<3, f32>;
-using f16V = builder::vec<3, f16>;
-using i32V = builder::vec<3, i32>;
-using u32V = builder::vec<3, u32>;
-using f32M = builder::mat<3, 2, f32>;
-using f16M = builder::mat<3, 2, f16>;
-using f32A = builder::array<3, f32>;
-using f16A = builder::array<3, f16>;
-using i32A = builder::array<3, i32>;
-using u32A = builder::array<3, u32>;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
+using AFloatV = vec3<AFloat>;
+using AFloatM = mat3x2<AFloat>;
+using AFloatA = array<AFloat, 3>;
+using AIntV = vec3<AInt>;
+using AIntA = array<AInt, 3>;
+using f32V = vec3<f32>;
+using f16V = vec3<f16>;
+using i32V = vec3<i32>;
+using u32V = vec3<u32>;
+using f32M = mat3x2<f32>;
+using f16M = mat3x2<f16>;
+using f32A = array<f32, 3>;
+using f16A = array<f16, 3>;
+using i32A = array<i32, 3>;
+using u32A = array<u32, 3>;
 
 constexpr double kTooBigF32 = static_cast<double>(3.5e+38);
 constexpr double kTooBigF16 = static_cast<double>(6.6e+4);
@@ -1276,7 +1277,7 @@
 
 TEST_F(MaterializeAbstractStructure, Modf_Vector_DefaultType) {
     // var v = modf(vec2(1));
-    auto* call = Call("modf", Call(ty.vec2<Infer>(), 1_a));
+    auto* call = Call("modf", Call<vec2<Infer>>(1_a));
     WrapInFunction(Decl(Var("v", call)));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* sem = Sem().Get(call);
@@ -1316,8 +1317,8 @@
     // var v = modf(vec2(1_h)); // v is __modf_result_vec2_f16
     // v = modf(vec2(1));       // __modf_result_vec2_f16 <- __modf_result_vec2_abstract
     Enable(builtin::Extension::kF16);
-    auto* call = Call("modf", Call(ty.vec2<Infer>(), 1_a));
-    WrapInFunction(Decl(Var("v", Call("modf", Call(ty.vec2<Infer>(), 1_h)))), Assign("v", call));
+    auto* call = Call("modf", Call<vec2<Infer>>(1_a));
+    WrapInFunction(Decl(Var("v", Call("modf", Call<vec2<Infer>>(1_h)))), Assign("v", call));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* sem = Sem().Get(call);
     ASSERT_TRUE(sem->Is<sem::Materialize>());
@@ -1353,7 +1354,7 @@
 
 TEST_F(MaterializeAbstractStructure, Frexp_Vector_DefaultType) {
     // var v = frexp(vec2(1));
-    auto* call = Call("frexp", Call(ty.vec2<Infer>(), 1_a));
+    auto* call = Call("frexp", Call<vec2<Infer>>(1_a));
     WrapInFunction(Decl(Var("v", call)));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* sem = Sem().Get(call);
@@ -1399,8 +1400,8 @@
     // var v = frexp(vec2(1_h)); // v is __frexp_result_vec2_f16
     // v = frexp(vec2(1));       // __frexp_result_vec2_f16 <- __frexp_result_vec2_abstract
     Enable(builtin::Extension::kF16);
-    auto* call = Call("frexp", Call(ty.vec2<Infer>(), 1_a));
-    WrapInFunction(Decl(Var("v", Call("frexp", Call(ty.vec2<Infer>(), 1_h)))), Assign("v", call));
+    auto* call = Call("frexp", Call<vec2<Infer>>(1_a));
+    WrapInFunction(Decl(Var("v", Call("frexp", Call<vec2<Infer>>(1_h)))), Assign("v", call));
     ASSERT_TRUE(r()->Resolve()) << r()->error();
     auto* sem = Sem().Get(call);
     ASSERT_TRUE(sem->Is<sem::Materialize>());
diff --git a/src/tint/resolver/ptr_ref_validation_test.cc b/src/tint/resolver/ptr_ref_validation_test.cc
index f6da233..2da5cf0 100644
--- a/src/tint/resolver/ptr_ref_validation_test.cc
+++ b/src/tint/resolver/ptr_ref_validation_test.cc
@@ -19,11 +19,12 @@
 #include "src/tint/type/reference.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 struct ResolverPtrRefValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfLiteral) {
@@ -143,12 +144,11 @@
     // }
     auto* inner = Structure("Inner", utils::Vector{Member("arr", ty.array<i32, 4>())});
     auto* buf = Structure("S", utils::Vector{Member("inner", ty.Of(inner))});
-    auto* storage = GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage,
-                              builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
+    auto* var = GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage,
+                          builtin::Access::kReadWrite, Binding(0_a), Group(0_a));
 
-    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
-    auto* ptr =
-        Let(Source{{12, 34}}, "p", ty.ptr<i32>(builtin::AddressSpace::kStorage), AddressOf(expr));
+    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(var, "inner"), "arr"), 2_i);
+    auto* ptr = Let(Source{{12, 34}}, "p", ty.ptr<storage, i32>(), AddressOf(expr));
 
     WrapInFunction(ptr);
 
diff --git a/src/tint/resolver/resolver_behavior_test.cc b/src/tint/resolver/resolver_behavior_test.cc
index bc4af42..378642b 100644
--- a/src/tint/resolver/resolver_behavior_test.cc
+++ b/src/tint/resolver/resolver_behavior_test.cc
@@ -22,11 +22,12 @@
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/sem/while_statement.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 class ResolverBehaviorTest : public ResolverTest {
   protected:
     void SetUp() override {
@@ -82,7 +83,7 @@
     Func("ArrayDiscardOrNext", utils::Empty, ty.array<i32, 4>(),
          utils::Vector{
              If(true, Block(Discard())),
-             Return(array<i32, 4>()),
+             Return(Call<array<i32, 4>>()),
          });
 
     auto* stmt = Decl(Var("lhs", ty.i32(), IndexAccessor(Call("ArrayDiscardOrNext"), 1_i)));
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index eab9b86..c4d57aa 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -48,37 +48,18 @@
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/string_stream.h"
 
+namespace tint::resolver {
+namespace {
+
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
-
-namespace tint::resolver {
-namespace {
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 // Helpers and typedefs
 template <typename T>
 using DataType = builder::DataType<T>;
-template <int N, typename T>
-using vec = builder::vec<N, T>;
-template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <int N, int M, typename T>
-using mat = builder::mat<N, M, T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat2x3 = builder::mat2x3<T>;
-template <typename T>
-using mat3x2 = builder::mat3x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
 template <typename T, int ID = 0>
 using alias = builder::alias<T, ID>;
 template <typename T>
@@ -666,7 +647,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Initializer_Type_Vec2) {
-    auto* tc = vec2<f32>(1_f, 1_f);
+    auto* tc = Call<vec2<f32>>(1_f, 1_f);
     WrapInFunction(tc);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -678,7 +659,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Initializer_Type_Vec3) {
-    auto* tc = vec3<f32>(1_f, 1_f, 1_f);
+    auto* tc = Call<vec3<f32>>(1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -690,7 +671,7 @@
 }
 
 TEST_F(ResolverTest, Expr_Initializer_Type_Vec4) {
-    auto* tc = vec4<f32>(1_f, 1_f, 1_f, 1_f);
+    auto* tc = Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
     EXPECT_TRUE(r()->Resolve()) << r()->error();
@@ -756,7 +737,7 @@
     // var a : array<bool, 10u> = 0;
     // var idx : f32 = f32();
     // var f : f32 = a[idx];
-    auto* a = Var("a", ty.array<bool, 10>(), array<bool, 10>());
+    auto* a = Var("a", ty.array<bool, 10>(), Call<array<bool, 10>>());
     auto* idx = Var("idx", ty.f32(), Call<f32>());
     auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
     Func("my_func", utils::Empty, ty.void_(),
@@ -803,7 +784,7 @@
     auto* v = Expr("v");
     auto* p = Expr("p");
     auto* v_decl = Decl(Var("v", ty.f32()));
-    auto* p_decl = Decl(Let("p", ty.ptr<f32>(builtin::AddressSpace::kFunction), AddressOf(v)));
+    auto* p_decl = Decl(Let("p", ty.ptr<function, f32>(), AddressOf(v)));
     auto* assign = Assign(Deref(p), 1.23_f);
     Func("my_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -2138,7 +2119,7 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* call = Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f));
+    auto* call = Call("textureSample", "t", "s", Call<vec2<f32>>(1_f, 2_f));
     const ast::Function* f =
         Func("test_function", utils::Empty, ty.void_(), utils::Vector{Assign(Phony(), call)},
              utils::Vector{Stage(ast::PipelineStage::kFragment)});
@@ -2157,7 +2138,7 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* inner_call = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call = Assign(Phony(), Call("textureSample", "t", "s", Call<vec2<f32>>(1_f, 2_f)));
     const ast::Function* inner_func =
         Func("inner_func", utils::Empty, ty.void_(), utils::Vector{inner_call});
     auto* outer_call = CallStmt(Call("inner_func"));
@@ -2183,10 +2164,12 @@
               Binding(1_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(2_a));
 
-    auto* inner_call_1 = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call_1 =
+        Assign(Phony(), Call("textureSample", "t", "s", Call<vec2<f32>>(1_f, 2_f)));
     const ast::Function* inner_func_1 =
         Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
-    auto* inner_call_2 = Assign(Phony(), Call("textureSample", "t", "s", vec2<f32>(3_f, 4_f)));
+    auto* inner_call_2 =
+        Assign(Phony(), Call("textureSample", "t", "s", Call<vec2<f32>>(3_f, 4_f)));
     const ast::Function* inner_func_2 =
         Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
     auto* outer_call_1 = CallStmt(Call("inner_func_1"));
@@ -2220,10 +2203,12 @@
               Binding(2_a));
     GlobalVar("s", ty.sampler(type::SamplerKind::kSampler), Group(1_a), Binding(3_a));
 
-    auto* inner_call_1 = Assign(Phony(), Call("textureSample", "t1", "s", vec2<f32>(1_f, 2_f)));
+    auto* inner_call_1 =
+        Assign(Phony(), Call("textureSample", "t1", "s", Call<vec2<f32>>(1_f, 2_f)));
     const ast::Function* inner_func_1 =
         Func("inner_func_1", utils::Empty, ty.void_(), utils::Vector{inner_call_1});
-    auto* inner_call_2 = Assign(Phony(), Call("textureSample", "t2", "s", vec2<f32>(3_f, 4_f)));
+    auto* inner_call_2 =
+        Assign(Phony(), Call("textureSample", "t2", "s", Call<vec2<f32>>(3_f, 4_f)));
     const ast::Function* inner_func_2 =
         Func("inner_func_2", utils::Empty, ty.void_(), utils::Vector{inner_call_2});
     auto* outer_call_1 = CallStmt(Call("inner_func_1"));
@@ -2299,10 +2284,9 @@
 
     Func("helper",
          utils::Vector{
-             Param("sl", ty.ptr(builtin::AddressSpace::kFunction,
-                                ty.sampler(type::SamplerKind::kSampler))),
-             Param("tl", ty.ptr(builtin::AddressSpace::kFunction,
-                                ty.sampled_texture(type::TextureDimension::k2d, ty.f32()))),
+             Param("sl", ty.ptr<function>(ty.sampler(type::SamplerKind::kSampler))),
+             Param("tl",
+                   ty.ptr<function>(ty.sampled_texture(type::TextureDimension::k2d, ty.f32()))),
          },
          ty.vec4<f32>(),
          utils::Vector{
@@ -2537,7 +2521,7 @@
 }
 
 TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfVector_Valid) {
-    auto a = ty.array(ty.vec3<i32>(), 10_u);
+    auto a = ty.array<vec3<i32>, 10>();
     size_t depth = 2;  // Depth of array + vector
     size_t iterations = kMaxNestDepthOfCompositeType - depth;
     for (size_t i = 0; i < iterations; ++i) {
diff --git a/src/tint/resolver/resolver_test_helper.h b/src/tint/resolver/resolver_test_helper.h
index 706ba89..4f72b9c 100644
--- a/src/tint/resolver/resolver_test_helper.h
+++ b/src/tint/resolver/resolver_test_helper.h
@@ -130,51 +130,6 @@
 
 namespace builder {
 
-template <uint32_t N, typename T>
-struct vec {};
-
-template <typename T>
-using vec2 = vec<2, T>;
-
-template <typename T>
-using vec3 = vec<3, T>;
-
-template <typename T>
-using vec4 = vec<4, T>;
-
-template <uint32_t N, uint32_t M, typename T>
-struct mat {};
-
-template <typename T>
-using mat2x2 = mat<2, 2, T>;
-
-template <typename T>
-using mat2x3 = mat<2, 3, T>;
-
-template <typename T>
-using mat2x4 = mat<2, 4, T>;
-
-template <typename T>
-using mat3x2 = mat<3, 2, T>;
-
-template <typename T>
-using mat3x3 = mat<3, 3, T>;
-
-template <typename T>
-using mat3x4 = mat<3, 4, T>;
-
-template <typename T>
-using mat4x2 = mat<4, 2, T>;
-
-template <typename T>
-using mat4x3 = mat<4, 3, T>;
-
-template <typename T>
-using mat4x4 = mat<4, 4, T>;
-
-template <uint32_t N, typename T>
-struct array {};
-
 template <typename TO, int ID = 0>
 struct alias {};
 
@@ -187,9 +142,6 @@
 template <typename TO>
 using alias3 = alias<TO, 3>;
 
-template <typename TO>
-struct ptr {};
-
 /// A scalar value
 using Scalar = std::variant<i32, u32, f32, f16, AInt, AFloat, bool>;
 
@@ -446,7 +398,7 @@
 
 /// Helper for building vector types and expressions
 template <uint32_t N, typename T>
-struct DataType<vec<N, T>> {
+struct DataType<builtin::fluent_types::vec<N, T>> {
     /// The element type
     using ElementType = T;
 
@@ -457,7 +409,7 @@
     /// @return a new AST vector type
     static inline ast::Type AST(ProgramBuilder& b) {
         if (IsInferOrAbstract<T>) {
-            return b.ty.vec<Infer, N>();
+            return b.ty.vec<builtin::fluent_types::Infer, N>();
         } else {
             return b.ty.vec(DataType<T>::AST(b), N);
         }
@@ -498,7 +450,7 @@
 
 /// Helper for building matrix types and expressions
 template <uint32_t N, uint32_t M, typename T>
-struct DataType<mat<N, M, T>> {
+struct DataType<builtin::fluent_types::mat<N, M, T>> {
     /// The element type
     using ElementType = T;
 
@@ -509,7 +461,7 @@
     /// @return a new AST matrix type
     static inline ast::Type AST(ProgramBuilder& b) {
         if (IsInferOrAbstract<T>) {
-            return b.ty.mat<Infer, N, M>();
+            return b.ty.mat<builtin::fluent_types::Infer, N, M>();
         } else {
             return b.ty.mat(DataType<T>::AST(b), N, M);
         }
@@ -535,13 +487,14 @@
         utils::Vector<const ast::Expression*, N> r;
         for (uint32_t i = 0; i < N; ++i) {
             if (one_value) {
-                r.Push(DataType<vec<M, T>>::Expr(b, utils::Vector<Scalar, 1>{args[0]}));
+                r.Push(DataType<builtin::fluent_types::vec<M, T>>::Expr(
+                    b, utils::Vector<Scalar, 1>{args[0]}));
             } else {
                 utils::Vector<Scalar, M> v;
                 for (size_t j = 0; j < M; ++j) {
                     v.Push(args[next++]);
                 }
-                r.Push(DataType<vec<M, T>>::Expr(b, std::move(v)));
+                r.Push(DataType<builtin::fluent_types::vec<M, T>>::Expr(b, std::move(v)));
             }
         }
         return r;
@@ -618,7 +571,8 @@
 
 /// Helper for building pointer types and expressions
 template <typename T>
-struct DataType<ptr<T>> {
+struct DataType<
+    builtin::fluent_types::ptr<builtin::AddressSpace::kPrivate, T, builtin::Access::kUndefined>> {
     /// The element type
     using ElementType = typename DataType<T>::ElementType;
 
@@ -628,9 +582,9 @@
     /// @param b the ProgramBuilder
     /// @return a new AST alias type
     static inline ast::Type AST(ProgramBuilder& b) {
-        return b.ty.ptr(builtin::AddressSpace::kPrivate, DataType<T>::AST(b),
-                        builtin::Access::kUndefined);
+        return b.ty.ptr<builtin::AddressSpace::kPrivate, T>();
     }
+
     /// @param b the ProgramBuilder
     /// @return the semantic aliased type
     static inline const type::Type* Sem(ProgramBuilder& b) {
@@ -659,8 +613,8 @@
 };
 
 /// Helper for building array types and expressions
-template <uint32_t N, typename T>
-struct DataType<array<N, T>> {
+template <typename T, uint32_t N>
+struct DataType<builtin::fluent_types::array<T, N>> {
     /// The element type
     using ElementType = typename DataType<T>::ElementType;
 
@@ -673,7 +627,7 @@
         if (auto ast = DataType<T>::AST(b)) {
             return b.ty.array(ast, u32(N));
         }
-        return b.ty.array<Infer>();
+        return b.ty.array<builtin::fluent_types::Infer>();
     }
     /// @param b the ProgramBuilder
     /// @return the semantic array type
@@ -832,7 +786,7 @@
                   "Vector args must all be the same type");
     constexpr size_t N = sizeof...(args);
     utils::Vector<Scalar, sizeof...(args)> v{args...};
-    return Value::Create<vec<N, FirstT>>(std::move(v));
+    return Value::Create<builtin::fluent_types::vec<N, FirstT>>(std::move(v));
 }
 
 /// Creates a Value of DataType<array<N, T>> from N scalar `args`
@@ -843,7 +797,7 @@
                   "Array args must all be the same type");
     constexpr size_t N = sizeof...(args);
     utils::Vector<Scalar, sizeof...(args)> v{args...};
-    return Value::Create<array<N, FirstT>>(std::move(v));
+    return Value::Create<builtin::fluent_types::array<FirstT, N>>(std::move(v));
 }
 
 /// Creates a Value of DataType<mat<C,R,T> from C*R scalar `args`
@@ -855,7 +809,7 @@
             m.Push(m_in[i][j]);
         }
     }
-    return Value::Create<mat<C, R, T>>(std::move(m));
+    return Value::Create<builtin::fluent_types::mat<C, R, T>>(std::move(m));
 }
 
 /// Creates a Value of DataType<mat<2,R,T> from column vectors `c0` and `c1`
@@ -869,7 +823,7 @@
     for (auto v : c1) {
         m.Push(v);
     }
-    return Value::Create<mat<C, R, T>>(std::move(m));
+    return Value::Create<builtin::fluent_types::mat<C, R, T>>(std::move(m));
 }
 
 /// Creates a Value of DataType<mat<3,R,T> from column vectors `c0`, `c1`, and `c2`
@@ -886,7 +840,7 @@
     for (auto v : c2) {
         m.Push(v);
     }
-    return Value::Create<mat<C, R, T>>(std::move(m));
+    return Value::Create<builtin::fluent_types::mat<C, R, T>>(std::move(m));
 }
 
 /// Creates a Value of DataType<mat<4,R,T> from column vectors `c0`, `c1`, `c2`, and `c3`
@@ -906,7 +860,7 @@
     for (auto v : c3) {
         m.Push(v);
     }
-    return Value::Create<mat<C, R, T>>(std::move(m));
+    return Value::Create<builtin::fluent_types::mat<C, R, T>>(std::move(m));
 }
 }  // namespace builder
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/root_identifier_test.cc b/src/tint/resolver/root_identifier_test.cc
index 4ff43cb..f6d88f8 100644
--- a/src/tint/resolver/root_identifier_test.cc
+++ b/src/tint/resolver/root_identifier_test.cc
@@ -19,11 +19,12 @@
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 class ResolverRootIdentifierTest : public ResolverTest {};
 
 TEST_F(ResolverRootIdentifierTest, GlobalPrivateVar) {
@@ -142,7 +143,7 @@
     // {
     //   let b = a;
     // }
-    auto* param = Param("a", ty.ptr(builtin::AddressSpace::kFunction, ty.f32()));
+    auto* param = Param("a", ty.ptr<function, f32>());
     auto* expr_param = Expr(param);
     auto* let = Let("b", expr_param);
     auto* expr_let = Expr("b");
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index b4857f0..70e6046 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -20,13 +20,13 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/struct.h"
 
-using ::testing::UnorderedElementsAre;
-
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using ::testing::UnorderedElementsAre;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ResolverPipelineStageUseTest = ResolverTest;
 
 TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
@@ -68,7 +68,7 @@
     auto* s = Structure("S", utils::Vector{Member("a", ty.f32(), utils::Vector{Location(0_a)})});
 
     Func("main", utils::Vector{Param("param", ty.Of(s))}, ty.vec4<f32>(),
-         utils::Vector{Return(Call(ty.vec4<f32>()))},
+         utils::Vector{Return(Call<vec4<f32>>())},
          utils::Vector{Stage(ast::PipelineStage::kVertex)},
          utils::Vector{Builtin(builtin::BuiltinValue::kPosition)});
 
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index de79f85..cd6a66d 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -23,7 +23,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -32,32 +33,6 @@
 template <typename T>
 using DataType = builder::DataType<T>;
 template <typename T>
-using vec2 = builder::vec2<T>;
-template <typename T>
-using vec3 = builder::vec3<T>;
-template <typename T>
-using vec4 = builder::vec4<T>;
-template <typename T>
-using mat2x2 = builder::mat2x2<T>;
-template <typename T>
-using mat2x3 = builder::mat2x3<T>;
-template <typename T>
-using mat2x4 = builder::mat2x4<T>;
-template <typename T>
-using mat3x2 = builder::mat3x2<T>;
-template <typename T>
-using mat3x3 = builder::mat3x3<T>;
-template <typename T>
-using mat3x4 = builder::mat3x4<T>;
-template <typename T>
-using mat4x2 = builder::mat4x2<T>;
-template <typename T>
-using mat4x3 = builder::mat4x3<T>;
-template <typename T>
-using mat4x4 = builder::mat4x4<T>;
-template <int N, typename T>
-using array = builder::array<N, T>;
-template <typename T>
 using alias = builder::alias<T>;
 template <typename T>
 using alias1 = builder::alias1<T>;
@@ -331,7 +306,7 @@
 TEST_F(ResolverTypeValidationTest, ArraySize_IVecConst) {
     // const size = vec2<i32>(100, 100);
     // var<private> a : array<f32, size>;
-    GlobalConst("size", Call(ty.vec2<i32>(), 100_i, 100_i));
+    GlobalConst("size", Call<vec2<i32>>(100_i, 100_i));
     GlobalVar("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
               builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
@@ -881,7 +856,7 @@
 }
 
 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableTypeWithStride) {
-    auto ptr_ty = ty.ptr<u32>(Source{{12, 34}}, builtin::AddressSpace::kUniform);
+    auto ptr_ty = ty.ptr<uniform, u32>(Source{{12, 34}});
     GlobalVar("arr", ty.array(ptr_ty, 4_i, utils::Vector{Stride(16)}),
               builtin::AddressSpace::kPrivate);
 
@@ -1305,8 +1280,8 @@
                                          ParamsFor<mat2x2<f16>>(3, 2),
                                          ParamsFor<mat3x3<f16>>(3, 3),
                                          ParamsFor<mat4x4<f16>>(3, 4),
-                                         ParamsFor<array<2, f32>>(4, 2),
-                                         ParamsFor<array<2, f16>>(4, 2)));
+                                         ParamsFor<array<f32, 2>>(4, 2),
+                                         ParamsFor<array<f16, 2>>(4, 2)));
 }  // namespace MatrixTests
 
 namespace VectorTests {
@@ -1366,8 +1341,7 @@
               builtin::AddressSpace::kPrivate);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' "
-              "or 'u32'");
+              "12:34 error: vector element type must be 'bool', 'f32', 'f16', 'i32' or 'u32'");
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          InvalidVectorElementTypes,
@@ -1377,7 +1351,7 @@
                                          ParamsFor<mat2x2<f32>>(2),
                                          ParamsFor<mat3x3<f16>>(2),
                                          ParamsFor<mat4x4<f32>>(2),
-                                         ParamsFor<array<2, f32>>(2)));
+                                         ParamsFor<array<f32, 2>>(2)));
 }  // namespace VectorTests
 
 namespace BuiltinTypeAliasTests {
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index e890bcb..5bf5fda 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -25,7 +25,8 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -5301,8 +5302,7 @@
     }
     foo_body.Push(b.Decl(b.Let("rhs", rhs_init)));
     for (int i = 0; i < 255; i++) {
-        params.Push(
-            b.Param("p" + std::to_string(i), ty.ptr(builtin::AddressSpace::kFunction, ty.i32())));
+        params.Push(b.Param("p" + std::to_string(i), ty.ptr<function, i32>()));
         if (i > 0) {
             foo_body.Push(b.Assign(b.Deref("p" + std::to_string(i)), "rhs"));
         }
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index ca958ad..238120f 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -43,7 +43,8 @@
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -380,7 +381,7 @@
     //     let x: f32 = (*p).z;
     //     return x;
     // }
-    auto* p = Param("p", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()));
+    auto* p = Param("p", ty.ptr<function, vec4<f32>>());
     auto* star_p = Deref(p);
     auto* accessor_expr = MemberAccessor(star_p, "z");
     auto* x = Var("x", ty.f32(), accessor_expr);
@@ -397,7 +398,7 @@
     //     let x: f32 = *p.z;
     //     return x;
     // }
-    auto* p = Param("p", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()));
+    auto* p = Param("p", ty.ptr<function, vec4<f32>>());
     auto* accessor_expr = MemberAccessor(p, Ident(Source{{12, 34}}, "z"));
     auto* star_p = Deref(accessor_expr);
     auto* x = Var("x", ty.f32(), star_p);
@@ -1234,8 +1235,8 @@
 
 TEST_F(ResolverTest, Expr_Initializer_Cast_Pointer) {
     auto* vf = Var("vf", ty.f32());
-    auto* c = Call(Source{{12, 34}}, ty.ptr<i32>(builtin::AddressSpace::kFunction), ExprList(vf));
-    auto* ip = Let("ip", ty.ptr<i32>(builtin::AddressSpace::kFunction), c);
+    auto* c = Call(Source{{12, 34}}, ty.ptr<function, i32>(), ExprList(vf));
+    auto* ip = Let("ip", ty.ptr<function, i32>(), c);
     WrapInFunction(Decl(vf), Decl(ip));
 
     EXPECT_FALSE(r()->Resolve());
diff --git a/src/tint/resolver/value_constructor_validation_test.cc b/src/tint/resolver/value_constructor_validation_test.cc
index 3b7ad64..4e41d25 100644
--- a/src/tint/resolver/value_constructor_validation_test.cc
+++ b/src/tint/resolver/value_constructor_validation_test.cc
@@ -19,11 +19,12 @@
 #include "src/tint/type/reference.h"
 #include "src/tint/utils/string_stream.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::resolver {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ::testing::HasSubstr;
 
 // Helpers and typedefs
@@ -34,14 +35,6 @@
 using builder::CreatePtrs;
 using builder::CreatePtrsFor;
 using builder::DataType;
-using builder::mat2x2;
-using builder::mat2x3;
-using builder::mat3x2;
-using builder::mat3x3;
-using builder::mat4x4;
-using builder::vec2;
-using builder::vec3;
-using builder::vec4;
 
 class ResolverValueConstructorValidationTest : public resolver::TestHelper, public testing::Test {};
 
@@ -478,7 +471,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, ConversionConstructorInvalid_InvalidConstructor) {
-    auto* a = Var("a", ty.f32(), Call(Source{{12, 34}}, ty.f32(), Call(ty.array<f32, 4>())));
+    auto* a = Var("a", ty.f32(), Call(Source{{12, 34}}, ty.f32(), Call<array<f32, 4>>()));
     WrapInFunction(a);
 
     ASSERT_FALSE(r()->Resolve());
@@ -492,7 +485,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, Array_ZeroValue_Pass) {
     // array<u32, 10u>();
-    auto* tc = array<u32, 10>();
+    auto* tc = Call<array<u32, 10>>();
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -508,7 +501,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, Array_U32U32U32) {
     // array<u32, 3u>(0u, 10u, 20u);
-    auto* tc = array<u32, 3>(0_u, 10_u, 20_u);
+    auto* tc = Call<array<u32, 3>>(0_u, 10_u, 20_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -527,7 +520,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArray_U32U32U32) {
     // array(0u, 10u, 20u);
-    auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 10_u, 20_u);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 0_u, 10_u, 20_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -546,7 +539,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, Array_U32AIU32) {
     // array<u32, 3u>(0u, 10, 20u);
-    auto* tc = array<u32, 3>(0_u, 10_a, 20_u);
+    auto* tc = Call<array<u32, 3>>(0_u, 10_a, 20_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -565,7 +558,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArray_U32AIU32) {
     // array(0u, 10u, 20u);
-    auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 10_a, 20_u);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 0_u, 10_a, 20_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -584,7 +577,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayU32_AIAIAI) {
     // array<u32, 3u>(0, 10, 20);
-    auto* tc = array<u32, 3>(0_a, 10_a, 20_a);
+    auto* tc = Call<array<u32, 3>>(0_a, 10_a, 20_a);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -603,7 +596,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArray_AIAIAI) {
     // const c = array(0, 10, 20);
-    auto* tc = array<Infer>(Source{{12, 34}}, 0_a, 10_a, 20_a);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 0_a, 10_a, 20_a);
     WrapInFunction(Decl(Const("C", tc)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -622,9 +615,9 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayU32_VecI32_VecAI) {
     // array(vec2(10i), vec2(20));
-    auto* tc = array<Infer>(Source{{12, 34}},              //
-                            Call(ty.vec<Infer>(2), 20_i),  //
-                            Call(ty.vec<Infer>(2), 20_a));
+    auto* tc = Call<array<Infer>>(Source{{12, 34}},         //
+                                  Call<vec2<Infer>>(20_i),  //
+                                  Call<vec2<Infer>>(20_a));
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -644,9 +637,9 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayU32_VecAI_VecF32) {
     // array(vec2(20), vec2(10f));
-    auto* tc = array<Infer>(Source{{12, 34}},              //
-                            Call(ty.vec<Infer>(2), 20_a),  //
-                            Call(ty.vec<Infer>(2), 20_f));
+    auto* tc = Call<array<Infer>>(Source{{12, 34}},         //
+                                  Call<vec2<Infer>>(20_a),  //
+                                  Call<vec2<Infer>>(20_f));
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -666,7 +659,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_U32F32) {
     // array<u32, 3u>(0u, 1.0f, 20u);
-    auto* tc = array<u32, 3>(0_u, Expr(Source{{12, 34}}, 1_f), 20_u);
+    auto* tc = Call<array<u32, 3>>(0_u, Expr(Source{{12, 34}}, 1_f), 20_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -675,7 +668,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32F32) {
     // array(0u, 1.0f, 20u);
-    auto* tc = array<Infer>(Source{{12, 34}}, 0_u, 1_f, 20_u);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 0_u, 1_f, 20_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -687,7 +680,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_F32I32) {
     // array<f32, 1u>(1i);
-    auto* tc = array<f32, 1>(Expr(Source{{12, 34}}, 1_i));
+    auto* tc = Call<array<f32, 1>>(Expr(Source{{12, 34}}, 1_i));
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -696,7 +689,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_F32I32) {
     // array(1f, 1i);
-    auto* tc = array<Infer>(Source{{12, 34}}, 1_f, 1_i);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 1_f, 1_i);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -708,7 +701,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_U32I32) {
     // array<u32, 1u>(1i, 0u, 0u, 0u, 0u, 0u);
-    auto* tc = array<u32, 1>(Expr(Source{{12, 34}}, 1_i), 0_u, 0_u, 0_u, 0_u);
+    auto* tc = Call<array<u32, 1>>(Expr(Source{{12, 34}}, 1_i), 0_u, 0_u, 0_u, 0_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -717,7 +710,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_U32I32) {
     // array(1i, 0u, 0u, 0u, 0u, 0u);
-    auto* tc = array<Infer>(Source{{12, 34}}, 1_i, 0_u, 0_u, 0_u, 0_u);
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 1_i, 0_u, 0_u, 0_u, 0_u);
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -729,7 +722,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_I32Vec2) {
     // array<i32, 3u>(1i, vec2<i32>());
-    auto* tc = array<i32, 3>(1_i, vec2<i32>(Source{{12, 34}}));
+    auto* tc = Call<array<i32, 3>>(1_i, Call<vec2<i32>>(Source{{12, 34}}));
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -738,7 +731,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_I32Vec2) {
     // array(1i, vec2<i32>());
-    auto* tc = array<Infer>(Source{{12, 34}}, 1_i, vec2<i32>());
+    auto* tc = Call<array<Infer>>(Source{{12, 34}}, 1_i, Call<vec2<i32>>());
     WrapInFunction(tc);
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
@@ -749,7 +742,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
     // array<vec3<i32>, 2u>(vec3<u32>(), vec3<u32>());
-    auto* t = array(ty.vec3<i32>(), 2_u, vec3<u32>(Source{{12, 34}}), vec3<u32>());
+    auto* t = Call<array<vec3<i32>, 2>>(Call<vec3<u32>>(Source{{12, 34}}), Call<vec3<u32>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -759,7 +752,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3u32) {
     // array(vec3<i32>(), vec3<u32>());
-    auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), vec3<u32>());
+    auto* t = Call<array<Infer>>(Source{{12, 34}}, Call<vec3<i32>>(), Call<vec3<u32>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -771,7 +764,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3AF) {
     // array(vec3<i32>(), vec3(1.0));
-    auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), Call("vec3", 1._a));
+    auto* t = Call<array<Infer>>(Source{{12, 34}}, Call<vec3<i32>>(), Call("vec3", 1._a));
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -783,7 +776,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
     // array<vec3<i32>, 2u>(vec3<i32>(), vec3<bool>());
-    auto* t = array(ty.vec3<i32>(), 2_u, vec3<i32>(), vec3<bool>());
+    auto* t = Call<array<vec3<i32>, 2>>(Call<vec3<i32>>(), Call<vec3<bool>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -793,7 +786,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayArgumentTypeMismatch_Vec3i32_Vec3bool) {
     // array(vec3<i32>(), vec3<bool>());
-    auto* t = array<Infer>(Source{{12, 34}}, vec3<i32>(), vec3<bool>());
+    auto* t = Call<array<Infer>>(Source{{12, 34}}, Call<vec3<i32>>(), Call<vec3<bool>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -805,7 +798,8 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayOfArray_SubElemSizeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
-    auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 3>(), array<i32, 2>());
+    auto* t = Call<array<array<i32, 2>, 2>>(Source{{12, 34}}, Call<array<i32, 3>>(),
+                                            Call<array<i32, 2>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -815,7 +809,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayOfArray_SubElemSizeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
-    auto* t = array<Infer>(Source{{12, 34}}, array<i32, 3>(), array<i32, 2>());
+    auto* t = Call<array<Infer>>(Source{{12, 34}}, Call<array<i32, 3>>(), Call<array<i32, 2>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -827,7 +821,8 @@
 
 TEST_F(ResolverValueConstructorValidationTest, ArrayOfArray_SubElemTypeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
-    auto* t = array(Source{{12, 34}}, ty.array<i32, 2>(), 2_i, array<i32, 2>(), array<u32, 2>());
+    auto* t = Call<array<array<i32, 2>, 2>>(Source{{12, 34}}, Call<array<i32, 2>>(),
+                                            Call<array<u32, 2>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -837,7 +832,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, InferredArrayOfArray_SubElemTypeMismatch) {
     // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
-    auto* t = array<Infer>(Source{{12, 34}}, array<i32, 2>(), array<u32, 2>());
+    auto* t = Call<array<Infer>>(Source{{12, 34}}, Call<array<i32, 2>>(), Call<array<u32, 2>>());
     WrapInFunction(t);
 
     EXPECT_FALSE(r()->Resolve());
@@ -850,7 +845,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Array_TooFewElements) {
     // array<i32, 4u>(1i, 2i, 3i);
     SetSource(Source::Location({12, 34}));
-    auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i));
+    auto* tc = Call<array<i32, 4>>(Expr(1_i), Expr(2_i), Expr(3_i));
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -861,7 +856,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Array_TooManyElements) {
     // array<i32, 4u>(1i, 2i, 3i, 4i, 5i);
     SetSource(Source::Location({12, 34}));
-    auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i), Expr(5_i));
+    auto* tc = Call<array<i32, 4>>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i), Expr(5_i));
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -873,7 +868,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, Array_Runtime) {
     // array<i32>(1i);
-    auto* tc = array<i32>(Source{{12, 34}}, Expr(1_i));
+    auto* tc = Call<array<i32>>(Source{{12, 34}}, Expr(1_i));
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -882,7 +877,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, Array_RuntimeZeroValue) {
     // array<i32>();
-    auto* tc = array<i32>(Source{{12, 34}});
+    auto* tc = Call<array<i32>>(Source{{12, 34}});
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -1048,7 +1043,7 @@
 namespace VectorConstructor {
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2F32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_i, 2_f));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, 1_i, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1058,7 +1053,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec2F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec2<f16>(Source{{12, 34}}, 1_h, 2_f));
+    WrapInFunction(Call<vec2<f16>>(Source{{12, 34}}, 1_h, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1066,7 +1061,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2U32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec2<u32>(Source{{12, 34}}, 1_u, 2_i));
+    WrapInFunction(Call<vec2<u32>>(Source{{12, 34}}, 1_u, 2_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1074,7 +1069,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2I32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec2<i32>(Source{{12, 34}}, 1_u, 2_i));
+    WrapInFunction(Call<vec2<i32>>(Source{{12, 34}}, 1_u, 2_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1082,7 +1077,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2Bool_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec2<bool>(Source{{12, 34}}, true, 1_i));
+    WrapInFunction(Call<vec2<bool>>(Source{{12, 34}}, true, 1_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1090,7 +1085,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, vec3<f32>()));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1098,7 +1093,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, vec4<f32>()));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, Call<vec4<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1106,7 +1101,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsScalar) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1114,7 +1109,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVector) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1123,7 +1118,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_TooManyArgumentsVectorAndScalar) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1131,7 +1126,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Error_InvalidArgumentType) {
-    WrapInFunction(vec2<f32>(Source{{12, 34}}, mat2x2<f32>()));
+    WrapInFunction(Call<vec2<f32>>(Source{{12, 34}}, Call<mat2x2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1139,7 +1134,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_ZeroValue) {
-    auto* tc = vec2<f32>();
+    auto* tc = Call<vec2<f32>>();
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1158,7 +1153,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2F32_Success_Scalar) {
-    auto* tc = vec2<f32>(1_f, 1_f);
+    auto* tc = Call<vec2<f32>>(1_f, 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1181,7 +1176,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec2F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
-    auto* tc = vec2<f16>(1_h, 1_h);
+    auto* tc = Call<vec2<f16>>(1_h, 1_h);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1202,7 +1197,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2U32_Success_Scalar) {
-    auto* tc = vec2<u32>(1_u, 1_u);
+    auto* tc = Call<vec2<u32>>(1_u, 1_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1223,7 +1218,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2I32_Success_Scalar) {
-    auto* tc = vec2<i32>(1_i, 1_i);
+    auto* tc = Call<vec2<i32>>(1_i, 1_i);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1244,7 +1239,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2Bool_Success_Scalar) {
-    auto* tc = vec2<bool>(true, false);
+    auto* tc = Call<vec2<bool>>(true, false);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1265,7 +1260,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_Identity) {
-    auto* tc = vec2<f32>(vec2<f32>());
+    auto* tc = Call<vec2<f32>>(Call<vec2<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1285,7 +1280,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec2_Success_Vec2TypeConversion) {
-    auto* tc = vec2<f32>(vec2<i32>());
+    auto* tc = Call<vec2<f32>>(Call<vec2<i32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1305,7 +1300,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3F32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_i));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, 1_f, 2_f, 3_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1315,7 +1310,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec3F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(Source{{12, 34}}, 1_h, 2_h, 3_f));
+    WrapInFunction(Call<vec3<f16>>(Source{{12, 34}}, 1_h, 2_h, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1323,7 +1318,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3U32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec3<u32>(Source{{12, 34}}, 1_u, 2_i, 3_u));
+    WrapInFunction(Call<vec3<u32>>(Source{{12, 34}}, 1_u, 2_i, 3_u));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1331,7 +1326,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3I32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec3<i32>(Source{{12, 34}}, 1_i, 2_u, 3_i));
+    WrapInFunction(Call<vec3<i32>>(Source{{12, 34}}, 1_i, 2_u, 3_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1339,7 +1334,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3Bool_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec3<bool>(Source{{12, 34}}, false, 1_i, true));
+    WrapInFunction(Call<vec3<bool>>(Source{{12, 34}}, false, 1_i, true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1347,7 +1342,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, vec4<f32>()));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<vec4<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1355,7 +1350,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsScalar) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, 1_f, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1363,7 +1358,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsScalar) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1372,7 +1367,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooFewArgumentsVec2) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>()));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<vec2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1380,7 +1375,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>()));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1389,7 +1384,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec2AndScalar) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 1_f));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), 1_f, 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1398,7 +1393,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_TooManyArgumentsVec3) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, vec3<f32>(), 1_f));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<vec3<f32>>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1406,7 +1401,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Error_InvalidArgumentType) {
-    WrapInFunction(vec3<f32>(Source{{12, 34}}, mat2x2<f32>()));
+    WrapInFunction(Call<vec3<f32>>(Source{{12, 34}}, Call<mat2x2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1414,7 +1409,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_ZeroValue) {
-    auto* tc = vec3<f32>();
+    auto* tc = Call<vec3<f32>>();
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1433,7 +1428,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3F32_Success_Scalar) {
-    auto* tc = vec3<f32>(1_f, 1_f, 1_f);
+    auto* tc = Call<vec3<f32>>(1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1457,7 +1452,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec3F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
-    auto* tc = vec3<f16>(1_h, 1_h, 1_h);
+    auto* tc = Call<vec3<f16>>(1_h, 1_h, 1_h);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1479,7 +1474,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3U32_Success_Scalar) {
-    auto* tc = vec3<u32>(1_u, 1_u, 1_u);
+    auto* tc = Call<vec3<u32>>(1_u, 1_u, 1_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1501,7 +1496,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3I32_Success_Scalar) {
-    auto* tc = vec3<i32>(1_i, 1_i, 1_i);
+    auto* tc = Call<vec3<i32>>(1_i, 1_i, 1_i);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1523,7 +1518,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3Bool_Success_Scalar) {
-    auto* tc = vec3<bool>(true, false, true);
+    auto* tc = Call<vec3<bool>>(true, false, true);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1545,7 +1540,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Vec2AndScalar) {
-    auto* tc = vec3<f32>(vec2<f32>(), 1_f);
+    auto* tc = Call<vec3<f32>>(Call<vec2<f32>>(), 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1566,7 +1561,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_ScalarAndVec2) {
-    auto* tc = vec3<f32>(1_f, vec2<f32>());
+    auto* tc = Call<vec3<f32>>(1_f, Call<vec2<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1587,7 +1582,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Identity) {
-    auto* tc = vec3<f32>(vec3<f32>());
+    auto* tc = Call<vec3<f32>>(Call<vec3<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1607,7 +1602,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec3_Success_Vec3TypeConversion) {
-    auto* tc = vec3<f32>(vec3<i32>());
+    auto* tc = Call<vec3<f32>>(Call<vec3<i32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1627,7 +1622,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4F32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 1_f, 1_i, 1_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, 1_f, 1_f, 1_i, 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1638,7 +1633,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec4F16_Error_ScalarArgumentTypeMismatch) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec4<f16>(Source{{12, 34}}, 1_h, 1_h, 1_f, 1_h));
+    WrapInFunction(Call<vec4<f16>>(Source{{12, 34}}, 1_h, 1_h, 1_f, 1_h));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1647,7 +1642,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4U32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec4<u32>(Source{{12, 34}}, 1_u, 1_u, 1_i, 1_u));
+    WrapInFunction(Call<vec4<u32>>(Source{{12, 34}}, 1_u, 1_u, 1_i, 1_u));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1656,7 +1651,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4I32_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec4<i32>(Source{{12, 34}}, 1_i, 1_i, 1_u, 1_i));
+    WrapInFunction(Call<vec4<i32>>(Source{{12, 34}}, 1_i, 1_i, 1_u, 1_i));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1665,7 +1660,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4Bool_Error_ScalarArgumentTypeMismatch) {
-    WrapInFunction(vec4<bool>(Source{{12, 34}}, true, false, 1_i, true));
+    WrapInFunction(Call<vec4<bool>>(Source{{12, 34}}, true, false, 1_i, true));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1674,7 +1669,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsScalar) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1682,7 +1677,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsScalar) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f, 5_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, 1_f, 2_f, 3_f, 4_f, 5_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1691,7 +1686,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec2AndScalar) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1699,7 +1694,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndScalars) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), 1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), 1_f, 2_f, 3_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1708,7 +1703,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), 1_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec2<f32>>(), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1717,7 +1712,8 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec2<f32>(), vec2<f32>()));
+    WrapInFunction(
+        Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec2<f32>>(), Call<vec2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1727,7 +1723,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooFewArgumentsVec3) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>()));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1735,7 +1731,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndScalars) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), 1_f, 2_f));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec3<f32>>(), 1_f, 2_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1744,7 +1740,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec2) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec2<f32>()));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec3<f32>>(), Call<vec2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1753,7 +1749,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec2AndVec3) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec2<f32>(), vec3<f32>()));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec2<f32>>(), Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1762,7 +1758,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_TooManyArgumentsVec3AndVec3) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, vec3<f32>(), vec3<f32>()));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<vec3<f32>>(), Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(
@@ -1771,7 +1767,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Error_InvalidArgumentType) {
-    WrapInFunction(vec4<f32>(Source{{12, 34}}, mat2x2<f32>()));
+    WrapInFunction(Call<vec4<f32>>(Source{{12, 34}}, Call<mat2x2<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1779,7 +1775,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ZeroValue) {
-    auto* tc = vec4<f32>();
+    auto* tc = Call<vec4<f32>>();
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1791,7 +1787,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4F32_Success_Scalar) {
-    auto* tc = vec4<f32>(1_f, 1_f, 1_f, 1_f);
+    auto* tc = Call<vec4<f32>>(1_f, 1_f, 1_f, 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1805,7 +1801,7 @@
 TEST_F(ResolverValueConstructorValidationTest, Vec4F16_Success_Scalar) {
     Enable(builtin::Extension::kF16);
 
-    auto* tc = vec4<f16>(1_h, 1_h, 1_h, 1_h);
+    auto* tc = Call<vec4<f16>>(1_h, 1_h, 1_h, 1_h);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1817,7 +1813,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4U32_Success_Scalar) {
-    auto* tc = vec4<u32>(1_u, 1_u, 1_u, 1_u);
+    auto* tc = Call<vec4<u32>>(1_u, 1_u, 1_u, 1_u);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1829,7 +1825,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4I32_Success_Scalar) {
-    auto* tc = vec4<i32>(1_i, 1_i, 1_i, 1_i);
+    auto* tc = Call<vec4<i32>>(1_i, 1_i, 1_i, 1_i);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1841,7 +1837,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4Bool_Success_Scalar) {
-    auto* tc = vec4<bool>(true, false, true, false);
+    auto* tc = Call<vec4<bool>>(true, false, true, false);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1853,7 +1849,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec2ScalarScalar) {
-    auto* tc = vec4<f32>(vec2<f32>(), 1_f, 1_f);
+    auto* tc = Call<vec4<f32>>(Call<vec2<f32>>(), 1_f, 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1865,7 +1861,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarVec2Scalar) {
-    auto* tc = vec4<f32>(1_f, vec2<f32>(), 1_f);
+    auto* tc = Call<vec4<f32>>(1_f, Call<vec2<f32>>(), 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1877,7 +1873,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarScalarVec2) {
-    auto* tc = vec4<f32>(1_f, 1_f, vec2<f32>());
+    auto* tc = Call<vec4<f32>>(1_f, 1_f, Call<vec2<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1889,7 +1885,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec2AndVec2) {
-    auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
+    auto* tc = Call<vec4<f32>>(Call<vec2<f32>>(), Call<vec2<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1901,7 +1897,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec3AndScalar) {
-    auto* tc = vec4<f32>(vec3<f32>(), 1_f);
+    auto* tc = Call<vec4<f32>>(Call<vec3<f32>>(), 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1913,7 +1909,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_ScalarAndVec3) {
-    auto* tc = vec4<f32>(1_f, vec3<f32>());
+    auto* tc = Call<vec4<f32>>(1_f, Call<vec3<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1925,7 +1921,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Identity) {
-    auto* tc = vec4<f32>(vec4<f32>());
+    auto* tc = Call<vec4<f32>>(Call<vec4<f32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1937,7 +1933,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, Vec4_Success_Vec4TypeConversion) {
-    auto* tc = vec4<f32>(vec4<i32>());
+    auto* tc = Call<vec4<f32>>(Call<vec4<i32>>());
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1949,9 +1945,9 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, NestedVectorConstructors_InnerError) {
-    WrapInFunction(vec4<f32>(vec4<f32>(1_f, 1_f,  //
-                                       vec3<f32>(Source{{12, 34}}, 1_f, 1_f)),
-                             1_f));
+    WrapInFunction(Call<vec4<f32>>(Call<vec4<f32>>(1_f, 1_f,  //
+                                                   Call<vec3<f32>>(Source{{12, 34}}, 1_f, 1_f)),
+                                   1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -1959,7 +1955,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, NestedVectorConstructors_Success) {
-    auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1_f, 1_f), 1_f), 1_f);
+    auto* tc = Call<vec4<f32>>(Call<vec3<f32>>(Call<vec2<f32>>(1_f, 1_f), 1_f), 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -1974,7 +1970,7 @@
     auto* alias = Alias("UnsignedInt", ty.u32());
     GlobalVar("uint_var", ty.Of(alias), builtin::AddressSpace::kPrivate);
 
-    auto* tc = vec2<f32>(Source{{12, 34}}, "uint_var");
+    auto* tc = Call<vec2<f32>>(Source{{12, 34}}, "uint_var");
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -1987,7 +1983,7 @@
     GlobalVar("my_f32", ty.Of(f32_alias), builtin::AddressSpace::kPrivate);
     GlobalVar("my_vec2", ty.Of(vec2_alias), builtin::AddressSpace::kPrivate);
 
-    auto* tc = vec3<f32>("my_vec2", "my_f32");
+    auto* tc = Call<vec3<f32>>("my_vec2", "my_f32");
     WrapInFunction(tc);
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
@@ -2020,7 +2016,7 @@
 
     // vec3<u32>(vec<Float32>(), 1.0f)
     auto vec_type = ty.vec(ty.Of(f32_alias), 2);
-    WrapInFunction(vec3<u32>(Source{{12, 34}}, Call(vec_type), 1_f));
+    WrapInFunction(Call<vec3<u32>>(Source{{12, 34}}, Call(vec_type), 1_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_THAT(r()->error(),
@@ -2032,7 +2028,7 @@
 
     // vec3<f32>(vec<Float32>(), 1.0f)
     auto vec_type = ty.vec(ty.Of(f32_alias), 2);
-    auto* tc = vec3<f32>(Call(Source{{12, 34}}, vec_type), 1_f);
+    auto* tc = Call<vec3<f32>>(Call(Source{{12, 34}}, vec_type), 1_f);
     WrapInFunction(tc);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2041,11 +2037,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec2ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec2_bool = vec2<Infer>(true, false);
-    auto* vec2_i32 = vec2<Infer>(1_i, 2_i);
-    auto* vec2_u32 = vec2<Infer>(1_u, 2_u);
-    auto* vec2_f32 = vec2<Infer>(1_f, 2_f);
-    auto* vec2_f16 = vec2<Infer>(1_h, 2_h);
+    auto* vec2_bool = Call<vec2<Infer>>(true, false);
+    auto* vec2_i32 = Call<vec2<Infer>>(1_i, 2_i);
+    auto* vec2_u32 = Call<vec2<Infer>>(1_u, 2_u);
+    auto* vec2_f32 = Call<vec2<Infer>>(1_f, 2_f);
+    auto* vec2_f16 = Call<vec2<Infer>>(1_h, 2_h);
     WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32, vec2_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2070,11 +2066,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec2ElementTypeFromVec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec2_bool = vec2<Infer>(vec2<bool>(true, false));
-    auto* vec2_i32 = vec2<Infer>(vec2<i32>(1_i, 2_i));
-    auto* vec2_u32 = vec2<Infer>(vec2<u32>(1_u, 2_u));
-    auto* vec2_f32 = vec2<Infer>(vec2<f32>(1_f, 2_f));
-    auto* vec2_f16 = vec2<Infer>(vec2<f16>(1_h, 2_h));
+    auto* vec2_bool = Call<vec2<Infer>>(Call<vec2<bool>>(true, false));
+    auto* vec2_i32 = Call<vec2<Infer>>(Call<vec2<i32>>(1_i, 2_i));
+    auto* vec2_u32 = Call<vec2<Infer>>(Call<vec2<u32>>(1_u, 2_u));
+    auto* vec2_f32 = Call<vec2<Infer>>(Call<vec2<f32>>(1_f, 2_f));
+    auto* vec2_f16 = Call<vec2<Infer>>(Call<vec2<f16>>(1_h, 2_h));
     WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32, vec2_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2099,11 +2095,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec3_bool = vec3<Infer>(Expr(true), Expr(false), Expr(true));
-    auto* vec3_i32 = vec3<Infer>(Expr(1_i), Expr(2_i), Expr(3_i));
-    auto* vec3_u32 = vec3<Infer>(Expr(1_u), Expr(2_u), Expr(3_u));
-    auto* vec3_f32 = vec3<Infer>(Expr(1_f), Expr(2_f), Expr(3_f));
-    auto* vec3_f16 = vec3<Infer>(Expr(1_h), Expr(2_h), Expr(3_h));
+    auto* vec3_bool = Call<vec3<Infer>>(true, false, true);
+    auto* vec3_i32 = Call<vec3<Infer>>(1_i, 2_i, 3_i);
+    auto* vec3_u32 = Call<vec3<Infer>>(1_u, 2_u, 3_u);
+    auto* vec3_f32 = Call<vec3<Infer>>(1_f, 2_f, 3_f);
+    auto* vec3_f16 = Call<vec3<Infer>>(1_h, 2_h, 3_h);
     WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2128,11 +2124,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromVec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec3_bool = vec3<Infer>(vec3<bool>(true, false, true));
-    auto* vec3_i32 = vec3<Infer>(vec3<i32>(1_i, 2_i, 3_i));
-    auto* vec3_u32 = vec3<Infer>(vec3<u32>(1_u, 2_u, 3_u));
-    auto* vec3_f32 = vec3<Infer>(vec3<f32>(1_f, 2_f, 3_f));
-    auto* vec3_f16 = vec3<Infer>(vec3<f16>(1_h, 2_h, 3_h));
+    auto* vec3_bool = Call<vec3<Infer>>(Call<vec3<bool>>(true, false, true));
+    auto* vec3_i32 = Call<vec3<Infer>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
+    auto* vec3_u32 = Call<vec3<Infer>>(Call<vec3<u32>>(1_u, 2_u, 3_u));
+    auto* vec3_f32 = Call<vec3<Infer>>(Call<vec3<f32>>(1_f, 2_f, 3_f));
+    auto* vec3_f16 = Call<vec3<Infer>>(Call<vec3<f16>>(1_h, 2_h, 3_h));
     WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2157,11 +2153,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec3_bool = vec3<Infer>(Expr(true), vec2<bool>(false, true));
-    auto* vec3_i32 = vec3<Infer>(Expr(1_i), vec2<i32>(2_i, 3_i));
-    auto* vec3_u32 = vec3<Infer>(Expr(1_u), vec2<u32>(2_u, 3_u));
-    auto* vec3_f32 = vec3<Infer>(Expr(1_f), vec2<f32>(2_f, 3_f));
-    auto* vec3_f16 = vec3<Infer>(Expr(1_h), vec2<f16>(2_h, 3_h));
+    auto* vec3_bool = Call<vec3<Infer>>(true, Call<vec2<bool>>(false, true));
+    auto* vec3_i32 = Call<vec3<Infer>>(1_i, Call<vec2<i32>>(2_i, 3_i));
+    auto* vec3_u32 = Call<vec3<Infer>>(1_u, Call<vec2<u32>>(2_u, 3_u));
+    auto* vec3_f32 = Call<vec3<Infer>>(1_f, Call<vec2<f32>>(2_f, 3_f));
+    auto* vec3_f16 = Call<vec3<Infer>>(1_h, Call<vec2<f16>>(2_h, 3_h));
     WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32, vec3_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2186,11 +2182,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromScalars) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec4_bool = vec4<Infer>(Expr(true), Expr(false), Expr(true), Expr(false));
-    auto* vec4_i32 = vec4<Infer>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i));
-    auto* vec4_u32 = vec4<Infer>(Expr(1_u), Expr(2_u), Expr(3_u), Expr(4_u));
-    auto* vec4_f32 = vec4<Infer>(Expr(1_f), Expr(2_f), Expr(3_f), Expr(4_f));
-    auto* vec4_f16 = vec4<Infer>(Expr(1_h), Expr(2_h), Expr(3_h), Expr(4_h));
+    auto* vec4_bool = Call<vec4<Infer>>(true, false, true, false);
+    auto* vec4_i32 = Call<vec4<Infer>>(1_i, 2_i, 3_i, 4_i);
+    auto* vec4_u32 = Call<vec4<Infer>>(1_u, 2_u, 3_u, 4_u);
+    auto* vec4_f32 = Call<vec4<Infer>>(1_f, 2_f, 3_f, 4_f);
+    auto* vec4_f16 = Call<vec4<Infer>>(1_h, 2_h, 3_h, 4_h);
     WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2215,11 +2211,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromVec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec4_bool = vec4<Infer>(vec4<bool>(true, false, true, false));
-    auto* vec4_i32 = vec4<Infer>(vec4<i32>(1_i, 2_i, 3_i, 4_i));
-    auto* vec4_u32 = vec4<Infer>(vec4<u32>(1_u, 2_u, 3_u, 4_u));
-    auto* vec4_f32 = vec4<Infer>(vec4<f32>(1_f, 2_f, 3_f, 4_f));
-    auto* vec4_f16 = vec4<Infer>(vec4<f16>(1_h, 2_h, 3_h, 4_h));
+    auto* vec4_bool = Call<vec4<Infer>>(Call<vec4<bool>>(true, false, true, false));
+    auto* vec4_i32 = Call<vec4<Infer>>(Call<vec4<i32>>(1_i, 2_i, 3_i, 4_i));
+    auto* vec4_u32 = Call<vec4<Infer>>(Call<vec4<u32>>(1_u, 2_u, 3_u, 4_u));
+    auto* vec4_f32 = Call<vec4<Infer>>(Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
+    auto* vec4_f16 = Call<vec4<Infer>>(Call<vec4<f16>>(1_h, 2_h, 3_h, 4_h));
     WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2244,11 +2240,11 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec4_bool = vec4<Infer>(Expr(true), vec3<bool>(false, true, false));
-    auto* vec4_i32 = vec4<Infer>(Expr(1_i), vec3<i32>(2_i, 3_i, 4_i));
-    auto* vec4_u32 = vec4<Infer>(Expr(1_u), vec3<u32>(2_u, 3_u, 4_u));
-    auto* vec4_f32 = vec4<Infer>(Expr(1_f), vec3<f32>(2_f, 3_f, 4_f));
-    auto* vec4_f16 = vec4<Infer>(Expr(1_h), vec3<f16>(2_h, 3_h, 4_h));
+    auto* vec4_bool = Call<vec4<Infer>>(true, Call<vec3<bool>>(false, true, false));
+    auto* vec4_i32 = Call<vec4<Infer>>(1_i, Call<vec3<i32>>(2_i, 3_i, 4_i));
+    auto* vec4_u32 = Call<vec4<Infer>>(1_u, Call<vec3<u32>>(2_u, 3_u, 4_u));
+    auto* vec4_f32 = Call<vec4<Infer>>(1_f, Call<vec3<f32>>(2_f, 3_f, 4_f));
+    auto* vec4_f16 = Call<vec4<Infer>>(1_h, Call<vec3<f16>>(2_h, 3_h, 4_h));
     WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2273,11 +2269,12 @@
 TEST_F(ResolverValueConstructorValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec4_bool = vec4<Infer>(vec2<bool>(true, false), vec2<bool>(true, false));
-    auto* vec4_i32 = vec4<Infer>(vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i));
-    auto* vec4_u32 = vec4<Infer>(vec2<u32>(1_u, 2_u), vec2<u32>(3_u, 4_u));
-    auto* vec4_f32 = vec4<Infer>(vec2<f32>(1_f, 2_f), vec2<f32>(3_f, 4_f));
-    auto* vec4_f16 = vec4<Infer>(vec2<f16>(1_h, 2_h), vec2<f16>(3_h, 4_h));
+    auto* vec4_bool =
+        Call<vec4<Infer>>(Call<vec2<bool>>(true, false), Call<vec2<bool>>(true, false));
+    auto* vec4_i32 = Call<vec4<Infer>>(Call<vec2<i32>>(1_i, 2_i), Call<vec2<i32>>(3_i, 4_i));
+    auto* vec4_u32 = Call<vec4<Infer>>(Call<vec2<u32>>(1_u, 2_u), Call<vec2<u32>>(3_u, 4_u));
+    auto* vec4_f32 = Call<vec4<Infer>>(Call<vec2<f32>>(1_f, 2_f), Call<vec2<f32>>(3_f, 4_f));
+    auto* vec4_f16 = Call<vec4<Infer>>(Call<vec2<f16>>(1_h, 2_h), Call<vec2<f16>>(3_h, 4_h));
     WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32, vec4_f16);
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
@@ -2300,9 +2297,9 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, InferVecNoArgs) {
-    auto* v2 = vec2<Infer>();
-    auto* v3 = vec3<Infer>();
-    auto* v4 = vec4<Infer>();
+    auto* v2 = Call<vec2<Infer>>();
+    auto* v3 = Call<vec3<Infer>>();
+    auto* v4 = Call<vec4<Infer>>();
 
     GlobalConst("v2", v2);
     GlobalConst("v3", v3);
@@ -2409,8 +2406,8 @@
         DataType<T>::Name,
         DataType<T>::AST,
         DataType<T>::ExprFromDouble,
-        DataType<tint::resolver::builder::vec<R, T>>::AST,
-        DataType<tint::resolver::builder::mat<C, R, T>>::AST,
+        DataType<vec<R, T>>::AST,
+        DataType<mat<C, R, T>>::AST,
     };
 }
 
@@ -2776,7 +2773,7 @@
 
 TEST_F(ResolverValueConstructorValidationTest, MatrixConstructor_ArgumentTypeAlias_Error) {
     auto* alias = Alias("VectorUnsigned2", ty.vec2<u32>());
-    auto* tc = Call(Source{{12, 34}}, ty.mat2x2<f32>(), Call(ty.Of(alias)), vec2<f32>());
+    auto* tc = Call(Source{{12, 34}}, ty.mat2x2<f32>(), Call(ty.Of(alias)), Call<vec2<f32>>());
     WrapInFunction(tc);
 
     EXPECT_FALSE(r()->Resolve());
@@ -2973,12 +2970,6 @@
 namespace StructConstructor {
 using builder::CreatePtrs;
 using builder::CreatePtrsFor;
-using builder::mat2x2;
-using builder::mat3x3;
-using builder::mat4x4;
-using builder::vec2;
-using builder::vec3;
-using builder::vec4;
 
 constexpr CreatePtrs all_types[] = {
     CreatePtrsFor<bool>(),         //
@@ -3170,7 +3161,7 @@
 }
 
 TEST_F(ResolverValueConstructorValidationTest, BuilinTypeConstructorAsStatement) {
-    WrapInFunction(CallStmt(vec2<f32>(Source{{12, 34}}, 1_f, 2_f)));
+    WrapInFunction(CallStmt(Call<vec2<f32>>(Source{{12, 34}}, 1_f, 2_f)));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: value constructor evaluated but not used");
diff --git a/src/tint/resolver/variable_test.cc b/src/tint/resolver/variable_test.cc
index 7095cfe..2054885 100644
--- a/src/tint/resolver/variable_test.cc
+++ b/src/tint/resolver/variable_test.cc
@@ -21,7 +21,8 @@
 namespace tint::resolver {
 namespace {
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 struct ResolverVariableTest : public resolver::TestHelper, public testing::Test {};
 
@@ -421,7 +422,7 @@
     auto* b = Let("b", ty.bool_(), b_c);
     auto* s = Let("s", ty.Of(S), s_c);
     auto* a = Let("a", ty.Of(A), a_c);
-    auto* p = Let("p", ty.ptr<i32>(builtin::AddressSpace::kFunction), p_c);
+    auto* p = Let("p", ty.ptr<function, i32>(), p_c);
 
     Func("F", utils::Empty, ty.void_(),
          utils::Vector{
@@ -898,10 +899,10 @@
     auto* c_i32 = Const("a", ty.i32(), Expr(0_i));
     auto* c_u32 = Const("b", ty.u32(), Expr(0_u));
     auto* c_f32 = Const("c", ty.f32(), Expr(0_f));
-    auto* c_vi32 = Const("d", ty.vec3<i32>(), vec3<i32>());
-    auto* c_vu32 = Const("e", ty.vec3<u32>(), vec3<u32>());
-    auto* c_vf32 = Const("f", ty.vec3<f32>(), vec3<f32>());
-    auto* c_mf32 = Const("g", ty.mat3x3<f32>(), mat3x3<f32>());
+    auto* c_vi32 = Const("d", ty.vec3<i32>(), Call<vec3<i32>>());
+    auto* c_vu32 = Const("e", ty.vec3<u32>(), Call<vec3<u32>>());
+    auto* c_vf32 = Const("f", ty.vec3<f32>(), Call<vec3<f32>>());
+    auto* c_mf32 = Const("g", ty.mat3x3<f32>(), Call<mat3x3<f32>>());
     auto* c_s = Const("h", ty("S"), Call("S"));
 
     WrapInFunction(c_i32, c_u32, c_f32, c_vi32, c_vu32, c_vf32, c_mf32, c_s);
@@ -944,16 +945,16 @@
     auto* c_f32 = Const("c", Expr(0_f));
     auto* c_ai = Const("d", Expr(0_a));
     auto* c_af = Const("e", Expr(0._a));
-    auto* c_vi32 = Const("f", vec3<i32>());
-    auto* c_vu32 = Const("g", vec3<u32>());
-    auto* c_vf32 = Const("h", vec3<f32>());
-    auto* c_vai = Const("i", Call(ty.vec<Infer>(3), Expr(0_a)));
-    auto* c_vaf = Const("j", Call(ty.vec<Infer>(3), Expr(0._a)));
-    auto* c_mf32 = Const("k", mat3x3<f32>());
-    auto* c_maf32 =
-        Const("l", Call(ty.mat3x3<Infer>(),  //
-                        Call(ty.vec<Infer>(3), Expr(0._a)), Call(ty.vec<Infer>(3), Expr(0._a)),
-                        Call(ty.vec<Infer>(3), Expr(0._a))));
+    auto* c_vi32 = Const("f", Call<vec3<i32>>());
+    auto* c_vu32 = Const("g", Call<vec3<u32>>());
+    auto* c_vf32 = Const("h", Call<vec3<f32>>());
+    auto* c_vai = Const("i", Call<vec3<Infer>>(0_a));
+    auto* c_vaf = Const("j", Call<vec3<Infer>>(0._a));
+    auto* c_mf32 = Const("k", Call<mat3x3<f32>>());
+    auto* c_maf32 = Const("l", Call<mat3x3<Infer>>(          //
+                                   Call<vec3<Infer>>(0._a),  //
+                                   Call<vec3<Infer>>(0._a),  //
+                                   Call<vec3<Infer>>(0._a)));
     auto* c_s = Const("m", Call("S"));
 
     WrapInFunction(c_i32, c_u32, c_f32, c_ai, c_af, c_vi32, c_vu32, c_vf32, c_vai, c_vaf, c_mf32,
@@ -1082,10 +1083,10 @@
     auto* c_i32 = GlobalConst("a", ty.i32(), Expr(0_i));
     auto* c_u32 = GlobalConst("b", ty.u32(), Expr(0_u));
     auto* c_f32 = GlobalConst("c", ty.f32(), Expr(0_f));
-    auto* c_vi32 = GlobalConst("d", ty.vec3<i32>(), vec3<i32>());
-    auto* c_vu32 = GlobalConst("e", ty.vec3<u32>(), vec3<u32>());
-    auto* c_vf32 = GlobalConst("f", ty.vec3<f32>(), vec3<f32>());
-    auto* c_mf32 = GlobalConst("g", ty.mat3x3<f32>(), mat3x3<f32>());
+    auto* c_vi32 = GlobalConst("d", ty.vec3<i32>(), Call<vec3<i32>>());
+    auto* c_vu32 = GlobalConst("e", ty.vec3<u32>(), Call<vec3<u32>>());
+    auto* c_vf32 = GlobalConst("f", ty.vec3<f32>(), Call<vec3<f32>>());
+    auto* c_mf32 = GlobalConst("g", ty.mat3x3<f32>(), Call<mat3x3<f32>>());
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
@@ -1120,16 +1121,16 @@
     auto* c_f32 = GlobalConst("c", Expr(0_f));
     auto* c_ai = GlobalConst("d", Expr(0_a));
     auto* c_af = GlobalConst("e", Expr(0._a));
-    auto* c_vi32 = GlobalConst("f", vec3<i32>());
-    auto* c_vu32 = GlobalConst("g", vec3<u32>());
-    auto* c_vf32 = GlobalConst("h", vec3<f32>());
-    auto* c_vai = GlobalConst("i", Call(ty.vec<Infer>(3), Expr(0_a)));
-    auto* c_vaf = GlobalConst("j", Call(ty.vec<Infer>(3), Expr(0._a)));
-    auto* c_mf32 = GlobalConst("k", mat3x3<f32>());
-    auto* c_maf32 = GlobalConst(
-        "l", Call(ty.mat3x3<Infer>(),  //
-                  Call(ty.vec<Infer>(3), Expr(0._a)), Call(ty.vec<Infer>(3), Expr(0._a)),
-                  Call(ty.vec<Infer>(3), Expr(0._a))));
+    auto* c_vi32 = GlobalConst("f", Call<vec3<i32>>());
+    auto* c_vu32 = GlobalConst("g", Call<vec3<u32>>());
+    auto* c_vf32 = GlobalConst("h", Call<vec3<f32>>());
+    auto* c_vai = GlobalConst("i", Call<vec3<Infer>>(0_a));
+    auto* c_vaf = GlobalConst("j", Call<vec3<Infer>>(0._a));
+    auto* c_mf32 = GlobalConst("k", Call<mat3x3<f32>>());
+    auto* c_maf32 = GlobalConst("l", Call<mat3x3<Infer>>(          //
+                                         Call<vec3<Infer>>(0._a),  //
+                                         Call<vec3<Infer>>(0._a),  //
+                                         Call<vec3<Infer>>(0._a)));
 
     ASSERT_TRUE(r()->Resolve()) << r()->error();
 
diff --git a/src/tint/resolver/variable_validation_test.cc b/src/tint/resolver/variable_validation_test.cc
index 9656574..d29f8b0 100644
--- a/src/tint/resolver/variable_validation_test.cc
+++ b/src/tint/resolver/variable_validation_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/type/texture_dimension.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -132,8 +133,8 @@
     // var i : i32;
     // var p : pointer<function, i32> = &v;
     auto* i = Var("i", ty.i32());
-    auto* p = Var("a", ty.ptr<i32>(Source{{56, 78}}, builtin::AddressSpace::kFunction),
-                  builtin::AddressSpace::kUndefined, AddressOf(Source{{12, 34}}, "i"));
+    auto* p = Var("a", ty.ptr<function, i32>(Source{{56, 78}}), builtin::AddressSpace::kUndefined,
+                  AddressOf(Source{{12, 34}}, "i"));
     WrapInFunction(i, p);
 
     EXPECT_FALSE(r()->Resolve());
@@ -162,7 +163,7 @@
 
 TEST_F(ResolverVariableValidationTest, OverrideInferedTypeNotScalar) {
     // override o = vec3(1.0f);
-    Override(Source{{56, 78}}, "o", vec3<f32>(1.0_f));
+    Override(Source{{56, 78}}, "o", Call<vec3<f32>>(1.0_f));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "56:78 error: vec3<f32> cannot be used as the type of a 'override'");
@@ -314,13 +315,11 @@
     auto* buf = Structure("S", utils::Vector{
                                    Member("inner", ty.Of(inner)),
                                });
-    auto* storage =
+    auto* var =
         GlobalVar("s", ty.Of(buf), builtin::AddressSpace::kStorage, Binding(0_a), Group(0_a));
 
-    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
-    auto* ptr = Let(Source{{12, 34}}, "p",
-                    ty.ptr<i32>(builtin::AddressSpace::kStorage, builtin::Access::kReadWrite),
-                    AddressOf(expr));
+    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(var, "inner"), "arr"), 2_i);
+    auto* ptr = Let(Source{{12, 34}}, "p", ty.ptr<storage, i32, read_write>(), AddressOf(expr));
 
     WrapInFunction(ptr);
 
@@ -390,7 +389,7 @@
 
 TEST_F(ResolverVariableValidationTest, VectorConstNoType) {
     // const a vec3 = vec3<f32>();
-    WrapInFunction(Const("a", ty.vec3<Infer>(Source{{12, 34}}), vec3<f32>()));
+    WrapInFunction(Const("a", ty.vec3<Infer>(Source{{12, 34}}), Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'vec3'");
@@ -398,7 +397,7 @@
 
 TEST_F(ResolverVariableValidationTest, VectorLetNoType) {
     // let a : vec3 = vec3<f32>();
-    WrapInFunction(Let("a", ty.vec3<Infer>(Source{{12, 34}}), vec3<f32>()));
+    WrapInFunction(Let("a", ty.vec3<Infer>(Source{{12, 34}}), Call<vec3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'vec3'");
@@ -414,7 +413,7 @@
 
 TEST_F(ResolverVariableValidationTest, MatrixConstNoType) {
     // const a : mat3x3 = mat3x3<f32>();
-    WrapInFunction(Const("a", ty.mat3x3<Infer>(Source{{12, 34}}), mat3x3<f32>()));
+    WrapInFunction(Const("a", ty.mat3x3<Infer>(Source{{12, 34}}), Call<mat3x3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'mat3x3'");
@@ -422,7 +421,7 @@
 
 TEST_F(ResolverVariableValidationTest, MatrixLetNoType) {
     // let a : mat3x3 = mat3x3<f32>();
-    WrapInFunction(Let("a", ty.mat3x3<Infer>(Source{{12, 34}}), mat3x3<f32>()));
+    WrapInFunction(Let("a", ty.mat3x3<Infer>(Source{{12, 34}}), Call<mat3x3<f32>>()));
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(), "12:34 error: expected '<' for 'mat3x3'");
diff --git a/src/tint/sem/statement.h b/src/tint/sem/statement.h
index 87214a2..1d9b6cb 100644
--- a/src/tint/sem/statement.h
+++ b/src/tint/sem/statement.h
@@ -88,7 +88,7 @@
     /// pointer to that template argument type, otherwise a CompoundStatement
     /// pointer is returned.
     template <typename... TYPES>
-    const detail::FindFirstParentReturnType<TYPES...>* FindFirstParent() const;
+    const sem::detail::FindFirstParentReturnType<TYPES...>* FindFirstParent() const;
 
     /// @return the closest enclosing block for this statement
     const BlockStatement* Block() const;
@@ -181,8 +181,8 @@
 }
 
 template <typename... TYPES>
-const detail::FindFirstParentReturnType<TYPES...>* Statement::FindFirstParent() const {
-    using ReturnType = detail::FindFirstParentReturnType<TYPES...>;
+const sem::detail::FindFirstParentReturnType<TYPES...>* Statement::FindFirstParent() const {
+    using ReturnType = sem::detail::FindFirstParentReturnType<TYPES...>;
     if (sizeof...(TYPES) == 1) {
         if (auto* p = As<ReturnType>()) {
             return p;
diff --git a/src/tint/switch.h b/src/tint/switch.h
index df5bd95..4073bb8 100644
--- a/src/tint/switch.h
+++ b/src/tint/switch.h
@@ -110,8 +110,8 @@
 template <typename... CASE_RETURN_TYPES>
 struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true, utils::detail::Infer, CASE_RETURN_TYPES...> {
   private:
-    using InferredType = utils::CastableCommonBase<
-        detail::NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>;
+    using InferredType =
+        utils::CastableCommonBase<NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>;
 
   public:
     /// `const T*` or `T*`, where T is the common base type for all the castable case types.
@@ -166,8 +166,9 @@
           typename T = utils::CastableBase,
           typename... CASES>
 inline auto Switch(T* object, CASES&&... cases) {
-    using ReturnType = detail::SwitchReturnType<RETURN_TYPE, utils::traits::ReturnType<CASES>...>;
-    static constexpr int kDefaultIndex = detail::IndexOfDefaultCase<std::tuple<CASES...>>();
+    using ReturnType =
+        tint::detail::SwitchReturnType<RETURN_TYPE, utils::traits::ReturnType<CASES>...>;
+    static constexpr int kDefaultIndex = tint::detail::IndexOfDefaultCase<std::tuple<CASES...>>();
     static constexpr bool kHasDefaultCase = kDefaultIndex >= 0;
     static constexpr bool kHasReturnType = !std::is_same_v<ReturnType, void>;
 
@@ -202,8 +203,8 @@
     struct alignas(alignof(ReturnTypeOrU8)) ReturnStorage {
         uint8_t data[sizeof(ReturnTypeOrU8)];
     };
-    ReturnStorage storage;
-    auto* result = utils::Bitcast<ReturnTypeOrU8*>(&storage);
+    ReturnStorage return_storage;
+    auto* result = utils::Bitcast<ReturnTypeOrU8*>(&return_storage);
 
     const utils::TypeInfo& type_info = object->TypeInfo();
 
@@ -217,7 +218,7 @@
     // `result` pointer.
     auto try_case = [&](auto&& case_fn) {
         using CaseFunc = std::decay_t<decltype(case_fn)>;
-        using CaseType = detail::SwitchCaseType<CaseFunc>;
+        using CaseType = tint::detail::SwitchCaseType<CaseFunc>;
         bool success = false;
         if constexpr (std::is_same_v<CaseType, Default>) {
             if constexpr (kHasReturnType) {
diff --git a/src/tint/type/manager.cc b/src/tint/type/manager.cc
index f5f382b..97e69d1 100644
--- a/src/tint/type/manager.cc
+++ b/src/tint/type/manager.cc
@@ -158,7 +158,7 @@
 
 const type::Pointer* Manager::ptr(builtin::AddressSpace address_space,
                                   const type::Type* subtype,
-                                  builtin::Access access) {
+                                  builtin::Access access /* = builtin::Access::kReadWrite */) {
     return Get<type::Pointer>(address_space, subtype, access);
 }
 
diff --git a/src/tint/type/manager.h b/src/tint/type/manager.h
index a9bdbeb..31f49d8 100644
--- a/src/tint/type/manager.h
+++ b/src/tint/type/manager.h
@@ -19,7 +19,8 @@
 
 #include "src/tint/builtin/access.h"
 #include "src/tint/builtin/address_space.h"
-#include "src/tint/number.h"
+#include "src/tint/builtin/fluent_types.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/type/type.h"
 #include "src/tint/type/unique_node.h"
 #include "src/tint/utils/hash.h"
@@ -43,9 +44,6 @@
 
 namespace tint::type {
 
-template <typename T>
-struct CppToType;
-
 /// The type manager holds all the pointers to the known types.
 class Manager final {
   public:
@@ -92,10 +90,31 @@
     /// the same pointer is returned.
     template <typename T, typename... ARGS>
     auto* Get(ARGS&&... args) {
-        using N = ToType<T>;
-        if constexpr (utils::traits::IsTypeOrDerived<N, Type>) {
-            return types_.Get<N>(std::forward<ARGS>(args)...);
-        } else if constexpr (utils::traits::IsTypeOrDerived<N, UniqueNode>) {
+        if constexpr (std::is_same_v<T, tint::AInt>) {
+            return Get<type::AbstractInt>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, tint::AFloat>) {
+            return Get<type::AbstractFloat>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, tint::i32>) {
+            return Get<type::I32>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, tint::u32>) {
+            return Get<type::U32>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, tint::f32>) {
+            return Get<type::F32>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, tint::f16>) {
+            return Get<type::F16>(std::forward<ARGS>(args)...);
+        } else if constexpr (std::is_same_v<T, bool>) {
+            return Get<type::Bool>(std::forward<ARGS>(args)...);
+        } else if constexpr (builtin::fluent_types::IsVector<T>) {
+            return vec<typename T::type, T::width>(std::forward<ARGS>(args)...);
+        } else if constexpr (builtin::fluent_types::IsMatrix<T>) {
+            return mat<T::columns, T::rows, typename T::type>(std::forward<ARGS>(args)...);
+        } else if constexpr (builtin::fluent_types::IsPointer<T>) {
+            return ptr<T::address, typename T::type, T::access>(std::forward<ARGS>(args)...);
+        } else if constexpr (builtin::fluent_types::IsArray<T>) {
+            return array<typename T::type, T::length>(std::forward<ARGS>(args)...);
+        } else if constexpr (utils::traits::IsTypeOrDerived<T, Type>) {
+            return types_.Get<T>(std::forward<ARGS>(args)...);
+        } else if constexpr (utils::traits::IsTypeOrDerived<T, UniqueNode>) {
             return unique_nodes_.Get<T>(std::forward<ARGS>(args)...);
         } else {
             return nodes_.Create<T>(std::forward<ARGS>(args)...);
@@ -158,6 +177,7 @@
     /// @returns the vector type
     template <typename T, size_t N>
     const type::Vector* vec() {
+        TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
         static_assert(N >= 2 && N <= 4);
         switch (N) {
             case 2:
@@ -167,6 +187,8 @@
             case 4:
                 return vec4<T>();
         }
+        return nullptr;  // unreachable
+        TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
     }
 
     /// @tparam T the element type
@@ -295,6 +317,24 @@
         return mat4x4(Get<T>());
     }
 
+    /// @param columns the number of columns of the matrix
+    /// @param rows the number of rows of the matrix
+    /// @tparam T the element type
+    /// @returns a matrix with the given number of columns and rows
+    template <typename T>
+    const type::Matrix* mat(uint32_t columns, uint32_t rows) {
+        return mat(Get<T>(), columns, rows);
+    }
+
+    /// @tparam C the number of columns in the matrix
+    /// @tparam R the number of rows in the matrix
+    /// @tparam T the element type
+    /// @returns a matrix with the given number of columns and rows
+    template <uint32_t C, uint32_t R, typename T>
+    const type::Matrix* mat() {
+        return mat(Get<T>(), C, R);
+    }
+
     /// @param elem_ty the array element type
     /// @param count the array element count
     /// @param stride the optional array element stride
@@ -325,7 +365,7 @@
     /// @returns the pointer type
     const type::Pointer* ptr(builtin::AddressSpace address_space,
                              const type::Type* subtype,
-                             builtin::Access access);
+                             builtin::Access access = builtin::Access::kReadWrite);
 
     /// @tparam SPACE the address space
     /// @tparam T the storage type
@@ -338,6 +378,15 @@
         return ptr(SPACE, Get<T>(), ACCESS);
     }
 
+    /// @param subtype the pointer subtype
+    /// @tparam SPACE the address space
+    /// @tparam ACCESS the access mode
+    /// @returns the pointer type with the templated address space, storage type and access.
+    template <builtin::AddressSpace SPACE, builtin::Access ACCESS = builtin::Access::kReadWrite>
+    const type::Pointer* ptr(const type::Type* subtype) {
+        return ptr(SPACE, subtype, ACCESS);
+    }
+
     /// @returns an iterator to the beginning of the types
     TypeIterator begin() const { return types_.begin(); }
     /// @returns an iterator to the end of the types
@@ -362,46 +411,6 @@
     utils::BlockAllocator<Node> nodes_;
 };
 
-//! @cond Doxygen_Suppress
-// Various template specializations for Manager::ToTypeImpl.
-template <>
-struct Manager::ToTypeImpl<AInt> {
-    using type = type::AbstractInt;
-};
-template <>
-struct Manager::ToTypeImpl<AFloat> {
-    using type = type::AbstractFloat;
-};
-template <>
-struct Manager::ToTypeImpl<i32> {
-    using type = type::I32;
-};
-template <>
-struct Manager::ToTypeImpl<u32> {
-    using type = type::U32;
-};
-template <>
-struct Manager::ToTypeImpl<f32> {
-    using type = type::F32;
-};
-template <>
-struct Manager::ToTypeImpl<f16> {
-    using type = type::F16;
-};
-template <>
-struct Manager::ToTypeImpl<bool> {
-    using type = type::Bool;
-};
-template <typename T>
-struct Manager::ToTypeImpl<const T> {
-    using type = const Manager::ToType<T>;
-};
-template <typename T>
-struct Manager::ToTypeImpl<T*> {
-    using type = Manager::ToType<T>*;
-};
-//! @endcond
-
 }  // namespace tint::type
 
 #endif  // SRC_TINT_TYPE_MANAGER_H_
diff --git a/src/tint/utils/castable.cc b/src/tint/utils/castable.cc
index b7756b3..484014f 100644
--- a/src/tint/utils/castable.cc
+++ b/src/tint/utils/castable.cc
@@ -19,7 +19,7 @@
 /// The unique TypeInfo for the CastableBase type
 /// @return doxygen-thinks-this-static-field-is-a-function :(
 template <>
-const TypeInfo detail::TypeInfoOf<CastableBase>::info{
+const TypeInfo utils::detail::TypeInfoOf<CastableBase>::info{
     nullptr,
     "CastableBase",
     tint::utils::TypeInfo::HashCodeOf<CastableBase>(),
diff --git a/src/tint/utils/castable.h b/src/tint/utils/castable.h
index f402c1c..176b107 100644
--- a/src/tint/utils/castable.h
+++ b/src/tint/utils/castable.h
@@ -176,7 +176,7 @@
     /// @returns the static TypeInfo for the type T
     template <typename T>
     static const TypeInfo& Of() {
-        return detail::TypeInfoOf<std::remove_cv_t<T>>::info;
+        return utils::detail::TypeInfoOf<std::remove_cv_t<T>>::info;
     }
 
     /// @returns a compile-time hashcode for the type `T`.
@@ -281,7 +281,7 @@
 /// @returns true if `obj` is a valid pointer, and is of, or derives from the class `TO`
 /// @param obj the object to test from
 /// @see CastFlags
-template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
+template <typename TO, int FLAGS = 0, typename FROM = utils::detail::Infer>
 inline bool Is(FROM* obj) {
     if (obj == nullptr) {
         return false;
@@ -295,7 +295,10 @@
 /// @param pred predicate function with signature `bool(const TYPE*)` called iff object is of, or
 /// derives from the class `TYPE`.
 /// @see CastFlags
-template <typename TYPE, int FLAGS = 0, typename OBJ = detail::Infer, typename Pred = detail::Infer>
+template <typename TYPE,
+          int FLAGS = 0,
+          typename OBJ = utils::detail::Infer,
+          typename Pred = utils::detail::Infer>
 inline bool Is(OBJ* obj, Pred&& pred) {
     return Is<TYPE, FLAGS, OBJ>(obj) && pred(static_cast<std::add_const_t<TYPE>*>(obj));
 }
@@ -315,7 +318,7 @@
 /// `TO`.
 /// @param obj the object to cast from
 /// @see CastFlags
-template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
+template <typename TO, int FLAGS = 0, typename FROM = utils::detail::Infer>
 inline TO* As(FROM* obj) {
     auto* as_castable = static_cast<CastableBase*>(obj);
     return Is<TO, FLAGS>(obj) ? static_cast<TO*>(as_castable) : nullptr;
@@ -325,7 +328,7 @@
 /// `TO`.
 /// @param obj the object to cast from
 /// @see CastFlags
-template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
+template <typename TO, int FLAGS = 0, typename FROM = utils::detail::Infer>
 inline const TO* As(const FROM* obj) {
     auto* as_castable = static_cast<const CastableBase*>(obj);
     return Is<TO, FLAGS>(obj) ? static_cast<const TO*>(as_castable) : nullptr;
@@ -361,7 +364,7 @@
     /// returns true
     /// @param pred predicate function with signature `bool(const TO*)` called iff object is of, or
     /// derives from the class `TO`.
-    template <typename TO, int FLAGS = 0, typename Pred = detail::Infer>
+    template <typename TO, int FLAGS = 0, typename Pred = utils::detail::Infer>
     inline bool Is(Pred&& pred) const {
         return tint::utils::Is<TO, FLAGS>(this, std::forward<Pred>(pred));
     }
@@ -445,7 +448,7 @@
     /// pred(const TO*) returns true
     /// @param pred predicate function with signature `bool(const TO*)` called iff
     /// object is of, or derives from the class `TO`.
-    template <int FLAGS = 0, typename Pred = detail::Infer>
+    template <int FLAGS = 0, typename Pred = utils::detail::Infer>
     inline bool Is(Pred&& pred) const {
         using TO = typename std::remove_pointer<utils::traits::ParameterType<Pred, 0>>::type;
         return tint::utils::Is<TO, FLAGS>(static_cast<const CLASS*>(this),
@@ -534,7 +537,7 @@
 
 /// Resolves to the common most derived type that each of the types in `TYPES` derives from.
 template <typename... TYPES>
-using CastableCommonBase = detail::CastableCommonBase<TYPES...>;
+using CastableCommonBase = utils::detail::CastableCommonBase<TYPES...>;
 
 }  // namespace tint::utils
 
diff --git a/src/tint/utils/hash.h b/src/tint/utils/hash.h
index fe1614e..f02c777 100644
--- a/src/tint/utils/hash.h
+++ b/src/tint/utils/hash.h
@@ -209,7 +209,7 @@
 ///          The returned hash is dependent on the order of the arguments.
 template <typename... ARGS>
 size_t HashCombine(size_t hash, const ARGS&... values) {
-    constexpr size_t offset = detail::HashCombineOffset<sizeof(size_t)>::value();
+    constexpr size_t offset = utils::detail::HashCombineOffset<sizeof(size_t)>::value();
     ((hash ^= Hash(values) + (offset ^ (hash >> 2))), ...);
     return hash;
 }
diff --git a/src/tint/utils/slice.h b/src/tint/utils/slice.h
index ca25949..49483ec 100644
--- a/src/tint/utils/slice.h
+++ b/src/tint/utils/slice.h
@@ -94,7 +94,8 @@
 ///  * `FROM` and `TO` are pointers to CastableBase (or derived), and the pointee type of `TO` is of
 ///     the same type as, or is an ancestor of the pointee type of `FROM`.
 template <ReinterpretMode MODE, typename TO, typename FROM>
-static constexpr bool CanReinterpretSlice = detail::CanReinterpretSlice<MODE, TO, FROM>::value;
+static constexpr bool CanReinterpretSlice =
+    utils::detail::CanReinterpretSlice<MODE, TO, FROM>::value;
 
 /// A slice represents a contigious array of elements of type T.
 template <typename T>
diff --git a/src/tint/utils/traits.h b/src/tint/utils/traits.h
index 711ea36..f37b073 100644
--- a/src/tint/utils/traits.h
+++ b/src/tint/utils/traits.h
@@ -148,14 +148,14 @@
 /// `[OFFSET..OFFSET+COUNT)`
 template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
 constexpr auto Slice(TUPLE&& t) {
-    return detail::Swizzle<TUPLE>(std::forward<TUPLE>(t), Range<OFFSET, COUNT>());
+    return traits::detail::Swizzle<TUPLE>(std::forward<TUPLE>(t), Range<OFFSET, COUNT>());
 }
 
 /// Resolves to the slice of the tuple `t` with the tuple elements
 /// `[OFFSET..OFFSET+COUNT)`
 template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
 using SliceTuple =
-    std::remove_pointer_t<decltype(detail::SwizzlePtrTy<TUPLE>(Range<OFFSET, COUNT>()))>;
+    std::remove_pointer_t<decltype(traits::detail::SwizzlePtrTy<TUPLE>(Range<OFFSET, COUNT>()))>;
 
 namespace detail {
 /// Base template for IsTypeIn
@@ -171,7 +171,7 @@
 /// Works for std::variant, std::tuple, std::pair, or any typename template where all parameters are
 /// types.
 template <typename T, typename TypeContainer>
-static constexpr bool IsTypeIn = detail::IsTypeIn<T, TypeContainer>::value;
+static constexpr bool IsTypeIn = traits::detail::IsTypeIn<T, TypeContainer>::value;
 
 /// Evaluates to the decayed pointer element type, or the decayed type T if T is not a pointer.
 template <typename T>
@@ -207,7 +207,7 @@
 /// Evaluates to `char*` or `const char*` if `T` is `char[N]` or `const char[N]`, respectively,
 /// otherwise T.
 template <typename T>
-using CharArrayToCharPtr = typename detail::CharArrayToCharPtrImpl<T>::type;
+using CharArrayToCharPtr = typename traits::detail::CharArrayToCharPtrImpl<T>::type;
 
 }  // namespace tint::utils::traits
 
diff --git a/src/tint/utils/vector.h b/src/tint/utils/vector.h
index 8b8fc0f..78cddbd 100644
--- a/src/tint/utils/vector.h
+++ b/src/tint/utils/vector.h
@@ -571,7 +571,7 @@
 /// Helper for determining the Vector element type (`T`) from the vector's constuctor arguments
 template <typename... Ts>
 using VectorCommonType =
-    typename detail::VectorCommonType<IsCastable<std::remove_pointer_t<Ts>...>, Ts...>::type;
+    typename utils::detail::VectorCommonType<IsCastable<std::remove_pointer_t<Ts>...>, Ts...>::type;
 
 /// Deduction guide for Vector
 template <typename... Ts>
@@ -792,7 +792,7 @@
 
 /// True if T is a Vector<T, N> or VectorRef<T>
 template <typename T>
-static constexpr bool IsVectorLike = detail::IsVectorLike<T>::value;
+static constexpr bool IsVectorLike = utils::detail::IsVectorLike<T>::value;
 
 }  // namespace tint::utils
 
diff --git a/src/tint/writer/append_vector_test.cc b/src/tint/writer/append_vector_test.cc
index ff58ba3..b9e7857 100644
--- a/src/tint/writer/append_vector_test.cc
+++ b/src/tint/writer/append_vector_test.cc
@@ -20,11 +20,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 class AppendVectorTest : public ::testing::Test, public ProgramBuilder {};
 
 // AppendVector(vec2<i32>(1, 2), 3) -> vec3<i32>(1, 2, 3)
@@ -32,7 +33,7 @@
     auto* scalar_1 = Expr(1_i);
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr(3_i);
-    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    auto* vec_12 = Call<vec2<i32>>(scalar_1, scalar_2);
     WrapInFunction(vec_12, scalar_3);
 
     resolver::Resolver resolver(this);
@@ -73,7 +74,7 @@
     auto* scalar_1 = Expr(1_i);
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr(3_u);
-    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    auto* vec_12 = Call<vec2<i32>>(scalar_1, scalar_2);
     WrapInFunction(vec_12, scalar_3);
 
     resolver::Resolver resolver(this);
@@ -120,8 +121,8 @@
     auto* scalar_1 = Expr(1_u);
     auto* scalar_2 = Expr(2_u);
     auto* scalar_3 = Expr(3_u);
-    auto* uvec_12 = vec2<u32>(scalar_1, scalar_2);
-    auto* vec_12 = vec2<i32>(uvec_12);
+    auto* uvec_12 = Call<vec2<u32>>(scalar_1, scalar_2);
+    auto* vec_12 = Call<vec2<i32>>(uvec_12);
     WrapInFunction(vec_12, scalar_3);
 
     resolver::Resolver resolver(this);
@@ -170,7 +171,7 @@
     auto* scalar_1 = Expr(1_i);
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr(3_f);
-    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    auto* vec_12 = Call<vec2<i32>>(scalar_1, scalar_2);
     WrapInFunction(vec_12, scalar_3);
 
     resolver::Resolver resolver(this);
@@ -216,7 +217,7 @@
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr(3_i);
     auto* scalar_4 = Expr(4_i);
-    auto* vec_123 = vec3<i32>(scalar_1, scalar_2, scalar_3);
+    auto* vec_123 = Call<vec3<i32>>(scalar_1, scalar_2, scalar_3);
     WrapInFunction(vec_123, scalar_4);
 
     resolver::Resolver resolver(this);
@@ -298,7 +299,7 @@
     auto* scalar_1 = Expr(1_i);
     auto* scalar_2 = Expr(2_i);
     auto* scalar_3 = Expr("scalar_3");
-    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    auto* vec_12 = Call<vec2<i32>>(scalar_1, scalar_2);
     WrapInFunction(vec_12, scalar_3);
 
     resolver::Resolver resolver(this);
@@ -455,7 +456,7 @@
 // AppendVector(vec3<i32>(), 4) -> vec3<bool>(0, 0, 0, 4)
 TEST_F(AppendVectorTest, ZeroVec3i32_i32) {
     auto* scalar = Expr(4_i);
-    auto* vec000 = vec3<i32>();
+    auto* vec000 = Call<vec3<i32>>();
     WrapInFunction(vec000, scalar);
 
     resolver::Resolver resolver(this);
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index 9be3fa4..7ca2b09 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -19,11 +19,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using GlslGeneratorImplTest_Binary = TestHelper;
 
 struct BinaryData {
@@ -160,7 +161,7 @@
                     BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f32) {
-    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("a", Call<vec3<f32>>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("a");
     auto* rhs = Expr(1_f);
 
@@ -179,7 +180,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
+    GlobalVar("a", Call<vec3<f16>>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("a");
     auto* rhs = Expr(1_h);
 
@@ -196,7 +197,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f32) {
-    GlobalVar("a", vec3<f32>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("a", Call<vec3<f32>>(1_f, 1_f, 1_f), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_f);
     auto* rhs = Expr("a");
 
@@ -215,7 +216,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector_f16) {
     Enable(builtin::Extension::kF16);
 
-    GlobalVar("a", vec3<f16>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
+    GlobalVar("a", Call<vec3<f16>>(1_h, 1_h, 1_h), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr(1_h);
     auto* rhs = Expr("a");
 
@@ -302,7 +303,7 @@
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
     GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
     WrapInFunction(expr);
@@ -320,7 +321,7 @@
 
     GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
     WrapInFunction(expr);
@@ -335,7 +336,7 @@
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
     GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* rhs = Expr("mat");
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -353,7 +354,7 @@
     Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
     auto* rhs = Expr("mat");
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index e7d1a61..18fa324 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -21,7 +21,8 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::glsl {
 namespace {
@@ -371,9 +372,9 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Select_Vector) {
-    GlobalVar("a", vec2<i32>(1_i, 2_i), builtin::AddressSpace::kPrivate);
-    GlobalVar("b", vec2<i32>(3_i, 4_i), builtin::AddressSpace::kPrivate);
-    auto* call = Call("select", "a", "b", vec2<bool>(true, false));
+    GlobalVar("a", Call<vec2<i32>>(1_i, 2_i), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", Call<vec2<i32>>(3_i, 4_i), builtin::AddressSpace::kPrivate);
+    auto* call = Call("select", "a", "b", Call<vec2<bool>>(true, false));
     WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
@@ -495,7 +496,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("f", vec3<f32>(1.5_f, 2.5_f, 3.5_f))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -532,7 +533,7 @@
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -625,7 +626,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f32>(1.5_f, 2.5_f, 3.5_f)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -654,7 +655,7 @@
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -755,7 +756,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f32) {
-    WrapInFunction(Var("f", Expr(vec3<f32>())),  //
+    WrapInFunction(Var("f", Call<vec3<f32>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -792,7 +793,7 @@
 TEST_F(GlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Var("f", Expr(vec3<f16>())),  //
+    WrapInFunction(Var("f", Call<vec3<f16>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -885,7 +886,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f32>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f32>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -914,7 +915,7 @@
 TEST_F(GlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f16>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -1576,7 +1577,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec2) {
-    GlobalVar("v", vec2<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec2<f32>>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1604,7 +1605,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec3) {
-    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec3<f32>>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1634,7 +1635,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, QuantizeToF16_Vec4) {
-    GlobalVar("v", vec4<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec4<f32>>(2_f), builtin::AddressSpace::kPrivate);
     WrapInFunction(Call("quantizeToF16", "v"));
 
     GeneratorImpl& gen = SanitizeAndBuild();
diff --git a/src/tint/writer/glsl/generator_impl_cast_test.cc b/src/tint/writer/glsl/generator_impl_cast_test.cc
index 4773a4b..b39bc2e 100644
--- a/src/tint/writer/glsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_cast_test.cc
@@ -17,7 +17,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::glsl {
 namespace {
@@ -37,7 +38,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Cast, EmitExpression_Cast_Vector) {
-    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    auto* cast = Call<vec3<f32>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/glsl/generator_impl_constructor_test.cc b/src/tint/writer/glsl/generator_impl_constructor_test.cc
index 2983382..d0fc0bc 100644
--- a/src/tint/writer/glsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_constructor_test.cc
@@ -15,7 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::glsl {
 namespace {
@@ -121,7 +122,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_F32) {
-    WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec3<f32>>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -132,7 +133,7 @@
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+    WrapInFunction(Call<vec3<f16>>(1_h, 2_h, 3_h));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -141,7 +142,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
-    WrapInFunction(vec3<f32>());
+    WrapInFunction(Call<vec3<f32>>());
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -152,7 +153,7 @@
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>());
+    WrapInFunction(Call<vec3<f16>>());
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -161,7 +162,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
-    WrapInFunction(vec3<f32>(2_f));
+    WrapInFunction(Call<vec3<f32>>(2_f));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -172,7 +173,7 @@
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(2_h));
+    WrapInFunction(Call<vec3<f16>>(2_h));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -182,7 +183,7 @@
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
-    auto* cast = vec3<f32>(var);
+    auto* cast = Call<vec3<f32>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -196,7 +197,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
-    auto* cast = vec3<f16>(var);
+    auto* cast = Call<vec3<f16>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -207,7 +208,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool) {
-    WrapInFunction(vec3<bool>(true));
+    WrapInFunction(Call<vec3<bool>>(true));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -216,7 +217,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
-    WrapInFunction(vec3<i32>(2_i));
+    WrapInFunction(Call<vec3<i32>>(2_i));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -225,7 +226,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
-    WrapInFunction(vec3<u32>(2_u));
+    WrapInFunction(Call<vec3<u32>>(2_u));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -234,7 +235,8 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_F32) {
-    WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
+    WrapInFunction(
+        Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -245,7 +247,8 @@
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+    WrapInFunction(
+        Call<mat2x3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(3_h, 4_h, 5_h)));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -262,14 +265,14 @@
     //     vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
     //   );
     auto* vector_literal =
-        vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
-    auto* vector_zero_init = vec4<f32>();
-    auto* vector_single_scalar_init = vec4<f32>(Expr(f32(7.0)));
-    auto* vector_identical_init =
-        vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+        Call<vec4<f32>>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
+    auto* vector_zero_init = Call<vec4<f32>>();
+    auto* vector_single_scalar_init = Call<vec4<f32>>(Expr(f32(7.0)));
+    auto* vector_identical_init = Call<vec4<f32>>(
+        Call<vec4<f32>>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
 
-    auto* ctor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                             vector_identical_init);
+    auto* ctor = Call<mat4x4<f32>>(vector_literal, vector_zero_init, vector_single_scalar_init,
+                                   vector_identical_init);
 
     WrapInFunction(ctor);
 
@@ -290,14 +293,14 @@
     Enable(builtin::Extension::kF16);
 
     auto* vector_literal =
-        vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
-    auto* vector_zero_init = vec4<f16>();
-    auto* vector_single_scalar_init = vec4<f16>(Expr(f16(7.0)));
-    auto* vector_identical_init =
-        vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+        Call<vec4<f16>>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
+    auto* vector_zero_init = Call<vec4<f16>>();
+    auto* vector_single_scalar_init = Call<vec4<f16>>(Expr(f16(7.0)));
+    auto* vector_identical_init = Call<vec4<f16>>(
+        Call<vec4<f16>>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
 
-    auto* ctor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                             vector_identical_init);
+    auto* ctor = Call<mat4x4<f16>>(vector_literal, vector_zero_init, vector_single_scalar_init,
+                                   vector_identical_init);
 
     WrapInFunction(ctor);
 
@@ -310,7 +313,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
-    WrapInFunction(mat2x3<f32>());
+    WrapInFunction(Call<mat2x3<f32>>());
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -321,7 +324,7 @@
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>());
+    WrapInFunction(Call<mat2x3<f16>>());
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -336,8 +339,8 @@
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
     // }
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -355,8 +358,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -367,8 +370,9 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Array) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
-                        vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
+    WrapInFunction(Call<array<vec3<f32>, 3>>(Call<vec3<f32>>(1_f, 2_f, 3_f),
+                                             Call<vec3<f32>>(4_f, 5_f, 6_f),
+                                             Call<vec3<f32>>(7_f, 8_f, 9_f)));
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -379,7 +383,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, Type_Array_Empty) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u)));
+    WrapInFunction(Call<array<vec3<f32>, 3>>());
 
     GeneratorImpl& gen = Build();
     gen.Generate();
@@ -394,7 +398,7 @@
                                    Member("c", ty.vec3<i32>()),
                                });
 
-    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, vec3<i32>(3_i, 4_i, 5_i)));
+    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, Call<vec3<i32>>(3_i, 4_i, 5_i)));
 
     GeneratorImpl& gen = SanitizeAndBuild();
     gen.Generate();
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index 34375f7..43f8773 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -20,11 +20,12 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using GlslGeneratorImplTest_Function = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function) {
@@ -110,7 +111,7 @@
     // fn f(foo : ptr<function, f32>) -> f32 {
     //   return *foo;
     // }
-    Func("f", utils::Vector{Param("foo", ty.ptr<f32>(builtin::AddressSpace::kFunction))}, ty.f32(),
+    Func("f", utils::Vector{Param("foo", ty.ptr<function, f32>())}, ty.f32(),
          utils::Vector{Return(Deref("foo"))});
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -207,7 +208,7 @@
     //   @location(2) col2 : f32;
     // };
     // fn vert_main() -> Interface {
-    //   return Interface(vec4<f32>(), 0.4, 0.6);
+    //   return Interface(vec4<f32>(), 0.5, 0.25);
     // }
     // fn frag_main(inputs : Interface) {
     //   const r = inputs.col1;
@@ -223,8 +224,7 @@
         });
 
     Func("vert_main", utils::Empty, ty.Of(interface_struct),
-         utils::Vector{Return(
-             Call(ty.Of(interface_struct), Call(ty.vec4<f32>()), Expr(0.5_f), Expr(0.25_f)))},
+         utils::Vector{Return(Call(ty.Of(interface_struct), Call<vec4<f32>>(), 0.5_f, 0.25_f))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)});
 
     Func("frag_main", utils::Vector{Param("inputs", ty.Of(interface_struct))}, ty.void_(),
@@ -301,7 +301,7 @@
 
   Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
        {Return(Call(ty.Of(vertex_output_struct),
-                         Call(ty.vec4<f32>(), "x", "x", "x", Expr(1_f))))},
+                         Call<vec4<f32>>( "x", "x", "x", 1_f)))},
        {});
 
   Func("vert_main1", utils::Empty, ty.Of(vertex_output_struct),
@@ -845,7 +845,7 @@
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
     Func("my_func", utils::Empty, ty.array<f32, 5>(),
          utils::Vector{
-             Return(Call(ty.array<f32, 5>())),
+             Return(Call<array<f32, 5>>()),
          });
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/glsl/generator_impl_import_test.cc b/src/tint/writer/glsl/generator_impl_import_test.cc
index 6f772ea..0f27e4b 100644
--- a/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -17,11 +17,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using GlslGeneratorImplTest_Import = TestHelper;
 
 struct GlslImportData {
@@ -95,7 +96,7 @@
 TEST_P(GlslImportData_SingleVectorParamTest, FloatVector) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(0.1_f, 0.2_f, 0.3_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(0.1_f, 0.2_f, 0.3_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -162,7 +163,7 @@
 TEST_P(GlslImportData_DualParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -227,8 +228,8 @@
 TEST_P(GlslImportData_TripleParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f),
-                      vec3<f32>(7_f, 8_f, 9_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f),
+                      Call<vec3<f32>>(7_f, 8_f, 9_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index 041e72c..7f252b1 100644
--- a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -17,12 +17,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
 using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using create_type_func_ptr = ast::Type (*)(const ProgramBuilder::TypesBuilder& ty);
 
@@ -275,7 +275,7 @@
     });
 
     SetupFunction(utils::Vector{
-        Assign(MemberAccessor("data", "b"), Call(ty.mat2x3<f32>())),
+        Assign(MemberAccessor("data", "b"), Call<mat2x3<f32>>()),
     });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -769,7 +769,7 @@
 
     SetupFunction(utils::Vector{
         Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
-               vec3<f32>(1_f, 2_f, 3_f)),
+               Call<vec3<f32>>(1_f, 2_f, 3_f)),
     });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -868,7 +868,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, Swizzle_xyz) {
-    auto* var = Var("my_vec", ty.vec4<f32>(), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+    auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
     auto* expr = MemberAccessor("my_vec", "xyz");
     WrapInFunction(var, expr);
 
@@ -879,7 +879,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, Swizzle_gbr) {
-    auto* var = Var("my_vec", ty.vec4<f32>(), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+    auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
     auto* expr = MemberAccessor("my_vec", "gbr");
     WrapInFunction(var, expr);
 
diff --git a/src/tint/writer/glsl/generator_impl_module_constant_test.cc b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
index 8de0dd0..9a80721 100644
--- a/src/tint/writer/glsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
@@ -17,15 +17,16 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using GlslGeneratorImplTest_ModuleConstant = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalLet) {
-    auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1_f, 2_f, 3_f));
+    auto* var = Let("pos", ty.array<f32, 3>(), Call<array<f32, 3>>(1_f, 2_f, 3_f));
     WrapInFunction(Decl(var));
 
     GeneratorImpl& gen = Build();
@@ -152,7 +153,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -171,7 +172,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -190,7 +191,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
-    auto* var = GlobalConst("G", vec3<f32>(1_f, 2_f, 3_f));
+    auto* var = GlobalConst("G", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -211,7 +212,7 @@
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
+    auto* var = GlobalConst("G", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -231,7 +232,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* var = GlobalConst("G", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -250,7 +251,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
-    auto* var = GlobalConst("G", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* var = GlobalConst("G", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -271,7 +272,7 @@
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* var = GlobalConst("G", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -291,7 +292,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
-    auto* var = GlobalConst("G", Call(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    auto* var = GlobalConst("G", Call<array<f32, 3>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
@@ -310,10 +311,10 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
-    auto* var = GlobalConst("G", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                                      vec2<bool>(true, false),         //
-                                      vec2<bool>(false, true),         //
-                                      vec2<bool>(true, true)));
+    auto* var = GlobalConst("G", Call<array<vec2<bool>, 3>>(         //
+                                     Call<vec2<bool>>(true, false),  //
+                                     Call<vec2<bool>>(false, true),  //
+                                     Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", Expr(var))),
diff --git a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
index fdd216f..ca60d36 100644
--- a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
@@ -19,11 +19,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using GlslSanitizerTest = TestHelper;
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength) {
@@ -149,7 +150,7 @@
 }
 
 TEST_F(GlslSanitizerTest, PromoteArrayInitializerToConstVar) {
-    auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
+    auto* array_init = Call<array<i32, 4>>(1_i, 2_i, 3_i, 4_i);
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -189,7 +190,7 @@
                                    Member("c", ty.i32()),
                                });
     auto* runtime_value = Var("runtime_value", Expr(3_f));
-    auto* struct_init = Call(ty.Of(str), 1_i, vec3<f32>(2_f, runtime_value, 4_f), 4_i);
+    auto* struct_init = Call(ty.Of(str), 1_i, Call<vec3<f32>>(2_f, runtime_value, 4_f), 4_i);
     auto* struct_access = MemberAccessor(struct_init, "b");
     auto* pos = Var("pos", ty.vec3<f32>(), struct_access);
 
@@ -235,7 +236,7 @@
     // let p : ptr<function, i32> = &v;
     // let x : i32 = *p;
     auto* v = Var("v", ty.i32());
-    auto* p = Let("p", ty.ptr<i32>(builtin::AddressSpace::kFunction), AddressOf(v));
+    auto* p = Let("p", ty.ptr<function, i32>(), AddressOf(v));
     auto* x = Var("x", ty.i32(), Deref(p));
 
     Func("main", utils::Empty, ty.void_(),
@@ -276,12 +277,9 @@
     // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
     // let v : vec4<f32> = *vp;
     auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
-    auto* ap = Let("ap", ty.ptr(builtin::AddressSpace::kFunction, ty.array(ty.mat4x4<f32>(), 4_u)),
-                   AddressOf(a));
-    auto* mp = Let("mp", ty.ptr(builtin::AddressSpace::kFunction, ty.mat4x4<f32>()),
-                   AddressOf(IndexAccessor(Deref(ap), 3_i)));
-    auto* vp = Let("vp", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()),
-                   AddressOf(IndexAccessor(Deref(mp), 2_i)));
+    auto* ap = Let("ap", ty.ptr<function, array<mat4x4<f32>, 4>>(), AddressOf(a));
+    auto* mp = Let("mp", ty.ptr<function, mat4x4<f32>>(), AddressOf(IndexAccessor(Deref(ap), 3_i)));
+    auto* vp = Let("vp", ty.ptr<function, vec4<f32>>(), AddressOf(IndexAccessor(Deref(mp), 2_i)));
     auto* v = Var("v", ty.vec4<f32>(), Deref(vp));
 
     Func("main", utils::Empty, ty.void_(),
diff --git a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
index 821b0e9..8ebe654 100644
--- a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/number.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
 #include "gmock/gmock.h"
diff --git a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
index 80a1fa0..d4171c5 100644
--- a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
@@ -17,12 +17,12 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::glsl {
 namespace {
 
 using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using GlslGeneratorImplTest_VariableDecl = TestHelper;
 
@@ -186,7 +186,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* C = Const("C", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -206,7 +206,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* C = Const("C", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -226,7 +226,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
-    auto* C = Const("C", vec3<f32>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -248,7 +248,7 @@
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
+    auto* C = Const("C", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -269,7 +269,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
-    auto* C = Const("C", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* C = Const("C", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -289,7 +289,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
-    auto* C = Const("C", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -311,7 +311,7 @@
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* C = Const("C", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -332,7 +332,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32) {
-    auto* C = Const("C", Call(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<array<f32, 3>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -352,7 +352,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_f32_zero) {
-    auto* C = Const("C", Call(ty.array<f32, 2>()));
+    auto* C = Const("C", Call<array<f32, 2>>());
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -372,7 +372,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_arr_f32_zero) {
-    auto* C = Const("C", Call(ty.array(ty.array<f32, 2>(), 3_i)));
+    auto* C = Const("C", Call<array<array<f32, 2>, 3>>());
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -418,10 +418,10 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
-    auto* C = Const("C", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                              vec2<bool>(true, false),         //
-                              vec2<bool>(false, true),         //
-                              vec2<bool>(true, true)));
+    auto* C = Const("C", Call<array<vec2<bool>, 3>>(         //
+                             Call<vec2<bool>>(true, false),  //
+                             Call<vec2<bool>>(false, true),  //
+                             Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -466,7 +466,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_f32) {
-    auto* var = Var("a", ty.vec3<f32>(), vec3<f32>());
+    auto* var = Var("a", ty.vec3<f32>(), Call<vec3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -481,7 +481,7 @@
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
+    auto* var = Var("a", ty.vec3<f16>(), Call<vec3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -494,7 +494,7 @@
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_f32) {
-    auto* var = Var("a", ty.mat2x3<f32>(), mat2x3<f32>());
+    auto* var = Var("a", ty.mat2x3<f32>(), Call<mat2x3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -510,7 +510,7 @@
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
+    auto* var = Var("a", ty.mat2x3<f16>(), Call<mat2x3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index 61a4ee1..f851976 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -176,7 +177,7 @@
                                BinaryData::Types::Float}));
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar_f32) {
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* rhs = Expr(1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -193,7 +194,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
     auto* rhs = Expr(1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -209,7 +210,7 @@
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector_f32) {
     auto* lhs = Expr(1_f);
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
@@ -226,7 +227,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* lhs = Expr(1_h);
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
@@ -306,7 +307,7 @@
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector_f32) {
     GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
     WrapInFunction(expr);
@@ -323,7 +324,7 @@
 
     GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
     auto* lhs = Expr("mat");
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
     WrapInFunction(expr);
@@ -337,7 +338,7 @@
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix_f32) {
     GlobalVar("mat", ty.mat3x3<f32>(), builtin::AddressSpace::kPrivate);
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* rhs = Expr("mat");
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -354,7 +355,7 @@
     Enable(builtin::Extension::kF16);
 
     GlobalVar("mat", ty.mat3x3<f16>(), builtin::AddressSpace::kPrivate);
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
     auto* rhs = Expr("mat");
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 92406a6..415917a 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -21,7 +21,8 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -368,9 +369,9 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Select_Vector) {
-    GlobalVar("a", vec2<i32>(1_i, 2_i), builtin::AddressSpace::kPrivate);
-    GlobalVar("b", vec2<i32>(3_i, 4_i), builtin::AddressSpace::kPrivate);
-    auto* call = Call("select", "a", "b", vec2<bool>(true, false));
+    GlobalVar("a", Call<vec2<i32>>(1_i, 2_i), builtin::AddressSpace::kPrivate);
+    GlobalVar("b", Call<vec2<i32>>(3_i, 4_i), builtin::AddressSpace::kPrivate);
+    auto* call = Call("select", "a", "b", Call<vec2<bool>>(true, false));
     WrapInFunction(Decl(Var("r", call)));
     GeneratorImpl& gen = Build();
 
@@ -435,7 +436,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("f", vec3<f32>(1.5_f, 2.5_f, 3.5_f))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -463,7 +464,7 @@
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -527,7 +528,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f32>(1.5_f, 2.5_f, 3.5_f)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -547,7 +548,7 @@
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -568,10 +569,10 @@
     WrapInFunction(
         // Declare a variable with the result of a modf call.
         // This is required to infer the 'var' type.
-        Decl(Var("v", Call("modf", vec3<f32>(1.5_f, 2.5_f, 3.5_f)))),
+        Decl(Var("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))),
         // Now assign 'v' again with another modf call.
         // This requires generating a temporary variable for the struct initializer.
-        Assign("v", Call("modf", vec3<f32>(4.5_a, 5.5_a, 6.5_a))));
+        Assign("v", Call("modf", Call<vec3<f32>>(4.5_a, 5.5_a, 6.5_a))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -647,7 +648,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f32) {
-    WrapInFunction(Var("f", Expr(vec3<f32>())),  //
+    WrapInFunction(Var("f", Call<vec3<f32>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -676,7 +677,7 @@
 TEST_F(HlslGeneratorImplTest_Builtin, Runtime_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Var("f", Expr(vec3<f16>())),  //
+    WrapInFunction(Var("f", Call<vec3<f16>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -741,7 +742,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f32>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f32>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -761,7 +762,7 @@
 TEST_F(HlslGeneratorImplTest_Builtin, Const_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f16>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -782,10 +783,10 @@
     WrapInFunction(
         // Declare a variable with the result of a frexp call.
         // This is required to infer the 'var' type.
-        Decl(Var("v", Call("frexp", vec3<f32>(1.5_f, 2.5_f, 3.5_f)))),
+        Decl(Var("v", Call("frexp", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))),
         // Now assign 'v' again with another frexp call.
         // This requires generating a temporary variable for the struct initializer.
-        Assign("v", Call("frexp", vec3<f32>(4.5_a, 5.5_a, 6.5_a))));
+        Assign("v", Call("frexp", Call<vec3<f32>>(4.5_a, 5.5_a, 6.5_a))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
diff --git a/src/tint/writer/hlsl/generator_impl_cast_test.cc b/src/tint/writer/hlsl/generator_impl_cast_test.cc
index 73bc170..ac269c8 100644
--- a/src/tint/writer/hlsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_cast_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -34,7 +35,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Vector) {
-    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    auto* cast = Call<vec3<f32>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/hlsl/generator_impl_constructor_test.cc b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
index f9c41ea..38a333d 100644
--- a/src/tint/writer/hlsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
@@ -15,7 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -121,7 +122,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_F32) {
-    WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec3<f32>>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
 
@@ -132,7 +133,7 @@
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+    WrapInFunction(Call<vec3<f16>>(1_h, 2_h, 3_h));
 
     GeneratorImpl& gen = Build();
 
@@ -143,7 +144,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
-    WrapInFunction(vec3<f32>());
+    WrapInFunction(Call<vec3<f32>>());
 
     GeneratorImpl& gen = Build();
 
@@ -154,7 +155,7 @@
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>());
+    WrapInFunction(Call<vec3<f16>>());
 
     GeneratorImpl& gen = Build();
 
@@ -163,7 +164,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
-    WrapInFunction(vec3<f32>(2_f));
+    WrapInFunction(Call<vec3<f32>>(2_f));
 
     GeneratorImpl& gen = Build();
 
@@ -174,7 +175,7 @@
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(2_h));
+    WrapInFunction(Call<vec3<f16>>(2_h));
 
     GeneratorImpl& gen = Build();
 
@@ -184,7 +185,7 @@
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
-    auto* cast = vec3<f32>(var);
+    auto* cast = Call<vec3<f32>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -198,7 +199,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
-    auto* cast = vec3<f16>(var);
+    auto* cast = Call<vec3<f16>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -209,7 +210,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool_Literal) {
-    WrapInFunction(vec3<bool>(true));
+    WrapInFunction(Call<vec3<bool>>(true));
 
     GeneratorImpl& gen = Build();
 
@@ -219,7 +220,7 @@
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool_Var) {
     auto* var = Var("v", Expr(true));
-    auto* cast = vec3<bool>(var);
+    auto* cast = Call<vec3<bool>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -230,7 +231,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
-    WrapInFunction(vec3<i32>(2_i));
+    WrapInFunction(Call<vec3<i32>>(2_i));
 
     GeneratorImpl& gen = Build();
 
@@ -239,7 +240,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
-    WrapInFunction(vec3<u32>(2_u));
+    WrapInFunction(Call<vec3<u32>>(2_u));
 
     GeneratorImpl& gen = Build();
 
@@ -248,7 +249,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_F32) {
-    WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
+    WrapInFunction(
+        Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -261,7 +263,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+    WrapInFunction(
+        Call<mat2x3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(3_h, 4_h, 5_h)));
 
     GeneratorImpl& gen = Build();
 
@@ -280,15 +283,14 @@
     //     vec4<f32>(7.0f),
     //     vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
     //   );
-    auto* vector_literal =
-        vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
-    auto* vector_zero_init = vec4<f32>();
-    auto* vector_single_scalar_init = vec4<f32>(Expr(f32(7.0)));
+    auto* vector_literal = Call<vec4<f32>>(f32(2.0), f32(3.0), f32(4.0), f32(8.0));
+    auto* vector_zero_init = Call<vec4<f32>>();
+    auto* vector_single_scalar_init = Call<vec4<f32>>(f32(7.0));
     auto* vector_identical_init =
-        vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+        Call<vec4<f32>>(Call<vec4<f32>>(f32(42.0), f32(21.0), f32(6.0), f32(-5.0)));
 
-    auto* constructor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* constructor = Call<mat4x4<f32>>(vector_literal, vector_zero_init,
+                                          vector_single_scalar_init, vector_identical_init);
 
     WrapInFunction(constructor);
 
@@ -309,15 +311,14 @@
     //   );
     Enable(builtin::Extension::kF16);
 
-    auto* vector_literal =
-        vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
-    auto* vector_zero_init = vec4<f16>();
-    auto* vector_single_scalar_init = vec4<f16>(Expr(f16(7.0)));
+    auto* vector_literal = Call<vec4<f16>>(f16(2.0), f16(3.0), f16(4.0), f16(8.0));
+    auto* vector_zero_init = Call<vec4<f16>>();
+    auto* vector_single_scalar_init = Call<vec4<f16>>(f16(7.0));
     auto* vector_identical_init =
-        vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+        Call<vec4<f16>>(Call<vec4<f16>>(f16(42.0), f16(21.0), f16(6.0), f16(-5.0)));
 
-    auto* constructor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* constructor = Call<mat4x4<f16>>(vector_literal, vector_zero_init,
+                                          vector_single_scalar_init, vector_identical_init);
 
     WrapInFunction(constructor);
 
@@ -334,7 +335,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
-    WrapInFunction(mat2x3<f32>());
+    WrapInFunction(Call<mat2x3<f32>>());
 
     GeneratorImpl& gen = Build();
 
@@ -346,7 +347,7 @@
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>());
+    WrapInFunction(Call<mat2x3<f16>>());
 
     GeneratorImpl& gen = Build();
 
@@ -362,8 +363,8 @@
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
     // }
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -382,8 +383,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -396,8 +397,9 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Array) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
-                        vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
+    WrapInFunction(Call<array<vec3<f32>, 3>>(Call<vec3<f32>>(1_f, 2_f, 3_f),
+                                             Call<vec3<f32>>(4_f, 5_f, 6_f),
+                                             Call<vec3<f32>>(7_f, 8_f, 9_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -409,7 +411,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, Type_Array_Empty) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u)));
+    WrapInFunction(Call<array<vec3<f32>, 3>>());
 
     GeneratorImpl& gen = Build();
 
@@ -424,7 +426,7 @@
                                    Member("c", ty.vec3<i32>()),
                                });
 
-    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, vec3<i32>(3_i, 4_i, 5_i)));
+    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, Call<vec3<i32>>(3_i, 4_i, 5_i)));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index 37d94c3..a374924 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -20,11 +20,12 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::hlsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using HlslGeneratorImplTest_Function = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
@@ -101,7 +102,7 @@
     // fn f(foo : ptr<function, f32>) -> f32 {
     //   return *foo;
     // }
-    Func("f", utils::Vector{Param("foo", ty.ptr<f32>(builtin::AddressSpace::kFunction))}, ty.f32(),
+    Func("f", utils::Vector{Param("foo", ty.ptr<function, f32>())}, ty.f32(),
          utils::Vector{Return(Deref("foo"))});
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -216,7 +217,7 @@
 
     Func("vert_main", utils::Empty, ty.Of(interface_struct),
          utils::Vector{
-             Return(Call(ty.Of(interface_struct), Call(ty.vec4<f32>()), Expr(0.5_f), Expr(0.25_f))),
+             Return(Call(ty.Of(interface_struct), Call<vec4<f32>>(), 0.5_f, 0.25_f)),
          },
          utils::Vector{Stage(ast::PipelineStage::kVertex)});
 
@@ -296,8 +297,7 @@
 
     Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
          utils::Vector{
-             Return(
-                 Call(ty.Of(vertex_output_struct), Call(ty.vec4<f32>(), "x", "x", "x", Expr(1_f)))),
+             Return(Call(ty.Of(vertex_output_struct), Call<vec4<f32>>("x", "x", "x", 1_f))),
          },
          utils::Empty);
 
@@ -752,7 +752,7 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
     Func("my_func", utils::Empty, ty.array<f32, 5>(),
          utils::Vector{
-             Return(Call(ty.array<f32, 5>())),
+             Return(Call<array<f32, 5>>()),
          });
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/hlsl/generator_impl_import_test.cc b/src/tint/writer/hlsl/generator_impl_import_test.cc
index 67af40d..17efb89 100644
--- a/src/tint/writer/hlsl/generator_impl_import_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_import_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -89,7 +90,7 @@
 TEST_P(HlslImportData_SingleVectorParamTest, FloatVector) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(0.1_f, 0.2_f, 0.3_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(0.1_f, 0.2_f, 0.3_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -152,7 +153,7 @@
 TEST_P(HlslImportData_DualParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -215,8 +216,8 @@
 TEST_P(HlslImportData_TripleParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f),
-                      vec3<f32>(7_f, 8_f, 9_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f),
+                      Call<vec3<f32>>(7_f, 8_f, 9_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -279,7 +280,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Import, HlslImportData_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec3<f32>>(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
diff --git a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
index 389b8f2..6232315 100644
--- a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -18,11 +18,12 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::hlsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using create_type_func_ptr = ast::Type (*)(const ProgramBuilder::TypesBuilder& ty);
 
 inline ast::Type ty_i32(const ProgramBuilder::TypesBuilder& ty) {
@@ -1133,7 +1134,7 @@
     });
 
     SetupFunction(utils::Vector{
-        Assign(MemberAccessor("data", "b"), Call(ty.mat2x3<f32>())),
+        Assign(MemberAccessor("data", "b"), Call<mat2x3<f32>>()),
     });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1330,7 +1331,7 @@
 
     SetupUniformBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array(ty.vec4(ty.i32()), 5_i)),
+        Member("a", ty.array<vec4<i32>, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -1505,7 +1506,7 @@
 
     SetupUniformBuffer(utils::Vector{
         Member("z", ty.f32()),
-        Member("a", ty.array(ty.vec4(ty.i32()), 5_i)),
+        Member("a", ty.array<vec4<i32>, 5>()),
     });
 
     SetupFunction(utils::Vector{
@@ -1922,7 +1923,7 @@
 
     SetupFunction(utils::Vector{
         Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
-               vec3<f32>(1_f, 2_f, 3_f)),
+               Call<vec3<f32>>(1_f, 2_f, 3_f)),
     });
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -1981,7 +1982,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, Swizzle_xyz) {
-    auto* var = Var("my_vec", ty.vec4<f32>(), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+    auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
     auto* expr = MemberAccessor("my_vec", "xyz");
     WrapInFunction(var, expr);
 
@@ -1991,7 +1992,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, Swizzle_gbr) {
-    auto* var = Var("my_vec", ty.vec4<f32>(), vec4<f32>(1_f, 2_f, 3_f, 4_f));
+    auto* var = Var("my_vec", ty.vec4<f32>(), Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f));
     auto* expr = MemberAccessor("my_vec", "gbr");
     WrapInFunction(var, expr);
 
diff --git a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
index e7805a7..009b85a 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -109,7 +110,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AInt) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -123,7 +124,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -137,7 +138,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f32) {
-    auto* var = GlobalConst("G", vec3<f32>(1_f, 2_f, 3_f));
+    auto* var = GlobalConst("G", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -153,7 +154,7 @@
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
+    auto* var = GlobalConst("G", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -167,7 +168,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* var = GlobalConst("G", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -181,7 +182,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f32) {
-    auto* var = GlobalConst("G", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* var = GlobalConst("G", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -197,7 +198,7 @@
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* var = GlobalConst("G", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -211,7 +212,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_f32) {
-    auto* var = GlobalConst("G", Call(ty.array<f32, 3>(), 1_f, 2_f, 3_f));
+    auto* var = GlobalConst("G", Call<array<f32, 3>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -225,10 +226,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_GlobalConst_arr_vec2_bool) {
-    auto* var = GlobalConst("G", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                                      vec2<bool>(true, false),         //
-                                      vec2<bool>(false, true),         //
-                                      vec2<bool>(true, true)));
+    auto* var = GlobalConst("G", Call<array<vec2<bool>, 3>>(         //
+                                     Call<vec2<bool>>(true, false),  //
+                                     Call<vec2<bool>>(false, true),  //
+                                     Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
index b1fef10..473e623 100644
--- a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::hlsl {
 namespace {
@@ -170,7 +171,7 @@
 }
 
 TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
-    auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
+    auto* array_init = Call<array<i32, 4>>(1_i, 2_i, 3_i, 4_i);
 
     Func("main", utils::Empty, ty.void_(),
          utils::Vector{
@@ -203,7 +204,7 @@
                                    Member("b", ty.vec3<f32>()),
                                    Member("c", ty.i32()),
                                });
-    auto* struct_init = Call(ty.Of(str), 1_i, vec3<f32>(2_f, runtime_value, 4_f), 4_i);
+    auto* struct_init = Call(ty.Of(str), 1_i, Call<vec3<f32>>(2_f, runtime_value, 4_f), 4_i);
     auto* struct_access = MemberAccessor(struct_init, "b");
     auto* pos = Var("pos", ty.vec3<f32>(), struct_access);
 
@@ -242,7 +243,7 @@
     // let p : ptr<function, i32> = &v;
     // let x : i32 = *p;
     auto* v = Var("v", ty.i32());
-    auto* p = Let("p", ty.ptr<i32>(builtin::AddressSpace::kFunction), AddressOf(v));
+    auto* p = Let("p", ty.ptr<function, i32>(), AddressOf(v));
     auto* x = Var("x", ty.i32(), Deref(p));
 
     Func("main", utils::Empty, ty.void_(),
@@ -276,12 +277,9 @@
     // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
     // let v : vec4<f32> = *vp;
     auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
-    auto* ap = Let("ap", ty.ptr(builtin::AddressSpace::kFunction, ty.array(ty.mat4x4<f32>(), 4_u)),
-                   AddressOf(a));
-    auto* mp = Let("mp", ty.ptr(builtin::AddressSpace::kFunction, ty.mat4x4<f32>()),
-                   AddressOf(IndexAccessor(Deref(ap), 3_i)));
-    auto* vp = Let("vp", ty.ptr(builtin::AddressSpace::kFunction, ty.vec4<f32>()),
-                   AddressOf(IndexAccessor(Deref(mp), 2_i)));
+    auto* ap = Let("ap", ty.ptr<function, array<mat4x4<f32>, 4>>(), AddressOf(a));
+    auto* mp = Let("mp", ty.ptr<function, mat4x4<f32>>(), AddressOf(IndexAccessor(Deref(ap), 3_i)));
+    auto* vp = Let("vp", ty.ptr<function, vec4<f32>>(), AddressOf(IndexAccessor(Deref(mp), 2_i)));
     auto* v = Var("v", ty.vec4<f32>(), Deref(vp));
 
     Func("main", utils::Empty, ty.void_(),
diff --git a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index f50ab58..f53eee2 100644
--- a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -16,11 +16,12 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::hlsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using ::testing::HasSubstr;
 
 using HlslGeneratorImplTest_VariableDecl = TestHelper;
@@ -175,7 +176,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AInt) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* C = Const("C", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -193,7 +194,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_AFloat) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* C = Const("C", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -211,7 +212,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f32) {
-    auto* C = Const("C", vec3<f32>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -231,7 +232,7 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
+    auto* C = Const("C", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -249,7 +250,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
-    auto* C = Const("C", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* C = Const("C", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -267,7 +268,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f32) {
-    auto* C = Const("C", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -287,7 +288,7 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* C = Const("C", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -323,10 +324,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
-    auto* C = Const("C", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                              vec2<bool>(true, false),         //
-                              vec2<bool>(false, true),         //
-                              vec2<bool>(true, true)));
+    auto* C = Const("C", Call<array<vec2<bool>, 3>>(         //
+                             Call<vec2<bool>>(true, false),  //
+                             Call<vec2<bool>>(false, true),  //
+                             Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -370,7 +371,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F32) {
-    auto* var = Var("a", ty.vec3<f32>(), vec3<f32>());
+    auto* var = Var("a", ty.vec3<f32>(), Call<vec3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -385,7 +386,7 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
+    auto* var = Var("a", ty.vec3<f16>(), Call<vec3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -398,7 +399,7 @@
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F32) {
-    auto* var = Var("a", ty.mat2x3<f32>(), mat2x3<f32>());
+    auto* var = Var("a", ty.mat2x3<f32>(), Call<mat2x3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -414,7 +415,7 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
+    auto* var = Var("a", ty.mat2x3<f16>(), Call<mat2x3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 5a38ba2..aae56b1 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -473,7 +474,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("f", vec3<f32>(1.5_f, 2.5_f, 3.5_f))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -505,7 +506,7 @@
 TEST_F(MslGeneratorImplTest, Runtime_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("f", vec3<f16>(1.5_h, 2.5_h, 3.5_h))),  //
+    WrapInFunction(Decl(Let("f", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h))),  //
                    Decl(Let("v", Call("modf", "f"))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -581,7 +582,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Modf_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f32>(1.5_f, 2.5_f, 3.5_f)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f32>>(1.5_f, 2.5_f, 3.5_f)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -605,7 +606,7 @@
 TEST_F(MslGeneratorImplTest, Const_Modf_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("modf", vec3<f16>(1.5_h, 2.5_h, 3.5_h)))));
+    WrapInFunction(Decl(Let("v", Call("modf", Call<vec3<f16>>(1.5_h, 2.5_h, 3.5_h)))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -689,7 +690,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Runtime_Frexp_Vector_f32) {
-    WrapInFunction(Var("f", Expr(vec3<f32>())),  //
+    WrapInFunction(Var("f", Call<vec3<f32>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -721,7 +722,7 @@
 TEST_F(MslGeneratorImplTest, Runtime_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Var("f", Expr(vec3<f16>())),  //
+    WrapInFunction(Var("f", Call<vec3<f16>>()),  //
                    Var("v", Call("frexp", "f")));
 
     GeneratorImpl& gen = SanitizeAndBuild();
@@ -797,7 +798,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Const_Frexp_Vector_f32) {
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f32>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f32>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
@@ -821,7 +822,7 @@
 TEST_F(MslGeneratorImplTest, Const_Frexp_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(Decl(Let("v", Call("frexp", vec3<f16>()))));
+    WrapInFunction(Decl(Let("v", Call("frexp", Call<vec3<f16>>()))));
 
     GeneratorImpl& gen = SanitizeAndBuild();
 
diff --git a/src/tint/writer/msl/generator_impl_cast_test.cc b/src/tint/writer/msl/generator_impl_cast_test.cc
index 78d6c58..77d2119 100644
--- a/src/tint/writer/msl/generator_impl_cast_test.cc
+++ b/src/tint/writer/msl/generator_impl_cast_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -34,7 +35,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Cast_Vector) {
-    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    auto* cast = Call<vec3<f32>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/msl/generator_impl_constructor_test.cc b/src/tint/writer/msl/generator_impl_constructor_test.cc
index b3a333e..22b7d5e 100644
--- a/src/tint/writer/msl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/msl/generator_impl_constructor_test.cc
@@ -15,7 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -121,7 +122,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_F32) {
-    WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec3<f32>>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
 
@@ -132,7 +133,7 @@
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+    WrapInFunction(Call<vec3<f16>>(1_h, 2_h, 3_h));
 
     GeneratorImpl& gen = Build();
 
@@ -141,7 +142,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_Empty_F32) {
-    WrapInFunction(vec3<f32>());
+    WrapInFunction(Call<vec3<f32>>());
 
     GeneratorImpl& gen = Build();
 
@@ -152,7 +153,7 @@
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>());
+    WrapInFunction(Call<vec3<f16>>());
 
     GeneratorImpl& gen = Build();
 
@@ -161,7 +162,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Literal) {
-    WrapInFunction(vec3<f32>(2_f));
+    WrapInFunction(Call<vec3<f32>>(2_f));
 
     GeneratorImpl& gen = Build();
 
@@ -172,7 +173,7 @@
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(2_h));
+    WrapInFunction(Call<vec3<f16>>(2_h));
 
     GeneratorImpl& gen = Build();
 
@@ -182,7 +183,7 @@
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_F32_Var) {
     auto* var = Var("v", Expr(2_f));
-    auto* cast = vec3<f32>(var);
+    auto* cast = Call<vec3<f32>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -196,7 +197,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("v", Expr(2_h));
-    auto* cast = vec3<f16>(var);
+    auto* cast = Call<vec3<f16>>(var);
     WrapInFunction(var, cast);
 
     GeneratorImpl& gen = Build();
@@ -207,7 +208,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Bool) {
-    WrapInFunction(vec3<bool>(true));
+    WrapInFunction(Call<vec3<bool>>(true));
 
     GeneratorImpl& gen = Build();
 
@@ -216,7 +217,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_Int) {
-    WrapInFunction(vec3<i32>(2_i));
+    WrapInFunction(Call<vec3<i32>>(2_i));
 
     GeneratorImpl& gen = Build();
 
@@ -225,7 +226,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Vec_SingleScalar_UInt) {
-    WrapInFunction(vec3<u32>(2_u));
+    WrapInFunction(Call<vec3<u32>>(2_u));
 
     GeneratorImpl& gen = Build();
 
@@ -234,7 +235,8 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_F32) {
-    WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
+    WrapInFunction(
+        Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -247,7 +249,8 @@
 TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+    WrapInFunction(
+        Call<mat2x3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(3_h, 4_h, 5_h)));
 
     GeneratorImpl& gen = Build();
 
@@ -264,15 +267,14 @@
     //     vec4<f32>(7.0f),
     //     vec4<f32>(vec4<f32>(42.0f, 21.0f, 6.0f, -5.0f)),
     //   );
-    auto* vector_literal =
-        vec4<f32>(Expr(f32(2.0)), Expr(f32(3.0)), Expr(f32(4.0)), Expr(f32(8.0)));
-    auto* vector_zero_init = vec4<f32>();
-    auto* vector_single_scalar_init = vec4<f32>(Expr(f32(7.0)));
+    auto* vector_literal = Call<vec4<f32>>(f32(2.0), f32(3.0), f32(4.0), f32(8.0));
+    auto* vector_zero_init = Call<vec4<f32>>();
+    auto* vector_single_scalar_init = Call<vec4<f32>>(f32(7.0));
     auto* vector_identical_init =
-        vec4<f32>(vec4<f32>(Expr(f32(42.0)), Expr(f32(21.0)), Expr(f32(6.0)), Expr(f32(-5.0))));
+        Call<vec4<f32>>(Call<vec4<f32>>(f32(42.0), f32(21.0), f32(6.0), f32(-5.0)));
 
-    auto* constructor = mat4x4<f32>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* constructor = Call<mat4x4<f32>>(vector_literal, vector_zero_init,
+                                          vector_single_scalar_init, vector_identical_init);
 
     WrapInFunction(constructor);
 
@@ -293,15 +295,14 @@
     //   );
     Enable(builtin::Extension::kF16);
 
-    auto* vector_literal =
-        vec4<f16>(Expr(f16(2.0)), Expr(f16(3.0)), Expr(f16(4.0)), Expr(f16(8.0)));
-    auto* vector_zero_init = vec4<f16>();
-    auto* vector_single_scalar_init = vec4<f16>(Expr(f16(7.0)));
+    auto* vector_literal = Call<vec4<f16>>(f16(2.0), f16(3.0), f16(4.0), f16(8.0));
+    auto* vector_zero_init = Call<vec4<f16>>();
+    auto* vector_single_scalar_init = Call<vec4<f16>>(f16(7.0));
     auto* vector_identical_init =
-        vec4<f16>(vec4<f16>(Expr(f16(42.0)), Expr(f16(21.0)), Expr(f16(6.0)), Expr(f16(-5.0))));
+        Call<vec4<f16>>(Call<vec4<f16>>(f16(42.0), f16(21.0), f16(6.0), f16(-5.0)));
 
-    auto* constructor = mat4x4<f16>(vector_literal, vector_zero_init, vector_single_scalar_init,
-                                    vector_identical_init);
+    auto* constructor = Call<mat4x4<f16>>(vector_literal, vector_zero_init,
+                                          vector_single_scalar_init, vector_identical_init);
 
     WrapInFunction(constructor);
 
@@ -314,7 +315,7 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Empty_F32) {
-    WrapInFunction(mat2x3<f32>());
+    WrapInFunction(Call<mat2x3<f32>>());
 
     GeneratorImpl& gen = Build();
 
@@ -327,7 +328,7 @@
 TEST_F(MslGeneratorImplTest_Constructor, Type_Mat_Empty_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>());
+    WrapInFunction(Call<mat2x3<f16>>());
 
     GeneratorImpl& gen = Build();
 
@@ -343,8 +344,8 @@
     //     var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
     // }
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), mat4x4<f32>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), mat4x4<f32>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f32()), Call<mat4x4<f32>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -363,8 +364,8 @@
 
     Enable(builtin::Extension::kF16);
 
-    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), mat4x4<f16>());
-    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), mat4x4<f16>(m_1));
+    auto* m_1 = Var("m_1", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>());
+    auto* m_2 = Var("m_2", ty.mat4x4(ty.f16()), Call<mat4x4<f16>>(m_1));
 
     WrapInFunction(m_1, m_2);
 
@@ -376,8 +377,9 @@
 }
 
 TEST_F(MslGeneratorImplTest_Constructor, Type_Array) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
-                        vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
+    WrapInFunction(Call<array<vec3<f32>, 3>>(Call<vec3<f32>>(1_f, 2_f, 3_f),
+                                             Call<vec3<f32>>(4_f, 5_f, 6_f),
+                                             Call<vec3<f32>>(7_f, 8_f, 9_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -393,7 +395,7 @@
                                    Member("c", ty.vec3<i32>()),
                                });
 
-    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, vec3<i32>(3_i, 4_i, 5_i)));
+    WrapInFunction(Call(ty.Of(str), 1_i, 2_f, Call<vec3<i32>>(3_i, 4_i, 5_i)));
 
     GeneratorImpl& gen = Build();
 
diff --git a/src/tint/writer/msl/generator_impl_function_test.cc b/src/tint/writer/msl/generator_impl_function_test.cc
index b828574..1fbffe2 100644
--- a/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/src/tint/writer/msl/generator_impl_function_test.cc
@@ -16,7 +16,8 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -194,7 +195,7 @@
         });
 
     Func("vert_main", utils::Empty, ty.Of(interface_struct),
-         utils::Vector{Return(Call(ty.Of(interface_struct), 0.5_f, 0.25_f, vec4<f32>()))},
+         utils::Vector{Return(Call(ty.Of(interface_struct), 0.5_f, 0.25_f, Call<vec4<f32>>()))},
          utils::Vector{Stage(ast::PipelineStage::kVertex)});
 
     Func("frag_main", utils::Vector{Param("colors", ty.Of(interface_struct))}, ty.void_(),
@@ -276,8 +277,7 @@
 
     Func("foo", utils::Vector{Param("x", ty.f32())}, ty.Of(vertex_output_struct),
          utils::Vector{
-             Return(
-                 Call(ty.Of(vertex_output_struct), Call(ty.vec4<f32>(), "x", "x", "x", Expr(1_f)))),
+             Return(Call(ty.Of(vertex_output_struct), Call<vec4<f32>>("x", "x", "x", 1_f))),
          });
     Func("vert_main1", utils::Empty, ty.Of(vertex_output_struct),
          utils::Vector{Return(Expr(Call("foo", Expr(0.5_f))))},
diff --git a/src/tint/writer/msl/generator_impl_import_test.cc b/src/tint/writer/msl/generator_impl_import_test.cc
index d221665..bab2b71 100644
--- a/src/tint/writer/msl/generator_impl_import_test.cc
+++ b/src/tint/writer/msl/generator_impl_import_test.cc
@@ -16,7 +16,8 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -134,7 +135,7 @@
 TEST_P(MslImportData_DualParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -196,8 +197,8 @@
 TEST_P(MslImportData_TripleParam_VectorTest, Float) {
     auto param = GetParam();
 
-    auto* expr = Call(param.name, vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f),
-                      vec3<f32>(7_f, 8_f, 9_f));
+    auto* expr = Call(param.name, Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(4_f, 5_f, 6_f),
+                      Call<vec3<f32>>(7_f, 8_f, 9_f));
     WrapInFunction(expr);
 
     GeneratorImpl& gen = Build();
@@ -262,7 +263,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, MslImportData_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec3<f32>>(2_f), builtin::AddressSpace::kPrivate);
 
     auto* expr = Call("quantizeToF16", "v");
     WrapInFunction(expr);
diff --git a/src/tint/writer/msl/generator_impl_module_constant_test.cc b/src/tint/writer/msl/generator_impl_module_constant_test.cc
index 4d977b0..e3b8f86 100644
--- a/src/tint/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/msl/generator_impl_module_constant_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::msl {
 namespace {
@@ -133,7 +134,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AInt) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -151,7 +152,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* var = GlobalConst("G", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -169,7 +170,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f32) {
-    auto* var = GlobalConst("G", vec3<f32>(1_f, 2_f, 3_f));
+    auto* var = GlobalConst("G", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -189,7 +190,7 @@
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", vec3<f16>(1_h, 2_h, 3_h));
+    auto* var = GlobalConst("G", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -207,7 +208,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_AFloat) {
-    auto* var = GlobalConst("G", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* var = GlobalConst("G", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -225,7 +226,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f32) {
-    auto* var = GlobalConst("G", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* var = GlobalConst("G", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -245,7 +246,7 @@
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = GlobalConst("G", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* var = GlobalConst("G", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
@@ -294,10 +295,9 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_GlobalConst_arr_vec2_bool) {
-    auto* var = GlobalConst("G", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                                      vec2<bool>(true, false),         //
-                                      vec2<bool>(false, true),         //
-                                      vec2<bool>(true, true)));
+    auto* var = GlobalConst("G", Call<array<vec2<bool>, 3>>(Call<vec2<bool>>(true, false),  //
+                                                            Call<vec2<bool>>(false, true),  //
+                                                            Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(Let("l", Expr(var)))});
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc
index 52d02ee..05109c0 100644
--- a/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/src/tint/writer/msl/generator_impl_type_test.cc
@@ -26,13 +26,13 @@
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using ::testing::HasSubstr;
-
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::msl {
 namespace {
 
+using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 void FormatMSLField(utils::StringStream& out,
                     const char* addr,
                     const char* type,
@@ -562,7 +562,7 @@
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
     // array: size(64), align(16)
-    auto array = ty.array(ty.vec3<f32>(), 4_u);
+    auto array = ty.array<vec3<f32>, 4>();
 
     auto* s = Structure("S", utils::Vector{
                                  Member("a", ty.i32()),
diff --git a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
index 3660be5..be9fe72 100644
--- a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -16,12 +16,12 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/msl/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::msl {
 namespace {
 
 using ::testing::HasSubstr;
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 using MslGeneratorImplTest = TestHelper;
 
@@ -175,7 +175,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
-    auto* C = Const("C", vec3<Infer>(1_a, 2_a, 3_a));
+    auto* C = Const("C", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -193,7 +193,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
-    auto* C = Const("C", vec3<Infer>(1._a, 2._a, 3._a));
+    auto* C = Const("C", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -211,7 +211,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
-    auto* C = Const("C", vec3<f32>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -231,7 +231,7 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
+    auto* C = Const("C", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -249,7 +249,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
-    auto* C = Const("C", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* C = Const("C", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -267,7 +267,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
-    auto* C = Const("C", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -287,7 +287,7 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* C = Const("C", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -305,7 +305,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
-    auto* C = Const("C", array<f32, 3>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<array<f32, 3>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -336,10 +336,10 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
-    auto* C = Const("C", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                              vec2<bool>(true, false),         //
-                              vec2<bool>(false, true),         //
-                              vec2<bool>(true, true)));
+    auto* C = Const("C", Call<array<vec2<bool>, 3>>(         //
+                             Call<vec2<bool>>(true, false),  //
+                             Call<vec2<bool>>(false, true),  //
+                             Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(), utils::Vector{Decl(C), Decl(Let("l", Expr(C)))});
 
     GeneratorImpl& gen = Build();
@@ -460,7 +460,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec_f32) {
-    auto* var = Var("a", ty.vec3<f32>(), vec3<f32>());
+    auto* var = Var("a", ty.vec3<f32>(), Call<vec3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -475,7 +475,7 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.vec3<f16>(), vec3<f16>());
+    auto* var = Var("a", ty.vec3<f16>(), Call<vec3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -488,7 +488,7 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroMat_f32) {
-    auto* var = Var("a", ty.mat2x3<f32>(), mat2x3<f32>());
+    auto* var = Var("a", ty.mat2x3<f32>(), Call<mat2x3<f32>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
@@ -504,7 +504,7 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroMat_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Var("a", ty.mat2x3<f16>(), mat2x3<f16>());
+    auto* var = Var("a", ty.mat2x3<f16>(), Call<mat2x3<f16>>());
 
     auto* stmt = Decl(var);
     WrapInFunction(stmt);
diff --git a/src/tint/writer/spirv/builder_accessor_expression_test.cc b/src/tint/writer/spirv/builder_accessor_expression_test.cc
index d93b414..e14a79a 100644
--- a/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -26,7 +27,7 @@
     // let ary = vec3<i32>(1, 2, 3);
     // var x = ary[1i];
 
-    auto* ary = Let("ary", vec3<i32>(1_i, 2_i, 3_i));
+    auto* ary = Let("ary", Call<vec3<i32>>(1_i, 2_i, 3_i));
     auto* x = Var("x", IndexAccessor(ary, 1_i));
     WrapInFunction(ary, x);
 
@@ -61,7 +62,7 @@
     // const ary = vec3<i32>(1, 2, 3);
     // var x = ary[1i];
 
-    auto* ary = Const("ary", vec3<i32>(1_i, 2_i, 3_i));
+    auto* ary = Const("ary", Call<vec3<i32>>(1_i, 2_i, 3_i));
     auto* x = Var("x", IndexAccessor(ary, 1_i));
     WrapInFunction(ary, x);
 
@@ -169,7 +170,7 @@
     // let ary : vec3<i32>(1, 2, 3);
     // var x = ary[1i + 1i];
 
-    auto* ary = Let("ary", vec3<i32>(1_i, 2_i, 3_i));
+    auto* ary = Let("ary", Call<vec3<i32>>(1_i, 2_i, 3_i));
     auto* x = Var("x", IndexAccessor(ary, Add(1_i, 1_i)));
     WrapInFunction(ary, x);
 
@@ -286,8 +287,8 @@
     // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
     // var x = ary[1i][2i];
 
-    auto* ary = Let("ary", array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f),
-                                 vec3<f32>(4._f, 5._f, 6._f)));
+    auto* ary = Let("ary", Call<array<vec3<f32>, 2>>(Call<vec3<f32>>(1._f, 2._f, 3._f),
+                                                     Call<vec3<f32>>(4._f, 5._f, 6._f)));
     auto* x = Var("x", IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
     WrapInFunction(ary, x);
 
@@ -334,8 +335,8 @@
     // const ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
     // var x = ary[1i][2i];
 
-    auto* ary = Const("ary", array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f),
-                                   vec3<f32>(4._f, 5._f, 6._f)));
+    auto* ary = Const("ary", Call<array<vec3<f32>, 2>>(Call<vec3<f32>>(1._f, 2._f, 3._f),
+                                                       Call<vec3<f32>>(4._f, 5._f, 6._f)));
     auto* x = Var("x", IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
     WrapInFunction(ary, x);
 
@@ -365,7 +366,7 @@
     // var ary : array<vec3<f32>, 4u>;
     // var x = ary[1i][2i];
 
-    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* ary = Var("ary", ty.array<vec3<f32>, 4>());
     auto* x = Var("x", IndexAccessor(IndexAccessor(ary, 1_i), 2_i));
     WrapInFunction(ary, x);
 
@@ -407,7 +408,7 @@
     // var one = 1i;
     // var x = ary[one][2i];
 
-    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* ary = Var("ary", ty.array<vec3<f32>, 4>());
     auto* one = Var("one", Expr(3_i));
     auto* x = Var("x", IndexAccessor(IndexAccessor(ary, one), 2_i));
     WrapInFunction(ary, one, x);
@@ -453,8 +454,8 @@
     // let ary = array<vec3<f32>, 2u>(vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(4.0f, 5.0f, 6.0f));
     // var x = a[1i].xy;
 
-    auto* ary = Let("ary", array(ty.vec3<f32>(), 2_u, vec3<f32>(1._f, 2._f, 3._f),
-                                 vec3<f32>(4._f, 5._f, 6._f)));
+    auto* ary = Let("ary", Call<array<vec3<f32>, 2>>(Call<vec3<f32>>(1._f, 2._f, 3._f),
+                                                     Call<vec3<f32>>(4._f, 5._f, 6._f)));
     auto* x = Var("x", MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
     WrapInFunction(ary, x);
 
@@ -501,7 +502,7 @@
     // var ary : array<vec3<f32>, 4u>;
     // var x = ary[1i].xy;
 
-    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* ary = Var("ary", ty.array<vec3<f32>, 4>());
     auto* x = Var("x", MemberAccessor(IndexAccessor("ary", 1_i), "xy"));
     WrapInFunction(ary, x);
 
@@ -545,7 +546,7 @@
     // var one = 1i;
     // var x = ary[one].xy;
 
-    auto* ary = Var("ary", ty.array(ty.vec3<f32>(), 4_u));
+    auto* ary = Var("ary", ty.array<vec3<f32>, 4>());
     auto* one = Var("one", Expr(1_i));
     auto* x = Var("x", MemberAccessor(IndexAccessor("ary", one), "xy"));
     WrapInFunction(ary, one, x);
@@ -596,9 +597,10 @@
     //   array<f32, 2>(0.5, -0.5));
     // var x = pos[1u][0u];
 
-    auto* pos = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
-                    Call(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
-                         vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+    auto* pos =
+        Let("pos", ty.array<vec2<f32>, 3>(),
+            Call<array<vec2<f32>, 3>>(Call<vec2<f32>>(0_f, 0.5_f), Call<vec2<f32>>(-0.5_f, -0.5_f),
+                                      Call<vec2<f32>>(0.5_f, -0.5_f)));
     auto* x = Var("x", IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
     WrapInFunction(pos, x);
 
@@ -644,9 +646,10 @@
     //   array<f32, 2>(0.5, -0.5));
     // var x = pos[1u][0u];
 
-    auto* pos = Const("pos", ty.array(ty.vec2<f32>(), 3_u),
-                      Call(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0_f, 0.5_f),
-                           vec2<f32>(-0.5_f, -0.5_f), vec2<f32>(0.5_f, -0.5_f)));
+    auto* pos = Const(
+        "pos", ty.array<vec2<f32>, 3>(),
+        Call<array<vec2<f32>, 3>>(Call<vec2<f32>>(0_f, 0.5_f), Call<vec2<f32>>(-0.5_f, -0.5_f),
+                                  Call<vec2<f32>>(0.5_f, -0.5_f)));
     auto* x = Var("x", IndexAccessor(IndexAccessor(pos, 1_u), 0_u));
     WrapInFunction(pos, x);
 
@@ -676,7 +679,7 @@
     // var pos : array<vec3<f32>, 3u>;
     // var x = pos[1u][2u];
 
-    auto* pos = Var("pos", ty.array(ty.vec3<f32>(), 3_a));
+    auto* pos = Var("pos", ty.array<vec3<f32>, 3>());
     auto* x = Var("x", IndexAccessor(IndexAccessor(pos, 1_u), 2_u));
     WrapInFunction(pos, x);
 
@@ -762,9 +765,10 @@
     // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
     // var x = a[1i]
 
-    auto* a =
-        Let("a", ty.mat2x2<f32>(),
-            Call(ty.mat2x2<f32>(), Call(ty.vec2<f32>(), 1_f, 2_f), Call(ty.vec2<f32>(), 3_f, 4_f)));
+    auto* a = Let("a", ty.mat2x2<f32>(),
+                  Call<mat2x2<f32>>(              //
+                      Call<vec2<f32>>(1_f, 2_f),  //
+                      Call<vec2<f32>>(3_f, 4_f)));
     auto* x = Var("x", IndexAccessor("a", 1_i));
     WrapInFunction(a, x);
 
@@ -805,9 +809,10 @@
     // const a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
     // var x = a[1i]
 
-    auto* a = Const(
-        "a", ty.mat2x2<f32>(),
-        Call(ty.mat2x2<f32>(), Call(ty.vec2<f32>(), 1_f, 2_f), Call(ty.vec2<f32>(), 3_f, 4_f)));
+    auto* a = Const("a", ty.mat2x2<f32>(),
+                    Call<mat2x2<f32>>(              //
+                        Call<vec2<f32>>(1_f, 2_f),  //
+                        Call<vec2<f32>>(3_f, 4_f)));
     auto* x = Var("x", IndexAccessor("a", 1_i));
     WrapInFunction(a, x);
 
diff --git a/src/tint/writer/spirv/builder_assign_test.cc b/src/tint/writer/spirv/builder_assign_test.cc
index e37563a..11ae7940 100644
--- a/src/tint/writer/spirv/builder_assign_test.cc
+++ b/src/tint/writer/spirv/builder_assign_test.cc
@@ -17,7 +17,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -75,7 +76,7 @@
 TEST_F(BuilderTest, Assign_Var_ZeroInitializer) {
     auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* val = vec3<f32>();
+    auto* val = Call<vec3<f32>>();
     auto* assign = Assign("var", val);
 
     WrapInFunction(assign);
@@ -102,7 +103,7 @@
 }
 
 TEST_F(BuilderTest, Assign_Var_Complex_InitializerNestedVector) {
-    auto* init = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
+    auto* init = Call<vec3<f32>>(Call<vec2<f32>>(1_f, 2_f), 3_f);
 
     auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
@@ -135,7 +136,7 @@
 }
 
 TEST_F(BuilderTest, Assign_Var_Complex_Initializer) {
-    auto* init = vec3<f32>(1_f, 2_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 2_f, 3_f);
 
     auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
@@ -214,7 +215,7 @@
 TEST_F(BuilderTest, Assign_Vector) {
     auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* val = vec3<f32>(1_f, 1_f, 3_f);
+    auto* val = Call<vec3<f32>>(1_f, 1_f, 3_f);
     auto* assign = Assign("var", val);
 
     WrapInFunction(assign);
diff --git a/src/tint/writer/spirv/builder_binary_expression_test.cc b/src/tint/writer/spirv/builder_binary_expression_test.cc
index 36bd427..0a4c963 100644
--- a/src/tint/writer/spirv/builder_binary_expression_test.cc
+++ b/src/tint/writer/spirv/builder_binary_expression_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -66,8 +67,8 @@
         return;
     }
 
-    auto* lhs = vec3<i32>(1_i, 1_i, 1_i);
-    auto* rhs = vec3<i32>(1_i, 1_i, 1_i);
+    auto* lhs = Call<vec3<i32>>(1_i, 1_i, 1_i);
+    auto* rhs = Call<vec3<i32>>(1_i, 1_i, 1_i);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -159,8 +160,8 @@
         return;
     }
 
-    auto* lhs = vec3<u32>(1_u, 1_u, 1_u);
-    auto* rhs = vec3<u32>(1_u, 1_u, 1_u);
+    auto* lhs = Call<vec3<u32>>(1_u, 1_u, 1_u);
+    auto* rhs = Call<vec3<u32>>(1_u, 1_u, 1_u);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -220,8 +221,8 @@
 TEST_P(BinaryArithF32Test, Vector) {
     auto param = GetParam();
 
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -279,8 +280,8 @@
 
     auto param = GetParam();
 
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -334,8 +335,8 @@
 TEST_P(BinaryOperatorBoolTest, Vector) {
     auto param = GetParam();
 
-    auto* lhs = vec3<bool>(false, true, false);
-    auto* rhs = vec3<bool>(true, false, true);
+    auto* lhs = Call<vec3<bool>>(false, true, false);
+    auto* rhs = Call<vec3<bool>>(true, false, true);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -391,8 +392,8 @@
 TEST_P(BinaryCompareUnsignedIntegerTest, Vector) {
     auto param = GetParam();
 
-    auto* lhs = vec3<u32>(1_u, 1_u, 1_u);
-    auto* rhs = vec3<u32>(1_u, 1_u, 1_u);
+    auto* lhs = Call<vec3<u32>>(1_u, 1_u, 1_u);
+    auto* rhs = Call<vec3<u32>>(1_u, 1_u, 1_u);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -451,8 +452,8 @@
 TEST_P(BinaryCompareSignedIntegerTest, Vector) {
     auto param = GetParam();
 
-    auto* lhs = vec3<i32>(1_i, 1_i, 1_i);
-    auto* rhs = vec3<i32>(1_i, 1_i, 1_i);
+    auto* lhs = Call<vec3<i32>>(1_i, 1_i, 1_i);
+    auto* rhs = Call<vec3<i32>>(1_i, 1_i, 1_i);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -511,8 +512,8 @@
 TEST_P(BinaryCompareF32Test, Vector) {
     auto param = GetParam();
 
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -575,8 +576,8 @@
 
     auto param = GetParam();
 
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
@@ -608,7 +609,7 @@
                     BinaryData{ast::BinaryOp::kNotEqual, "OpFOrdNotEqual"}));
 
 TEST_F(BuilderTest, Binary_Multiply_VectorScalar_F32) {
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* rhs = Expr(1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -633,7 +634,7 @@
 TEST_F(BuilderTest, Binary_Multiply_VectorScalar_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
     auto* rhs = Expr(1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
@@ -657,7 +658,7 @@
 
 TEST_F(BuilderTest, Binary_Multiply_ScalarVector_F32) {
     auto* lhs = Expr(1_f);
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
@@ -682,7 +683,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* lhs = Expr(1_h);
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
@@ -813,7 +814,7 @@
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixVector_F32) {
     auto* var = Var("mat", ty.mat3x3<f32>());
-    auto* rhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* rhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), rhs);
 
     WrapInFunction(var, expr);
@@ -843,7 +844,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
-    auto* rhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* rhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), rhs);
 
     WrapInFunction(var, expr);
@@ -871,7 +872,7 @@
 
 TEST_F(BuilderTest, Binary_Multiply_VectorMatrix_F32) {
     auto* var = Var("mat", ty.mat3x3<f32>());
-    auto* lhs = vec3<f32>(1_f, 1_f, 1_f);
+    auto* lhs = Call<vec3<f32>>(1_f, 1_f, 1_f);
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, Expr("mat"));
 
     WrapInFunction(var, expr);
@@ -901,7 +902,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Var("mat", ty.mat3x3<f16>());
-    auto* lhs = vec3<f16>(1_h, 1_h, 1_h);
+    auto* lhs = Call<vec3<f16>>(1_h, 1_h, 1_h);
 
     auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, Expr("mat"));
 
@@ -1252,19 +1253,23 @@
     auto name = builder->Symbols().New();
     switch (type) {
         case Type::f32:
-            builder->GlobalVar(name, builder->ty.vec3<f32>(), builder->vec3<f32>(1_f, 1_f, 1_f),
+            builder->GlobalVar(name, builder->ty.vec3<f32>(),
+                               builder->Call<vec3<f32>>(1_f, 1_f, 1_f),
                                builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
-            builder->GlobalVar(name, builder->ty.vec3<f16>(), builder->vec3<f16>(1_h, 1_h, 1_h),
+            builder->GlobalVar(name, builder->ty.vec3<f16>(),
+                               builder->Call<vec3<f16>>(1_h, 1_h, 1_h),
                                builtin::AddressSpace::kPrivate);
             break;
         case Type::i32:
-            builder->GlobalVar(name, builder->ty.vec3<i32>(), builder->vec3<i32>(1_i, 1_i, 1_i),
+            builder->GlobalVar(name, builder->ty.vec3<i32>(),
+                               builder->Call<vec3<i32>>(1_i, 1_i, 1_i),
                                builtin::AddressSpace::kPrivate);
             break;
         case Type::u32:
-            builder->GlobalVar(name, builder->ty.vec3<u32>(), builder->vec3<u32>(1_u, 1_u, 1_u),
+            builder->GlobalVar(name, builder->ty.vec3<u32>(),
+                               builder->Call<vec3<u32>>(1_u, 1_u, 1_u),
                                builtin::AddressSpace::kPrivate);
             break;
     }
@@ -1581,11 +1586,11 @@
     auto name = builder->Symbols().New();
     switch (type) {
         case Type::f32:
-            builder->GlobalVar(name, builder->ty.mat3x4<f32>(), builder->mat3x4<f32>(),
+            builder->GlobalVar(name, builder->ty.mat3x4<f32>(), builder->Call<mat3x4<f32>>(),
                                builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
-            builder->GlobalVar(name, builder->ty.mat3x4<f16>(), builder->mat3x4<f16>(),
+            builder->GlobalVar(name, builder->ty.mat3x4<f16>(), builder->Call<mat3x4<f16>>(),
                                builtin::AddressSpace::kPrivate);
             break;
     }
@@ -1595,11 +1600,11 @@
     auto name = builder->Symbols().New();
     switch (type) {
         case Type::f32:
-            builder->GlobalVar(name, builder->ty.mat4x3<f32>(), builder->mat4x3<f32>(),
+            builder->GlobalVar(name, builder->ty.mat4x3<f32>(), builder->Call<mat4x3<f32>>(),
                                builtin::AddressSpace::kPrivate);
             break;
         case Type::f16:
-            builder->GlobalVar(name, builder->ty.mat4x3<f16>(), builder->mat4x3<f16>(),
+            builder->GlobalVar(name, builder->ty.mat4x3<f16>(), builder->Call<mat4x3<f16>>(),
                                builtin::AddressSpace::kPrivate);
     }
     return builder->Expr(name);
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index ba33a44..a60dfd2 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -20,7 +20,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -47,8 +48,10 @@
     auto* tex = GlobalVar("texture", t, Binding(0_a), Group(0_a));
     auto* sampler = GlobalVar("sampler", s, Binding(1_a), Group(0_a));
 
-    auto* expr1 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
-    auto* expr2 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1_f, 2_f), 2_f);
+    auto* expr1 =
+        Call("textureSampleCompare", "texture", "sampler", Call<vec2<f32>>(1_f, 2_f), 2_f);
+    auto* expr2 =
+        Call("textureSampleCompare", "texture", "sampler", Call<vec2<f32>>(1_f, 2_f), 2_f);
 
     Func("f1", utils::Empty, ty.void_(),
          utils::Vector{
@@ -561,7 +564,7 @@
     auto param = GetParam();
 
     // Use a variable to prevent the function being evaluated as constant.
-    auto* vec = Var("a", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call(param.name, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -605,7 +608,7 @@
     auto param = GetParam();
 
     // Use a variable to prevent the function being evaluated as constant.
-    auto* vec = Var("a", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call(param.name, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -743,7 +746,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Length_Vector_f32) {
-    auto* vec = Var("a", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call("length", vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -782,7 +785,7 @@
 TEST_F(BuiltinBuilderTest, Call_Length_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("a", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call("length", vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -819,7 +822,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Normalize_f32) {
-    auto* vec = Var("a", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("a", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call("normalize", vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -858,7 +861,7 @@
 TEST_F(BuiltinBuilderTest, Call_Normalize_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("a", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("a", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call("normalize", vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -977,7 +980,7 @@
 
 TEST_P(Builtin_Builder_DualParam_Float_Test, Call_Vector_f32) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call(param.name, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1020,7 +1023,7 @@
     Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call(param.name, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1068,7 +1071,7 @@
                                          BuiltinData{"step", "Step"}));
 
 TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f32) {
-    auto* vec = Var("vec", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call("reflect", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1108,7 +1111,7 @@
 TEST_F(BuiltinBuilderTest, Call_Reflect_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call("reflect", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1220,7 +1223,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f32) {
-    auto* vec = Var("vec", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call("distance", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1260,7 +1263,7 @@
 TEST_F(BuiltinBuilderTest, Call_Distance_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call("distance", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1298,7 +1301,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Cross_f32) {
-    auto* vec = Var("vec", vec3<f32>(1_f, 1_f, 1_f));
+    auto* vec = Var("vec", Call<vec3<f32>>(1_f, 1_f, 1_f));
     auto* expr = Call("cross", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1338,7 +1341,7 @@
 TEST_F(BuiltinBuilderTest, Call_Cross_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec3<f16>(1_h, 1_h, 1_h));
+    auto* vec = Var("vec", Call<vec3<f16>>(1_h, 1_h, 1_h));
     auto* expr = Call("cross", vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1460,7 +1463,7 @@
 
 TEST_P(Builtin_Builder_ThreeParam_Float_Test, Call_Vector_f32) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call(param.name, vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1504,7 +1507,7 @@
     Enable(builtin::Extension::kF16);
 
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call(param.name, vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1553,7 +1556,7 @@
                                          BuiltinData{"smoothstep", "SmoothStep"}));
 
 TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f32) {
-    auto* vec = Var("vec", vec2<f32>(1_f, 1_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 1_f));
     auto* expr = Call("faceForward", vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1594,7 +1597,7 @@
 TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec2<f16>(1_h, 1_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 1_h));
     auto* expr = Call("faceForward", vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -1633,7 +1636,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Runtime_Call_Modf_f32) {
-    auto* vec = Var("vec", vec2<f32>(1_f, 2_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f));
     auto* expr = Call("modf", vec);
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -1687,7 +1690,7 @@
 TEST_F(BuiltinBuilderTest, Runtime_Call_Modf_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec2<f16>(1_h, 2_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h));
     auto* expr = Call("modf", vec);
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -1743,7 +1746,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Const_Call_Modf_f32) {
-    auto* expr = Call("modf", vec2<f32>(1_f, 2_f));
+    auto* expr = Call("modf", Call<vec2<f32>>(1_f, 2_f));
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", expr)),
@@ -1789,7 +1792,7 @@
 TEST_F(BuiltinBuilderTest, Const_Call_Modf_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* expr = Call("modf", vec2<f16>(1_h, 2_h));
+    auto* expr = Call("modf", Call<vec2<f16>>(1_h, 2_h));
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(Let("l", expr)),
@@ -1837,7 +1840,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Runtime_Call_Frexp_f32) {
-    auto* vec = Var("vec", vec2<f32>(1_f, 2_f));
+    auto* vec = Var("vec", Call<vec2<f32>>(1_f, 2_f));
     auto* expr = Call("frexp", vec);
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -1893,7 +1896,7 @@
 TEST_F(BuiltinBuilderTest, Runtime_Call_Frexp_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* vec = Var("vec", vec2<f16>(1_h, 2_h));
+    auto* vec = Var("vec", Call<vec2<f16>>(1_h, 2_h));
     auto* expr = Call("frexp", vec);
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -1953,7 +1956,7 @@
 TEST_F(BuiltinBuilderTest, Const_Call_Frexp_f32) {
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Let("l", Call("frexp", vec2<f32>(1_f, 2_f)))),
+             Decl(Let("l", Call("frexp", Call<vec2<f32>>(1_f, 2_f)))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -2001,7 +2004,7 @@
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
-             Decl(Let("l", Call("frexp", vec2<f16>(1_h, 2_h)))),
+             Decl(Let("l", Call("frexp", Call<vec2<f16>>(1_h, 2_h)))),
          },
          utils::Vector{
              Stage(ast::PipelineStage::kFragment),
@@ -2088,7 +2091,7 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_QuantizeToF16_Vector) {
-    GlobalVar("v", vec3<f32>(2_f), builtin::AddressSpace::kPrivate);
+    GlobalVar("v", Call<vec3<f32>>(2_f), builtin::AddressSpace::kPrivate);
 
     Func("a_func", utils::Empty, ty.void_(),
          utils::Vector{
@@ -2320,7 +2323,7 @@
 
 TEST_P(Builtin_Builder_SingleParam_Sint_Test, Call_Vector) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<i32>(1_i, 1_i));
+    auto* vec = Var("vec", Call<vec2<i32>>(1_i, 1_i));
     auto* expr = Call(param.name, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -2397,7 +2400,7 @@
 }
 
 TEST_F(Builtin_Builder_Abs_Uint_Test, Call_Vector) {
-    auto* scalar = Var("scalar", vec2<u32>(1_u, 1_u));
+    auto* scalar = Var("scalar", Call<vec2<u32>>(1_u, 1_u));
     auto* expr = Call("abs", scalar);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -2473,7 +2476,7 @@
 
 TEST_P(Builtin_Builder_DualParam_SInt_Test, Call_Vector) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<i32>(1_i, 1_i));
+    auto* vec = Var("vec", Call<vec2<i32>>(1_i, 1_i));
     auto* expr = Call(param.name, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -2557,7 +2560,7 @@
 
 TEST_P(Builtin_Builder_DualParam_UInt_Test, Call_Vector) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<u32>(1_u, 1_u));
+    auto* vec = Var("vec", Call<vec2<u32>>(1_u, 1_u));
     auto* expr = Call(param.name, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -2642,7 +2645,7 @@
 
 TEST_P(Builtin_Builder_ThreeParam_Sint_Test, Call_Vector) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<i32>(1_i, 1_i));
+    auto* vec = Var("vec", Call<vec2<i32>>(1_i, 1_i));
     auto* expr = Call(param.name, vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -2728,7 +2731,7 @@
 
 TEST_P(Builtin_Builder_ThreeParam_Uint_Test, Call_Vector) {
     auto param = GetParam();
-    auto* vec = Var("vec", vec2<u32>(1_u, 1_u));
+    auto* vec = Var("vec", Call<vec2<u32>>(1_u, 1_u));
     auto* expr = Call(param.name, vec, vec, vec);
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
@@ -3945,7 +3948,8 @@
     auto param = GetParam();
 
     bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
-    auto* call = pack4 ? Call(param.name, vec4<f32>("one")) : Call(param.name, vec2<f32>("one"));
+    auto* call =
+        pack4 ? Call(param.name, Call<vec4<f32>>("one")) : Call(param.name, Call<vec2<f32>>("one"));
     auto* func = Func("a_func", utils::Empty, ty.void_(),
                       utils::Vector{
                           Decl(Let("one", Expr(1_f))),
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index 7416bc2..ea449cb 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -37,7 +38,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type) {
-    auto* t = vec3<f32>(1_f, 1_f, 3_f);
+    auto* t = Call<vec3<f32>>(1_f, 1_f, 3_f);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -54,7 +55,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_WithCasts) {
-    auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(1_i));
+    auto* t = Call<vec2<f32>>(Call<f32>(1_i), Call<f32>(1_i));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -94,7 +95,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_IdentifierExpression_Param) {
     auto* var = Var("ident", ty.f32());
 
-    auto* t = vec2<f32>(1_f, "ident");
+    auto* t = Call<vec2<f32>>(1_f, "ident");
     WrapInFunction(var, t);
 
     spirv::Builder& b = Build();
@@ -122,7 +123,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Vector_Bitcast_Params) {
-    auto* var = Var("v", vec3<f32>(1_f, 2_f, 3_f));
+    auto* var = Var("v", Call<vec3<f32>>(1_f, 2_f, 3_f));
     auto* cast = Bitcast(ty.vec3<u32>(), var);
     WrapInFunction(var, cast);
 
@@ -230,7 +231,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Literal) {
-    auto* cast = vec2<bool>(true);
+    auto* cast = Call<vec2<bool>>(true);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -248,7 +249,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Var) {
     auto* var = Var("v", Expr(true));
-    auto* cast = vec2<bool>(var);
+    auto* cast = Call<vec2<bool>>(var);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -271,7 +272,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Literal) {
-    auto* cast = vec2<f32>(2_f);
+    auto* cast = Call<vec2<f32>>(2_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -290,7 +291,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_Literal) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(2_h);
+    auto* cast = Call<vec2<f16>>(2_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -308,7 +309,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
-    auto* cast = vec2<f32>("x", "x");
+    auto* cast = Call<vec2<f32>>("x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -335,7 +336,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
-    auto* cast = vec2<f16>("x", "x");
+    auto* cast = Call<vec2<f16>>("x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -359,7 +360,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32_Const) {
-    auto* cast = vec2<f32>(1_f, 2_f);
+    auto* cast = Call<vec2<f32>>(1_f, 2_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -379,7 +380,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(1_h, 2_h);
+    auto* cast = Call<vec2<f16>>(1_h, 2_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -397,8 +398,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
-    auto* cast = vec2<f32>("x");
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(1_f, 2_f)));
+    auto* cast = Call<vec2<f32>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -424,8 +425,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
-    auto* cast = vec2<f16>("x");
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(1_h, 2_h)));
+    auto* cast = Call<vec2<f16>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -449,7 +450,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_F32_With_Vec2_Const) {
-    auto* cast = vec2<f32>(vec2<f32>(1_f, 2_f));
+    auto* cast = Call<vec2<f32>>(Call<vec2<f32>>(1_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -469,7 +470,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_F16_With_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(vec2<f16>(1_h, 2_h));
+    auto* cast = Call<vec2<f16>>(Call<vec2<f16>>(1_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -488,7 +489,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
-    auto* cast = vec3<f32>("x", "x", "x");
+    auto* cast = Call<vec3<f32>>("x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -516,7 +517,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
-    auto* cast = vec3<f16>("x", "x", "x");
+    auto* cast = Call<vec3<f16>>("x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -541,7 +542,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Const) {
-    auto* cast = vec3<f32>(1_f, 2_f, 3_f);
+    auto* cast = Call<vec3<f32>>(1_f, 2_f, 3_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -562,7 +563,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+    auto* cast = Call<vec3<f16>>(1_h, 2_h, 3_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -582,7 +583,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
     auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
-    auto* cast = vec3<bool>("x", "x", "x");
+    auto* cast = Call<vec3<bool>>("x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -607,7 +608,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool_Const) {
-    auto* cast = vec3<bool>(true, false, true);
+    auto* cast = Call<vec3<bool>>(true, false, true);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -626,7 +627,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
-    auto* cast = vec3<f32>("x", "x", "x");
+    auto* cast = Call<vec3<f32>>("x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -654,7 +655,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
-    auto* cast = vec3<f16>("x", "x", "x");
+    auto* cast = Call<vec3<f16>>("x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -679,7 +680,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32_Const) {
-    auto* cast = vec3<f32>(1_f, 2_f, 3_f);
+    auto* cast = Call<vec3<f32>>(1_f, 2_f, 3_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -700,7 +701,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(1_h, 2_h, 3_h);
+    auto* cast = Call<vec3<f16>>(1_h, 2_h, 3_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -719,8 +720,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
-    auto* cast = vec3<f32>(1_f, "x");
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(2_f, 3_f)));
+    auto* cast = Call<vec3<f32>>(1_f, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -751,8 +752,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
-    auto* cast = vec3<f16>(1_h, "x");
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(2_h, 3_h)));
+    auto* cast = Call<vec3<f16>>(1_h, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -781,7 +782,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2_Const) {
-    auto* cast = vec3<f32>(1_f, vec2<f32>(2_f, 3_f));
+    auto* cast = Call<vec3<f32>>(1_f, Call<vec2<f32>>(2_f, 3_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -802,7 +803,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F16_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(1_h, vec2<f16>(2_h, 3_h));
+    auto* cast = Call<vec3<f16>>(1_h, Call<vec2<f16>>(2_h, 3_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -821,8 +822,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
-    auto* cast = vec3<f32>("x", 3_f);
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(1_f, 2_f)));
+    auto* cast = Call<vec3<f32>>("x", 3_f);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -853,8 +854,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
-    auto* cast = vec3<f16>("x", 3_h);
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(1_h, 2_h)));
+    auto* cast = Call<vec3<f16>>("x", 3_h);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -883,7 +884,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32_Const) {
-    auto* cast = vec3<f32>(vec2<f32>(1_f, 2_f), 3_f);
+    auto* cast = Call<vec3<f32>>(Call<vec2<f32>>(1_f, 2_f), 3_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -904,7 +905,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec2<f16>(1_h, 2_h), 3_h);
+    auto* cast = Call<vec3<f16>>(Call<vec2<f16>>(1_h, 2_h), 3_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -923,8 +924,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3) {
-    auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(1_f, 2_f, 3_f)));
-    auto* cast = vec3<f32>("x");
+    auto* var = Decl(Var("x", ty.vec3<f32>(), Call<vec3<f32>>(1_f, 2_f, 3_f)));
+    auto* cast = Call<vec3<f32>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -951,8 +952,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(1_h, 2_h, 3_h)));
-    auto* cast = vec3<f16>("x");
+    auto* var = Decl(Var("x", ty.vec3<f16>(), Call<vec3<f16>>(1_h, 2_h, 3_h)));
+    auto* cast = Call<vec3<f16>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -977,7 +978,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_F32_With_Vec3_Const) {
-    auto* cast = vec3<f32>(vec3<f32>(1_f, 2_f, 3_f));
+    auto* cast = Call<vec3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -998,7 +999,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_F16_With_Vec3_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec3<f16>(1_h, 2_h, 3_h));
+    auto* cast = Call<vec3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1018,7 +1019,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
     auto* var = Decl(Var("x", ty.bool_(), Expr(true)));
-    auto* cast = vec4<bool>("x");
+    auto* cast = Call<vec4<bool>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1041,7 +1042,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool_Const) {
-    auto* cast = vec4<bool>(true);
+    auto* cast = Call<vec4<bool>>(true);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1059,7 +1060,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
-    auto* cast = vec4<f32>("x");
+    auto* cast = Call<vec4<f32>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1085,7 +1086,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
-    auto* cast = vec4<f16>("x");
+    auto* cast = Call<vec4<f16>>("x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1108,7 +1109,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Const) {
-    auto* cast = vec4<f32>(2_f);
+    auto* cast = Call<vec4<f32>>(2_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1127,7 +1128,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h);
+    auto* cast = Call<vec4<f16>>(2_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1145,7 +1146,7 @@
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
     auto* var = Decl(Var("x", ty.f32(), Expr(2_f)));
-    auto* cast = vec4<f32>("x", "x", "x", "x");
+    auto* cast = Call<vec4<f32>>("x", "x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1174,7 +1175,7 @@
     Enable(builtin::Extension::kF16);
 
     auto* var = Decl(Var("x", ty.f16(), Expr(2_h)));
-    auto* cast = vec4<f16>("x", "x", "x", "x");
+    auto* cast = Call<vec4<f16>>("x", "x", "x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1200,7 +1201,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32_Const) {
-    auto* cast = vec4<f32>(1_f, 2_f, 3_f, 4_f);
+    auto* cast = Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1222,7 +1223,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(1_h, 2_h, 3_h, 4_h);
+    auto* cast = Call<vec4<f16>>(1_h, 2_h, 3_h, 4_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1242,8 +1243,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
-    auto* cast = vec4<f32>(1_f, 2_f, "x");
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(1_f, 2_f)));
+    auto* cast = Call<vec4<f32>>(1_f, 2_f, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1273,8 +1274,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
-    auto* cast = vec4<f16>(1_h, 2_h, "x");
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(1_h, 2_h)));
+    auto* cast = Call<vec4<f16>>(1_h, 2_h, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1302,7 +1303,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2_Const) {
-    auto* cast = vec4<f32>(1_f, 2_f, vec2<f32>(3_f, 4_f));
+    auto* cast = Call<vec4<f32>>(1_f, 2_f, Call<vec2<f32>>(3_f, 4_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1324,7 +1325,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_F16_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(1_h, 2_h, vec2<f16>(3_h, 4_h));
+    auto* cast = Call<vec4<f16>>(1_h, 2_h, Call<vec2<f16>>(3_h, 4_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1344,8 +1345,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(2_f, 3_f)));
-    auto* cast = vec4<f32>(1_f, "x", 4_f);
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(2_f, 3_f)));
+    auto* cast = Call<vec4<f32>>(1_f, "x", 4_f);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1377,8 +1378,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(2_h, 3_h)));
-    auto* cast = vec4<f16>(1_h, "x", 4_h);
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(2_h, 3_h)));
+    auto* cast = Call<vec4<f16>>(1_h, "x", 4_h);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1408,7 +1409,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32_Const) {
-    auto* cast = vec4<f32>(1_f, vec2<f32>(2_f, 3_f), 4_f);
+    auto* cast = Call<vec4<f32>>(1_f, Call<vec2<f32>>(2_f, 3_f), 4_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1430,7 +1431,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec2_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(1_h, vec2<f16>(2_h, 3_h), 4_h);
+    auto* cast = Call<vec4<f16>>(1_h, Call<vec2<f16>>(2_h, 3_h), 4_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1450,8 +1451,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
-    auto* cast = vec4<f32>("x", 3_f, 4_f);
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(1_f, 2_f)));
+    auto* cast = Call<vec4<f32>>("x", 3_f, 4_f);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1483,8 +1484,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
-    auto* cast = vec4<f16>("x", 3_h, 4_h);
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(1_h, 2_h)));
+    auto* cast = Call<vec4<f16>>("x", 3_h, 4_h);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1514,7 +1515,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32_Const) {
-    auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), 3_f, 4_f);
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(1_f, 2_f), 3_f, 4_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1536,7 +1537,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F16_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), 3_h, 4_h);
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(1_h, 2_h), 3_h, 4_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1556,8 +1557,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2) {
-    auto* var = Decl(Var("x", ty.vec2<f32>(), vec2<f32>(1_f, 2_f)));
-    auto* cast = vec4<f32>("x", "x");
+    auto* var = Decl(Var("x", ty.vec2<f32>(), Call<vec2<f32>>(1_f, 2_f)));
+    auto* cast = Call<vec4<f32>>("x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1590,8 +1591,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec2<f16>(), vec2<f16>(1_h, 2_h)));
-    auto* cast = vec4<f16>("x", "x");
+    auto* var = Decl(Var("x", ty.vec2<f16>(), Call<vec2<f16>>(1_h, 2_h)));
+    auto* cast = Call<vec4<f16>>("x", "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1622,7 +1623,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec2_Vec2_Const) {
-    auto* cast = vec4<f32>(vec2<f32>(1_f, 2_f), vec2<f32>(1_f, 2_f));
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(1_f, 2_f), Call<vec2<f32>>(1_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1642,7 +1643,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec2_Vec2_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(1_h, 2_h), vec2<f16>(1_h, 2_h));
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(1_h, 2_h), Call<vec2<f16>>(1_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1660,8 +1661,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
-    auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
-    auto* cast = vec4<f32>(2_f, "x");
+    auto* var = Decl(Var("x", ty.vec3<f32>(), Call<vec3<f32>>(2_f, 2_f, 2_f)));
+    auto* cast = Call<vec4<f32>>(2_f, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1691,8 +1692,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
-    auto* cast = vec4<f16>(2_h, "x");
+    auto* var = Decl(Var("x", ty.vec3<f16>(), Call<vec3<f16>>(2_h, 2_h, 2_h)));
+    auto* cast = Call<vec4<f16>>(2_h, "x");
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1720,7 +1721,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3_Const) {
-    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(2_f, Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1739,7 +1740,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F16_Vec3_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(2_h, Call<vec3<f16>>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1756,8 +1757,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
-    auto* var = Decl(Var("x", ty.vec3<f32>(), vec3<f32>(2_f, 2_f, 2_f)));
-    auto* cast = vec4<f32>("x", 2_f);
+    auto* var = Decl(Var("x", ty.vec3<f32>(), Call<vec3<f32>>(2_f, 2_f, 2_f)));
+    auto* cast = Call<vec4<f32>>("x", 2_f);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1787,8 +1788,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* var = Decl(Var("x", ty.vec3<f16>(), vec3<f16>(2_h, 2_h, 2_h)));
-    auto* cast = vec4<f16>("x", 2_h);
+    auto* var = Decl(Var("x", ty.vec3<f16>(), Call<vec3<f16>>(2_h, 2_h, 2_h)));
+    auto* cast = Call<vec4<f16>>("x", 2_h);
     WrapInFunction(var, cast);
 
     spirv::Builder& b = Build();
@@ -1816,7 +1817,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32_Const) {
-    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
+    auto* cast = Call<vec4<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), 2_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1835,7 +1836,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F16_Const) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+    auto* cast = Call<vec4<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), 2_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1852,8 +1853,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F32_With_Vec4) {
-    auto* value = vec4<f32>(2_f, 2_f, 2_f, 2_f);
-    auto* cast = vec4<f32>(value);
+    auto* value = Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f);
+    auto* cast = Call<vec4<f32>>(value);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -1872,8 +1873,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* value = vec4<f16>(2_h, 2_h, 2_h, 2_h);
-    auto* cast = vec4<f16>(value);
+    auto* value = Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h);
+    auto* cast = Call<vec4<f16>>(value);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -2050,7 +2051,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F32) {
-    auto* cast = vec2<f32>(2_f);
+    auto* cast = Call<vec2<f32>>(2_f);
     GlobalConst("g", ty.vec2<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2075,7 +2076,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(2_h);
+    auto* cast = Call<vec2<f16>>(2_h);
     GlobalConst("g", ty.vec2<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2098,7 +2099,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F32) {
-    auto* cast = vec2<f32>(2_f);
+    auto* cast = Call<vec2<f32>>(2_f);
     auto* g = GlobalVar("g", ty.vec2<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2116,7 +2117,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(2_h);
+    auto* cast = Call<vec2<f16>>(2_h);
     auto* g = GlobalVar("g", ty.vec2<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2132,7 +2133,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F32_With_Vec2) {
-    auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec2<f32>>(Call<vec2<f32>>(2_f, 2_f));
     GlobalConst("g", ty.vec2<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2157,7 +2158,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec2<f16>>(Call<vec2<f16>>(2_h, 2_h));
     GlobalConst("g", ty.vec2<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2180,7 +2181,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F32_With_Vec2) {
-    auto* cast = vec2<f32>(vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec2<f32>>(Call<vec2<f32>>(2_f, 2_f));
     GlobalVar("a", ty.vec2<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2202,7 +2203,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec2_F16_With_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec2<f16>(vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec2<f16>>(Call<vec2<f16>>(2_h, 2_h));
     GlobalVar("a", ty.vec2<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2222,7 +2223,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F32_With_Vec3) {
-    auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<vec3<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2247,7 +2248,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<vec3<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h));
     GlobalConst("g", ty.vec3<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2270,7 +2271,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F32_With_Vec3) {
-    auto* cast = vec3<f32>(vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<vec3<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f));
     GlobalVar("a", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2292,7 +2293,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_F16_With_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<vec3<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h));
     GlobalVar("a", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2312,7 +2313,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec4) {
-    auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2337,7 +2338,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2360,7 +2361,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec4) {
-    auto* cast = vec4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f));
     GlobalVar("a", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2382,7 +2383,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h));
     GlobalVar("a", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -2402,7 +2403,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32) {
-    auto* cast = vec3<f32>(2_f);
+    auto* cast = Call<vec3<f32>>(2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2427,7 +2428,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(2_h);
+    auto* cast = Call<vec3<f16>>(2_h);
     GlobalConst("g", ty.vec3<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2450,7 +2451,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32) {
-    auto* cast = vec3<f32>(2_f);
+    auto* cast = Call<vec3<f32>>(2_f);
     auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2468,7 +2469,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(2_h);
+    auto* cast = Call<vec3<f16>>(2_h);
     auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2484,7 +2485,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F32_Vec2) {
-    auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec3<f32>>(2_f, Call<vec2<f32>>(2_f, 2_f));
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2509,7 +2510,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec3<f16>>(2_h, Call<vec2<f16>>(2_h, 2_h));
     GlobalConst("g", ty.vec3<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2532,7 +2533,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F32_Vec2) {
-    auto* cast = vec3<f32>(2_f, vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec3<f32>>(2_f, Call<vec2<f32>>(2_f, 2_f));
     auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2550,7 +2551,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(2_h, vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec3<f16>>(2_h, Call<vec2<f16>>(2_h, 2_h));
     auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2566,7 +2567,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F32) {
-    auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
+    auto* cast = Call<vec3<f32>>(Call<vec2<f32>>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec3<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2591,7 +2592,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+    auto* cast = Call<vec3<f16>>(Call<vec2<f16>>(2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec3<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2614,7 +2615,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F32) {
-    auto* cast = vec3<f32>(vec2<f32>(2_f, 2_f), 2_f);
+    auto* cast = Call<vec3<f32>>(Call<vec2<f32>>(2_f, 2_f), 2_f);
     auto* g = GlobalVar("g", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2632,7 +2633,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec3_With_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec2<f16>(2_h, 2_h), 2_h);
+    auto* cast = Call<vec3<f16>>(Call<vec2<f16>>(2_h, 2_h), 2_h);
     auto* g = GlobalVar("g", ty.vec3<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2648,7 +2649,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32) {
-    auto* cast = vec4<f32>(2_f);
+    auto* cast = Call<vec4<f32>>(2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2673,7 +2674,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h);
+    auto* cast = Call<vec4<f16>>(2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2696,7 +2697,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32) {
-    auto* cast = vec4<f32>(2_f);
+    auto* cast = Call<vec4<f32>>(2_f);
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2714,7 +2715,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h);
+    auto* cast = Call<vec4<f16>>(2_h);
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2730,7 +2731,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_F32_Vec2) {
-    auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(2_f, 2_f, Call<vec2<f32>>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2755,7 +2756,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(2_h, 2_h, Call<vec2<f16>>(2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2778,7 +2779,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_F32_Vec2) {
-    auto* cast = vec4<f32>(2_f, 2_f, vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(2_f, 2_f, Call<vec2<f32>>(2_f, 2_f));
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2796,7 +2797,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_F16_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, 2_h, vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(2_h, 2_h, Call<vec2<f16>>(2_h, 2_h));
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2812,7 +2813,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec2_F32) {
-    auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
+    auto* cast = Call<vec4<f32>>(2_f, Call<vec2<f32>>(2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2837,7 +2838,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+    auto* cast = Call<vec4<f16>>(2_h, Call<vec2<f16>>(2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2860,7 +2861,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec2_F32) {
-    auto* cast = vec4<f32>(2_f, vec2<f32>(2_f, 2_f), 2_f);
+    auto* cast = Call<vec4<f32>>(2_f, Call<vec2<f32>>(2_f, 2_f), 2_f);
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2878,7 +2879,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec2_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, vec2<f16>(2_h, 2_h), 2_h);
+    auto* cast = Call<vec4<f16>>(2_h, Call<vec2<f16>>(2_h, 2_h), 2_h);
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2894,7 +2895,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F32_F32) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(2_f, 2_f), 2_f, 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2919,7 +2920,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(2_h, 2_h), 2_h, 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -2942,7 +2943,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F32_F32) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), 2_f, 2_f);
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(2_f, 2_f), 2_f, 2_f);
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2960,7 +2961,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec2_F16_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), 2_h, 2_h);
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(2_h, 2_h), 2_h, 2_h);
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -2976,7 +2977,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F32_With_Vec2_Vec2) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -3001,7 +3002,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h));
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -3024,7 +3025,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F32_With_Vec2_Vec2) {
-    auto* cast = vec4<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f));
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3042,7 +3043,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h));
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3058,7 +3059,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_F32_Vec3) {
-    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(2_f, Call<vec3<f32>>(2_f, 2_f, 2_f));
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -3081,7 +3082,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F32_Vec3) {
-    auto* cast = vec4<f32>(2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<vec4<f32>>(2_f, Call<vec3<f32>>(2_f, 2_f, 2_f));
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3099,7 +3100,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_F16_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(2_h, vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<vec4<f16>>(2_h, Call<vec3<f16>>(2_h, 2_h, 2_h));
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3115,7 +3116,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F32) {
-    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
+    auto* cast = Call<vec4<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), 2_f);
     GlobalConst("g", ty.vec4<f32>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -3140,7 +3141,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalConst_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+    auto* cast = Call<vec4<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), 2_h);
     GlobalConst("g", ty.vec4<f16>(), cast);
     WrapInFunction(Decl(Var("l", Expr("g"))));
 
@@ -3163,7 +3164,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F32) {
-    auto* cast = vec4<f32>(vec3<f32>(2_f, 2_f, 2_f), 2_f);
+    auto* cast = Call<vec4<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), 2_f);
     auto* g = GlobalVar("g", ty.vec4<f32>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3181,7 +3182,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_GlobalVar_Vec4_With_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec4<f16>(vec3<f16>(2_h, 2_h, 2_h), 2_h);
+    auto* cast = Call<vec4<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), 2_h);
     auto* g = GlobalVar("g", ty.vec4<f16>(), builtin::AddressSpace::kPrivate, cast);
 
     spirv::Builder& b = Build();
@@ -3197,7 +3198,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F32_With_Vec2_Vec2) {
-    auto* cast = mat2x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+    auto* cast = Call<mat2x2<f32>>(Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3217,7 +3218,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_F16_With_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat2x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+    auto* cast = Call<mat2x2<f16>>(Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3235,7 +3236,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F32_With_Vec2_Vec2_Vec2) {
-    auto* cast = mat3x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f));
+    auto* cast = Call<mat3x2<f32>>(Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f),
+                                   Call<vec2<f32>>(2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3255,7 +3257,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_F16_With_Vec2_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat3x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h));
+    auto* cast = Call<mat3x2<f16>>(Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h),
+                                   Call<vec2<f16>>(2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3273,8 +3276,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F32_With_Vec2_Vec2_Vec2_Vec2) {
-    auto* cast = mat4x2<f32>(vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f), vec2<f32>(2_f, 2_f),
-                             vec2<f32>(2_f, 2_f));
+    auto* cast = Call<mat4x2<f32>>(Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f),
+                                   Call<vec2<f32>>(2_f, 2_f), Call<vec2<f32>>(2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3294,8 +3297,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_F16_With_Vec2_Vec2_Vec2_Vec2) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat4x2<f16>(vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h), vec2<f16>(2_h, 2_h),
-                             vec2<f16>(2_h, 2_h));
+    auto* cast = Call<mat4x2<f16>>(Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h),
+                                   Call<vec2<f16>>(2_h, 2_h), Call<vec2<f16>>(2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3313,7 +3316,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F32_With_Vec3_Vec3) {
-    auto* cast = mat2x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<mat2x3<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3333,7 +3336,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_F16_With_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat2x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<mat2x3<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), Call<vec3<f16>>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3351,8 +3354,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F32_With_Vec3_Vec3_Vec3) {
-    auto* cast =
-        mat3x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<mat3x3<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), Call<vec3<f32>>(2_f, 2_f, 2_f),
+                                   Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3372,8 +3375,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_F16_With_Vec3_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast =
-        mat3x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<mat3x3<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), Call<vec3<f16>>(2_h, 2_h, 2_h),
+                                   Call<vec3<f16>>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3391,8 +3394,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F32_With_Vec3_Vec3_Vec3_Vec3) {
-    auto* cast = mat4x3<f32>(vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f),
-                             vec3<f32>(2_f, 2_f, 2_f), vec3<f32>(2_f, 2_f, 2_f));
+    auto* cast = Call<mat4x3<f32>>(Call<vec3<f32>>(2_f, 2_f, 2_f), Call<vec3<f32>>(2_f, 2_f, 2_f),
+                                   Call<vec3<f32>>(2_f, 2_f, 2_f), Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3412,8 +3415,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_F16_With_Vec3_Vec3_Vec3_Vec3) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat4x3<f16>(vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h),
-                             vec3<f16>(2_h, 2_h, 2_h), vec3<f16>(2_h, 2_h, 2_h));
+    auto* cast = Call<mat4x3<f16>>(Call<vec3<f16>>(2_h, 2_h, 2_h), Call<vec3<f16>>(2_h, 2_h, 2_h),
+                                   Call<vec3<f16>>(2_h, 2_h, 2_h), Call<vec3<f16>>(2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3431,7 +3434,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F32_With_Vec4_Vec4) {
-    auto* cast = mat2x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    auto* cast =
+        Call<mat2x4<f32>>(Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f), Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3451,7 +3455,8 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_F16_With_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat2x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+    auto* cast =
+        Call<mat2x4<f16>>(Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h), Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3469,8 +3474,9 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F32_With_Vec4_Vec4_Vec4) {
-    auto* cast = mat3x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
-                             vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    auto* cast =
+        Call<mat3x4<f32>>(Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f), Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f),
+                          Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3490,8 +3496,9 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_F16_With_Vec4_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat3x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
-                             vec4<f16>(2_h, 2_h, 2_h, 2_h));
+    auto* cast =
+        Call<mat3x4<f16>>(Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h), Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h),
+                          Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3509,8 +3516,9 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F32_With_Vec4_Vec4_Vec4_Vec4) {
-    auto* cast = mat4x4<f32>(vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f),
-                             vec4<f32>(2_f, 2_f, 2_f, 2_f), vec4<f32>(2_f, 2_f, 2_f, 2_f));
+    auto* cast =
+        Call<mat4x4<f32>>(Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f), Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f),
+                          Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f), Call<vec4<f32>>(2_f, 2_f, 2_f, 2_f));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3530,8 +3538,9 @@
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_F16_With_Vec4_Vec4_Vec4_Vec4) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = mat4x4<f16>(vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h),
-                             vec4<f16>(2_h, 2_h, 2_h, 2_h), vec4<f16>(2_h, 2_h, 2_h, 2_h));
+    auto* cast =
+        Call<mat4x4<f16>>(Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h), Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h),
+                          Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h), Call<vec4<f16>>(2_h, 2_h, 2_h, 2_h));
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3549,7 +3558,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
-    auto* cast = array<f32, 5>(2_f, 2_f, 2_f, 2_f, 2_f);
+    auto* cast = Call<array<f32, 5>>(2_f, 2_f, 2_f, 2_f, 2_f);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3569,7 +3578,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Array_5_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = array<f16, 5>(2_h, 2_h, 2_h, 2_h, 2_h);
+    auto* cast = Call<array<f16, 5>>(2_h, 2_h, 2_h, 2_h, 2_h);
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -3587,9 +3596,9 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F32) {
-    auto* first = vec3<f32>(1_f, 2_f, 3_f);
-    auto* second = vec3<f32>(1_f, 2_f, 3_f);
-    auto* t = Call(ty.array(ty.vec3<f32>(), 2_u), first, second);
+    auto* first = Call<vec3<f32>>(1_f, 2_f, 3_f);
+    auto* second = Call<vec3<f32>>(1_f, 2_f, 3_f);
+    auto* t = Call(ty.array<vec3<f32>, 2>(), first, second);
     WrapInFunction(t);
     spirv::Builder& b = Build();
 
@@ -3611,9 +3620,9 @@
 TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* first = vec3<f16>(1_h, 2_h, 3_h);
-    auto* second = vec3<f16>(1_h, 2_h, 3_h);
-    auto* t = Call(ty.array(ty.vec3<f16>(), 2_u), first, second);
+    auto* first = Call<vec3<f16>>(1_h, 2_h, 3_h);
+    auto* second = Call<vec3<f16>>(1_h, 2_h, 3_h);
+    auto* t = Call(ty.array<vec3<f16>, 2>(), first, second);
     WrapInFunction(t);
     spirv::Builder& b = Build();
 
@@ -3633,8 +3642,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
-    auto* v1 = vec3<f32>(2_f, 2_f, 2_f);
-    auto* v2 = vec3<f32>(2_f, 2_f, 2_f);
+    auto* v1 = Call<vec3<f32>>(2_f, 2_f, 2_f);
+    auto* v2 = Call<vec3<f32>>(2_f, 2_f, 2_f);
     WrapInFunction(WrapInStatement(v1), WrapInStatement(v2));
 
     spirv::Builder& b = Build();
@@ -3651,8 +3660,8 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoArrays) {
-    auto* a1 = array<f32, 3>(2_f, 2_f, 2_f);
-    auto* a2 = array<f32, 3>(2_f, 2_f, 2_f);
+    auto* a1 = Call<array<f32, 3>>(2_f, 2_f, 2_f);
+    auto* a2 = Call<array<f32, 3>>(2_f, 2_f, 2_f);
     WrapInFunction(WrapInStatement(a1), WrapInStatement(a2));
 
     spirv::Builder& b = Build();
@@ -3674,8 +3683,8 @@
     // Test that initializers of different types with the same values produce
     // different OpConstantComposite instructions.
     // crbug.com/tint/777
-    auto* a1 = array<f32, 2>(1_f, 2_f);
-    auto* a2 = vec2<f32>(1_f, 2_f);
+    auto* a1 = Call<array<f32, 2>>(1_f, 2_f);
+    auto* a2 = Call<vec2<f32>>(1_f, 2_f);
     WrapInFunction(WrapInStatement(a1), WrapInStatement(a2));
     spirv::Builder& b = Build();
 
@@ -3701,7 +3710,7 @@
                                          Member("b", ty.vec3<f32>()),
                                      });
 
-    auto* t = Call(ty.Of(s), 2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* t = Call(ty.Of(s), 2_f, Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -3808,7 +3817,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Vector) {
-    auto* t = vec2<i32>();
+    auto* t = Call<vec2<i32>>();
 
     WrapInFunction(t);
 
@@ -3826,7 +3835,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F32) {
-    auto* t = mat4x2<f32>();
+    auto* t = Call<mat4x2<f32>>();
 
     WrapInFunction(t);
 
@@ -3847,7 +3856,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix_F16) {
     Enable(builtin::Extension::kF16);
 
-    auto* t = mat4x2<f16>();
+    auto* t = Call<mat4x2<f16>>();
 
     WrapInFunction(t);
 
@@ -3866,7 +3875,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
-    auto* t = array<i32, 2>();
+    auto* t = Call<array<i32, 2>>();
 
     WrapInFunction(t);
 
@@ -4206,7 +4215,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
     auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<i32>("i");
+    auto* cast = Call<vec3<i32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4232,7 +4241,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) {
     auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<i32>("i");
+    auto* cast = Call<vec3<i32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4260,7 +4269,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<i32>("i");
+    auto* cast = Call<vec3<i32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4286,7 +4295,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
     auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<u32>("i");
+    auto* cast = Call<vec3<u32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4312,7 +4321,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) {
     auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<u32>("i");
+    auto* cast = Call<vec3<u32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4340,7 +4349,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<u32>("i");
+    auto* cast = Call<vec3<u32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4366,7 +4375,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
     auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f32>("i");
+    auto* cast = Call<vec3<f32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4392,7 +4401,7 @@
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
     auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f32>("i");
+    auto* cast = Call<vec3<f32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4420,7 +4429,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<f16>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f32>("i");
+    auto* cast = Call<vec3<f32>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4448,7 +4457,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<i32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f16>("i");
+    auto* cast = Call<vec3<f16>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4476,7 +4485,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<u32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f16>("i");
+    auto* cast = Call<vec3<f16>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4504,7 +4513,7 @@
 
     auto* var = GlobalVar("i", ty.vec3<f32>(), builtin::AddressSpace::kPrivate);
 
-    auto* cast = vec3<f16>("i");
+    auto* cast = Call<vec3<f16>>("i");
     WrapInFunction(cast);
 
     spirv::Builder& b = Build();
@@ -4529,7 +4538,7 @@
 
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithAllConstInitializers) {
     // vec3<f32>(1.0, 2.0, 3.0)  -> true
-    auto* t = vec3<f32>(1_f, 2_f, 3_f);
+    auto* t = Call<vec3<f32>>(1_f, 2_f, 3_f);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4541,8 +4550,8 @@
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalArrayWithAllConstInitializers) {
     // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
     //   -> true
-    auto* t =
-        Call(ty.array(ty.vec3<f32>(), 2_u), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(1_f, 2_f, 3_f));
+    auto* t = Call(ty.array<vec3<f32>, 2>(), Call<vec3<f32>>(1_f, 2_f, 3_f),
+                   Call<vec3<f32>>(1_f, 2_f, 3_f));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4554,7 +4563,7 @@
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithMatchingTypeInitializers) {
     // vec2<f32>(f32(1.0), f32(2.0))  -> false
 
-    auto* t = vec2<f32>(Call<f32>(1_f), Call<f32>(2_f));
+    auto* t = Call<vec2<f32>>(Call<f32>(1_f), Call<f32>(2_f));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4566,7 +4575,7 @@
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalWithTypeConversionInitializer) {
     // vec2<f32>(f32(1), f32(2)) -> false
 
-    auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(2_i));
+    auto* t = Call<vec2<f32>>(Call<f32>(1_i), Call<f32>(2_i));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4578,7 +4587,7 @@
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithAllConstInitializers) {
     // vec3<f32>(1.0, 2.0, 3.0)  -> true
 
-    auto* t = vec3<f32>(1_f, 2_f, 3_f);
+    auto* t = Call<vec3<f32>>(1_f, 2_f, 3_f);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4594,7 +4603,7 @@
     GlobalVar("b", ty.f32(), builtin::AddressSpace::kPrivate);
     GlobalVar("c", ty.f32(), builtin::AddressSpace::kPrivate);
 
-    auto* t = vec3<f32>("a", "b", "c");
+    auto* t = Call<vec3<f32>>("a", "b", "c");
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4607,10 +4616,10 @@
     // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
     //   -> true
 
-    auto* first = vec3<f32>(1_f, 2_f, 3_f);
-    auto* second = vec3<f32>(1_f, 2_f, 3_f);
+    auto* first = Call<vec3<f32>>(1_f, 2_f, 3_f);
+    auto* second = Call<vec3<f32>>(1_f, 2_f, 3_f);
 
-    auto* t = Call(ty.array(ty.vec3<f32>(), 2_u), first, second);
+    auto* t = Call(ty.array<vec3<f32>, 2>(), first, second);
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4622,7 +4631,7 @@
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithTypeConversionConstInitializers) {
     // vec2<f32>(f32(1), f32(2))  -> false
 
-    auto* t = vec2<f32>(Call<f32>(1_i), Call<f32>(2_i));
+    auto* t = Call<vec2<f32>>(Call<f32>(1_i), Call<f32>(2_i));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4632,7 +4641,7 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
-    auto* t = vec2<u32>(Call<u32>(1_i), Call<u32>(1_i));
+    auto* t = Call<vec2<u32>>(Call<u32>(1_i), Call<u32>(1_i));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4647,7 +4656,7 @@
                                          Member("b", ty.vec3<f32>()),
                                      });
 
-    auto* t = Call(ty.Of(s), 2_f, vec3<f32>(2_f, 2_f, 2_f));
+    auto* t = Call(ty.Of(s), 2_f, Call<vec3<f32>>(2_f, 2_f, 2_f));
     WrapInFunction(t);
 
     spirv::Builder& b = Build();
@@ -4680,8 +4689,8 @@
     // }
     // let y = vec3<f32>(1.0, 2.0, 3.0); // Reuses the ID 'x'
 
-    WrapInFunction(If(true, Block(Decl(Let("x", vec3<f32>(1_f, 2_f, 3_f))))),
-                   Decl(Let("y", vec3<f32>(1_f, 2_f, 3_f))));
+    WrapInFunction(If(true, Block(Decl(Let("x", Call<vec3<f32>>(1_f, 2_f, 3_f))))),
+                   Decl(Let("y", Call<vec3<f32>>(1_f, 2_f, 3_f))));
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
@@ -4725,8 +4734,8 @@
     // let y = vec3<f32>(one, 2.0, 3.0); // Mustn't reuse the ID 'x'
 
     WrapInFunction(Decl(Var("one", Expr(1_f))),
-                   If(true, Block(Decl(Let("x", vec3<f32>("one", 2_f, 3_f))))),
-                   Decl(Let("y", vec3<f32>("one", 2_f, 3_f))));
+                   If(true, Block(Decl(Let("x", Call<vec3<f32>>("one", 2_f, 3_f))))),
+                   Decl(Let("y", Call<vec3<f32>>("one", 2_f, 3_f))));
 
     spirv::Builder& b = SanitizeAndBuild();
     ASSERT_TRUE(b.Build());
diff --git a/src/tint/writer/spirv/builder_entry_point_test.cc b/src/tint/writer/spirv/builder_entry_point_test.cc
index 0e057a3..b13eb1d 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -29,7 +29,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -215,7 +216,7 @@
             Member("pos", ty.vec4<f32>(), utils::Vector{Builtin(builtin::BuiltinValue::kPosition)}),
         });
 
-    auto* vert_retval = Call(ty.Of(interface), 42_f, vec4<f32>());
+    auto* vert_retval = Call(ty.Of(interface), 42_f, Call<vec4<f32>>());
     Func("vert_main", utils::Empty, ty.Of(interface), utils::Vector{Return(vert_retval)},
          utils::Vector{
              Stage(ast::PipelineStage::kVertex),
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index c47429b..2bdcc44 100644
--- a/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -19,11 +19,12 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::spirv {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Attribute_Stage) {
@@ -61,7 +62,7 @@
     if (params.stage == ast::PipelineStage::kVertex) {
         ret_type = ty.vec4<f32>();
         ret_type_attrs.Push(Builtin(builtin::BuiltinValue::kPosition));
-        body.Push(Return(Call(ty.vec4<f32>())));
+        body.Push(Return(Call<vec4<f32>>()));
     }
 
     utils::Vector<const ast::Attribute*, 2> deco_list{Stage(params.stage)};
diff --git a/src/tint/writer/spirv/builder_function_variable_test.cc b/src/tint/writer/spirv/builder_function_variable_test.cc
index 9f77d4e..c83def6 100644
--- a/src/tint/writer/spirv/builder_function_variable_test.cc
+++ b/src/tint/writer/spirv/builder_function_variable_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -44,7 +45,7 @@
 }
 
 TEST_F(BuilderTest, FunctionVar_WithConstantInitializer) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 1_f, 3_f);
     auto* v = Var("var", ty.vec3<f32>(), builtin::AddressSpace::kFunction, init);
     WrapInFunction(v);
 
@@ -74,7 +75,7 @@
 
 TEST_F(BuilderTest, FunctionVar_WithNonConstantInitializer) {
     auto* a = Let("a", Expr(3_f));
-    auto* init = vec2<f32>(1_f, Add(Expr("a"), 3_f));
+    auto* init = Call<vec2<f32>>(1_f, Add(Expr("a"), 3_f));
 
     auto* v = Var("var", ty.vec2<f32>(), init);
     WrapInFunction(a, v);
@@ -207,7 +208,7 @@
 }
 
 TEST_F(BuilderTest, FunctionVar_Let) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 1_f, 3_f);
 
     auto* v = Let("var", ty.vec3<f32>(), init);
 
@@ -227,7 +228,7 @@
 }
 
 TEST_F(BuilderTest, FunctionVar_Const) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 1_f, 3_f);
 
     auto* v = Const("var", ty.vec3<f32>(), init);
 
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index 671bacc..b921d07 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -18,7 +18,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -41,7 +42,7 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_WithInitializer) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 1_f, 3_f);
 
     auto* v = GlobalVar("var", ty.vec3<f32>(), builtin::AddressSpace::kPrivate, init);
 
@@ -91,7 +92,7 @@
     // const c = vec3<f32>(1f, 2f, 3f);
     // var v = c;
 
-    auto* c = GlobalConst("c", vec3<f32>(1_f, 2_f, 3_f));
+    auto* c = GlobalConst("c", Call<vec3<f32>>(1_f, 2_f, 3_f));
     GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -121,7 +122,7 @@
     // var v = c;
     Enable(builtin::Extension::kF16);
 
-    auto* c = GlobalConst("c", vec3<f16>(1_h, 2_h, 3_h));
+    auto* c = GlobalConst("c", Call<vec3<f16>>(1_h, 2_h, 3_h));
     GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -150,7 +151,7 @@
     // const c = vec3(1, 2, 3);
     // var v = c;
 
-    auto* c = GlobalConst("c", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* c = GlobalConst("c", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -179,7 +180,7 @@
     // const c = vec3(1.0, 2.0, 3.0);
     // var v = c;
 
-    auto* c = GlobalConst("c", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* c = GlobalConst("c", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
@@ -208,7 +209,7 @@
     // const c = vec3<f32>(vec2<f32>(1f, 2f), 3f));
     // var v = c;
 
-    auto* c = GlobalConst("c", vec3<f32>(vec2<f32>(1_f, 2_f), 3_f));
+    auto* c = GlobalConst("c", Call<vec3<f32>>(Call<vec2<f32>>(1_f, 2_f), 3_f));
     GlobalVar("v", builtin::AddressSpace::kPrivate, Expr(c));
 
     spirv::Builder& b = SanitizeAndBuild();
diff --git a/src/tint/writer/spirv/builder_ident_expression_test.cc b/src/tint/writer/spirv/builder_ident_expression_test.cc
index 5ab7c19..55a24c4 100644
--- a/src/tint/writer/spirv/builder_ident_expression_test.cc
+++ b/src/tint/writer/spirv/builder_ident_expression_test.cc
@@ -16,7 +16,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -28,7 +29,7 @@
         {
             ProgramBuilder pb;
 
-            auto* init = pb.vec3<f32>(1_f, 1_f, 3_f);
+            auto* init = pb.Call<vec3<f32>>(1_f, 1_f, 3_f);
 
             auto* v = pb.GlobalConst("c", pb.ty.vec3<f32>(), init);
 
@@ -66,7 +67,7 @@
 }
 
 TEST_F(BuilderTest, IdentifierExpression_FunctionConst) {
-    auto* init = vec3<f32>(1_f, 1_f, 3_f);
+    auto* init = Call<vec3<f32>>(1_f, 1_f, 3_f);
 
     auto* v = Let("var", ty.vec3<f32>(), init);
 
diff --git a/src/tint/writer/spirv/builder_return_test.cc b/src/tint/writer/spirv/builder_return_test.cc
index 13a65d6..a93a276 100644
--- a/src/tint/writer/spirv/builder_return_test.cc
+++ b/src/tint/writer/spirv/builder_return_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -37,7 +38,7 @@
 }
 
 TEST_F(BuilderTest, Return_WithValue) {
-    auto* val = vec3<f32>(1_f, 1_f, 3_f);
+    auto* val = Call<vec3<f32>>(1_f, 1_f, 3_f);
 
     auto* ret = Return(val);
     Func("test", utils::Empty, ty.vec3<f32>(), utils::Vector{ret}, utils::Empty);
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
index fa5c977..13a526f 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_access_test.cc
@@ -14,17 +14,13 @@
 
 #include "src/tint/writer/spirv/ir/test_helper_ir.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
 
-class SpvGeneratorImplTest_Access : public SpvGeneratorImplTest {
-  protected:
-    const type::Pointer* ptr(const type::Type* elem) {
-        return ty.ptr(builtin::AddressSpace::kFunction, elem, builtin::Access::kReadWrite);
-    }
-};
+using SpvGeneratorImplTest_Access = SpvGeneratorImplTest;
 
 TEST_F(SpvGeneratorImplTest_Access, Array_Value_ConstantIndex) {
     auto* arr_val = b.FunctionParam(ty.array(ty.i32(), 4));
@@ -59,8 +55,8 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* arr_var = sb.Var(ptr(ty.array(ty.i32(), 4)));
-    sb.Access(ptr(ty.i32()), arr_var, 1_u);
+    auto* arr_var = sb.Var(ty.ptr<function, array<i32, 4>>());
+    sb.Access(ty.ptr<function, i32>(), arr_var, 1_u);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -90,10 +86,10 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx_var = sb.Var(ty.ptr<function, i32>());
     auto* idx = sb.Load(idx_var);
-    auto* arr_var = sb.Var(ptr(ty.array(ty.i32(), 4)));
-    sb.Access(ptr(ty.i32()), arr_var, idx);
+    auto* arr_var = sb.Var(ty.ptr<function, array<i32, 4>>());
+    sb.Access(ty.ptr<function, i32>(), arr_var, idx);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -153,9 +149,9 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* mat_var = sb.Var(ptr(ty.mat2x2(ty.f32())));
-    sb.Access(ptr(ty.vec2(ty.f32())), mat_var, 1_u);
-    sb.Access(ptr(ty.f32()), mat_var, 1_u, 0_u);
+    auto* mat_var = sb.Var(ty.ptr<function, mat2x2<f32>>());
+    sb.Access(ty.ptr<function, vec2<f32>>(), mat_var, 1_u);
+    sb.Access(ty.ptr<function, f32>(), mat_var, 1_u, 0_u);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -187,11 +183,11 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx_var = sb.Var(ty.ptr<function, i32>());
     auto* idx = sb.Load(idx_var);
-    auto* mat_var = sb.Var(ptr(ty.mat2x2(ty.f32())));
-    sb.Access(ptr(ty.vec2(ty.f32())), mat_var, idx);
-    sb.Access(ptr(ty.f32()), mat_var, idx, idx);
+    auto* mat_var = sb.Var(ty.ptr<function, mat2x2<f32>>());
+    sb.Access(ty.ptr<function, vec2<f32>>(), mat_var, idx);
+    sb.Access(ty.ptr<function, f32>(), mat_var, idx, idx);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -252,7 +248,7 @@
     func->SetParams({vec_val});
 
     auto sb = b.With(func->StartTarget());
-    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx_var = sb.Var(ty.ptr<function, i32>());
     auto* idx = sb.Load(idx_var);
     sb.Access(ty.i32(), vec_val, idx);
     sb.Return(func);
@@ -281,8 +277,8 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* vec_var = sb.Var(ptr(ty.vec4(ty.i32())));
-    sb.Access(ptr(ty.i32()), vec_var, 1_u);
+    auto* vec_var = sb.Var(ty.ptr<function, vec4<i32>>());
+    sb.Access(ty.ptr<function, i32>(), vec_var, 1_u);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -310,10 +306,10 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx_var = sb.Var(ty.ptr<function, i32>());
     auto* idx = sb.Load(idx_var);
-    auto* vec_var = sb.Var(ptr(ty.vec4(ty.i32())));
-    sb.Access(ptr(ty.i32()), vec_var, idx);
+    auto* vec_var = sb.Var(ty.ptr<function, vec4<i32>>());
+    sb.Access(ty.ptr<function, i32>(), vec_var, idx);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -343,7 +339,7 @@
     func->SetParams({val});
 
     auto sb = b.With(func->StartTarget());
-    auto* idx_var = sb.Var(ptr(ty.i32()));
+    auto* idx_var = sb.Var(ty.ptr<function, i32>());
     auto* idx = sb.Load(idx_var);
     sb.Access(ty.i32(), val, 1_u, 2_u, idx);
     sb.Return(func);
@@ -429,13 +425,12 @@
                                        16u, type::StructMemberAttributes{}),
         },
         16u, 32u, 32u);
-
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* str_var = sb.Var(ptr(str));
-    sb.Access(ptr(ty.i32()), str_var, 1_u);
-    sb.Access(ptr(ty.i32()), str_var, 1_u, 2_u);
+    auto* str_var = sb.Var(ty.ptr(function, str, read_write));
+    sb.Access(ty.ptr<function, i32>(), str_var, 1_u);
+    sb.Access(ty.ptr<function, i32>(), str_var, 1_u, 2_u);
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
index 06ae700..deff321 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
+++ b/src/tint/writer/spirv/ir/generator_impl_ir_var_test.cc
@@ -15,7 +15,8 @@
 #include "src/tint/type/pointer.h"
 #include "src/tint/writer/spirv/ir/test_helper_ir.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::spirv {
 namespace {
@@ -24,7 +25,7 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    sb.Var(ty.ptr<function, i32>());
     sb.Return(func);
 
     ASSERT_TRUE(IRIsValid()) << Error();
@@ -47,8 +48,7 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* v =
-        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = sb.Var(ty.ptr<function, i32>());
     v->SetInitializer(b.Constant(42_i));
 
     sb.Return(func);
@@ -75,8 +75,7 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* v =
-        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = sb.Var(ty.ptr<function, i32>());
     sb.Return(func);
 
     mod.SetName(v, "myvar");
@@ -104,8 +103,7 @@
     auto* i = b.If(true);
 
     auto tb = b.With(i->True());
-    auto* v =
-        tb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = tb.Var(ty.ptr<function, i32>());
     v->SetInitializer(b.Constant(42_i));
     tb.ExitIf(i);
 
@@ -147,8 +145,7 @@
     auto sb = b.With(func->StartTarget());
 
     auto* store_ty = ty.i32();
-    auto* v =
-        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, store_ty, builtin::Access::kReadWrite));
+    auto* v = sb.Var(ty.ptr(function, store_ty));
     sb.Load(v);
     sb.Return(func);
 
@@ -173,8 +170,7 @@
     auto* func = b.Function("foo", ty.void_());
 
     auto sb = b.With(func->StartTarget());
-    auto* v =
-        sb.Var(ty.ptr(builtin::AddressSpace::kFunction, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = sb.Var(ty.ptr<function, i32>());
     sb.Store(v, 42_i);
     sb.Return(func);
 
@@ -197,8 +193,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_NoInit) {
-    b.RootBlock()->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite)));
+    b.RootBlock()->Append(b.Var(ty.ptr<private_, i32>()));
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -219,7 +214,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_WithInit) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<private_, i32>());
     v->SetInitializer(b.Constant(42_i));
     b.RootBlock()->Append(v);
 
@@ -243,7 +238,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, PrivateVar_Name) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<private_, i32>());
     v->SetInitializer(b.Constant(42_i));
     b.RootBlock()->Append(v);
 
@@ -274,7 +269,7 @@
     mod.functions.Push(func);
 
     auto* store_ty = ty.i32();
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kPrivate, store_ty, builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr(private_, store_ty));
     v->SetInitializer(b.Constant(42_i));
     b.RootBlock()->Append(v);
 
@@ -308,8 +303,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar) {
-    b.RootBlock()->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
+    b.RootBlock()->Append(b.Var(ty.ptr<workgroup, i32>()));
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
     EXPECT_EQ(DumpModule(generator_.Module()), R"(OpCapability Shader
@@ -330,8 +324,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar_Name) {
-    auto* v = b.RootBlock()->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
+    auto* v = b.RootBlock()->Append(b.Var(ty.ptr<workgroup, i32>()));
     mod.SetName(v, "myvar");
 
     ASSERT_TRUE(generator_.Generate()) << generator_.Diagnostics().str();
@@ -359,8 +352,7 @@
     mod.functions.Push(func);
 
     auto* store_ty = ty.i32();
-    auto* v = b.RootBlock()->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, store_ty, builtin::Access::kReadWrite)));
+    auto* v = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, store_ty)));
 
     auto sb = b.With(func->StartTarget());
     sb.Load(v);
@@ -391,8 +383,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, WorkgroupVar_ZeroInitializeWithExtension) {
-    b.RootBlock()->Append(
-        b.Var(ty.ptr(builtin::AddressSpace::kWorkgroup, ty.i32(), builtin::Access::kReadWrite)));
+    b.RootBlock()->Append(b.Var(ty.ptr<workgroup, i32>()));
 
     // Create a generator with the zero_init_workgroup_memory flag set to `true`.
     spirv::GeneratorImplIr gen(&mod, true);
@@ -416,7 +407,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, StorageVar) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<storage, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
 
@@ -446,7 +437,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, StorageVar_Name) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<storage, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
     mod.SetName(v, "myvar");
@@ -477,7 +468,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, StorageVar_LoadAndStore) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kStorage, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<storage, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
 
@@ -527,7 +518,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, UniformVar) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<uniform, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
 
@@ -557,7 +548,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, UniformVar_Name) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<uniform, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
     mod.SetName(v, "myvar");
@@ -588,7 +579,7 @@
 }
 
 TEST_F(SpvGeneratorImplTest, UniformVar_Load) {
-    auto* v = b.Var(ty.ptr(builtin::AddressSpace::kUniform, ty.i32(), builtin::Access::kReadWrite));
+    auto* v = b.Var(ty.ptr<uniform, i32>());
     v->SetBindingPoint(0, 0);
     b.RootBlock()->Append(v);
 
diff --git a/src/tint/writer/spirv/scalar_constant.h b/src/tint/writer/spirv/scalar_constant.h
index dd4dfd0..7d79dab 100644
--- a/src/tint/writer/spirv/scalar_constant.h
+++ b/src/tint/writer/spirv/scalar_constant.h
@@ -20,7 +20,7 @@
 #include <cstring>
 #include <functional>
 
-#include "src/tint/number.h"
+#include "src/tint/builtin/number.h"
 #include "src/tint/utils/hash.h"
 
 // Forward declarations
diff --git a/src/tint/writer/wgsl/generator_impl_cast_test.cc b/src/tint/writer/wgsl/generator_impl_cast_test.cc
index 890c52c..27c4546 100644
--- a/src/tint/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_cast_test.cc
@@ -17,7 +17,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::wgsl {
 namespace {
@@ -51,7 +52,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F32_From_I32) {
-    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    auto* cast = Call<vec3<f32>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
 
     GeneratorImpl& gen = Build();
@@ -65,7 +66,7 @@
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector_F16_From_I32) {
     Enable(builtin::Extension::kF16);
 
-    auto* cast = vec3<f16>(vec3<i32>(1_i, 2_i, 3_i));
+    auto* cast = Call<vec3<f16>>(Call<vec3<i32>>(1_i, 2_i, 3_i));
     WrapInFunction(cast);
 
     GeneratorImpl& gen = Build();
diff --git a/src/tint/writer/wgsl/generator_impl_constructor_test.cc b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
index fa40ff6..e360be2 100644
--- a/src/tint/writer/wgsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
@@ -18,11 +18,12 @@
 
 using ::testing::HasSubstr;
 
-using namespace tint::number_suffixes;  // NOLINT
-
 namespace tint::writer::wgsl {
 namespace {
 
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
+
 using WgslGeneratorImplTest_Constructor = TestHelper;
 
 TEST_F(WgslGeneratorImplTest_Constructor, Bool) {
@@ -129,7 +130,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest_Constructor, Type_Vec_F32) {
-    WrapInFunction(vec3<f32>(1_f, 2_f, 3_f));
+    WrapInFunction(Call<vec3<f32>>(1_f, 2_f, 3_f));
 
     GeneratorImpl& gen = Build();
 
@@ -141,7 +142,7 @@
 TEST_F(WgslGeneratorImplTest_Constructor, Type_Vec_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(vec3<f16>(1_h, 2_h, 3_h));
+    WrapInFunction(Call<vec3<f16>>(1_h, 2_h, 3_h));
 
     GeneratorImpl& gen = Build();
 
@@ -151,7 +152,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest_Constructor, Type_Mat_F32) {
-    WrapInFunction(mat2x3<f32>(vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(3_f, 4_f, 5_f)));
+    WrapInFunction(
+        Call<mat2x3<f32>>(Call<vec3<f32>>(1_f, 2_f, 3_f), Call<vec3<f32>>(3_f, 4_f, 5_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -164,7 +166,8 @@
 TEST_F(WgslGeneratorImplTest_Constructor, Type_Mat_F16) {
     Enable(builtin::Extension::kF16);
 
-    WrapInFunction(mat2x3<f16>(vec3<f16>(1_h, 2_h, 3_h), vec3<f16>(3_h, 4_h, 5_h)));
+    WrapInFunction(
+        Call<mat2x3<f16>>(Call<vec3<f16>>(1_h, 2_h, 3_h), Call<vec3<f16>>(3_h, 4_h, 5_h)));
 
     GeneratorImpl& gen = Build();
 
@@ -175,8 +178,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest_Constructor, Type_Array) {
-    WrapInFunction(Call(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1_f, 2_f, 3_f),
-                        vec3<f32>(4_f, 5_f, 6_f), vec3<f32>(7_f, 8_f, 9_f)));
+    WrapInFunction(Call(ty.array<vec3<f32>, 3>(), Call<vec3<f32>>(1_f, 2_f, 3_f),
+                        Call<vec3<f32>>(4_f, 5_f, 6_f), Call<vec3<f32>>(7_f, 8_f, 9_f)));
 
     GeneratorImpl& gen = Build();
 
@@ -188,8 +191,8 @@
 }
 
 TEST_F(WgslGeneratorImplTest_Constructor, Type_ImplicitArray) {
-    WrapInFunction(Call(ty.array<Infer>(), vec3<f32>(1_f, 2_f, 3_f), vec3<f32>(4_f, 5_f, 6_f),
-                        vec3<f32>(7_f, 8_f, 9_f)));
+    WrapInFunction(Call(ty.array<Infer>(), Call<vec3<f32>>(1_f, 2_f, 3_f),
+                        Call<vec3<f32>>(4_f, 5_f, 6_f), Call<vec3<f32>>(7_f, 8_f, 9_f)));
 
     GeneratorImpl& gen = Build();
 
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index cb790cb..835f353 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -22,7 +22,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::wgsl {
 namespace {
@@ -146,7 +147,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
-    auto type = Alias("make_type_reachable", ty.ptr<f32>(builtin::AddressSpace::kWorkgroup))->type;
+    auto type = Alias("make_type_reachable", ty.ptr<workgroup, f32>())->type;
 
     GeneratorImpl& gen = Build();
 
@@ -157,9 +158,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_PointerAccessMode) {
-    auto type = Alias("make_type_reachable",
-                      ty.ptr<f32>(builtin::AddressSpace::kStorage, builtin::Access::kReadWrite))
-                    ->type;
+    auto type = Alias("make_type_reachable", ty.ptr<storage, f32, read_write>())->type;
 
     GeneratorImpl& gen = Build();
 
diff --git a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index 59d761e..78a4e3c 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -17,7 +17,8 @@
 
 #include "gmock/gmock.h"
 
-using namespace tint::number_suffixes;  // NOLINT
+using namespace tint::builtin::fluent_types;  // NOLINT
+using namespace tint::number_suffixes;        // NOLINT
 
 namespace tint::writer::wgsl {
 namespace {
@@ -167,7 +168,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AInt) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1_a, 2_a, 3_a));
+    auto* C = Const("C", Call<vec3<Infer>>(1_a, 2_a, 3_a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -185,7 +186,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_AFloat) {
-    auto* C = Const("C", Call(ty.vec3<Infer>(), 1._a, 2._a, 3._a));
+    auto* C = Const("C", Call<vec3<Infer>>(1._a, 2._a, 3._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -203,7 +204,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f32) {
-    auto* C = Const("C", vec3<f32>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<vec3<f32>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -223,7 +224,7 @@
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_vec3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", vec3<f16>(1_h, 2_h, 3_h));
+    auto* C = Const("C", Call<vec3<f16>>(1_h, 2_h, 3_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -243,7 +244,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_AFloat) {
-    auto* C = Const("C", Call(ty.mat2x3<Infer>(), 1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
+    auto* C = Const("C", Call<mat2x3<Infer>>(1._a, 2._a, 3._a, 4._a, 5._a, 6._a));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -261,7 +262,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f32) {
-    auto* C = Const("C", mat2x3<f32>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
+    auto* C = Const("C", Call<mat2x3<f32>>(1_f, 2_f, 3_f, 4_f, 5_f, 6_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -281,7 +282,7 @@
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_mat2x3_f16) {
     Enable(builtin::Extension::kF16);
 
-    auto* C = Const("C", mat2x3<f16>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
+    auto* C = Const("C", Call<mat2x3<f16>>(1_h, 2_h, 3_h, 4_h, 5_h, 6_h));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -301,7 +302,7 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_f32) {
-    auto* C = Const("C", array<f32, 3>(1_f, 2_f, 3_f));
+    auto* C = Const("C", Call<array<f32, 3>>(1_f, 2_f, 3_f));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),
@@ -319,10 +320,10 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Const_arr_vec2_bool) {
-    auto* C = Const("C", Call(ty.array(ty.vec2<bool>(), 3_u),  //
-                              vec2<bool>(true, false),         //
-                              vec2<bool>(false, true),         //
-                              vec2<bool>(true, true)));
+    auto* C = Const("C", Call<array<vec2<bool>, 3>>(         //
+                             Call<vec2<bool>>(true, false),  //
+                             Call<vec2<bool>>(false, true),  //
+                             Call<vec2<bool>>(true, true)));
     Func("f", utils::Empty, ty.void_(),
          utils::Vector{
              Decl(C),