Remove more uses of AST to_str() and type_name()

These methods are going to be removed as they provide little benefit over the WGSL form, are a maintainance burden and they massively bloat our codebase.

This change introduces sem::CallTargetSignature, which can be used as a std::unordered_map key.
This is used in writer/spirv to replace a map that was keyed off ast::Function::type_name().

Bug: tint:1225
Change-Id: Ic220b3155011f21b14d49eecc8042001148e4ca5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/66443
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index d244c11..d4fa744 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -806,13 +806,13 @@
       continue;
     }
 
-    const auto& params = i->Parameters();
-    int sampler_index = sem::IndexOf(params, sem::ParameterUsage::kSampler);
+    const auto& signature = i->Signature();
+    int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
     if (sampler_index == -1) {
       continue;
     }
 
-    int texture_index = sem::IndexOf(params, sem::ParameterUsage::kTexture);
+    int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
     if (texture_index == -1) {
       continue;
     }
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 1efef81..bda54c0 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -1495,7 +1495,7 @@
   // with elem stride of 16, and that is 16-byte aligned within the struct)
   ast::Struct* foo_struct_type = Structure(
       "foo_type",
-      {Member("0__i32", ty.i32()),
+      {Member("0i32", ty.i32()),
        Member("b", ty.array(ty.u32(), 4, /*stride*/ 16), {MemberAlign(16)})},
       {create<ast::StructBlockDecoration>()});
 
diff --git a/src/inspector/test_inspector_builder.cc b/src/inspector/test_inspector_builder.cc
index b364218..1d42d58 100644
--- a/src/inspector/test_inspector_builder.cc
+++ b/src/inspector/test_inspector_builder.cc
@@ -84,7 +84,7 @@
 }
 
 std::string InspectorBuilder::StructMemberName(size_t idx, ast::Type* type) {
-  return std::to_string(idx) + type->type_name();
+  return std::to_string(idx) + type->FriendlyName(Symbols());
 }
 
 ast::Struct* InspectorBuilder::MakeStructType(
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index cc64de0..2afd09c 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2538,8 +2538,8 @@
     return false;
   }
   std::string func_name = intrinsic->str();
-  auto index =
-      sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kOffset);
+  auto& signature = intrinsic->Signature();
+  auto index = signature.IndexOf(sem::ParameterUsage::kOffset);
   if (index > -1) {
     auto* param = ast_call->args()[index];
     if (param->Is<ast::TypeConstructorExpression>()) {
diff --git a/src/sem/call_target.cc b/src/sem/call_target.cc
index b8bf12c..9ea38bf 100644
--- a/src/sem/call_target.cc
+++ b/src/sem/call_target.cc
@@ -15,6 +15,7 @@
 #include "src/sem/call_target.h"
 
 #include "src/symbol_table.h"
+#include "src/utils/hash.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::CallTarget);
 
@@ -22,15 +23,20 @@
 namespace sem {
 
 CallTarget::CallTarget(sem::Type* return_type, const ParameterList& parameters)
-    : return_type_(return_type), parameters_(parameters) {
+    : signature_{return_type, parameters} {
   TINT_ASSERT(Semantic, return_type);
 }
 
 CallTarget::CallTarget(const CallTarget&) = default;
-
 CallTarget::~CallTarget() = default;
 
-int IndexOf(const ParameterList& parameters, ParameterUsage usage) {
+CallTargetSignature::CallTargetSignature(sem::Type* ret_ty,
+                                         const ParameterList& params)
+    : return_type(ret_ty), parameters(params) {}
+CallTargetSignature::CallTargetSignature(const CallTargetSignature&) = default;
+CallTargetSignature::~CallTargetSignature() = default;
+
+int CallTargetSignature::IndexOf(ParameterUsage usage) const {
   for (size_t i = 0; i < parameters.size(); i++) {
     if (parameters[i]->Usage() == usage) {
       return static_cast<int>(i);
@@ -39,5 +45,33 @@
   return -1;
 }
 
+bool CallTargetSignature::operator==(const CallTargetSignature& other) const {
+  if (return_type != other.return_type ||
+      parameters.size() != other.parameters.size()) {
+    return false;
+  }
+  for (size_t i = 0; i < parameters.size(); i++) {
+    auto* a = parameters[i];
+    auto* b = other.parameters[i];
+    if (a->Type() != b->Type() || a->Usage() != b->Usage()) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace sem
 }  // namespace tint
+
+namespace std {
+
+std::size_t hash<tint::sem::CallTargetSignature>::operator()(
+    const tint::sem::CallTargetSignature& sig) const {
+  size_t hash = tint::utils::Hash(sig.parameters.size());
+  for (auto* p : sig.parameters) {
+    tint::utils::HashCombine(&hash, p->Type(), p->Usage());
+  }
+  return tint::utils::Hash(hash, sig.return_type);
+}
+
+}  // namespace std
diff --git a/src/sem/call_target.h b/src/sem/call_target.h
index 33d5029..c0e7b8e 100644
--- a/src/sem/call_target.h
+++ b/src/sem/call_target.h
@@ -27,11 +27,34 @@
 // Forward declarations
 class Type;
 
-/// @param parameters the list of parameters
-/// @param usage the parameter usage to find
-/// @returns the index of the parameter with the given usage, or -1 if no
-/// parameter with the given usage exists.
-int IndexOf(const ParameterList& parameters, ParameterUsage usage);
+/// CallTargetSignature holds the return type and parameters for a call target
+struct CallTargetSignature {
+  /// Constructor
+  /// @param ret_ty the call target return type
+  /// @param params the call target parameters
+  CallTargetSignature(sem::Type* ret_ty, const ParameterList& params);
+
+  /// Copy constructor
+  CallTargetSignature(const CallTargetSignature&);
+
+  /// Destructor
+  ~CallTargetSignature();
+
+  /// The type of the call target return value
+  sem::Type* const return_type = nullptr;
+  /// The parameters of the call target
+  ParameterList const parameters;
+
+  /// Equality operator
+  /// @param other the signature to compare this to
+  /// @returns true if this signature is equal to other
+  bool operator==(const CallTargetSignature& other) const;
+
+  /// @param usage the parameter usage to find
+  /// @returns the index of the parameter with the given usage, or -1 if no
+  /// parameter with the given usage exists.
+  int IndexOf(ParameterUsage usage) const;
+};
 
 /// CallTarget is the base for callable functions
 class CallTarget : public Castable<CallTarget, Node> {
@@ -44,21 +67,38 @@
   /// Copy constructor
   CallTarget(const CallTarget&);
 
-  /// @return the return type of the call target
-  sem::Type* ReturnType() const { return return_type_; }
-
   /// Destructor
   ~CallTarget() override;
 
+  /// @return the return type of the call target
+  sem::Type* ReturnType() const { return signature_.return_type; }
+
   /// @return the parameters of the call target
-  const ParameterList& Parameters() const { return parameters_; }
+  const ParameterList& Parameters() const { return signature_.parameters; }
+
+  /// @return the signature of the call target
+  const CallTargetSignature& Signature() const { return signature_; }
 
  private:
-  sem::Type* const return_type_;
-  ParameterList const parameters_;
+  CallTargetSignature signature_;
 };
 
 }  // namespace sem
 }  // namespace tint
 
+namespace std {
+
+/// Custom std::hash specialization for tint::sem::CallTargetSignature so
+/// CallTargetSignature can be used as keys for std::unordered_map and
+/// std::unordered_set.
+template <>
+class hash<tint::sem::CallTargetSignature> {
+ public:
+  /// @param sig the CallTargetSignature to hash
+  /// @return the hash value
+  std::size_t operator()(const tint::sem::CallTargetSignature& sig) const;
+};
+
+}  // namespace std
+
 #endif  // SRC_SEM_CALL_TARGET_H_
diff --git a/src/transform/robustness.cc b/src/transform/robustness.cc
index b6a111e..a5f1eac 100644
--- a/src/transform/robustness.cc
+++ b/src/transform/robustness.cc
@@ -208,14 +208,11 @@
 
     // Indices of the mandatory texture and coords parameters, and the optional
     // array and level parameters.
-    auto texture_idx =
-        sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kTexture);
-    auto coords_idx =
-        sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kCoords);
-    auto array_idx =
-        sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kArrayIndex);
-    auto level_idx =
-        sem::IndexOf(intrinsic->Parameters(), sem::ParameterUsage::kLevel);
+    auto& signature = intrinsic->Signature();
+    auto texture_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
+    auto coords_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
+    auto array_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
+    auto level_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
 
     auto* texture_arg = expr->args()[texture_idx];
     auto* coords_arg = expr->args()[coords_idx];
diff --git a/src/writer/glsl/generator_impl.cc b/src/writer/glsl/generator_impl.cc
index 91fb6dc..54aa31e 100644
--- a/src/writer/glsl/generator_impl.cc
+++ b/src/writer/glsl/generator_impl.cc
@@ -960,12 +960,12 @@
                                     const sem::Intrinsic* intrinsic) {
   using Usage = sem::ParameterUsage;
 
-  auto parameters = intrinsic->Parameters();
+  auto& signature = intrinsic->Signature();
   auto arguments = expr->args();
 
   // Returns the argument with the given usage
   auto arg = [&](Usage usage) {
-    int idx = sem::IndexOf(parameters, usage);
+    int idx = signature.IndexOf(usage);
     return (idx >= 0) ? arguments[idx] : nullptr;
   };
 
@@ -1395,8 +1395,9 @@
     return EmitUnaryOp(out, u);
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown expression type: " + builder_.str(expr));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown expression type: " + std::string(expr->TypeInfo().name));
   return false;
 }
 
@@ -2235,8 +2236,9 @@
     return EmitVariable(v->variable());
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown statement type: " + builder_.str(stmt));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown statement type: " + std::string(stmt->TypeInfo().name));
   return false;
 }
 
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 7301166..90eeaa0 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -1620,12 +1620,12 @@
                                     const sem::Intrinsic* intrinsic) {
   using Usage = sem::ParameterUsage;
 
-  auto parameters = intrinsic->Parameters();
+  auto& signature = intrinsic->Signature();
   auto arguments = expr->args();
 
   // Returns the argument with the given usage
   auto arg = [&](Usage usage) {
-    int idx = sem::IndexOf(parameters, usage);
+    int idx = signature.IndexOf(usage);
     return (idx >= 0) ? arguments[idx] : nullptr;
   };
 
@@ -2215,8 +2215,9 @@
     return EmitUnaryOp(out, u);
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown expression type: " + builder_.str(expr));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown expression type: " + std::string(expr->TypeInfo().name));
   return false;
 }
 
@@ -2934,8 +2935,9 @@
     return EmitVariable(v->variable());
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown statement type: " + builder_.str(stmt));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown statement type: " + std::string(stmt->TypeInfo().name));
   return false;
 }
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 6c839fb..89e8d06 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -764,12 +764,12 @@
                                     const sem::Intrinsic* intrinsic) {
   using Usage = sem::ParameterUsage;
 
-  auto parameters = intrinsic->Parameters();
+  auto& signature = intrinsic->Signature();
   auto arguments = expr->args();
 
   // Returns the argument with the given usage
   auto arg = [&](Usage usage) {
-    int idx = sem::IndexOf(parameters, usage);
+    int idx = signature.IndexOf(usage);
     return (idx >= 0) ? arguments[idx] : nullptr;
   };
 
@@ -1427,8 +1427,9 @@
     return EmitUnaryOp(out, u);
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown expression type: " + program_->str(expr));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown expression type: " + std::string(expr->TypeInfo().name));
   return false;
 }
 
@@ -2052,8 +2053,9 @@
     return EmitVariable(var);
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown statement type: " + program_->str(stmt));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown statement type: " + std::string(stmt->TypeInfo().name));
   return false;
 }
 
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 23be508..0de0335 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -584,7 +584,7 @@
     return GenerateUnaryOpExpression(u);
   }
 
-  error_ = "unknown expression type: " + builder_.str(expr);
+  error_ = "unknown expression type: " + std::string(expr->TypeInfo().name);
   return 0;
 }
 
@@ -659,32 +659,28 @@
 }
 
 uint32_t Builder::GenerateFunctionTypeIfNeeded(const sem::Function* func) {
-  auto val = type_name_to_id_.find(func->Declaration()->type_name());
-  if (val != type_name_to_id_.end()) {
-    return val->second;
-  }
+  return utils::GetOrCreate(
+      func_sig_to_id_, func->Signature(), [&]() -> uint32_t {
+        auto func_op = result_op();
+        auto func_type_id = func_op.to_i();
 
-  auto func_op = result_op();
-  auto func_type_id = func_op.to_i();
+        auto ret_id = GenerateTypeIfNeeded(func->ReturnType());
+        if (ret_id == 0) {
+          return 0;
+        }
 
-  auto ret_id = GenerateTypeIfNeeded(func->ReturnType());
-  if (ret_id == 0) {
-    return 0;
-  }
+        OperandList ops = {func_op, Operand::Int(ret_id)};
+        for (auto* param : func->Parameters()) {
+          auto param_type_id = GenerateTypeIfNeeded(param->Type());
+          if (param_type_id == 0) {
+            return 0;
+          }
+          ops.push_back(Operand::Int(param_type_id));
+        }
 
-  OperandList ops = {func_op, Operand::Int(ret_id)};
-  for (auto* param : func->Parameters()) {
-    auto param_type_id = GenerateTypeIfNeeded(param->Type());
-    if (param_type_id == 0) {
-      return 0;
-    }
-    ops.push_back(Operand::Int(param_type_id));
-  }
-
-  push_type(spv::Op::OpTypeFunction, std::move(ops));
-
-  type_name_to_id_[func->Declaration()->type_name()] = func_type_id;
-  return func_type_id;
+        push_type(spv::Op::OpTypeFunction, std::move(ops));
+        return func_type_id;
+      });
 }
 
 bool Builder::GenerateFunctionVariable(ast::Variable* var) {
@@ -1139,7 +1135,8 @@
       }
 
     } else {
-      error_ = "invalid accessor in list: " + builder_.str(accessor);
+      error_ =
+          "invalid accessor in list: " + std::string(accessor->TypeInfo().name);
       return 0;
     }
   }
@@ -2662,7 +2659,7 @@
                                        Operand result_id) {
   using Usage = sem::ParameterUsage;
 
-  auto parameters = intrinsic->Parameters();
+  auto& signature = intrinsic->Signature();
   auto arguments = call->args();
 
   // Generates the given expression, returning the operand ID
@@ -2678,7 +2675,7 @@
 
   // Returns the argument with the given usage
   auto arg = [&](Usage usage) {
-    int idx = sem::IndexOf(parameters, usage);
+    int idx = signature.IndexOf(usage);
     return (idx >= 0) ? arguments[idx] : nullptr;
   };
 
@@ -3785,7 +3782,7 @@
     return GenerateVariableDeclStatement(v);
   }
 
-  error_ = "Unknown statement: " + builder_.str(stmt);
+  error_ = "Unknown statement: " + std::string(stmt->TypeInfo().name);
   return false;
 }
 
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 8af4cf2..baa4d7f 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -585,6 +585,7 @@
 
   std::unordered_map<std::string, uint32_t> import_name_to_id_;
   std::unordered_map<Symbol, uint32_t> func_symbol_to_id_;
+  std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_;
   std::unordered_map<std::string, uint32_t> type_name_to_id_;
   std::unordered_map<ScalarConstant, uint32_t> const_to_id_;
   std::unordered_map<std::string, uint32_t> type_constructor_to_id_;
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 1d12bcb..c226b1f 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -524,8 +524,9 @@
   } else if (auto* tn = ty->As<ast::TypeName>()) {
     out << program_->Symbols().NameFor(tn->name());
   } else {
-    diagnostics_.add_error(diag::System::Writer,
-                           "unknown type in EmitType: " + ty->type_name());
+    diagnostics_.add_error(
+        diag::System::Writer,
+        "unknown type in EmitType: " + std::string(ty->TypeInfo().name));
     return false;
   }
   return true;
@@ -869,8 +870,9 @@
     return EmitVariable(line(), v->variable());
   }
 
-  diagnostics_.add_error(diag::System::Writer,
-                         "unknown statement type: " + program_->str(stmt));
+  diagnostics_.add_error(
+      diag::System::Writer,
+      "unknown statement type: " + std::string(stmt->TypeInfo().name));
   return false;
 }