Replace SkSL::Type constructors with named factory functions.

This makes it much easier to understand what sorts of types we are
creating.

This has some minor repercussions for the SPIR-V code generator, which
actually created temporary Types on the stack occasionally, but these
were simple to fix.

Change-Id: I1ca43cdef0445d2b9789a435221dce50b03d954a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/343517
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index fabad1a..7141372 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -21,173 +21,266 @@
 class Context {
 public:
     Context()
-    : fInvalid_Type(new Type("<INVALID>"))
-    , fVoid_Type(new Type("void"))
-    , fNull_Type(new Type("null"))
-    , fFloatLiteral_Type(new Type("$floatLiteral", Type::NumberKind::kFloat, 3))
-    , fIntLiteral_Type(new Type("$intLiteral", Type::NumberKind::kSigned, 1))
-    , fFloat_Type(new Type("float", Type::NumberKind::kFloat, 5, true))
-    , fFloat2_Type(new Type("float2", *fFloat_Type, 2))
-    , fFloat3_Type(new Type("float3", *fFloat_Type, 3))
-    , fFloat4_Type(new Type("float4", *fFloat_Type, 4))
-    , fHalf_Type(new Type("half", Type::NumberKind::kFloat, 4))
-    , fHalf2_Type(new Type("half2", *fHalf_Type, 2))
-    , fHalf3_Type(new Type("half3", *fHalf_Type, 3))
-    , fHalf4_Type(new Type("half4", *fHalf_Type, 4))
-    , fUInt_Type(new Type("uint", Type::NumberKind::kUnsigned, 2, true))
-    , fUInt2_Type(new Type("uint2", *fUInt_Type, 2))
-    , fUInt3_Type(new Type("uint3", *fUInt_Type, 3))
-    , fUInt4_Type(new Type("uint4", *fUInt_Type, 4))
-    , fInt_Type(new Type("int", Type::NumberKind::kSigned, 2, true))
-    , fInt2_Type(new Type("int2", *fInt_Type, 2))
-    , fInt3_Type(new Type("int3", *fInt_Type, 3))
-    , fInt4_Type(new Type("int4", *fInt_Type, 4))
-    , fUShort_Type(new Type("ushort", Type::NumberKind::kUnsigned, 0))
-    , fUShort2_Type(new Type("ushort2", *fUShort_Type, 2))
-    , fUShort3_Type(new Type("ushort3", *fUShort_Type, 3))
-    , fUShort4_Type(new Type("ushort4", *fUShort_Type, 4))
-    , fShort_Type(new Type("short", Type::NumberKind::kSigned, 0))
-    , fShort2_Type(new Type("short2", *fShort_Type, 2))
-    , fShort3_Type(new Type("short3", *fShort_Type, 3))
-    , fShort4_Type(new Type("short4", *fShort_Type, 4))
-    , fUByte_Type(new Type("ubyte", Type::NumberKind::kUnsigned, 0))
-    , fUByte2_Type(new Type("ubyte2", *fUByte_Type, 2))
-    , fUByte3_Type(new Type("ubyte3", *fUByte_Type, 3))
-    , fUByte4_Type(new Type("ubyte4", *fUByte_Type, 4))
-    , fByte_Type(new Type("byte", Type::NumberKind::kSigned, 0))
-    , fByte2_Type(new Type("byte2", *fByte_Type, 2))
-    , fByte3_Type(new Type("byte3", *fByte_Type, 3))
-    , fByte4_Type(new Type("byte4", *fByte_Type, 4))
-    , fBool_Type(new Type("bool", Type::NumberKind::kBoolean, -1))
-    , fBool2_Type(new Type("bool2", *fBool_Type, 2))
-    , fBool3_Type(new Type("bool3", *fBool_Type, 3))
-    , fBool4_Type(new Type("bool4", *fBool_Type, 4))
-    , fFloat2x2_Type(new Type("float2x2", *fFloat_Type, 2, 2))
-    , fFloat2x3_Type(new Type("float2x3", *fFloat_Type, 2, 3))
-    , fFloat2x4_Type(new Type("float2x4", *fFloat_Type, 2, 4))
-    , fFloat3x2_Type(new Type("float3x2", *fFloat_Type, 3, 2))
-    , fFloat3x3_Type(new Type("float3x3", *fFloat_Type, 3, 3))
-    , fFloat3x4_Type(new Type("float3x4", *fFloat_Type, 3, 4))
-    , fFloat4x2_Type(new Type("float4x2", *fFloat_Type, 4, 2))
-    , fFloat4x3_Type(new Type("float4x3", *fFloat_Type, 4, 3))
-    , fFloat4x4_Type(new Type("float4x4", *fFloat_Type, 4, 4))
-    , fHalf2x2_Type(new Type("half2x2", *fHalf_Type, 2, 2))
-    , fHalf2x3_Type(new Type("half2x3", *fHalf_Type, 2, 3))
-    , fHalf2x4_Type(new Type("half2x4", *fHalf_Type, 2, 4))
-    , fHalf3x2_Type(new Type("half3x2", *fHalf_Type, 3, 2))
-    , fHalf3x3_Type(new Type("half3x3", *fHalf_Type, 3, 3))
-    , fHalf3x4_Type(new Type("half3x4", *fHalf_Type, 3, 4))
-    , fHalf4x2_Type(new Type("half4x2", *fHalf_Type, 4, 2))
-    , fHalf4x3_Type(new Type("half4x3", *fHalf_Type, 4, 3))
-    , fHalf4x4_Type(new Type("half4x4", *fHalf_Type, 4, 4))
-    , fTexture1D_Type(new Type("texture1D", SpvDim1D, false, false, false, true))
-    , fTexture2D_Type(new Type("texture2D", SpvDim2D, false, false, false, true))
-    , fTexture3D_Type(new Type("texture3D", SpvDim3D, false, false, false, true))
-    , fTextureExternalOES_Type(new Type("textureExternalOES", SpvDim2D, false, false, false, true))
-    , fTextureCube_Type(new Type("textureCube", SpvDimCube, false, false, false, true))
-    , fTexture2DRect_Type(new Type("texture2DRect", SpvDimRect, false, false, false, true))
-    , fTextureBuffer_Type(new Type("textureBuffer", SpvDimBuffer, false, false, false, true))
-    , fITexture2D_Type(new Type("itexture2D", SpvDim2D, false, false, false, true))
-    , fSampler1D_Type(new Type("sampler1D", *fTexture1D_Type))
-    , fSampler2D_Type(new Type("sampler2D", *fTexture2D_Type))
-    , fSampler3D_Type(new Type("sampler3D", *fTexture3D_Type))
-    , fSamplerExternalOES_Type(new Type("samplerExternalOES", *fTextureExternalOES_Type))
-    , fSamplerCube_Type(new Type("samplerCube", *fTextureCube_Type))
-    , fSampler2DRect_Type(new Type("sampler2DRect", *fTexture2DRect_Type))
-    , fSampler1DArray_Type(new Type("sampler1DArray"))
-    , fSampler2DArray_Type(new Type("sampler2DArray"))
-    , fSamplerCubeArray_Type(new Type("samplerCubeArray"))
-    , fSamplerBuffer_Type(new Type("samplerBuffer", *fTextureBuffer_Type))
-    , fSampler2DMS_Type(new Type("sampler2DMS"))
-    , fSampler2DMSArray_Type(new Type("sampler2DMSArray"))
-    , fSampler1DShadow_Type(new Type("sampler1DShadow"))
-    , fSampler2DShadow_Type(new Type("sampler2DShadow"))
-    , fSamplerCubeShadow_Type(new Type("samplerCubeShadow"))
-    , fSampler2DRectShadow_Type(new Type("sampler2DRectShadow"))
-    , fSampler1DArrayShadow_Type(new Type("sampler1DArrayShadow"))
-    , fSampler2DArrayShadow_Type(new Type("sampler2DArrayShadow"))
-    , fSamplerCubeArrayShadow_Type(new Type("samplerCubeArrayShadow"))
+            : fInvalid_Type(Type::MakeOtherType("<INVALID>"))
+            , fVoid_Type(Type::MakeOtherType("void"))
+            , fNull_Type(Type::MakeOtherType("null"))
+            , fFloatLiteral_Type(Type::MakeScalarType(
+                      "$floatLiteral", Type::NumberKind::kFloat, /*priority=*/3))
+            , fIntLiteral_Type(Type::MakeScalarType(
+                      "$intLiteral", Type::NumberKind::kSigned, /*priority=*/1))
+            , fFloat_Type(Type::MakeScalarType(
+                      "float", Type::NumberKind::kFloat, /*priority=*/5, /*highPrecision=*/true))
+            , fFloat2_Type(Type::MakeVectorType("float2", *fFloat_Type, /*columns=*/2))
+            , fFloat3_Type(Type::MakeVectorType("float3", *fFloat_Type, /*columns=*/3))
+            , fFloat4_Type(Type::MakeVectorType("float4", *fFloat_Type, /*columns=*/4))
+            , fHalf_Type(Type::MakeScalarType("half", Type::NumberKind::kFloat, /*priority=*/4))
+            , fHalf2_Type(Type::MakeVectorType("half2", *fHalf_Type, /*columns=*/2))
+            , fHalf3_Type(Type::MakeVectorType("half3", *fHalf_Type, /*columns=*/3))
+            , fHalf4_Type(Type::MakeVectorType("half4", *fHalf_Type, /*columns=*/4))
+            , fUInt_Type(Type::MakeScalarType(
+                      "uint", Type::NumberKind::kUnsigned, /*priority=*/2, /*highPrecision=*/true))
+            , fUInt2_Type(Type::MakeVectorType("uint2", *fUInt_Type, /*columns=*/2))
+            , fUInt3_Type(Type::MakeVectorType("uint3", *fUInt_Type, /*columns=*/3))
+            , fUInt4_Type(Type::MakeVectorType("uint4", *fUInt_Type, /*columns=*/4))
+            , fInt_Type(Type::MakeScalarType(
+                      "int", Type::NumberKind::kSigned, /*priority=*/2, /*highPrecision=*/true))
+            , fInt2_Type(Type::MakeVectorType("int2", *fInt_Type, /*columns=*/2))
+            , fInt3_Type(Type::MakeVectorType("int3", *fInt_Type, /*columns=*/3))
+            , fInt4_Type(Type::MakeVectorType("int4", *fInt_Type, /*columns=*/4))
+            , fUShort_Type(
+                      Type::MakeScalarType("ushort", Type::NumberKind::kUnsigned, /*priority=*/0))
+            , fUShort2_Type(Type::MakeVectorType("ushort2", *fUShort_Type, /*columns=*/2))
+            , fUShort3_Type(Type::MakeVectorType("ushort3", *fUShort_Type, /*columns=*/3))
+            , fUShort4_Type(Type::MakeVectorType("ushort4", *fUShort_Type, /*columns=*/4))
+            , fShort_Type(Type::MakeScalarType("short", Type::NumberKind::kSigned, /*priority=*/0))
+            , fShort2_Type(Type::MakeVectorType("short2", *fShort_Type, /*columns=*/2))
+            , fShort3_Type(Type::MakeVectorType("short3", *fShort_Type, /*columns=*/3))
+            , fShort4_Type(Type::MakeVectorType("short4", *fShort_Type, /*columns=*/4))
+            , fUByte_Type(
+                      Type::MakeScalarType("ubyte", Type::NumberKind::kUnsigned, /*priority=*/0))
+            , fUByte2_Type(Type::MakeVectorType("ubyte2", *fUByte_Type, /*columns=*/2))
+            , fUByte3_Type(Type::MakeVectorType("ubyte3", *fUByte_Type, /*columns=*/3))
+            , fUByte4_Type(Type::MakeVectorType("ubyte4", *fUByte_Type, /*columns=*/4))
+            , fByte_Type(Type::MakeScalarType("byte", Type::NumberKind::kSigned, /*priority=*/0))
+            , fByte2_Type(Type::MakeVectorType("byte2", *fByte_Type, /*columns=*/2))
+            , fByte3_Type(Type::MakeVectorType("byte3", *fByte_Type, /*columns=*/3))
+            , fByte4_Type(Type::MakeVectorType("byte4", *fByte_Type, /*columns=*/4))
+            , fBool_Type(Type::MakeScalarType("bool", Type::NumberKind::kBoolean, /*priority=*/-1))
+            , fBool2_Type(Type::MakeVectorType("bool2", *fBool_Type, /*columns=*/2))
+            , fBool3_Type(Type::MakeVectorType("bool3", *fBool_Type, /*columns=*/3))
+            , fBool4_Type(Type::MakeVectorType("bool4", *fBool_Type, /*columns=*/4))
+            , fFloat2x2_Type(
+                      Type::MakeMatrixType("float2x2", *fFloat_Type, /*columns=*/2, /*rows=*/2))
+            , fFloat2x3_Type(
+                      Type::MakeMatrixType("float2x3", *fFloat_Type, /*columns=*/2, /*rows=*/3))
+            , fFloat2x4_Type(
+                      Type::MakeMatrixType("float2x4", *fFloat_Type, /*columns=*/2, /*rows=*/4))
+            , fFloat3x2_Type(
+                      Type::MakeMatrixType("float3x2", *fFloat_Type, /*columns=*/3, /*rows=*/2))
+            , fFloat3x3_Type(
+                      Type::MakeMatrixType("float3x3", *fFloat_Type, /*columns=*/3, /*rows=*/3))
+            , fFloat3x4_Type(
+                      Type::MakeMatrixType("float3x4", *fFloat_Type, /*columns=*/3, /*rows=*/4))
+            , fFloat4x2_Type(
+                      Type::MakeMatrixType("float4x2", *fFloat_Type, /*columns=*/4, /*rows=*/2))
+            , fFloat4x3_Type(
+                      Type::MakeMatrixType("float4x3", *fFloat_Type, /*columns=*/4, /*rows=*/3))
+            , fFloat4x4_Type(
+                      Type::MakeMatrixType("float4x4", *fFloat_Type, /*columns=*/4, /*rows=*/4))
+            , fHalf2x2_Type(Type::MakeMatrixType("half2x2", *fHalf_Type, /*columns=*/2, /*rows=*/2))
+            , fHalf2x3_Type(Type::MakeMatrixType("half2x3", *fHalf_Type, /*columns=*/2, /*rows=*/3))
+            , fHalf2x4_Type(Type::MakeMatrixType("half2x4", *fHalf_Type, /*columns=*/2, /*rows=*/4))
+            , fHalf3x2_Type(Type::MakeMatrixType("half3x2", *fHalf_Type, /*columns=*/3, /*rows=*/2))
+            , fHalf3x3_Type(Type::MakeMatrixType("half3x3", *fHalf_Type, /*columns=*/3, /*rows=*/3))
+            , fHalf3x4_Type(Type::MakeMatrixType("half3x4", *fHalf_Type, /*columns=*/3, /*rows=*/4))
+            , fHalf4x2_Type(Type::MakeMatrixType("half4x2", *fHalf_Type, /*columns=*/4, /*rows=*/2))
+            , fHalf4x3_Type(Type::MakeMatrixType("half4x3", *fHalf_Type, /*columns=*/4, /*rows=*/3))
+            , fHalf4x4_Type(Type::MakeMatrixType("half4x4", *fHalf_Type, /*columns=*/4, /*rows=*/4))
+            , fTexture1D_Type(Type::MakeTextureType("texture1D",
+                                                    SpvDim1D,
+                                                    /*isDepth=*/false,
+                                                    /*isArrayedTexture=*/false,
+                                                    /*isMultisampled=*/false,
+                                                    /*isSampled=*/true))
+            , fTexture2D_Type(Type::MakeTextureType("texture2D",
+                                                    SpvDim2D,
+                                                    /*isDepth=*/false,
+                                                    /*isArrayedTexture=*/false,
+                                                    /*isMultisampled=*/false,
+                                                    /*isSampled=*/true))
+            , fTexture3D_Type(Type::MakeTextureType("texture3D",
+                                                    SpvDim3D,
+                                                    /*isDepth=*/false,
+                                                    /*isArrayedTexture=*/false,
+                                                    /*isMultisampled=*/false,
+                                                    /*isSampled=*/true))
+            , fTextureExternalOES_Type(Type::MakeTextureType("textureExternalOES",
+                                                             SpvDim2D,
+                                                             /*isDepth=*/false,
+                                                             /*isArrayedTexture=*/false,
+                                                             /*isMultisampled=*/false,
+                                                             /*isSampled=*/true))
+            , fTextureCube_Type(Type::MakeTextureType("textureCube",
+                                                      SpvDimCube,
+                                                      /*isDepth=*/false,
+                                                      /*isArrayedTexture=*/false,
+                                                      /*isMultisampled=*/false,
+                                                      /*isSampled=*/true))
+            , fTexture2DRect_Type(Type::MakeTextureType("texture2DRect",
+                                                        SpvDimRect,
+                                                        /*isDepth=*/false,
+                                                        /*isArrayedTexture=*/false,
+                                                        /*isMultisampled=*/false,
+                                                        /*isSampled=*/true))
+            , fTextureBuffer_Type(Type::MakeTextureType("textureBuffer",
+                                                        SpvDimBuffer,
+                                                        /*isDepth=*/false,
+                                                        /*isArrayedTexture=*/false,
+                                                        /*isMultisampled=*/false,
+                                                        /*isSampled=*/true))
+            , fITexture2D_Type(Type::MakeTextureType("itexture2D",
+                                                     SpvDim2D,
+                                                     /*isDepth=*/false,
+                                                     /*isArrayedTexture=*/false,
+                                                     /*isMultisampled=*/false,
+                                                     /*isSampled=*/true))
+            , fSampler1D_Type(Type::MakeSamplerType("sampler1D", *fTexture1D_Type))
+            , fSampler2D_Type(Type::MakeSamplerType("sampler2D", *fTexture2D_Type))
+            , fSampler3D_Type(Type::MakeSamplerType("sampler3D", *fTexture3D_Type))
+            , fSamplerExternalOES_Type(
+                      Type::MakeSamplerType("samplerExternalOES", *fTextureExternalOES_Type))
+            , fSamplerCube_Type(Type::MakeSamplerType("samplerCube", *fTextureCube_Type))
+            , fSampler2DRect_Type(Type::MakeSamplerType("sampler2DRect", *fTexture2DRect_Type))
+            , fSampler1DArray_Type(Type::MakeOtherType("sampler1DArray"))
+            , fSampler2DArray_Type(Type::MakeOtherType("sampler2DArray"))
+            , fSamplerCubeArray_Type(Type::MakeOtherType("samplerCubeArray"))
+            , fSamplerBuffer_Type(Type::MakeSamplerType("samplerBuffer", *fTextureBuffer_Type))
+            , fSampler2DMS_Type(Type::MakeOtherType("sampler2DMS"))
+            , fSampler2DMSArray_Type(Type::MakeOtherType("sampler2DMSArray"))
+            , fSampler1DShadow_Type(Type::MakeOtherType("sampler1DShadow"))
+            , fSampler2DShadow_Type(Type::MakeOtherType("sampler2DShadow"))
+            , fSamplerCubeShadow_Type(Type::MakeOtherType("samplerCubeShadow"))
+            , fSampler2DRectShadow_Type(Type::MakeOtherType("sampler2DRectShadow"))
+            , fSampler1DArrayShadow_Type(Type::MakeOtherType("sampler1DArrayShadow"))
+            , fSampler2DArrayShadow_Type(Type::MakeOtherType("sampler2DArrayShadow"))
+            , fSamplerCubeArrayShadow_Type(Type::MakeOtherType("samplerCubeArrayShadow"))
 
-    // Related to below FIXME, gsampler*s don't currently expand to cover integer case.
-    , fISampler2D_Type(new Type("isampler2D", *fITexture2D_Type))
+            // Related to below FIXME, gsampler*s don't currently expand to cover integer case.
+            , fISampler2D_Type(Type::MakeSamplerType("isampler2D", *fITexture2D_Type))
 
-    , fSampler_Type(new Type("sampler", Type::TypeKind::kSeparateSampler))
-    // FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D.
-    , fImage2D_Type(new Type("image2D", SpvDim2D, false, false, false, true))
-    , fIImage2D_Type(new Type("iimage2D", SpvDim2D, false, false, false, true))
+            , fSampler_Type(Type::MakeSimpleType("sampler", Type::TypeKind::kSeparateSampler))
+            // FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D.
+            , fImage2D_Type(Type::MakeTextureType("image2D",
+                                                  SpvDim2D,
+                                                  /*isDepth=*/false,
+                                                  /*isArrayedTexture=*/false,
+                                                  /*isMultisampled=*/false,
+                                                  /*isSampled=*/true))
+            , fIImage2D_Type(Type::MakeTextureType("iimage2D",
+                                                   SpvDim2D,
+                                                   /*isDepth=*/false,
+                                                   /*isArrayedTexture=*/false,
+                                                   /*isMultisampled=*/false,
+                                                   /*isSampled=*/true))
 
-    // FIXME express these as "gsubpassInput" that expand to subpassInput, isubpassInput,
-    // and usubpassInput.
-    , fSubpassInput_Type(new Type("subpassInput", SpvDimSubpassData, false, false,
-                                  false, false))
-    , fSubpassInputMS_Type(new Type("subpassInputMS", SpvDimSubpassData, false, false,
-                                    true, false))
+            // FIXME express these as "gsubpassInput" that expand to subpassInput, isubpassInput,
+            // and usubpassInput.
+            , fSubpassInput_Type(Type::MakeTextureType("subpassInput",
+                                                       SpvDimSubpassData,
+                                                       /*isDepth=*/false,
+                                                       /*isArrayedTexture=*/false,
+                                                       /*isMultisampled=*/false,
+                                                       /*isSampled=*/false))
+            , fSubpassInputMS_Type(Type::MakeTextureType("subpassInputMS",
+                                                         SpvDimSubpassData,
+                                                         /*isDepth=*/false,
+                                                         /*isArrayedTexture=*/false,
+                                                         /*isMultisampled=*/true,
+                                                         /*isSampled=*/false))
 
-    // FIXME figure out what we're supposed to do with the gsampler et al. types)
-    , fGSampler1D_Type(new Type("$gsampler1D", static_type(*fSampler1D_Type)))
-    , fGSampler2D_Type(new Type("$gsampler2D", static_type(*fSampler2D_Type)))
-    , fGSampler3D_Type(new Type("$gsampler3D", static_type(*fSampler3D_Type)))
-    , fGSamplerCube_Type(new Type("$gsamplerCube", static_type(*fSamplerCube_Type)))
-    , fGSampler2DRect_Type(new Type("$gsampler2DRect", static_type(*fSampler2DRect_Type)))
-    , fGSampler1DArray_Type(new Type("$gsampler1DArray",
-                                     static_type(*fSampler1DArray_Type)))
-    , fGSampler2DArray_Type(new Type("$gsampler2DArray",
-                                     static_type(*fSampler2DArray_Type)))
-    , fGSamplerCubeArray_Type(new Type("$gsamplerCubeArray",
-                                       static_type(*fSamplerCubeArray_Type)))
-    , fGSamplerBuffer_Type(new Type("$gsamplerBuffer", static_type(*fSamplerBuffer_Type)))
-    , fGSampler2DMS_Type(new Type("$gsampler2DMS", static_type(*fSampler2DMS_Type)))
-    , fGSampler2DMSArray_Type(new Type("$gsampler2DMSArray",
-                                       static_type(*fSampler2DMSArray_Type)))
-    , fGSampler2DArrayShadow_Type(new Type("$gsampler2DArrayShadow",
-                                           static_type(*fSampler2DArrayShadow_Type)))
-    , fGSamplerCubeArrayShadow_Type(new Type("$gsamplerCubeArrayShadow",
-                                             static_type(*fSamplerCubeArrayShadow_Type)))
-    , fGenType_Type(new Type("$genType", { fFloat_Type.get(), fFloat2_Type.get(),
-                                           fFloat3_Type.get(), fFloat4_Type.get() }))
-    , fGenHType_Type(new Type("$genHType", { fHalf_Type.get(), fHalf2_Type.get(),
-                                             fHalf3_Type.get(), fHalf4_Type.get() }))
-    , fGenIType_Type(new Type("$genIType", { fInt_Type.get(), fInt2_Type.get(),
-                                             fInt3_Type.get(), fInt4_Type.get() }))
-    , fGenUType_Type(new Type("$genUType", { fUInt_Type.get(), fUInt2_Type.get(),
-                                             fUInt3_Type.get(), fUInt4_Type.get() }))
-    , fGenBType_Type(new Type("$genBType", { fBool_Type.get(), fBool2_Type.get(),
-                                             fBool3_Type.get(), fBool4_Type.get() }))
-    , fMat_Type(new Type("$mat", { fFloat2x2_Type.get(), fFloat2x3_Type.get(),
-                                   fFloat2x4_Type.get(), fFloat3x2_Type.get(),
-                                   fFloat3x3_Type.get(), fFloat3x4_Type.get(),
-                                   fFloat4x2_Type.get(), fFloat4x3_Type.get(),
-                                   fFloat4x4_Type.get() }))
-    , fMatH_Type(new Type("$matH", { fHalf2x2_Type.get(), fHalf2x3_Type.get(),
-                                     fHalf2x4_Type.get(), fHalf3x2_Type.get(),
-                                     fHalf3x3_Type.get(), fHalf3x4_Type.get(),
-                                     fHalf4x2_Type.get(), fHalf4x3_Type.get(),
-                                     fHalf4x4_Type.get() }))
-    , fVec_Type(new Type("$vec", { fInvalid_Type.get(), fFloat2_Type.get(),
-                                   fFloat3_Type.get(), fFloat4_Type.get() }))
-    , fGVec_Type(new Type("$gvec"))
-    , fGVec2_Type(new Type("$gfloat2"))
-    , fGVec3_Type(new Type("$gfloat3"))
-    , fGVec4_Type(new Type("$gfloat4", static_type(*fFloat4_Type)))
-    , fHVec_Type(new Type("$hvec", { fInvalid_Type.get(), fHalf2_Type.get(),
-                                     fHalf3_Type.get(), fHalf4_Type.get() }))
-    , fIVec_Type(new Type("$ivec", { fInvalid_Type.get(), fInt2_Type.get(),
-                                     fInt3_Type.get(), fInt4_Type.get() }))
-    , fUVec_Type(new Type("$uvec", { fInvalid_Type.get(), fUInt2_Type.get(),
-                                     fUInt3_Type.get(), fUInt4_Type.get() }))
-    , fSVec_Type(new Type("$svec", { fInvalid_Type.get(), fShort2_Type.get(),
-                                     fShort3_Type.get(), fShort4_Type.get() }))
-    , fUSVec_Type(new Type("$usvec", { fInvalid_Type.get(), fUShort2_Type.get(),
-                                       fUShort3_Type.get(), fUShort4_Type.get() }))
-    , fByteVec_Type(new Type("$bytevec", { fInvalid_Type.get(), fByte2_Type.get(),
-                                     fByte3_Type.get(), fByte4_Type.get() }))
-    , fUByteVec_Type(new Type("$ubytevec", { fInvalid_Type.get(), fUByte2_Type.get(),
-                                       fUByte3_Type.get(), fUByte4_Type.get() }))
-    , fBVec_Type(new Type("$bvec", { fInvalid_Type.get(), fBool2_Type.get(),
-                                     fBool3_Type.get(), fBool4_Type.get() }))
-    , fSkCaps_Type(new Type("$sk_Caps"))
-    , fFragmentProcessor_Type(fp_type(fInt_Type.get(), fBool_Type.get()))
-    , fDefined_Expression(new Defined(fInvalid_Type.get())) {}
+            // FIXME figure out what we're supposed to do with the gsampler et al. types)
+            , fGSampler1D_Type(Type::MakeGenericType("$gsampler1D", static_type(*fSampler1D_Type)))
+            , fGSampler2D_Type(Type::MakeGenericType("$gsampler2D", static_type(*fSampler2D_Type)))
+            , fGSampler3D_Type(Type::MakeGenericType("$gsampler3D", static_type(*fSampler3D_Type)))
+            , fGSamplerCube_Type(
+                      Type::MakeGenericType("$gsamplerCube", static_type(*fSamplerCube_Type)))
+            , fGSampler2DRect_Type(
+                      Type::MakeGenericType("$gsampler2DRect", static_type(*fSampler2DRect_Type)))
+            , fGSampler1DArray_Type(
+                      Type::MakeGenericType("$gsampler1DArray", static_type(*fSampler1DArray_Type)))
+            , fGSampler2DArray_Type(
+                      Type::MakeGenericType("$gsampler2DArray", static_type(*fSampler2DArray_Type)))
+            , fGSamplerCubeArray_Type(Type::MakeGenericType("$gsamplerCubeArray",
+                                                            static_type(*fSamplerCubeArray_Type)))
+            , fGSamplerBuffer_Type(
+                      Type::MakeGenericType("$gsamplerBuffer", static_type(*fSamplerBuffer_Type)))
+            , fGSampler2DMS_Type(
+                      Type::MakeGenericType("$gsampler2DMS", static_type(*fSampler2DMS_Type)))
+            , fGSampler2DMSArray_Type(Type::MakeGenericType("$gsampler2DMSArray",
+                                                            static_type(*fSampler2DMSArray_Type)))
+            , fGSampler2DArrayShadow_Type(Type::MakeGenericType(
+                      "$gsampler2DArrayShadow", static_type(*fSampler2DArrayShadow_Type)))
+            , fGSamplerCubeArrayShadow_Type(Type::MakeGenericType(
+                      "$gsamplerCubeArrayShadow", static_type(*fSamplerCubeArrayShadow_Type)))
+            , fGenType_Type(Type::MakeGenericType("$genType",
+                                                  {fFloat_Type.get(), fFloat2_Type.get(),
+                                                   fFloat3_Type.get(), fFloat4_Type.get()}))
+            , fGenHType_Type(Type::MakeGenericType(
+                      "$genHType",
+                      {fHalf_Type.get(), fHalf2_Type.get(), fHalf3_Type.get(), fHalf4_Type.get()}))
+            , fGenIType_Type(Type::MakeGenericType(
+                      "$genIType",
+                      {fInt_Type.get(), fInt2_Type.get(), fInt3_Type.get(), fInt4_Type.get()}))
+            , fGenUType_Type(Type::MakeGenericType(
+                      "$genUType",
+                      {fUInt_Type.get(), fUInt2_Type.get(), fUInt3_Type.get(), fUInt4_Type.get()}))
+            , fGenBType_Type(Type::MakeGenericType(
+                      "$genBType",
+                      {fBool_Type.get(), fBool2_Type.get(), fBool3_Type.get(), fBool4_Type.get()}))
+            , fMat_Type(Type::MakeGenericType(
+                      "$mat",
+                      {fFloat2x2_Type.get(), fFloat2x3_Type.get(), fFloat2x4_Type.get(),
+                       fFloat3x2_Type.get(), fFloat3x3_Type.get(), fFloat3x4_Type.get(),
+                       fFloat4x2_Type.get(), fFloat4x3_Type.get(), fFloat4x4_Type.get()}))
+            , fMatH_Type(Type::MakeGenericType(
+                      "$matH",
+                      {fHalf2x2_Type.get(), fHalf2x3_Type.get(), fHalf2x4_Type.get(),
+                       fHalf3x2_Type.get(), fHalf3x3_Type.get(), fHalf3x4_Type.get(),
+                       fHalf4x2_Type.get(), fHalf4x3_Type.get(), fHalf4x4_Type.get()}))
+            , fVec_Type(Type::MakeGenericType("$vec",
+                                              {fInvalid_Type.get(), fFloat2_Type.get(),
+                                               fFloat3_Type.get(), fFloat4_Type.get()}))
+            , fGVec_Type(Type::MakeOtherType("$gvec"))
+            , fGVec2_Type(Type::MakeOtherType("$gfloat2"))
+            , fGVec3_Type(Type::MakeOtherType("$gfloat3"))
+            , fGVec4_Type(Type::MakeGenericType("$gfloat4", static_type(*fFloat4_Type)))
+            , fHVec_Type(Type::MakeGenericType("$hvec",
+                                               {fInvalid_Type.get(), fHalf2_Type.get(),
+                                                fHalf3_Type.get(), fHalf4_Type.get()}))
+            , fIVec_Type(Type::MakeGenericType(
+                      "$ivec",
+                      {fInvalid_Type.get(), fInt2_Type.get(), fInt3_Type.get(), fInt4_Type.get()}))
+            , fUVec_Type(Type::MakeGenericType("$uvec",
+                                               {fInvalid_Type.get(), fUInt2_Type.get(),
+                                                fUInt3_Type.get(), fUInt4_Type.get()}))
+            , fSVec_Type(Type::MakeGenericType("$svec",
+                                               {fInvalid_Type.get(), fShort2_Type.get(),
+                                                fShort3_Type.get(), fShort4_Type.get()}))
+            , fUSVec_Type(Type::MakeGenericType("$usvec",
+                                                {fInvalid_Type.get(), fUShort2_Type.get(),
+                                                 fUShort3_Type.get(), fUShort4_Type.get()}))
+            , fByteVec_Type(Type::MakeGenericType("$bytevec",
+                                                  {fInvalid_Type.get(), fByte2_Type.get(),
+                                                   fByte3_Type.get(), fByte4_Type.get()}))
+            , fUByteVec_Type(Type::MakeGenericType("$ubytevec",
+                                                   {fInvalid_Type.get(), fUByte2_Type.get(),
+                                                    fUByte3_Type.get(), fUByte4_Type.get()}))
+            , fBVec_Type(Type::MakeGenericType("$bvec",
+                                               {fInvalid_Type.get(), fBool2_Type.get(),
+                                                fBool3_Type.get(), fBool4_Type.get()}))
+            , fSkCaps_Type(Type::MakeOtherType("$sk_Caps"))
+            , fFragmentProcessor_Type(fp_type(fInt_Type.get(), fBool_Type.get()))
+            , fDefined_Expression(new Defined(fInvalid_Type.get())) {}
 
     static std::vector<const Type*> static_type(const Type& t) {
         return { &t, &t, &t, &t };
@@ -385,7 +478,7 @@
             Type::Field(mods, "preservesOpaqueInput", boolType),
             Type::Field(mods, "hasConstantOutputForConstantInput", boolType)
         };
-        return std::make_unique<Type>("fragmentProcessor", fields);
+        return Type::MakeOtherStruct("fragmentProcessor", std::move(fields));
     }
 };
 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 4a3928e..3f013b8 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -1141,8 +1141,8 @@
             }
         }
     }
-    const Type* type = old->takeOwnershipOfSymbol(std::make_unique<Type>(intf.fOffset, id.fTypeName,
-                                                                         fields));
+    const Type* type = old->takeOwnershipOfSymbol(Type::MakeStructType(intf.fOffset, id.fTypeName,
+                                                                       fields));
     int arraySize = 0;
     if (id.fIsArray) {
         const ASTNode& size = *(iter++);
@@ -1290,8 +1290,8 @@
                 fErrors.error(type.fOffset, "type '" + td.fName + "' may not be used in "
                                             "an array");
             }
-            result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Type>(
-                    String(result->name()) + "?", Type::TypeKind::kNullable, *result));
+            result = fSymbolTable->takeOwnershipOfSymbol(
+                    Type::MakeNullableType(String(result->name()) + "?", *result));
         } else {
             fErrors.error(type.fOffset, "type '" + td.fName + "' may not be nullable");
         }
diff --git a/src/sksl/SkSLInliner.cpp b/src/sksl/SkSLInliner.cpp
index f1e4052..ec44c4a 100644
--- a/src/sksl/SkSLInliner.cpp
+++ b/src/sksl/SkSLInliner.cpp
@@ -197,10 +197,8 @@
 static const Type* copy_if_needed(const Type* src, SymbolTable& symbolTable) {
     if (src->isArray()) {
         const Type* innerType = copy_if_needed(&src->componentType(), symbolTable);
-        return symbolTable.takeOwnershipOfSymbol(std::make_unique<Type>(src->name(),
-                                                                        src->typeKind(),
-                                                                        *innerType,
-                                                                        src->columns()));
+        return symbolTable.takeOwnershipOfSymbol(Type::MakeArrayType(src->name(), *innerType,
+                                                                     src->columns()));
     }
     return src;
 }
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index 8bfe7bf..5ac1462 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -383,7 +383,7 @@
     if (!this->expect(Token::Kind::TK_LBRACE, "'{'")) {
         return ASTNode::ID::Invalid();
     }
-    fSymbols.add(std::make_unique<Type>(this->text(name), Type::TypeKind::kEnum));
+    fSymbols.add(Type::MakeSimpleType(this->text(name), Type::TypeKind::kEnum));
     ASTNode::ID result = this->createNode(name.fOffset, ASTNode::Kind::kEnum, this->text(name));
     if (!this->checkNext(Token::Kind::TK_RBRACE)) {
         Token id;
@@ -580,7 +580,7 @@
     if (!this->expect(Token::Kind::TK_RBRACE, "'}'")) {
         return ASTNode::ID::Invalid();
     }
-    auto newType = std::make_unique<Type>(name.fOffset, this->text(name), fields);
+    std::unique_ptr<Type> newType = Type::MakeStructType(name.fOffset, this->text(name), fields);
     if (struct_is_too_deeply_nested(*newType, kMaxStructDepth)) {
         this->error(name.fOffset, "struct '" + this->text(name) + "' is too deeply nested");
         return ASTNode::ID::Invalid();
diff --git a/src/sksl/SkSLRehydrator.cpp b/src/sksl/SkSLRehydrator.cpp
index 0d31ccb..5796560 100644
--- a/src/sksl/SkSLRehydrator.cpp
+++ b/src/sksl/SkSLRehydrator.cpp
@@ -157,7 +157,7 @@
                 name += "[" + to_string(count) + "]";
             }
             const Type* result = fSymbolTable->takeOwnershipOfSymbol(
-                    std::make_unique<Type>(name, Type::TypeKind::kArray, *componentType, count));
+                    Type::MakeArrayType(name, *componentType, count));
             this->addSymbol(id, result);
             return result;
         }
@@ -165,7 +165,7 @@
             uint16_t id = this->readU16();
             StringFragment name = this->readString();
             const Type* result = fSymbolTable->takeOwnershipOfSymbol(
-                    std::make_unique<Type>(name, Type::TypeKind::kEnum));
+                    Type::MakeSimpleType(name, Type::TypeKind::kEnum));
             this->addSymbol(id, result);
             return result;
         }
@@ -198,7 +198,7 @@
             uint16_t id = this->readU16();
             const Type* base = this->type();
             const Type* result = fSymbolTable->takeOwnershipOfSymbol(
-                    std::make_unique<Type>(base->name() + "?", Type::TypeKind::kNullable, *base));
+                    Type::MakeNullableType(base->name() + "?", *base));
             this->addSymbol(id, result);
             return result;
         }
@@ -215,7 +215,7 @@
                 fields.emplace_back(m, fieldName, type);
             }
             const Type* result = fSymbolTable->takeOwnershipOfSymbol(
-                    std::make_unique<Type>(/*offset=*/-1, name, std::move(fields)));
+                    Type::MakeStructType(/*offset=*/-1, name, std::move(fields)));
             this->addSymbol(id, result);
             return result;
         }
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index c63d84d..a83f6d6 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -1776,8 +1776,8 @@
             SpvId typeId;
             const Variable& var = *expr.as<VariableReference>().variable();
             if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
-                typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
-                                            var.type().componentType(), fSkInCount));
+                typeId = this->getType(*Type::MakeArrayType("sk_in", var.type().componentType(),
+                                                            fSkInCount));
             } else {
                 typeId = this->getType(type);
             }
@@ -1894,8 +1894,8 @@
                                     0),
                         SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
                 StringFragment name("sksl_synthetic_uniforms");
-                Type intfStruct(-1, name, fields);
-
+                std::unique_ptr<Type> intfStruct = Type::MakeStructType(/*offset=*/-1, name,
+                                                                        fields);
                 int binding = fProgram.fSettings.fRTHeightBinding;
                 if (binding == -1) {
                     fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
@@ -1912,7 +1912,7 @@
                         std::make_unique<Variable>(/*offset=*/-1,
                                                    fProgram.fModifiers->addToPool(modifiers),
                                                    name,
-                                                   &intfStruct,
+                                                   intfStruct.get(),
                                                    /*builtin=*/false,
                                                    Variable::Storage::kGlobal));
                 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
@@ -2734,6 +2734,7 @@
                                 MemoryLayout(MemoryLayout::k430_Standard) :
                                 fDefaultLayout;
     SpvId result = this->nextId();
+    std::unique_ptr<Type> rtHeightStructType;
     const Type* type = &intf.variable().type();
     if (!MemoryLayout::LayoutIsSupported(*type)) {
         fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
@@ -2748,8 +2749,10 @@
         fRTHeightStructId = result;
         fRTHeightFieldIndex = fields.size();
         fRTHeightStorageClass = storageClass;
-        fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
-        type = new Type(type->fOffset, type->name(), fields);
+        fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME),
+                            fContext.fFloat_Type.get());
+        rtHeightStructType = Type::MakeStructType(type->fOffset, type->name(), std::move(fields));
+        type = rtHeightStructType.get();
     }
     SpvId typeId;
     if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
@@ -2759,10 +2762,9 @@
                 update_sk_in_count(m, &fSkInCount);
             }
         }
-        typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
-                                    intf.variable().type().componentType(),
-                                    fSkInCount),
-                               memoryLayout);
+        typeId = this->getType(
+                *Type::MakeArrayType("sk_in", intf.variable().type().componentType(), fSkInCount),
+                memoryLayout);
     } else {
         typeId = this->getType(*type, memoryLayout);
     }
@@ -2780,9 +2782,6 @@
     }
     this->writeLayout(layout, result);
     fVariableMap[&intf.variable()] = result;
-    if (fProgram.fInputs.fRTHeight && appendRTHeight) {
-        delete type;
-    }
     return result;
 }
 
@@ -2857,7 +2856,7 @@
     SpvId typeId;
     if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
         typeId = this->getPointerType(
-                Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
+                *Type::MakeArrayType("sk_in", type.componentType(), fSkInCount),
                 storageClass);
     } else {
         typeId = this->getPointerType(type, storageClass);
diff --git a/src/sksl/ir/SkSLSymbolTable.cpp b/src/sksl/ir/SkSLSymbolTable.cpp
index 120f82e..837e8d0 100644
--- a/src/sksl/ir/SkSLSymbolTable.cpp
+++ b/src/sksl/ir/SkSLSymbolTable.cpp
@@ -127,9 +127,8 @@
         String arrayName = (arraySize != Type::kUnsizedArray)
                                    ? String::printf("%s[%d]", baseName.c_str(), arraySize)
                                    : String::printf("%s[]", baseName.c_str());
-        type = this->takeOwnershipOfSymbol(std::make_unique<Type>(std::move(arrayName),
-                                                                  Type::TypeKind::kArray,
-                                                                  *type, arraySize));
+        type = this->takeOwnershipOfSymbol(Type::MakeArrayType(std::move(arrayName),
+                                                               *type, arraySize));
     }
     return type;
 }
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index d3c7bf6..235c52d 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -99,140 +99,74 @@
 
     // Create an "other" (special) type with the given name. These types cannot be directly
     // referenced from user code.
-    Type(const char* name)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kOther)
-    , fNumberKind(NumberKind::kNonnumeric) {}
-
-    // Create an "other" (special) type that supports field access.
-    Type(const char* name, std::vector<Field> fields)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kOther)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fFields(std::move(fields)) {}
-
-    // Create a simple type.
-    Type(String name, TypeKind kind)
-    : INHERITED(-1, kSymbolKind, "")
-    , fNameString(std::move(name))
-    , fTypeKind(kind)
-    , fNumberKind(NumberKind::kNonnumeric) {
-        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    static std::unique_ptr<Type> MakeOtherType(const char* name) {
+        return std::unique_ptr<Type>(new Type(name));
     }
 
-    // Create a generic type which maps to the listed types.
-    Type(const char* name, std::vector<const Type*> types)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kGeneric)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fCoercibleTypes(std::move(types)) {}
+    // Create an "other" (special) type that supports field access.
+    static std::unique_ptr<Type> MakeOtherStruct(const char* name, std::vector<Field> fields) {
+        return std::unique_ptr<Type>(new Type(name, std::move(fields)));
+    }
+
+    // Create a simple type.
+    static std::unique_ptr<Type> MakeSimpleType(String name, TypeKind kind) {
+        return std::unique_ptr<Type>(new Type(std::move(name), kind));
+    }
+
+    // Create a generic type which maps to the listed types--e.g. $genType is a generic type which
+    // can match float, float2, float3 or float4.
+    static std::unique_ptr<Type> MakeGenericType(const char* name, std::vector<const Type*> types) {
+        return std::unique_ptr<Type>(new Type(name, std::move(types)));
+    }
 
     // Create a struct type with the given fields.
-    Type(int offset, String name, std::vector<Field> fields)
-    : INHERITED(offset, kSymbolKind, "")
-    , fNameString(std::move(name))
-    , fTypeKind(TypeKind::kStruct)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fFields(std::move(fields)) {
-        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    static std::unique_ptr<Type> MakeStructType(int offset, String name, std::vector<Field> fields) {
+        return std::unique_ptr<Type>(new Type(offset, std::move(name), std::move(fields)));
     }
 
     // Create a scalar type.
-    Type(const char* name, NumberKind numberKind, int priority, bool highPrecision = false)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kScalar)
-    , fNumberKind(numberKind)
-    , fPriority(priority)
-    , fColumns(1)
-    , fRows(1)
-    , fHighPrecision(highPrecision) {}
-
-    // Create a scalar type which can be coerced to the listed types.
-    Type(const char* name,
-         NumberKind numberKind,
-         int priority,
-         std::vector<const Type*> coercibleTypes)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kScalar)
-    , fNumberKind(numberKind)
-    , fPriority(priority)
-    , fCoercibleTypes(std::move(coercibleTypes))
-    , fColumns(1)
-    , fRows(1) {}
+    static std::unique_ptr<Type> MakeScalarType(const char* name, NumberKind numberKind,
+                                                int priority, bool highPrecision = false) {
+        return std::unique_ptr<Type>(new Type(name, numberKind, priority, highPrecision));
+    }
 
     // Create a nullable type.
-    Type(String name, TypeKind kind, const Type& componentType)
-    : INHERITED(-1, kSymbolKind, "")
-    , fNameString(std::move(name))
-    , fTypeKind(kind)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fComponentType(&componentType)
-    , fColumns(1)
-    , fRows(1)
-    , fDimensions(SpvDim1D) {
-        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    static std::unique_ptr<Type> MakeNullableType(String name, const Type& componentType) {
+        return std::unique_ptr<Type>(new Type(std::move(name), componentType));
     }
 
     // Create a vector type.
-    Type(const char* name, const Type& componentType, int columns)
-    : Type(name, TypeKind::kVector, componentType, columns) {}
+    static std::unique_ptr<Type> MakeVectorType(const char* name, const Type& componentType,
+                                                int columns) {
+        return std::unique_ptr<Type>(new Type(name, TypeKind::kVector, componentType, columns));
+    }
 
+    // Create an array type.
     static constexpr int kUnsizedArray = -1;
-
-    // Create a vector or array type.
-    Type(String name, TypeKind kind, const Type& componentType, int columns)
-    : INHERITED(-1, kSymbolKind, "")
-    , fNameString(std::move(name))
-    , fTypeKind(kind)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fComponentType(&componentType)
-    , fColumns(columns)
-    , fRows(1)
-    , fDimensions(SpvDim1D) {
-        if (this->isArray()) {
-            // Allow either explicitly-sized or unsized arrays.
-            SkASSERT(this->columns() > 0 || this->columns() == kUnsizedArray);
-            // Disallow multi-dimensional arrays.
-            SkASSERT(!this->componentType().isArray());
-        } else {
-            SkASSERT(this->columns() > 0);
-        }
-        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    static std::unique_ptr<Type> MakeArrayType(String name, const Type& componentType,
+                                               int columns) {
+        return std::unique_ptr<Type>(new Type(std::move(name), TypeKind::kArray, componentType,
+                                              columns));
     }
 
     // Create a matrix type.
-    Type(const char* name, const Type& componentType, int columns, int rows)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kMatrix)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fComponentType(&componentType)
-    , fColumns(columns)
-    , fRows(rows)
-    , fDimensions(SpvDim1D) {}
+    static std::unique_ptr<Type> MakeMatrixType(const char* name, const Type& componentType,
+                                                int columns, int rows) {
+        return std::unique_ptr<Type>(new Type(name, componentType, columns, rows));
+    }
 
     // Create a texture type.
-    Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayedTexture,
-         bool isMultisampled, bool isSampled)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kTexture)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fDimensions(dimensions)
-    , fIsDepth(isDepth)
-    , fIsArrayed(isArrayedTexture)
-    , fIsMultisampled(isMultisampled)
-    , fIsSampled(isSampled) {}
+    static std::unique_ptr<Type> MakeTextureType(const char* name, SpvDim_ dimensions,
+                                                 bool isDepth, bool isArrayedTexture,
+                                                 bool isMultisampled, bool isSampled) {
+        return std::unique_ptr<Type>(
+                new Type(name, dimensions, isDepth, isArrayedTexture, isMultisampled, isSampled));
+    }
 
     // Create a sampler type.
-    Type(const char* name, const Type& textureType)
-    : INHERITED(-1, kSymbolKind, name)
-    , fTypeKind(TypeKind::kSampler)
-    , fNumberKind(NumberKind::kNonnumeric)
-    , fDimensions(textureType.dimensions())
-    , fIsDepth(textureType.isDepth())
-    , fIsArrayed(textureType.isArrayedTexture())
-    , fIsMultisampled(textureType.isMultisampled())
-    , fIsSampled(textureType.isSampled())
-    , fTextureType(&textureType) {}
+    static std::unique_ptr<Type> MakeSamplerType(const char* name, const Type& textureType) {
+        return std::unique_ptr<Type>(new Type(name, textureType));
+    }
 
     String displayName() const {
         StringFragment name = this->name();
@@ -473,6 +407,123 @@
 private:
     using INHERITED = Symbol;
 
+    // Constructor for MakeOtherType.
+    Type(const char* name)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kOther)
+            , fNumberKind(NumberKind::kNonnumeric) {}
+
+    // Constructor for MakeOtherStruct.
+    Type(const char* name, std::vector<Field> fields)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kOther)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fFields(std::move(fields)) {}
+
+    // Constructor for MakeSimpleType.
+    Type(String name, TypeKind kind)
+            : INHERITED(-1, kSymbolKind, "")
+            , fNameString(std::move(name))
+            , fTypeKind(kind)
+            , fNumberKind(NumberKind::kNonnumeric) {
+        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    }
+
+    // Constructor for MakeGenericType.
+    Type(const char* name, std::vector<const Type*> types)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kGeneric)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fCoercibleTypes(std::move(types)) {}
+
+    // Constructor for MakeScalarType.
+    Type(const char* name, NumberKind numberKind, int priority, bool highPrecision = false)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kScalar)
+            , fNumberKind(numberKind)
+            , fPriority(priority)
+            , fColumns(1)
+            , fRows(1)
+            , fHighPrecision(highPrecision) {}
+
+    // Constructor shared by MakeVectorType and MakeArrayType.
+    Type(String name, TypeKind kind, const Type& componentType, int columns)
+            : INHERITED(-1, kSymbolKind, "")
+            , fNameString(std::move(name))
+            , fTypeKind(kind)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fComponentType(&componentType)
+            , fColumns(columns)
+            , fRows(1)
+            , fDimensions(SpvDim1D) {
+        if (this->isArray()) {
+            // Allow either explicitly-sized or unsized arrays.
+            SkASSERT(this->columns() > 0 || this->columns() == kUnsizedArray);
+            // Disallow multi-dimensional arrays.
+            SkASSERT(!this->componentType().isArray());
+        } else {
+            SkASSERT(this->columns() > 0);
+        }
+        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    }
+
+    // Constructor for MakeMatrixType.
+    Type(const char* name, const Type& componentType, int columns, int rows)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kMatrix)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fComponentType(&componentType)
+            , fColumns(columns)
+            , fRows(rows)
+            , fDimensions(SpvDim1D) {}
+
+    // Constructor for MakeStructType.
+    Type(int offset, String name, std::vector<Field> fields)
+            : INHERITED(offset, kSymbolKind, "")
+            , fNameString(std::move(name))
+            , fTypeKind(TypeKind::kStruct)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fFields(std::move(fields)) {
+        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    }
+
+    // Constructor for MakeNullableType.
+    Type(String name, const Type& componentType)
+            : INHERITED(-1, kSymbolKind, "")
+            , fNameString(std::move(name))
+            , fTypeKind(Type::TypeKind::kNullable)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fComponentType(&componentType)
+            , fColumns(1)
+            , fRows(1)
+            , fDimensions(SpvDim1D) {
+        fName = StringFragment(fNameString.c_str(), fNameString.length());
+    }
+
+    // Constructor for MakeTextureType.
+    Type(const char* name, SpvDim_ dimensions, bool isDepth, bool isArrayedTexture,
+         bool isMultisampled, bool isSampled)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kTexture)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fDimensions(dimensions)
+            , fIsDepth(isDepth)
+            , fIsArrayed(isArrayedTexture)
+            , fIsMultisampled(isMultisampled)
+            , fIsSampled(isSampled) {}
+
+    // Constructor for MakeSamplerType.
+    Type(const char* name, const Type& textureType)
+            : INHERITED(-1, kSymbolKind, name)
+            , fTypeKind(TypeKind::kSampler)
+            , fNumberKind(NumberKind::kNonnumeric)
+            , fDimensions(textureType.dimensions())
+            , fIsDepth(textureType.isDepth())
+            , fIsArrayed(textureType.isArrayedTexture())
+            , fIsMultisampled(textureType.isMultisampled())
+            , fIsSampled(textureType.isSampled())
+            , fTextureType(&textureType) {}
+
     String fNameString;
     TypeKind fTypeKind;
     // always kNonnumeric_NumberKind for non-scalar values
diff --git a/tests/SkSLMemoryLayoutTest.cpp b/tests/SkSLMemoryLayoutTest.cpp
index 2d0a597..c5a03ae 100644
--- a/tests/SkSLMemoryLayoutTest.cpp
+++ b/tests/SkSLMemoryLayoutTest.cpp
@@ -53,44 +53,44 @@
     // struct 1
     std::vector<SkSL::Type::Field> fields1;
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("a"), context.fFloat3_Type.get());
-    SkSL::Type s1(-1, SkSL::String("s1"), fields1);
-    REPORTER_ASSERT(r, 16 == layout.size(s1));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s1));
+    std::unique_ptr<SkSL::Type> s1 = SkSL::Type::MakeStructType(-1, SkSL::String("s1"), fields1);
+    REPORTER_ASSERT(r, 16 == layout.size(*s1));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s1));
 
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("b"), context.fFloat_Type.get());
-    SkSL::Type s2(-1, SkSL::String("s2"), fields1);
-    REPORTER_ASSERT(r, 16 == layout.size(s2));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s2));
+    std::unique_ptr<SkSL::Type> s2 = SkSL::Type::MakeStructType(-1, SkSL::String("s2"), fields1);
+    REPORTER_ASSERT(r, 16 == layout.size(*s2));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s2));
 
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("c"), context.fBool_Type.get());
-    SkSL::Type s3(-1, SkSL::String("s3"), fields1);
-    REPORTER_ASSERT(r, 32 == layout.size(s3));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s3));
+    std::unique_ptr<SkSL::Type> s3 = SkSL::Type::MakeStructType(-1, SkSL::String("s3"), fields1);
+    REPORTER_ASSERT(r, 32 == layout.size(*s3));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s3));
 
     // struct 2
     std::vector<SkSL::Type::Field> fields2;
     fields2.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("a"), context.fInt_Type.get());
-    SkSL::Type s4(-1, SkSL::String("s4"), fields2);
-    REPORTER_ASSERT(r, 16 == layout.size(s4));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s4));
+    std::unique_ptr<SkSL::Type> s4 = SkSL::Type::MakeStructType(-1, SkSL::String("s4"), fields2);
+    REPORTER_ASSERT(r, 16 == layout.size(*s4));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s4));
 
     fields2.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("b"), context.fFloat3_Type.get());
-    SkSL::Type s5(-1, SkSL::String("s5"), fields2);
-    REPORTER_ASSERT(r, 32 == layout.size(s5));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s5));
+    std::unique_ptr<SkSL::Type> s5 = SkSL::Type::MakeStructType(-1, SkSL::String("s5"), fields2);
+    REPORTER_ASSERT(r, 32 == layout.size(*s5));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s5));
 
     // arrays
-    SkSL::Type array1(SkSL::String("float[4]"), SkSL::Type::TypeKind::kArray, *context.fFloat_Type,
-                      4);
-    REPORTER_ASSERT(r, 64 == layout.size(array1));
-    REPORTER_ASSERT(r, 16 == layout.alignment(array1));
-    REPORTER_ASSERT(r, 16 == layout.stride(array1));
+    std::unique_ptr<SkSL::Type> array1 =
+            SkSL::Type::MakeArrayType(SkSL::String("float[4]"), *context.fFloat_Type, 4);
+    REPORTER_ASSERT(r, 64 == layout.size(*array1));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*array1));
+    REPORTER_ASSERT(r, 16 == layout.stride(*array1));
 
-    SkSL::Type array2(SkSL::String("float4[4]"), SkSL::Type::TypeKind::kArray,
-                      *context.fFloat4_Type, 4);
-    REPORTER_ASSERT(r, 64 == layout.size(array2));
-    REPORTER_ASSERT(r, 16 == layout.alignment(array2));
-    REPORTER_ASSERT(r, 16 == layout.stride(array2));
+    std::unique_ptr<SkSL::Type> array2 =
+            SkSL::Type::MakeArrayType(SkSL::String("float4[4]"), *context.fFloat4_Type, 4);
+    REPORTER_ASSERT(r, 64 == layout.size(*array2));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*array2));
+    REPORTER_ASSERT(r, 16 == layout.stride(*array2));
 }
 
 DEF_TEST(SkSLMemoryLayout430Test, r) {
@@ -136,42 +136,42 @@
     // struct 1
     std::vector<SkSL::Type::Field> fields1;
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("a"), context.fFloat3_Type.get());
-    SkSL::Type s1(-1, SkSL::String("s1"), fields1);
-    REPORTER_ASSERT(r, 16 == layout.size(s1));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s1));
+    std::unique_ptr<SkSL::Type> s1 = SkSL::Type::MakeStructType(-1, SkSL::String("s1"), fields1);
+    REPORTER_ASSERT(r, 16 == layout.size(*s1));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s1));
 
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("b"), context.fFloat_Type.get());
-    SkSL::Type s2(-1, SkSL::String("s2"), fields1);
-    REPORTER_ASSERT(r, 16 == layout.size(s2));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s2));
+    std::unique_ptr<SkSL::Type> s2 = SkSL::Type::MakeStructType(-1, SkSL::String("s2"), fields1);
+    REPORTER_ASSERT(r, 16 == layout.size(*s2));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s2));
 
     fields1.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("c"), context.fBool_Type.get());
-    SkSL::Type s3(-1, SkSL::String("s3"), fields1);
-    REPORTER_ASSERT(r, 32 == layout.size(s3));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s3));
+    std::unique_ptr<SkSL::Type> s3 = SkSL::Type::MakeStructType(-1, SkSL::String("s3"), fields1);
+    REPORTER_ASSERT(r, 32 == layout.size(*s3));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s3));
 
     // struct 2
     std::vector<SkSL::Type::Field> fields2;
     fields2.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("a"), context.fInt_Type.get());
-    SkSL::Type s4(-1, SkSL::String("s4"), fields2);
-    REPORTER_ASSERT(r, 4 == layout.size(s4));
-    REPORTER_ASSERT(r, 4 == layout.alignment(s4));
+    std::unique_ptr<SkSL::Type> s4 = SkSL::Type::MakeStructType(-1, SkSL::String("s4"), fields2);
+    REPORTER_ASSERT(r, 4 == layout.size(*s4));
+    REPORTER_ASSERT(r, 4 == layout.alignment(*s4));
 
     fields2.emplace_back(SkSL::Modifiers(), SkSL::StringFragment("b"), context.fFloat3_Type.get());
-    SkSL::Type s5(-1, SkSL::String("s5"), fields2);
-    REPORTER_ASSERT(r, 32 == layout.size(s5));
-    REPORTER_ASSERT(r, 16 == layout.alignment(s5));
+    std::unique_ptr<SkSL::Type> s5 = SkSL::Type::MakeStructType(-1, SkSL::String("s5"), fields2);
+    REPORTER_ASSERT(r, 32 == layout.size(*s5));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*s5));
 
     // arrays
-    SkSL::Type array1(SkSL::String("float[4]"), SkSL::Type::TypeKind::kArray, *context.fFloat_Type,
-                      4);
-    REPORTER_ASSERT(r, 16 == layout.size(array1));
-    REPORTER_ASSERT(r, 4 == layout.alignment(array1));
-    REPORTER_ASSERT(r, 4 == layout.stride(array1));
+    std::unique_ptr<SkSL::Type> array1 =
+            SkSL::Type::MakeArrayType(SkSL::String("float[4]"), *context.fFloat_Type, 4);
+    REPORTER_ASSERT(r, 16 == layout.size(*array1));
+    REPORTER_ASSERT(r, 4 == layout.alignment(*array1));
+    REPORTER_ASSERT(r, 4 == layout.stride(*array1));
 
-    SkSL::Type array2(SkSL::String("float4[4]"), SkSL::Type::TypeKind::kArray,
-                      *context.fFloat4_Type, 4);
-    REPORTER_ASSERT(r, 64 == layout.size(array2));
-    REPORTER_ASSERT(r, 16 == layout.alignment(array2));
-    REPORTER_ASSERT(r, 16 == layout.stride(array2));
+    std::unique_ptr<SkSL::Type> array2 =
+            SkSL::Type::MakeArrayType(SkSL::String("float4[4]"), *context.fFloat4_Type, 4);
+    REPORTER_ASSERT(r, 64 == layout.size(*array2));
+    REPORTER_ASSERT(r, 16 == layout.alignment(*array2));
+    REPORTER_ASSERT(r, 16 == layout.stride(*array2));
 }