tint: Replace type::UniqueNode::Hash() virtual with field

Virtual methods are expensive to call, and hashes are frequently tested.
The hash must be immutable, so just calculate it once in the constructor and store it as an immutable field.

Change-Id: I9d29fb3fc074e57e7af91367768a47193baa40f1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/114780
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/type/pointer.cc b/src/tint/type/pointer.cc
index 00c3d22..0ae8e0a 100644
--- a/src/tint/type/pointer.cc
+++ b/src/tint/type/pointer.cc
@@ -23,15 +23,15 @@
 namespace tint::type {
 
 Pointer::Pointer(const Type* subtype, ast::AddressSpace address_space, ast::Access access)
-    : Base(type::Flags{}), subtype_(subtype), address_space_(address_space), access_(access) {
+    : Base(utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, address_space, subtype, access),
+           type::Flags{}),
+      subtype_(subtype),
+      address_space_(address_space),
+      access_(access) {
     TINT_ASSERT(Type, !subtype->Is<Reference>());
     TINT_ASSERT(Type, access != ast::Access::kUndefined);
 }
 
-size_t Pointer::Hash() const {
-    return utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, address_space_, subtype_, access_);
-}
-
 bool Pointer::Equals(const UniqueNode& other) const {
     if (auto* o = other.As<Pointer>()) {
         return o->address_space_ == address_space_ && o->subtype_ == subtype_ &&
@@ -51,8 +51,6 @@
     return out.str();
 }
 
-Pointer::Pointer(Pointer&&) = default;
-
 Pointer::~Pointer() = default;
 
 }  // namespace tint::type