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);