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:
Родитель
8c056e335c
Коммит
1cb83a415e
|
@ -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
|
||||
|
|
310
go/types.cc
310
go/types.cc
|
@ -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
|
||||
|
|
79
go/types.h
79
go/types.h
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче