[ir] Move type member to Value base class

All but one subclass of Value declared its own type member and
SetType() method, as well as overriding the virtual Type()
getter. Instead, just declare the type in the base class and define
those methods in the base class too.

As well as removing an unnecessary virtual method and duplicated code
in the subclasses, this also makes it possible to call SetType() on a
value without first casting it to a subclass, which is used to
slightly simplify a callsite in ChangeImmediateToUniform.

Change-Id: Ib1f34b01fef841071e02a868a216b76cfe517f80
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/271117
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/block_param.cc b/src/tint/lang/core/ir/block_param.cc
index a0157cc..9ea1bb3 100644
--- a/src/tint/lang/core/ir/block_param.cc
+++ b/src/tint/lang/core/ir/block_param.cc
@@ -35,14 +35,14 @@
 
 namespace tint::core::ir {
 
-BlockParam::BlockParam(const core::type::Type* ty) : type_(ty) {
-    TINT_ASSERT(type_ != nullptr);
+BlockParam::BlockParam(const core::type::Type* ty) : Base(ty) {
+    TINT_ASSERT(ty != nullptr);
 }
 
 BlockParam::~BlockParam() = default;
 
 BlockParam* BlockParam::Clone(CloneContext& ctx) {
-    auto* new_bp = ctx.ir.CreateValue<BlockParam>(type_);
+    auto* new_bp = ctx.ir.CreateValue<BlockParam>(Type());
 
     auto name = ctx.ir.NameOf(this);
     if (name.IsValid()) {
diff --git a/src/tint/lang/core/ir/block_param.h b/src/tint/lang/core/ir/block_param.h
index 0b697a2..0d0ee82 100644
--- a/src/tint/lang/core/ir/block_param.h
+++ b/src/tint/lang/core/ir/block_param.h
@@ -46,9 +46,6 @@
     explicit BlockParam(const core::type::Type* type);
     ~BlockParam() override;
 
-    /// @returns the type of the parameter
-    const core::type::Type* Type() const override { return type_; }
-
     /// Sets the block that this parameter belongs to.
     /// @param block the block
     void SetBlock(MultiInBlock* block) { block_ = block; }
@@ -63,8 +60,6 @@
     BlockParam* Clone(CloneContext& ctx) override;
 
   private:
-    /// the type of the parameter
-    const core::type::Type* type_ = nullptr;
     /// the block that the parameter belongs to
     MultiInBlock* block_ = nullptr;
 };
diff --git a/src/tint/lang/core/ir/constant.cc b/src/tint/lang/core/ir/constant.cc
index b43d17a..97907e4 100644
--- a/src/tint/lang/core/ir/constant.cc
+++ b/src/tint/lang/core/ir/constant.cc
@@ -32,8 +32,9 @@
 
 namespace tint::core::ir {
 
-Constant::Constant(const core::constant::Value* val) : value_(val) {
+Constant::Constant(const core::constant::Value* val) : Base(nullptr), value_(val) {
     TINT_ASSERT(value_);
+    SetType(val->Type());
 }
 
 Constant::~Constant() = default;
diff --git a/src/tint/lang/core/ir/constant.h b/src/tint/lang/core/ir/constant.h
index c5fb574..0a57e3b 100644
--- a/src/tint/lang/core/ir/constant.h
+++ b/src/tint/lang/core/ir/constant.h
@@ -44,9 +44,6 @@
     /// @returns the constants value
     const core::constant::Value* Value() const { return value_; }
 
-    /// @returns the type of the constant
-    const core::type::Type* Type() const override { return value_->Type(); }
-
     /// @copydoc Value::Clone()
     Constant* Clone(CloneContext& ctx) override;
 
diff --git a/src/tint/lang/core/ir/function.cc b/src/tint/lang/core/ir/function.cc
index a618bfd..7479ec1 100644
--- a/src/tint/lang/core/ir/function.cc
+++ b/src/tint/lang/core/ir/function.cc
@@ -36,13 +36,13 @@
 
 namespace tint::core::ir {
 
-Function::Function() = default;
+Function::Function() : Base(nullptr) {}
 
 Function::Function(const core::type::Type* type,
                    const core::type::Type* rt,
                    PipelineStage stage,
                    std::optional<std::array<Value*, 3>> wg_size)
-    : pipeline_stage_(stage), workgroup_size_(wg_size), type_(type) {
+    : Base(type), pipeline_stage_(stage), workgroup_size_(wg_size) {
     TINT_ASSERT(rt != nullptr);
 
     return_.type = rt;
@@ -52,7 +52,7 @@
 
 Function* Function::Clone(CloneContext& ctx) {
     auto* new_func =
-        ctx.ir.CreateValue<Function>(type_, return_.type, pipeline_stage_, workgroup_size_);
+        ctx.ir.CreateValue<Function>(Type(), return_.type, pipeline_stage_, workgroup_size_);
     new_func->block_ = ctx.ir.blocks.Create<ir::Block>();
     new_func->SetParams(ctx.Clone<1>(params_.Slice()));
     new_func->return_.attributes = return_.attributes;
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index fffe873..e43f0ab 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -76,9 +76,6 @@
              std::optional<std::array<Value*, 3>> wg_size = {});
     ~Function() override;
 
-    /// @copydoc Value::Type()
-    const core::type::Type* Type() const override { return type_; }
-
     /// @copydoc Instruction::Clone()
     Function* Clone(CloneContext& ctx) override;
 
@@ -137,9 +134,6 @@
         }};
     }
 
-    /// @param type the type to return via ->Type()
-    void SetType(const core::type::Type* type) { type_ = type; }
-
     /// @param type the return type for the function
     void SetReturnType(const core::type::Type* type) { return_.type = type; }
 
@@ -224,8 +218,6 @@
     PipelineStage pipeline_stage_ = PipelineStage::kUndefined;
     std::optional<std::array<Value*, 3>> workgroup_size_;
 
-    const core::type::Type* type_ = nullptr;
-
     struct {
         const core::type::Type* type = nullptr;
         IOAttributes attributes = {};
diff --git a/src/tint/lang/core/ir/function_param.cc b/src/tint/lang/core/ir/function_param.cc
index f73d691..bb2f00a 100644
--- a/src/tint/lang/core/ir/function_param.cc
+++ b/src/tint/lang/core/ir/function_param.cc
@@ -36,12 +36,12 @@
 
 namespace tint::core::ir {
 
-FunctionParam::FunctionParam(const core::type::Type* ty) : type_(ty) {}
+FunctionParam::FunctionParam(const core::type::Type* ty) : Base(ty) {}
 
 FunctionParam::~FunctionParam() = default;
 
 FunctionParam* FunctionParam::Clone(CloneContext& ctx) {
-    auto* out = ctx.ir.CreateValue<FunctionParam>(type_);
+    auto* out = ctx.ir.CreateValue<FunctionParam>(Type());
     out->attributes_ = attributes_;
 
     auto name = ctx.ir.NameOf(this);
diff --git a/src/tint/lang/core/ir/function_param.h b/src/tint/lang/core/ir/function_param.h
index bde38b1..d39a59d 100644
--- a/src/tint/lang/core/ir/function_param.h
+++ b/src/tint/lang/core/ir/function_param.h
@@ -70,13 +70,6 @@
     /// @returns the index of the parameter in the function's parameter list
     uint32_t Index() const { return index_; }
 
-    /// @returns the type of the var
-    const core::type::Type* Type() const override { return type_; }
-
-    /// Sets the type of the parameter to @p type
-    /// @param type the new type of the parameter
-    void SetType(const core::type::Type* type) { type_ = type; }
-
     /// @copydoc Value::Clone()
     FunctionParam* Clone(CloneContext& ctx) override;
 
@@ -148,7 +141,6 @@
   private:
     ir::Function* func_ = nullptr;
     uint32_t index_ = 0xffffffff;
-    const core::type::Type* type_ = nullptr;
     IOAttributes attributes_;
 };
 
diff --git a/src/tint/lang/core/ir/instruction_result.cc b/src/tint/lang/core/ir/instruction_result.cc
index e88463b..9eb99f7 100644
--- a/src/tint/lang/core/ir/instruction_result.cc
+++ b/src/tint/lang/core/ir/instruction_result.cc
@@ -37,8 +37,8 @@
 
 namespace tint::core::ir {
 
-InstructionResult::InstructionResult(const core::type::Type* type) : type_(type) {
-    TINT_ASSERT(type_ != nullptr);
+InstructionResult::InstructionResult(const core::type::Type* type) : Base(type) {
+    TINT_ASSERT(type != nullptr);
 }
 
 InstructionResult::~InstructionResult() = default;
@@ -51,7 +51,7 @@
 InstructionResult* InstructionResult::Clone(CloneContext& ctx) {
     // Do not clone the `Instruction`. It will be set when this result is placed in the new parent
     // instruction.
-    return ctx.ir.CreateValue<InstructionResult>(type_);
+    return ctx.ir.CreateValue<InstructionResult>(Type());
 }
 
 }  // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/instruction_result.h b/src/tint/lang/core/ir/instruction_result.h
index 5aecd6e..58fd8d2 100644
--- a/src/tint/lang/core/ir/instruction_result.h
+++ b/src/tint/lang/core/ir/instruction_result.h
@@ -36,7 +36,7 @@
 class InstructionResult : public Castable<InstructionResult, Value> {
   public:
     /// Constructor
-    InstructionResult() = default;
+    InstructionResult() : Base(nullptr) {}
 
     /// Constructor
     /// @param type the type of the value
@@ -51,13 +51,6 @@
     /// @copydoc Value::Clone()
     InstructionResult* Clone(CloneContext& ctx) override;
 
-    /// Sets the type of the value to @p type
-    /// @param type the new type of the value
-    void SetType(const core::type::Type* type) { type_ = type; }
-
-    /// @returns the type of the value
-    const core::type::Type* Type() const override { return type_; }
-
     /// Sets the instruction for this value
     /// @param inst the instruction to set
     void SetInstruction(Instruction* inst) { instruction_ = inst; }
@@ -70,7 +63,6 @@
 
   private:
     ir::Instruction* instruction_ = nullptr;
-    const core::type::Type* type_ = nullptr;
 };
 
 }  // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/transform/change_immediate_to_uniform.cc b/src/tint/lang/core/ir/transform/change_immediate_to_uniform.cc
index 7a86792..7efda65 100644
--- a/src/tint/lang/core/ir/transform/change_immediate_to_uniform.cc
+++ b/src/tint/lang/core/ir/transform/change_immediate_to_uniform.cc
@@ -121,16 +121,7 @@
                 // when the function is called multiple times.
                 continue;
             }
-
-            // Change the type of the value.
-            auto* new_ptr_type = ty.ptr(core::AddressSpace::kUniform, ptr_type->StoreType());
-            if (auto* result = value->As<InstructionResult>()) {
-                result->SetType(new_ptr_type);
-            } else if (auto* param = value->As<FunctionParam>()) {
-                param->SetType(new_ptr_type);
-            } else {
-                TINT_IR_UNREACHABLE(ir);
-            }
+            value->SetType(ty.ptr(core::AddressSpace::kUniform, ptr_type->StoreType()));
 
             // Add all usages of the value to the queue.
             for (auto usage : value->UsagesUnsorted()) {
diff --git a/src/tint/lang/core/ir/unused.cc b/src/tint/lang/core/ir/unused.cc
index 37f8b24..5f6d20b 100644
--- a/src/tint/lang/core/ir/unused.cc
+++ b/src/tint/lang/core/ir/unused.cc
@@ -34,7 +34,7 @@
 
 namespace tint::core::ir {
 
-Unused::Unused() = default;
+Unused::Unused() : Base(nullptr) {}
 
 Unused::~Unused() = default;
 
diff --git a/src/tint/lang/core/ir/value.cc b/src/tint/lang/core/ir/value.cc
index 8d8fb7e..dfbb268 100644
--- a/src/tint/lang/core/ir/value.cc
+++ b/src/tint/lang/core/ir/value.cc
@@ -37,7 +37,7 @@
 
 namespace tint::core::ir {
 
-Value::Value() = default;
+Value::Value(const core::type::Type* type) : type_(type) {}
 
 Value::~Value() = default;
 
diff --git a/src/tint/lang/core/ir/value.h b/src/tint/lang/core/ir/value.h
index 54879fa..eff4347 100644
--- a/src/tint/lang/core/ir/value.h
+++ b/src/tint/lang/core/ir/value.h
@@ -81,7 +81,11 @@
     ~Value() override;
 
     /// @returns the type of the value
-    virtual const core::type::Type* Type() const { return nullptr; }
+    const core::type::Type* Type() const { return type_; }
+
+    /// Sets the type of the value to @p type
+    /// @param type the new type of the value
+    void SetType(const core::type::Type* type) { type_ = type; }
 
     /// Destroys the Value. Once called, the Value must not be used again.
     /// The Value must not be in use by any instruction.
@@ -144,7 +148,8 @@
 
   protected:
     /// Constructor
-    Value();
+    /// @param type the type of the value
+    explicit Value(const core::type::Type* type);
 
   private:
     /// Flags applied to an Value
@@ -153,6 +158,7 @@
         kDead,
     };
 
+    const core::type::Type* type_ = nullptr;
     Hashset<Usage, 4> uses_;
 
     /// Bitset of value flags