compiler: add Type::message_name

As we move toward generics, the error messages need to be able
to refer to types in a readable manner.  Add that capability,
and use it today in AST dumps.

Change-Id: I4284a7ce748276816dc8abec34c672747fd59875
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536716
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
diff --git a/go/ast-dump.cc b/go/ast-dump.cc
index eca0bf1..12f49e6 100644
--- a/go/ast-dump.cc
+++ b/go/ast-dump.cc
@@ -223,14 +223,7 @@
   if (t == NULL)
     this->ostream() << "(nil type)";
   else
-    // FIXME: write a type pretty printer instead of
-    // using mangled names.
-    if (this->gogo_ != NULL)
-      {
-	Backend_name bname;
-	t->backend_name(this->gogo_, &bname);
-	this->ostream() << "(" << bname.name() << ")";
-      }
+    this->ostream() << "(" << t->message_name() << ")";
 }
 
 // Dump a textual representation of a block to the
diff --git a/go/types.cc b/go/types.cc
index b349ad1..a39cfbf 100644
--- a/go/types.cc
+++ b/go/types.cc
@@ -270,6 +270,16 @@
   this->classification_ = TYPE_ERROR;
 }
 
+// Return a string version of this type to use in an error message.
+
+std::string
+Type::message_name() const
+{
+  std::string ret;
+  this->do_message_name(&ret);
+  return ret;
+}
+
 // If this is a pointer type, return the type to which it points.
 // Otherwise, return NULL.
 
@@ -742,16 +752,14 @@
     {
       if (rhs->interface_type() != NULL)
 	reason->assign(_("need explicit conversion"));
-      else if (lhs_orig->named_type() != NULL
-	       && rhs_orig->named_type() != NULL)
+      else
 	{
-	  size_t len = (lhs_orig->named_type()->name().length()
-			+ rhs_orig->named_type()->name().length()
-			+ 100);
+	  const std::string& lhs_name(lhs_orig->message_name());
+	  const std::string& rhs_name(rhs_orig->message_name());
+	  size_t len = lhs_name.length() + rhs_name.length() + 100;
 	  char* buf = new char[len];
 	  snprintf(buf, len, _("cannot use type %s as type %s"),
-		   rhs_orig->named_type()->message_name().c_str(),
-		   lhs_orig->named_type()->message_name().c_str());
+		   rhs_name.c_str(), lhs_name.c_str());
 	  reason->assign(buf);
 	  delete[] buf;
 	}
@@ -4244,6 +4252,33 @@
   return this->is_abstract_ == t->is_abstract_;
 }
 
+// Message name.
+
+void
+Integer_type::do_message_name(std::string* ret) const
+{
+  ret->append("<untyped ");
+  if (this->is_byte_)
+    ret->append("byte");
+  else if (this->is_rune_)
+    ret->append("rune");
+  else
+    {
+      if (this->is_unsigned_)
+	ret->push_back('u');
+      if (this->is_abstract_)
+	ret->append("int");
+      else
+	{
+	  ret->append("int");
+	  char buf[10];
+	  snprintf(buf, sizeof buf, "%d", this->bits_);
+	  ret->append(buf);
+	}
+    }
+  ret->push_back('>');
+}
+
 // Hash code.
 
 unsigned int
@@ -4382,6 +4417,21 @@
   return this->is_abstract_ == t->is_abstract_;
 }
 
+// Message name.
+
+void
+Float_type::do_message_name(std::string* ret) const
+{
+  ret->append("<untyped float");
+  if (!this->is_abstract_)
+    {
+      char buf[10];
+      snprintf(buf, sizeof buf, "%d", this->bits_);
+      ret->append(buf);
+    }
+  ret->push_back('>');
+}
+
 // Hash code.
 
 unsigned int
@@ -4496,6 +4546,21 @@
   return this->is_abstract_ == t->is_abstract_;
 }
 
+// Message name.
+
+void
+Complex_type::do_message_name(std::string* ret) const
+{
+  ret->append("<untyped complex");
+  if (!this->is_abstract_)
+    {
+      char buf[10];
+      snprintf(buf, sizeof buf, "%d", this->bits_);
+      ret->append(buf);
+    }
+  ret->push_back('>');
+}
+
 // Hash code.
 
 unsigned int
@@ -4661,6 +4726,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<SINK>"); }
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -4696,6 +4765,70 @@
 
 // Class Function_type.
 
+// Message name.
+
+void
+Function_type::do_message_name(std::string* ret) const
+{
+  ret->append("func");
+  if (this->receiver_ != NULL)
+    {
+      ret->append(" (receiver ");
+      this->append_message_name(this->receiver_->type(), ret);
+      ret->append(") ");
+    }
+  this->append_signature(ret);
+}
+
+// Append just the signature to RET.
+
+void
+Function_type::append_signature(std::string* ret) const
+{
+  ret->push_back('(');
+  if (this->parameters_ != NULL)
+    {
+      bool first = true;
+      for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
+	   p != this->parameters_->end();
+	   ++p)
+	{
+	  if (first)
+	    first = false;
+	  else
+	    ret->append(", ");
+	  this->append_message_name(p->type(), ret);
+	}
+    }
+  ret->push_back(')');
+
+  if (this->results_ != NULL)
+    {
+      if (this->results_->size() == 1)
+	{
+	  ret->push_back(' ');
+	  this->append_message_name(this->results_->front().type(), ret);
+	}
+      else
+	{
+	  ret->append(" (");
+	  bool first = true;
+	  for (Typed_identifier_list::const_iterator p =
+		 this->results_->begin();
+	       p != this->results_->end();
+	       ++p)
+	    {
+	      if (first)
+		first = false;
+	      else
+		ret->append(", ");
+	      this->append_message_name(p->type(), ret);
+	    }
+	  ret->push_back(')');
+	}
+    }
+}
+
 // Traversal.
 
 int
@@ -5548,6 +5681,20 @@
 
 // Class Pointer_type.
 
+// Message name.
+
+void
+Pointer_type::do_message_name(std::string* ret) const
+{
+  if (this->to_type_->is_void_type())
+    ret->append("unsafe.Pointer");
+  else
+    {
+      ret->push_back('*');
+      this->append_message_name(this->to_type_, ret);
+    }
+}
+
 // Traversal.
 
 int
@@ -5764,6 +5911,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<call-multiple-result>"); }
+
   bool
   do_has_pointer() const
   { return false; }
@@ -5940,6 +6091,41 @@
 
 Struct_type::Struct_method_tables Struct_type::struct_method_tables;
 
+// Message name.
+
+void
+Struct_type::do_message_name(std::string* ret) const
+{
+  if (this->fields_ == NULL || this->fields_->empty())
+    {
+      ret->append("struct{}");
+      return;
+    }
+
+  ret->append("struct {");
+
+  bool first = true;
+  for (Struct_field_list::const_iterator p = this->fields_->begin();
+       p != this->fields_->end();
+       ++p)
+    {
+      if (first)
+	first = false;
+      else
+	ret->append("; ");
+
+      if (!p->is_anonymous())
+	{
+	  ret->append(p->field_name());
+	  ret->push_back(' ');
+	}
+
+      this->append_message_name(p->type(), ret);
+    }
+
+  ret->append(" }");
+}
+
 // Traversal.
 
 int
@@ -7344,6 +7530,35 @@
   return false;
 }
 
+// Message name.
+
+void
+Array_type::do_message_name(std::string* ret) const
+{
+  ret->push_back('[');
+  if (!this->is_slice_type())
+    {
+      Numeric_constant nc;
+      if (!this->length_->numeric_constant_value(&nc))
+	ret->append("<unknown length>");
+      else
+	{
+	  mpz_t val;
+	  if (!nc.to_int(&val))
+	    ret->append("<unknown length>");
+	  else
+	    {
+	      char* s = mpz_get_str(NULL, 10, val);
+	      ret->append(s);
+	      free(s);
+	      mpz_clear(val);
+	    }
+	}
+    }
+  ret->push_back(']');
+  this->append_message_name(this->element_type_, ret);
+}
+
 // Traversal.
 
 int
@@ -8249,6 +8464,17 @@
   return zvar;
 }
 
+// Message name.
+
+void
+Map_type::do_message_name(std::string* ret) const
+{
+  ret->append("map[");
+  this->append_message_name(this->key_type_, ret);
+  ret->push_back(']');
+  this->append_message_name(this->val_type_, ret);
+}
+
 // Traversal.
 
 int
@@ -8803,6 +9029,20 @@
 
 // Class Channel_type.
 
+// Message name.
+
+void
+Channel_type::do_message_name(std::string* ret) const
+{
+  if (!this->may_send_)
+    ret->append("<-");
+  ret->append("chan");
+  if (!this->may_receive_)
+    ret->append("<-");
+  ret->push_back(' ');
+  this->append_message_name(this->element_type_, ret);
+}
+
 // Verify.
 
 bool
@@ -9053,6 +9293,45 @@
   return this->all_methods_ == NULL ? 0 : this->all_methods_->size();
 }
 
+// Message name.
+
+void
+Interface_type::do_message_name(std::string* ret) const
+{
+  const Typed_identifier_list* methods = (this->methods_are_finalized_
+					  ? this->all_methods_
+					  : this->parse_methods_);
+  if (methods == NULL || methods->empty())
+    {
+      ret->append("interface{}");
+      return;
+    }
+
+  ret->append("interface {");
+
+  bool first = true;
+  for (Typed_identifier_list::const_iterator p = methods->begin();
+       p != methods->end();
+       ++p)
+    {
+      if (first)
+	first = false;
+      else
+	ret->append("; ");
+
+      if (!p->name().empty())
+	ret->append(p->name());
+
+      Function_type* ft = p->type()->function_type();
+      if (ft == NULL)
+	this->append_message_name(p->type(), ret);
+      else
+	ft->append_signature(ret);
+    }
+
+  ret->append(" }");
+}
+
 // Traversal.
 
 int
@@ -10295,10 +10574,10 @@
 
 // Return the name of the type to use in an error message.
 
-std::string
-Named_type::message_name() const
+void
+Named_type::do_message_name(std::string* ret) const
 {
-  return this->named_object_->message_name();
+  ret->append(this->named_object_->message_name());
 }
 
 // Return the base type for this type.  We have to be careful about
@@ -12819,6 +13098,17 @@
   no->type_declaration_value()->add_existing_method(nom);
 }
 
+// Message name.
+
+void
+Forward_declaration_type::do_message_name(std::string* ret) const
+{
+  if (this->is_defined())
+    this->append_message_name(this->real_type(), ret);
+  else
+    ret->append(this->named_object_->message_name());
+}
+
 // Traversal.
 
 int
diff --git a/go/types.h b/go/types.h
index 3dd3279..cbc7ce0 100644
--- a/go/types.h
+++ b/go/types.h
@@ -575,6 +575,10 @@
   static Named_type*
   make_builtin_named_type(const char* name, Type* type);
 
+  // Return a string version of this type to use in an error message.
+  std::string
+  message_name() const;
+
   // Traverse a type.
   static int
   traverse(Type*, Traverse*);
@@ -1095,6 +1099,10 @@
 
   // Functions implemented by the child class.
 
+  // Message name.
+  virtual void
+  do_message_name(std::string*) const = 0;
+
   // Traverse the subtypes.
   virtual int
   do_traverse(Traverse*);
@@ -1195,6 +1203,11 @@
   type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
 			      const Methods*, bool only_value_methods);
 
+  // For the benefit of child class message name construction.
+  void
+  append_message_name(const Type* type, std::string* ret) const
+  { type->do_message_name(ret); }
+
   // For the benefit of child class reflection string generation.
   void
   append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
@@ -1656,6 +1669,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<ERROR>"); }
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -1683,6 +1700,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("void"); }
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -1712,6 +1733,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<untyped bool>"); }
+
   bool
   do_compare_is_identity(Gogo*)
   { return true; }
@@ -1797,6 +1822,9 @@
   { this->is_rune_ = true; }
 
 protected:
+  void
+  do_message_name(std::string* ret) const;
+
   bool
   do_compare_is_identity(Gogo*)
   { return true; }
@@ -1874,6 +1902,9 @@
   is_identical(const Float_type* t) const;
 
  protected:
+  void
+  do_message_name(std::string* ret) const;
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -1952,6 +1983,9 @@
   is_identical(const Complex_type* t) const;
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -2009,6 +2043,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<untyped string>"); }
+
   bool
   do_has_pointer() const
   { return true; }
@@ -2166,7 +2204,14 @@
   is_backend_function_type() const
   { return false; }
 
+  // Append just the signature of the function type.
+  void
+  append_signature(std::string*) const;
+
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse*);
 
@@ -2293,6 +2338,9 @@
   make_pointer_type_descriptor_type();
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse*);
 
@@ -2346,6 +2394,10 @@
   { }
 
  protected:
+  void
+  do_message_name(std::string* ret) const
+  { ret->append("<NIL>"); }
+
   bool
   do_compare_is_identity(Gogo*)
   { return false; }
@@ -2671,6 +2723,9 @@
   write_to_c_header(std::ostream&) const;
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse*);
 
@@ -2851,6 +2906,9 @@
   write_equal_function(Gogo*, Named_object* function, Named_type*);
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse* traverse);
 
@@ -2999,6 +3057,9 @@
   static const int bucket_size = 8;
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse*);
 
@@ -3118,6 +3179,9 @@
   select_case_type();
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse* traverse)
   { return Type::traverse(this->element_type_, traverse); }
@@ -3273,6 +3337,9 @@
   { return this->methods_are_finalized_; }
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse*);
 
@@ -3450,12 +3517,6 @@
   const std::string&
   name() const;
 
-  // Return the name of the type for an error message.  The difference
-  // is that if the type is defined in a different package, this will
-  // return PACKAGE.NAME.
-  std::string
-  message_name() const;
-
   // Return the underlying type.
   Type*
   real_type()
@@ -3599,6 +3660,9 @@
   convert(Gogo*);
 
  protected:
+  void
+  do_message_name(std::string* ret) const;
+
   int
   do_traverse(Traverse* traverse)
   { return Type::traverse(this->type_, traverse); }
@@ -3758,6 +3822,9 @@
   add_existing_method(Named_object*);
 
  protected:
+  void
+  do_message_name(std::string*) const;
+
   int
   do_traverse(Traverse* traverse);