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>
This commit is contained in:
Ian Lance Taylor 2023-10-20 10:25:04 -07:00
Родитель 8c056e335c
Коммит 1cb83a415e
3 изменённых файлов: 374 добавлений и 24 удалений

Просмотреть файл

@ -223,14 +223,7 @@ Ast_dump_context::dump_type(const Type* t)
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

Просмотреть файл

@ -270,6 +270,16 @@ Type::set_is_error()
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 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
{
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 @@ Integer_type::is_identical(const Integer_type* t) const
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 @@ Float_type::is_identical(const Float_type* t) const
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 @@ Complex_type::is_identical(const Complex_type *t) const
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 @@ class Sink_type : public Type
{ }
protected:
void
do_message_name(std::string* ret) const
{ ret->append("<SINK>"); }
bool
do_compare_is_identity(Gogo*)
{ return false; }
@ -4696,6 +4765,70 @@ Type::make_sink_type()
// 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 @@ Type::make_backend_function_type(Typed_identifier* receiver,
// 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 @@ class Call_multiple_result_type : public Type
{ }
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::Identical_structs Struct_type::identical_structs;
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 @@ Array_type::is_identical(const Array_type* t, int flags) const
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 @@ Map_type::backend_zero_value(Gogo* gogo)
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 @@ Type::make_map_type(Type* key_type, Type* val_type, Location location)
// 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 @@ Interface_type::method_count() const
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 @@ Named_type::name() const
// 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 @@ Forward_declaration_type::add_existing_method(Named_object* nom)
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

Просмотреть файл

@ -575,6 +575,10 @@ class Type
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 @@ class Type
// 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 @@ class Type
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 @@ class Error_type : public Type
{ }
protected:
void
do_message_name(std::string* ret) const
{ ret->append("<ERROR>"); }
bool
do_compare_is_identity(Gogo*)
{ return false; }
@ -1683,6 +1700,10 @@ class Void_type : public Type
{ }
protected:
void
do_message_name(std::string* ret) const
{ ret->append("void"); }
bool
do_compare_is_identity(Gogo*)
{ return false; }
@ -1712,6 +1733,10 @@ class Boolean_type : public Type
{ }
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 @@ class Integer_type : public Type
{ 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 @@ class Float_type : public Type
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 @@ class Complex_type : public Type
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 @@ class String_type : public Type
{ }
protected:
void
do_message_name(std::string* ret) const
{ ret->append("<untyped string>"); }
bool
do_has_pointer() const
{ return true; }
@ -2166,7 +2204,14 @@ class Function_type : public Type
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 @@ class Pointer_type : public Type
make_pointer_type_descriptor_type();
protected:
void
do_message_name(std::string*) const;
int
do_traverse(Traverse*);
@ -2346,6 +2394,10 @@ class Nil_type : public Type
{ }
protected:
void
do_message_name(std::string* ret) const
{ ret->append("<NIL>"); }
bool
do_compare_is_identity(Gogo*)
{ return false; }
@ -2671,6 +2723,9 @@ class Struct_type : public Type
write_to_c_header(std::ostream&) const;
protected:
void
do_message_name(std::string*) const;
int
do_traverse(Traverse*);
@ -2851,6 +2906,9 @@ class Array_type : public Type
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 @@ class Map_type : public Type
static const int bucket_size = 8;
protected:
void
do_message_name(std::string*) const;
int
do_traverse(Traverse*);
@ -3118,6 +3179,9 @@ class Channel_type : public Type
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 @@ class Interface_type : public Type
{ return this->methods_are_finalized_; }
protected:
void
do_message_name(std::string*) const;
int
do_traverse(Traverse*);
@ -3450,12 +3517,6 @@ class Named_type : public Type
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 @@ class Named_type : public Type
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 @@ class Forward_declaration_type : public Type
add_existing_method(Named_object*);
protected:
void
do_message_name(std::string*) const;
int
do_traverse(Traverse* traverse);