tint/sem: Add Type::Flags()

Use a utils::EnumSet to hold type flags.
This scales better than adding a virtual method for each flag.

Change IsConstructable() from virtual to inline method.

Also remove sem::MemoryLayout. This was some cruft from something
removed a long time ago.

Change-Id: Ib3371946d7f4b07692255641425ccf621dc3e2f4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/106220
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index 314e619..7b0e3bc 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -58,7 +58,7 @@
 /// A special type that matches all TypeMatchers
 class Any final : public Castable<Any, sem::Type> {
   public:
-    Any() = default;
+    Any() : Base(sem::TypeFlags{}) {}
     ~Any() override = default;
 
     // Stub implementations for sem::Type conformance.
diff --git a/src/tint/sem/abstract_numeric.cc b/src/tint/sem/abstract_numeric.cc
index e7d1846..39615cd 100644
--- a/src/tint/sem/abstract_numeric.cc
+++ b/src/tint/sem/abstract_numeric.cc
@@ -18,7 +18,7 @@
 
 namespace tint::sem {
 
-AbstractNumeric::AbstractNumeric() = default;
+AbstractNumeric::AbstractNumeric() : Base(TypeFlags{Flag::kConstructable}) {}
 AbstractNumeric::AbstractNumeric(AbstractNumeric&&) = default;
 AbstractNumeric::~AbstractNumeric() = default;
 
@@ -30,8 +30,4 @@
     return 0;
 }
 
-bool AbstractNumeric::IsConstructible() const {
-    return true;
-}
-
 }  // namespace tint::sem
diff --git a/src/tint/sem/abstract_numeric.h b/src/tint/sem/abstract_numeric.h
index 620c528..68f21ae 100644
--- a/src/tint/sem/abstract_numeric.h
+++ b/src/tint/sem/abstract_numeric.h
@@ -37,9 +37,6 @@
 
     /// @returns 0, as the type is abstract.
     uint32_t Align() const override;
-
-    /// @returns true.
-    bool IsConstructible() const override;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/array.cc b/src/tint/sem/array.cc
index 74ef382..ed95e62 100644
--- a/src/tint/sem/array.cc
+++ b/src/tint/sem/array.cc
@@ -26,6 +26,21 @@
 
 namespace tint::sem {
 
+namespace {
+
+TypeFlags FlagsFrom(const Type* element, ArrayCount count) {
+    TypeFlags flags;
+    // Only constant-expression sized arrays are constructible
+    if (std::holds_alternative<ConstantArrayCount>(count)) {
+        if (element->IsConstructible()) {
+            flags.Add(TypeFlag::kConstructable);
+        }
+    }
+    return flags;
+}
+
+}  // namespace
+
 const char* const Array::kErrExpectedConstantCount =
     "array size is an override-expression, when expected a constant-expression.\n"
     "Was the SubstituteOverride transform run?";
@@ -36,15 +51,13 @@
              uint32_t size,
              uint32_t stride,
              uint32_t implicit_stride)
-    : element_(element),
+    : Base(FlagsFrom(element, count)),
+      element_(element),
       count_(count),
       align_(align),
       size_(size),
       stride_(stride),
-      implicit_stride_(implicit_stride),
-      // Only constant-expression sized arrays are constructible
-      constructible_(std::holds_alternative<ConstantArrayCount>(count) &&
-                     element->IsConstructible()) {
+      implicit_stride_(implicit_stride) {
     TINT_ASSERT(Semantic, element_);
 }
 
@@ -62,10 +75,6 @@
     return false;
 }
 
-bool Array::IsConstructible() const {
-    return constructible_;
-}
-
 std::string Array::FriendlyName(const SymbolTable& symbols) const {
     std::ostringstream out;
     if (!IsStrideImplicit()) {
diff --git a/src/tint/sem/array.h b/src/tint/sem/array.h
index ca66a16..24b2ee8 100644
--- a/src/tint/sem/array.h
+++ b/src/tint/sem/array.h
@@ -184,10 +184,6 @@
     /// @returns true if this array is runtime sized
     bool IsRuntimeSized() const { return std::holds_alternative<RuntimeArrayCount>(count_); }
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @param symbols the program's symbol table
     /// @returns the name for this type that closely resembles how it would be
     /// declared in WGSL.
@@ -200,7 +196,6 @@
     const uint32_t size_;
     const uint32_t stride_;
     const uint32_t implicit_stride_;
-    const bool constructible_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/atomic.cc b/src/tint/sem/atomic.cc
index 52951f3..965ebe2 100644
--- a/src/tint/sem/atomic.cc
+++ b/src/tint/sem/atomic.cc
@@ -22,7 +22,7 @@
 
 namespace tint::sem {
 
-Atomic::Atomic(const sem::Type* subtype) : subtype_(subtype) {
+Atomic::Atomic(const sem::Type* subtype) : Base(TypeFlags{}), subtype_(subtype) {
     TINT_ASSERT(AST, !subtype->Is<Reference>());
 }
 
@@ -51,10 +51,6 @@
     return subtype_->Align();
 }
 
-bool Atomic::IsConstructible() const {
-    return false;
-}
-
 Atomic::Atomic(Atomic&&) = default;
 
 Atomic::~Atomic() = default;
diff --git a/src/tint/sem/atomic.h b/src/tint/sem/atomic.h
index 7f6c814..5b405a1 100644
--- a/src/tint/sem/atomic.h
+++ b/src/tint/sem/atomic.h
@@ -53,10 +53,6 @@
     /// @returns the alignment in bytes of the type.
     uint32_t Align() const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
   private:
     sem::Type const* const subtype_;
 };
diff --git a/src/tint/sem/bool.cc b/src/tint/sem/bool.cc
index 938a935..8d3d1bf 100644
--- a/src/tint/sem/bool.cc
+++ b/src/tint/sem/bool.cc
@@ -20,7 +20,7 @@
 
 namespace tint::sem {
 
-Bool::Bool() = default;
+Bool::Bool() : Base(TypeFlags{Flag::kConstructable}) {}
 
 Bool::Bool(Bool&&) = default;
 
@@ -38,10 +38,6 @@
     return "bool";
 }
 
-bool Bool::IsConstructible() const {
-    return true;
-}
-
 uint32_t Bool::Size() const {
     return 4;
 }
diff --git a/src/tint/sem/bool.h b/src/tint/sem/bool.h
index aae48d8..133ab72 100644
--- a/src/tint/sem/bool.h
+++ b/src/tint/sem/bool.h
@@ -48,10 +48,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type.
     /// @note: booleans are not host-sharable, but still may exist in workgroup
     /// storage.
diff --git a/src/tint/sem/f16.cc b/src/tint/sem/f16.cc
index 7da65fa..0595821 100644
--- a/src/tint/sem/f16.cc
+++ b/src/tint/sem/f16.cc
@@ -21,7 +21,7 @@
 namespace tint {
 namespace sem {
 
-F16::F16() = default;
+F16::F16() : Base(TypeFlags{Flag::kConstructable}) {}
 
 F16::F16(F16&&) = default;
 
@@ -39,10 +39,6 @@
     return "f16";
 }
 
-bool F16::IsConstructible() const {
-    return true;
-}
-
 uint32_t F16::Size() const {
     return 2;
 }
diff --git a/src/tint/sem/f16.h b/src/tint/sem/f16.h
index 87543ed..b126614 100644
--- a/src/tint/sem/f16.h
+++ b/src/tint/sem/f16.h
@@ -42,10 +42,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type.
     uint32_t Size() const override;
 
diff --git a/src/tint/sem/f32.cc b/src/tint/sem/f32.cc
index 83fffcc..c1f99eb 100644
--- a/src/tint/sem/f32.cc
+++ b/src/tint/sem/f32.cc
@@ -20,7 +20,7 @@
 
 namespace tint::sem {
 
-F32::F32() = default;
+F32::F32() : Base(TypeFlags{Flag::kConstructable}) {}
 
 F32::F32(F32&&) = default;
 
@@ -38,10 +38,6 @@
     return "f32";
 }
 
-bool F32::IsConstructible() const {
-    return true;
-}
-
 uint32_t F32::Size() const {
     return 4;
 }
diff --git a/src/tint/sem/f32.h b/src/tint/sem/f32.h
index c7d7ad6..0559dfd 100644
--- a/src/tint/sem/f32.h
+++ b/src/tint/sem/f32.h
@@ -42,10 +42,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type.
     uint32_t Size() const override;
 
diff --git a/src/tint/sem/i32.cc b/src/tint/sem/i32.cc
index d5a1e26..8047c29 100644
--- a/src/tint/sem/i32.cc
+++ b/src/tint/sem/i32.cc
@@ -20,7 +20,7 @@
 
 namespace tint::sem {
 
-I32::I32() = default;
+I32::I32() : Base(TypeFlags{Flag::kConstructable}) {}
 
 I32::I32(I32&&) = default;
 
@@ -38,10 +38,6 @@
     return "i32";
 }
 
-bool I32::IsConstructible() const {
-    return true;
-}
-
 uint32_t I32::Size() const {
     return 4;
 }
diff --git a/src/tint/sem/i32.h b/src/tint/sem/i32.h
index 3b564db..ff2df4d 100644
--- a/src/tint/sem/i32.h
+++ b/src/tint/sem/i32.h
@@ -42,10 +42,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type.
     uint32_t Size() const override;
 
diff --git a/src/tint/sem/matrix.cc b/src/tint/sem/matrix.cc
index 7f0383b..5a3eb09 100644
--- a/src/tint/sem/matrix.cc
+++ b/src/tint/sem/matrix.cc
@@ -23,7 +23,8 @@
 namespace tint::sem {
 
 Matrix::Matrix(const Vector* column_type, uint32_t columns)
-    : subtype_(column_type->type()),
+    : Base(TypeFlags{Flag::kConstructable}),
+      subtype_(column_type->type()),
       column_type_(column_type),
       rows_(column_type->Width()),
       columns_(columns) {
@@ -54,10 +55,6 @@
     return out.str();
 }
 
-bool Matrix::IsConstructible() const {
-    return true;
-}
-
 uint32_t Matrix::Size() const {
     return column_type_->Align() * columns();
 }
diff --git a/src/tint/sem/matrix.h b/src/tint/sem/matrix.h
index 0321c4b..5d32269 100644
--- a/src/tint/sem/matrix.h
+++ b/src/tint/sem/matrix.h
@@ -59,10 +59,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type. This may include tail padding.
     uint32_t Size() const override;
 
diff --git a/src/tint/sem/pointer.cc b/src/tint/sem/pointer.cc
index 3918233..b35185a 100644
--- a/src/tint/sem/pointer.cc
+++ b/src/tint/sem/pointer.cc
@@ -23,7 +23,7 @@
 namespace tint::sem {
 
 Pointer::Pointer(const Type* subtype, ast::AddressSpace address_space, ast::Access access)
-    : subtype_(subtype), address_space_(address_space), access_(access) {
+    : Base(TypeFlags{}), subtype_(subtype), address_space_(address_space), access_(access) {
     TINT_ASSERT(Semantic, !subtype->Is<Reference>());
     TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
 }
diff --git a/src/tint/sem/reference.cc b/src/tint/sem/reference.cc
index a3a9f24..8d3bb6d 100644
--- a/src/tint/sem/reference.cc
+++ b/src/tint/sem/reference.cc
@@ -22,7 +22,7 @@
 namespace tint::sem {
 
 Reference::Reference(const Type* subtype, ast::AddressSpace address_space, ast::Access access)
-    : subtype_(subtype), address_space_(address_space), access_(access) {
+    : Base(TypeFlags{}), subtype_(subtype), address_space_(address_space), access_(access) {
     TINT_ASSERT(Semantic, !subtype->Is<Reference>());
     TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
 }
diff --git a/src/tint/sem/sampler.cc b/src/tint/sem/sampler.cc
index 20993cc..598c696 100644
--- a/src/tint/sem/sampler.cc
+++ b/src/tint/sem/sampler.cc
@@ -21,7 +21,7 @@
 
 namespace tint::sem {
 
-Sampler::Sampler(ast::SamplerKind kind) : kind_(kind) {}
+Sampler::Sampler(ast::SamplerKind kind) : Base(TypeFlags{}), kind_(kind) {}
 
 Sampler::Sampler(Sampler&&) = default;
 
diff --git a/src/tint/sem/struct.cc b/src/tint/sem/struct.cc
index 7d457e8..4a0a3c1 100644
--- a/src/tint/sem/struct.cc
+++ b/src/tint/sem/struct.cc
@@ -27,6 +27,20 @@
 TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember);
 
 namespace tint::sem {
+namespace {
+
+TypeFlags FlagsFrom(const StructMemberList& members) {
+    TypeFlags flags{TypeFlag::kConstructable};
+    for (auto* member : members) {
+        if (!member->Type()->IsConstructible()) {
+            flags.Remove(TypeFlag::kConstructable);
+            break;
+        }
+    }
+    return flags;
+}
+
+}  // namespace
 
 Struct::Struct(const ast::Struct* declaration,
                Symbol name,
@@ -34,20 +48,13 @@
                uint32_t align,
                uint32_t size,
                uint32_t size_no_padding)
-    : declaration_(declaration),
+    : Base(FlagsFrom(members)),
+      declaration_(declaration),
       name_(name),
       members_(std::move(members)),
       align_(align),
       size_(size),
-      size_no_padding_(size_no_padding) {
-    constructible_ = true;
-    for (auto* member : members_) {
-        if (!member->Type()->IsConstructible()) {
-            constructible_ = false;
-            break;
-        }
-    }
-}
+      size_no_padding_(size_no_padding) {}
 
 Struct::~Struct() = default;
 
@@ -151,10 +158,6 @@
     return ss.str();
 }
 
-bool Struct::IsConstructible() const {
-    return constructible_;
-}
-
 StructMember::StructMember(const ast::StructMember* declaration,
                            Symbol name,
                            const sem::Type* type,
diff --git a/src/tint/sem/struct.h b/src/tint/sem/struct.h
index 80ab53b..f35d5f4 100644
--- a/src/tint/sem/struct.h
+++ b/src/tint/sem/struct.h
@@ -152,13 +152,7 @@
     /// including size and alignment information.
     std::string Layout(const tint::SymbolTable& symbols) const;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
   private:
-    uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
-
     ast::Struct const* const declaration_;
     const Symbol name_;
     const StructMemberList members_;
@@ -167,7 +161,6 @@
     const uint32_t size_no_padding_;
     std::unordered_set<ast::AddressSpace> address_space_usage_;
     std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
-    bool constructible_;
 };
 
 /// StructMember holds the semantic information for structure members.
diff --git a/src/tint/sem/texture.cc b/src/tint/sem/texture.cc
index 02fc918..5e5b1e2 100644
--- a/src/tint/sem/texture.cc
+++ b/src/tint/sem/texture.cc
@@ -18,7 +18,7 @@
 
 namespace tint::sem {
 
-Texture::Texture(ast::TextureDimension dim) : dim_(dim) {}
+Texture::Texture(ast::TextureDimension dim) : Base(TypeFlags{}), dim_(dim) {}
 
 Texture::Texture(Texture&&) = default;
 
diff --git a/src/tint/sem/type.cc b/src/tint/sem/type.cc
index fed75e6..7191fc6 100644
--- a/src/tint/sem/type.cc
+++ b/src/tint/sem/type.cc
@@ -34,7 +34,7 @@
 
 namespace tint::sem {
 
-Type::Type() = default;
+Type::Type(TypeFlags flags) : flags_(flags) {}
 
 Type::Type(Type&&) = default;
 
@@ -64,10 +64,6 @@
     return 0;
 }
 
-bool Type::IsConstructible() const {
-    return false;
-}
-
 bool Type::is_scalar() const {
     return IsAnyOf<F16, F32, U32, I32, AbstractNumeric, Bool>();
 }
diff --git a/src/tint/sem/type.h b/src/tint/sem/type.h
index ffa3d01..3b68946 100644
--- a/src/tint/sem/type.h
+++ b/src/tint/sem/type.h
@@ -19,6 +19,7 @@
 #include <string>
 
 #include "src/tint/sem/node.h"
+#include "src/tint/utils/enum_set.h"
 #include "src/tint/utils/vector.h"
 
 // Forward declarations
@@ -29,12 +30,21 @@
 
 namespace tint::sem {
 
-/// Supported memory layouts for calculating sizes
-enum class MemoryLayout { kUniformBuffer, kStorageBuffer };
+enum TypeFlag {
+    /// Type is constructable.
+    /// @see https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    kConstructable,
+};
+
+/// An alias to utils::EnumSet<TypeFlag>
+using TypeFlags = utils::EnumSet<TypeFlag>;
 
 /// Base class for a type in the system
 class Type : public Castable<Type, Node> {
   public:
+    /// Alias to TypeFlag
+    using Flag = TypeFlag;
+
     /// Move constructor
     Type(Type&&);
     ~Type() override;
@@ -66,9 +76,12 @@
     /// @note opaque types will return a size of 0.
     virtual uint32_t Align() const;
 
-    /// @returns true if constructible as per
+    /// @returns the flags on the type
+    TypeFlags Flags() { return flags_; }
+
+    /// @returns true if type is constructable
     /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    virtual bool IsConstructible() const;
+    inline bool IsConstructible() const { return flags_.Contains(Flag::kConstructable); }
 
     /// @returns true if this type is a scalar
     bool is_scalar() const;
@@ -166,7 +179,12 @@
     static const sem::Type* Common(utils::VectorRef<const Type*> types);
 
   protected:
-    Type();
+    /// Constructor
+    /// @param flags the flags of this type
+    explicit Type(TypeFlags flags);
+
+    /// The flags of this type.
+    const TypeFlags flags_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/u32.cc b/src/tint/sem/u32.cc
index dc3bd1d..91fd7d7 100644
--- a/src/tint/sem/u32.cc
+++ b/src/tint/sem/u32.cc
@@ -20,7 +20,7 @@
 
 namespace tint::sem {
 
-U32::U32() = default;
+U32::U32() : Base(TypeFlags{Flag::kConstructable}) {}
 
 U32::~U32() = default;
 
@@ -38,10 +38,6 @@
     return "u32";
 }
 
-bool U32::IsConstructible() const {
-    return true;
-}
-
 uint32_t U32::Size() const {
     return 4;
 }
diff --git a/src/tint/sem/u32.h b/src/tint/sem/u32.h
index 5ae01fb..b0143d9 100644
--- a/src/tint/sem/u32.h
+++ b/src/tint/sem/u32.h
@@ -42,10 +42,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the size in bytes of the type.
     uint32_t Size() const override;
 
diff --git a/src/tint/sem/vector.cc b/src/tint/sem/vector.cc
index 2df7cf0..e6d3acf 100644
--- a/src/tint/sem/vector.cc
+++ b/src/tint/sem/vector.cc
@@ -21,7 +21,8 @@
 
 namespace tint::sem {
 
-Vector::Vector(Type const* subtype, uint32_t width) : subtype_(subtype), width_(width) {
+Vector::Vector(Type const* subtype, uint32_t width)
+    : Base(TypeFlags{Flag::kConstructable}), subtype_(subtype), width_(width) {
     TINT_ASSERT(Semantic, width_ > 1);
     TINT_ASSERT(Semantic, width_ < 5);
 }
@@ -47,10 +48,6 @@
     return out.str();
 }
 
-bool Vector::IsConstructible() const {
-    return true;
-}
-
 uint32_t Vector::Size() const {
     return subtype_->Size() * width_;
 }
diff --git a/src/tint/sem/vector.h b/src/tint/sem/vector.h
index 8d9e7a3..163c70d 100644
--- a/src/tint/sem/vector.h
+++ b/src/tint/sem/vector.h
@@ -47,10 +47,6 @@
     /// declared in WGSL.
     std::string FriendlyName(const SymbolTable& symbols) const override;
 
-    /// @returns true if constructible as per
-    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-    bool IsConstructible() const override;
-
     /// @returns the number of elements in the vector
     uint32_t Width() const { return width_; }
 
diff --git a/src/tint/sem/void.cc b/src/tint/sem/void.cc
index b20b96e..8e5e3fb 100644
--- a/src/tint/sem/void.cc
+++ b/src/tint/sem/void.cc
@@ -20,7 +20,7 @@
 
 namespace tint::sem {
 
-Void::Void() = default;
+Void::Void() : Base(TypeFlags{}) {}
 
 Void::Void(Void&&) = default;