Commit a2bd02ae by Ian Lance Taylor

compiler: implement type aliases

    
    This is a start of implementing type aliases (`type T1 = T2`) in the
    Go frontend.  This is incomplete, in that the reflection information
    is not updated for an embedded type alias.  It is also not well
    tested.  Finally, the change to the language has not been approved.
    This should be regarded as preliminary work for experimental use.
    
    Update golang/go#18130.
    
    Reviewed-on: https://go-review.googlesource.com/35120

From-SVN: r244460
parent 3220ce78
0ba4563a4b0dec4c01b90d7b3c9e2ce2cd58a96f ea73a80a6047f477d92fccc7de143a3ee1021c65
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -608,6 +608,9 @@ Export::write_type(const Type* type) ...@@ -608,6 +608,9 @@ Export::write_type(const Type* type)
// definition of the type may refer to the named type via a // definition of the type may refer to the named type via a
// pointer. // pointer.
this->type_refs_[type] = index; this->type_refs_[type] = index;
if (named_type != NULL && named_type->is_alias())
this->write_c_string("= ");
} }
type->export_type(this); type->export_type(this);
......
...@@ -108,12 +108,14 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) ...@@ -108,12 +108,14 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
uint8_type->integer_type()->set_is_byte(); uint8_type->integer_type()->set_is_byte();
Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type, Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type,
loc); loc);
byte_type->type_value()->set_is_alias();
this->add_named_type(byte_type->type_value()); this->add_named_type(byte_type->type_value());
// "rune" is an alias for "int32". // "rune" is an alias for "int32".
int32_type->integer_type()->set_is_rune(); int32_type->integer_type()->set_is_rune();
Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type, Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type,
loc); loc);
rune_type->type_value()->set_is_alias();
this->add_named_type(rune_type->type_value()); this->add_named_type(rune_type->type_value());
this->add_named_type(Type::make_named_bool_type()); this->add_named_type(Type::make_named_bool_type());
...@@ -1775,6 +1777,10 @@ Gogo::start_function(const std::string& name, Function_type* type, ...@@ -1775,6 +1777,10 @@ Gogo::start_function(const std::string& name, Function_type* type,
if (rtype->classification() == Type::TYPE_POINTER) if (rtype->classification() == Type::TYPE_POINTER)
rtype = rtype->points_to(); rtype = rtype->points_to();
while (rtype->named_type() != NULL
&& rtype->named_type()->is_alias())
rtype = rtype->named_type()->real_type();
if (rtype->is_error_type()) if (rtype->is_error_type())
ret = Named_object::make_function(name, NULL, function); ret = Named_object::make_function(name, NULL, function);
else if (rtype->named_type() != NULL) else if (rtype->named_type() != NULL)
...@@ -6865,7 +6871,7 @@ Type_declaration::add_method_declaration(const std::string& name, ...@@ -6865,7 +6871,7 @@ Type_declaration::add_method_declaration(const std::string& name,
return ret; return ret;
} }
// Return whether any methods ere defined. // Return whether any methods are defined.
bool bool
Type_declaration::has_methods() const Type_declaration::has_methods() const
...@@ -6878,6 +6884,36 @@ Type_declaration::has_methods() const ...@@ -6878,6 +6884,36 @@ Type_declaration::has_methods() const
void void
Type_declaration::define_methods(Named_type* nt) Type_declaration::define_methods(Named_type* nt)
{ {
if (this->methods_.empty())
return;
while (nt->is_alias())
{
Type *t = nt->real_type()->forwarded();
if (t->named_type() != NULL)
nt = t->named_type();
else if (t->forward_declaration_type() != NULL)
{
Named_object* no = t->forward_declaration_type()->named_object();
Type_declaration* td = no->type_declaration_value();
td->methods_.insert(td->methods_.end(), this->methods_.begin(),
this->methods_.end());
this->methods_.clear();
return;
}
else
{
for (std::vector<Named_object*>::const_iterator p =
this->methods_.begin();
p != this->methods_.end();
++p)
go_error_at((*p)->location(),
("invalid receiver type "
"(receiver must be a named type"));
return;
}
}
for (std::vector<Named_object*>::const_iterator p = this->methods_.begin(); for (std::vector<Named_object*>::const_iterator p = this->methods_.begin();
p != this->methods_.end(); p != this->methods_.end();
++p) ++p)
......
...@@ -737,6 +737,13 @@ Import::read_type() ...@@ -737,6 +737,13 @@ Import::read_type()
this->require_c_string(" "); this->require_c_string(" ");
bool is_alias = false;
if (this->match_c_string("= "))
{
stream->advance(2);
is_alias = true;
}
// The package name may follow. This is the name of the package in // The package name may follow. This is the name of the package in
// the package clause of that package. The type name will include // the package clause of that package. The type name will include
// the pkgpath, which may be different. // the pkgpath, which may be different.
...@@ -810,6 +817,9 @@ Import::read_type() ...@@ -810,6 +817,9 @@ Import::read_type()
// This type has not yet been imported. // This type has not yet been imported.
ntype->clear_is_visible(); ntype->clear_is_visible();
if (is_alias)
ntype->set_is_alias();
if (!type->is_undefined() && type->interface_type() != NULL) if (!type->is_undefined() && type->interface_type() != NULL)
this->gogo_->record_interface_type(type->interface_type()); this->gogo_->record_interface_type(type->interface_type());
......
...@@ -1515,7 +1515,7 @@ Parse::type_decl() ...@@ -1515,7 +1515,7 @@ Parse::type_decl()
this->decl(&Parse::type_spec, NULL); this->decl(&Parse::type_spec, NULL);
} }
// TypeSpec = identifier Type . // TypeSpec = identifier ["="] Type .
void void
Parse::type_spec(void*) Parse::type_spec(void*)
...@@ -1531,6 +1531,13 @@ Parse::type_spec(void*) ...@@ -1531,6 +1531,13 @@ Parse::type_spec(void*)
Location location = token->location(); Location location = token->location();
token = this->advance_token(); token = this->advance_token();
bool is_alias = false;
if (token->is_op(OPERATOR_EQ))
{
is_alias = true;
token = this->advance_token();
}
// The scope of the type name starts at the point where the // The scope of the type name starts at the point where the
// identifier appears in the source code. We implement this by // identifier appears in the source code. We implement this by
// declaring the type before we read the type definition. // declaring the type before we read the type definition.
...@@ -1542,13 +1549,13 @@ Parse::type_spec(void*) ...@@ -1542,13 +1549,13 @@ Parse::type_spec(void*)
} }
Type* type; Type* type;
if (name == "_" && this->peek_token()->is_keyword(KEYWORD_INTERFACE)) if (name == "_" && token->is_keyword(KEYWORD_INTERFACE))
{ {
// We call Parse::interface_type explicity here because we do not want // We call Parse::interface_type explicity here because we do not want
// to record an interface with a blank type name. // to record an interface with a blank type name.
type = this->interface_type(false); type = this->interface_type(false);
} }
else if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) else if (!token->is_op(OPERATOR_SEMICOLON))
type = this->type(); type = this->type();
else else
{ {
...@@ -1579,9 +1586,11 @@ Parse::type_spec(void*) ...@@ -1579,9 +1586,11 @@ Parse::type_spec(void*)
type = Type::make_error_type(); type = Type::make_error_type();
} }
this->gogo_->define_type(named_type, Named_type* nt = Type::make_named_type(named_type, type, location);
Type::make_named_type(named_type, type, if (is_alias)
location)); nt->set_is_alias();
this->gogo_->define_type(named_type, nt);
go_assert(named_type->package() == NULL); go_assert(named_type->package() == NULL);
} }
else else
......
...@@ -328,10 +328,10 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, ...@@ -328,10 +328,10 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
t2 = t2->forwarded(); t2 = t2->forwarded();
// Ignore aliases for purposes of type identity. // Ignore aliases for purposes of type identity.
if (t1->named_type() != NULL && t1->named_type()->is_alias()) while (t1->named_type() != NULL && t1->named_type()->is_alias())
t1 = t1->named_type()->real_type(); t1 = t1->named_type()->real_type()->forwarded();
if (t2->named_type() != NULL && t2->named_type()->is_alias()) while (t2->named_type() != NULL && t2->named_type()->is_alias())
t2 = t2->named_type()->real_type(); t2 = t2->named_type()->real_type()->forwarded();
if (t1 == t2) if (t1 == t2)
return true; return true;
...@@ -822,6 +822,8 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) ...@@ -822,6 +822,8 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
unsigned int unsigned int
Type::hash_for_method(Gogo* gogo) const Type::hash_for_method(Gogo* gogo) const
{ {
if (this->named_type() != NULL && this->named_type()->is_alias())
return this->named_type()->real_type()->hash_for_method(gogo);
unsigned int ret = 0; unsigned int ret = 0;
if (this->classification_ != TYPE_FORWARD) if (this->classification_ != TYPE_FORWARD)
ret += this->classification_; ret += this->classification_;
...@@ -1165,8 +1167,8 @@ Bexpression* ...@@ -1165,8 +1167,8 @@ Bexpression*
Type::type_descriptor_pointer(Gogo* gogo, Location location) Type::type_descriptor_pointer(Gogo* gogo, Location location)
{ {
Type* t = this->forwarded(); Type* t = this->forwarded();
if (t->named_type() != NULL && t->named_type()->is_alias()) while (t->named_type() != NULL && t->named_type()->is_alias())
t = t->named_type()->real_type(); t = t->named_type()->real_type()->forwarded();
if (t->type_descriptor_var_ == NULL) if (t->type_descriptor_var_ == NULL)
{ {
t->make_type_descriptor_var(gogo); t->make_type_descriptor_var(gogo);
...@@ -1585,6 +1587,9 @@ Type::make_type_descriptor_ptr_type() ...@@ -1585,6 +1587,9 @@ Type::make_type_descriptor_ptr_type()
bool bool
Type::needs_specific_type_functions(Gogo* gogo) Type::needs_specific_type_functions(Gogo* gogo)
{ {
Named_type* nt = this->named_type();
if (nt != NULL && nt->is_alias())
return false;
if (!this->is_comparable()) if (!this->is_comparable())
return false; return false;
if (!this->compare_is_identity(gogo)) if (!this->compare_is_identity(gogo))
...@@ -1593,7 +1598,6 @@ Type::needs_specific_type_functions(Gogo* gogo) ...@@ -1593,7 +1598,6 @@ Type::needs_specific_type_functions(Gogo* gogo)
// We create a few predeclared types for type descriptors; they are // We create a few predeclared types for type descriptors; they are
// really just for the backend and don't need hash or equality // really just for the backend and don't need hash or equality
// functions. // functions.
Named_type* nt = this->named_type();
if (nt != NULL && Linemap::is_predeclared_location(nt->location())) if (nt != NULL && Linemap::is_predeclared_location(nt->location()))
return false; return false;
...@@ -1634,6 +1638,11 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, ...@@ -1634,6 +1638,11 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype,
Function_type* equal_fntype, Named_object** hash_fn, Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn) Named_object** equal_fn)
{ {
// If this loop leaves NAME as NULL, then the type does not have a
// name after all.
while (name != NULL && name->is_alias())
name = name->real_type()->named_type();
if (!this->is_comparable()) if (!this->is_comparable())
{ {
*hash_fn = NULL; *hash_fn = NULL;
...@@ -2164,6 +2173,11 @@ Type::write_named_hash(Gogo* gogo, Named_type* name, ...@@ -2164,6 +2173,11 @@ Type::write_named_hash(Gogo* gogo, Named_type* name,
Location bloc = Linemap::predeclared_location(); Location bloc = Linemap::predeclared_location();
Named_type* base_type = name->real_type()->named_type(); Named_type* base_type = name->real_type()->named_type();
while (base_type->is_alias())
{
base_type = base_type->real_type()->named_type();
go_assert(base_type != NULL);
}
go_assert(base_type != NULL); go_assert(base_type != NULL);
// The pointer to the type we are going to hash. This is an // The pointer to the type we are going to hash. This is an
...@@ -2371,8 +2385,8 @@ Bexpression* ...@@ -2371,8 +2385,8 @@ Bexpression*
Type::gc_symbol_pointer(Gogo* gogo) Type::gc_symbol_pointer(Gogo* gogo)
{ {
Type* t = this->forwarded(); Type* t = this->forwarded();
if (t->named_type() != NULL && t->named_type()->is_alias()) while (t->named_type() != NULL && t->named_type()->is_alias())
t = t->named_type()->real_type(); t = t->named_type()->real_type()->forwarded();
if (t->gc_symbol_var_ == NULL) if (t->gc_symbol_var_ == NULL)
{ {
t->make_gc_symbol_var(gogo); t->make_gc_symbol_var(gogo);
...@@ -4857,7 +4871,10 @@ Struct_field::field_name() const ...@@ -4857,7 +4871,10 @@ Struct_field::field_name() const
if (dt->forward_declaration_type() != NULL) if (dt->forward_declaration_type() != NULL)
return dt->forward_declaration_type()->name(); return dt->forward_declaration_type()->name();
else if (dt->named_type() != NULL) else if (dt->named_type() != NULL)
return dt->named_type()->name(); {
// Note that this can be an alias name.
return dt->named_type()->name();
}
else if (t->is_error_type() || dt->is_error_type()) else if (t->is_error_type() || dt->is_error_type())
{ {
static const std::string error_string = "*error*"; static const std::string error_string = "*error*";
...@@ -5786,7 +5803,12 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const ...@@ -5786,7 +5803,12 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
else else
ret->append(Gogo::unpack_hidden_name(p->field_name())); ret->append(Gogo::unpack_hidden_name(p->field_name()));
ret->push_back(' '); ret->push_back(' ');
this->append_reflection(p->type(), gogo, ret); if (p->is_anonymous()
&& p->type()->named_type() != NULL
&& p->type()->named_type()->is_alias())
p->type()->named_type()->append_reflection_type_name(gogo, true, ret);
else
this->append_reflection(p->type(), gogo, ret);
if (p->has_tag()) if (p->has_tag())
{ {
...@@ -5866,7 +5888,15 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const ...@@ -5866,7 +5888,15 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
ret->append(buf); ret->append(buf);
ret->append(n); ret->append(n);
} }
this->append_mangled_name(p->type(), gogo, ret);
// For an anonymous field with an alias type, the field name
// is the alias name.
if (p->is_anonymous()
&& p->type()->named_type() != NULL
&& p->type()->named_type()->is_alias())
p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
else
this->append_mangled_name(p->type(), gogo, ret);
if (p->has_tag()) if (p->has_tag())
{ {
const std::string& tag(p->tag()); const std::string& tag(p->tag());
...@@ -9313,18 +9343,6 @@ Named_type::message_name() const ...@@ -9313,18 +9343,6 @@ Named_type::message_name() const
return this->named_object_->message_name(); return this->named_object_->message_name();
} }
// Whether this is an alias. There are currently only two aliases so
// we just recognize them by name.
bool
Named_type::is_alias() const
{
if (!this->is_builtin())
return false;
const std::string& name(this->name());
return name == "byte" || name == "rune";
}
// Return the base type for this type. We have to be careful about // Return the base type for this type. We have to be careful about
// circular type definitions, which are invalid but may be seen here. // circular type definitions, which are invalid but may be seen here.
...@@ -9384,6 +9402,7 @@ Named_type::named_type_is_comparable(std::string* reason) const ...@@ -9384,6 +9402,7 @@ Named_type::named_type_is_comparable(std::string* reason) const
Named_object* Named_object*
Named_type::add_method(const std::string& name, Function* function) Named_type::add_method(const std::string& name, Function* function)
{ {
go_assert(!this->is_alias_);
if (this->local_methods_ == NULL) if (this->local_methods_ == NULL)
this->local_methods_ = new Bindings(NULL); this->local_methods_ = new Bindings(NULL);
return this->local_methods_->add_function(name, NULL, function); return this->local_methods_->add_function(name, NULL, function);
...@@ -9396,6 +9415,7 @@ Named_type::add_method_declaration(const std::string& name, Package* package, ...@@ -9396,6 +9415,7 @@ Named_type::add_method_declaration(const std::string& name, Package* package,
Function_type* type, Function_type* type,
Location location) Location location)
{ {
go_assert(!this->is_alias_);
if (this->local_methods_ == NULL) if (this->local_methods_ == NULL)
this->local_methods_ = new Bindings(NULL); this->local_methods_ = new Bindings(NULL);
return this->local_methods_->add_function_declaration(name, package, type, return this->local_methods_->add_function_declaration(name, package, type,
...@@ -9407,6 +9427,7 @@ Named_type::add_method_declaration(const std::string& name, Package* package, ...@@ -9407,6 +9427,7 @@ Named_type::add_method_declaration(const std::string& name, Package* package,
void void
Named_type::add_existing_method(Named_object* no) Named_type::add_existing_method(Named_object* no)
{ {
go_assert(!this->is_alias_);
if (this->local_methods_ == NULL) if (this->local_methods_ == NULL)
this->local_methods_ = new Bindings(NULL); this->local_methods_ = new Bindings(NULL);
this->local_methods_->add_named_object(no); this->local_methods_->add_named_object(no);
...@@ -9418,11 +9439,51 @@ Named_type::add_existing_method(Named_object* no) ...@@ -9418,11 +9439,51 @@ Named_type::add_existing_method(Named_object* no)
Named_object* Named_object*
Named_type::find_local_method(const std::string& name) const Named_type::find_local_method(const std::string& name) const
{ {
if (this->is_error_)
return NULL;
if (this->is_alias_)
{
Named_type* nt = this->type_->named_type();
if (nt != NULL)
{
if (this->seen_alias_)
return NULL;
this->seen_alias_ = true;
Named_object* ret = nt->find_local_method(name);
this->seen_alias_ = false;
return ret;
}
return NULL;
}
if (this->local_methods_ == NULL) if (this->local_methods_ == NULL)
return NULL; return NULL;
return this->local_methods_->lookup(name); return this->local_methods_->lookup(name);
} }
// Return the list of local methods.
const Bindings*
Named_type::local_methods() const
{
if (this->is_error_)
return NULL;
if (this->is_alias_)
{
Named_type* nt = this->type_->named_type();
if (nt != NULL)
{
if (this->seen_alias_)
return NULL;
this->seen_alias_ = true;
const Bindings* ret = nt->local_methods();
this->seen_alias_ = false;
return ret;
}
return NULL;
}
return this->local_methods_;
}
// Return whether NAME is an unexported field or method, for better // Return whether NAME is an unexported field or method, for better
// error reporting. // error reporting.
...@@ -9430,6 +9491,22 @@ bool ...@@ -9430,6 +9491,22 @@ bool
Named_type::is_unexported_local_method(Gogo* gogo, Named_type::is_unexported_local_method(Gogo* gogo,
const std::string& name) const const std::string& name) const
{ {
if (this->is_error_)
return false;
if (this->is_alias_)
{
Named_type* nt = this->type_->named_type();
if (nt != NULL)
{
if (this->seen_alias_)
return false;
this->seen_alias_ = true;
bool ret = nt->is_unexported_local_method(gogo, name);
this->seen_alias_ = false;
return ret;
}
return false;
}
Bindings* methods = this->local_methods_; Bindings* methods = this->local_methods_;
if (methods != NULL) if (methods != NULL)
{ {
...@@ -9454,6 +9531,8 @@ Named_type::is_unexported_local_method(Gogo* gogo, ...@@ -9454,6 +9531,8 @@ Named_type::is_unexported_local_method(Gogo* gogo,
void void
Named_type::finalize_methods(Gogo* gogo) Named_type::finalize_methods(Gogo* gogo)
{ {
if (this->is_alias_)
return;
if (this->all_methods_ != NULL) if (this->all_methods_ != NULL)
return; return;
...@@ -9474,6 +9553,56 @@ Named_type::finalize_methods(Gogo* gogo) ...@@ -9474,6 +9553,56 @@ Named_type::finalize_methods(Gogo* gogo)
Type::finalize_methods(gogo, this, this->location_, &this->all_methods_); Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
} }
// Return whether this type has any methods.
bool
Named_type::has_any_methods() const
{
if (this->is_error_)
return false;
if (this->is_alias_)
{
if (this->type_->named_type() != NULL)
{
if (this->seen_alias_)
return false;
this->seen_alias_ = true;
bool ret = this->type_->named_type()->has_any_methods();
this->seen_alias_ = false;
return ret;
}
if (this->type_->struct_type() != NULL)
return this->type_->struct_type()->has_any_methods();
return false;
}
return this->all_methods_ != NULL;
}
// Return the methods for this type.
const Methods*
Named_type::methods() const
{
if (this->is_error_)
return NULL;
if (this->is_alias_)
{
if (this->type_->named_type() != NULL)
{
if (this->seen_alias_)
return NULL;
this->seen_alias_ = true;
const Methods* ret = this->type_->named_type()->methods();
this->seen_alias_ = false;
return ret;
}
if (this->type_->struct_type() != NULL)
return this->type_->struct_type()->methods();
return NULL;
}
return this->all_methods_;
}
// Return the method NAME, or NULL if there isn't one or if it is // Return the method NAME, or NULL if there isn't one or if it is
// ambiguous. Set *IS_AMBIGUOUS if the method exists but is // ambiguous. Set *IS_AMBIGUOUS if the method exists but is
// ambiguous. // ambiguous.
...@@ -9481,6 +9610,26 @@ Named_type::finalize_methods(Gogo* gogo) ...@@ -9481,6 +9610,26 @@ Named_type::finalize_methods(Gogo* gogo)
Method* Method*
Named_type::method_function(const std::string& name, bool* is_ambiguous) const Named_type::method_function(const std::string& name, bool* is_ambiguous) const
{ {
if (this->is_error_)
return NULL;
if (this->is_alias_)
{
if (is_ambiguous != NULL)
*is_ambiguous = false;
if (this->type_->named_type() != NULL)
{
if (this->seen_alias_)
return NULL;
this->seen_alias_ = true;
Named_type* nt = this->type_->named_type();
Method* ret = nt->method_function(name, is_ambiguous);
this->seen_alias_ = false;
return ret;
}
if (this->type_->struct_type() != NULL)
return this->type_->struct_type()->method_function(name, is_ambiguous);
return NULL;
}
return Type::method_function(this->all_methods_, name, is_ambiguous); return Type::method_function(this->all_methods_, name, is_ambiguous);
} }
...@@ -9491,6 +9640,25 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const ...@@ -9491,6 +9640,25 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const
Expression* Expression*
Named_type::interface_method_table(Interface_type* interface, bool is_pointer) Named_type::interface_method_table(Interface_type* interface, bool is_pointer)
{ {
if (this->is_error_)
return Expression::make_error(this->location_);
if (this->is_alias_)
{
if (this->type_->named_type() != NULL)
{
if (this->seen_alias_)
return Expression::make_error(this->location_);
this->seen_alias_ = true;
Named_type* nt = this->type_->named_type();
Expression* ret = nt->interface_method_table(interface, is_pointer);
this->seen_alias_ = false;
return ret;
}
if (this->type_->struct_type() != NULL)
return this->type_->struct_type()->interface_method_table(interface,
is_pointer);
go_unreachable();
}
return Type::interface_method_table(this, interface, is_pointer, return Type::interface_method_table(this, interface, is_pointer,
&this->interface_method_tables_, &this->interface_method_tables_,
&this->pointer_interface_method_tables_); &this->pointer_interface_method_tables_);
...@@ -9609,6 +9777,55 @@ Find_type_use::type(Type* type) ...@@ -9609,6 +9777,55 @@ Find_type_use::type(Type* type)
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
} }
// Look for a circular reference of an alias.
class Find_alias : public Traverse
{
public:
Find_alias(Named_type* find_type)
: Traverse(traverse_types),
find_type_(find_type), found_(false)
{ }
// Whether we found the type.
bool
found() const
{ return this->found_; }
protected:
int
type(Type*);
private:
// The type we are looking for.
Named_type* find_type_;
// Whether we found the type.
bool found_;
};
int
Find_alias::type(Type* type)
{
Named_type* nt = type->named_type();
if (nt != NULL)
{
if (nt == this->find_type_)
{
this->found_ = true;
return TRAVERSE_EXIT;
}
// We started from `type T1 = T2`, where T1 is find_type_ and T2
// is, perhaps indirectly, the parameter TYPE. If TYPE is not
// an alias itself, it's OK if whatever T2 is defined as refers
// to T1.
if (!nt->is_alias())
return TRAVERSE_SKIP_COMPONENTS;
}
return TRAVERSE_CONTINUE;
}
// Verify that a named type does not refer to itself. // Verify that a named type does not refer to itself.
bool bool
...@@ -9618,6 +9835,22 @@ Named_type::do_verify() ...@@ -9618,6 +9835,22 @@ Named_type::do_verify()
return true; return true;
this->is_verified_ = true; this->is_verified_ = true;
if (this->is_error_)
return false;
if (this->is_alias_)
{
Find_alias find(this);
Type::traverse(this->type_, &find);
if (find.found())
{
go_error_at(this->location_, "invalid recursive alias %qs",
this->message_name().c_str());
this->is_error_ = true;
return false;
}
}
Find_type_use find(this); Find_type_use find(this);
Type::traverse(this->type_, &find); Type::traverse(this->type_, &find);
if (find.found()) if (find.found())
...@@ -9718,8 +9951,11 @@ Named_type::do_needs_key_update() ...@@ -9718,8 +9951,11 @@ Named_type::do_needs_key_update()
unsigned int unsigned int
Named_type::do_hash_for_method(Gogo* gogo) const Named_type::do_hash_for_method(Gogo* gogo) const
{ {
if (this->is_alias()) if (this->is_error_)
return this->type_->named_type()->do_hash_for_method(gogo); return 0;
// Aliases are handled in Type::hash_for_method.
go_assert(!this->is_alias_);
const std::string& name(this->named_object()->name()); const std::string& name(this->named_object()->name());
unsigned int ret = Type::hash_string(name, 0); unsigned int ret = Type::hash_string(name, 0);
...@@ -10089,8 +10325,17 @@ Named_type::do_get_backend(Gogo* gogo) ...@@ -10089,8 +10325,17 @@ Named_type::do_get_backend(Gogo* gogo)
Expression* Expression*
Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
{ {
if (name == NULL && this->is_alias()) if (this->is_error_)
return this->type_->type_descriptor(gogo, this->type_); return Expression::make_error(this->location_);
if (name == NULL && this->is_alias_)
{
if (this->seen_alias_)
return Expression::make_error(this->location_);
this->seen_alias_ = true;
Expression* ret = this->type_->type_descriptor(gogo, NULL);
this->seen_alias_ = false;
return ret;
}
// If NAME is not NULL, then we don't really want the type // If NAME is not NULL, then we don't really want the type
// descriptor for this type; we want the descriptor for the // descriptor for this type; we want the descriptor for the
...@@ -10106,9 +10351,25 @@ Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) ...@@ -10106,9 +10351,25 @@ Named_type::do_type_descriptor(Gogo* gogo, Named_type* name)
void void
Named_type::do_reflection(Gogo* gogo, std::string* ret) const Named_type::do_reflection(Gogo* gogo, std::string* ret) const
{ {
if (this->is_alias()) this->append_reflection_type_name(gogo, false, ret);
}
// Add to the reflection string. For an alias we normally use the
// real name, but if USE_ALIAS is true we use the alias name itself.
void
Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias,
std::string* ret) const
{
if (this->is_error_)
return;
if (this->is_alias_ && !use_alias)
{ {
if (this->seen_alias_)
return;
this->seen_alias_ = true;
this->append_reflection(this->type_, gogo, ret); this->append_reflection(this->type_, gogo, ret);
this->seen_alias_ = false;
return; return;
} }
if (!this->is_builtin()) if (!this->is_builtin())
...@@ -10173,9 +10434,25 @@ Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals, ...@@ -10173,9 +10434,25 @@ Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
void void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{ {
if (this->is_alias()) this->append_mangled_type_name(gogo, false, ret);
}
// Get the mangled name. For an alias we normally get the real name,
// but if USE_ALIAS is true we use the alias name itself.
void
Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
std::string* ret) const
{
if (this->is_error_)
return;
if (this->is_alias_ && !use_alias)
{ {
if (this->seen_alias_)
return;
this->seen_alias_ = true;
this->append_mangled_name(this->type_, gogo, ret); this->append_mangled_name(this->type_, gogo, ret);
this->seen_alias_ = false;
return; return;
} }
Named_object* no = this->named_object_; Named_object* no = this->named_object_;
...@@ -11392,7 +11669,7 @@ Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name) ...@@ -11392,7 +11669,7 @@ Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name)
if (name != NULL) if (name != NULL)
return this->named_type_descriptor(gogo, t, name); return this->named_type_descriptor(gogo, t, name);
else else
return Expression::make_type_descriptor(t, ploc); return Expression::make_error(this->named_object_->location());
} }
} }
......
...@@ -3061,10 +3061,10 @@ class Named_type : public Type ...@@ -3061,10 +3061,10 @@ class Named_type : public Type
type_(type), local_methods_(NULL), all_methods_(NULL), type_(type), local_methods_(NULL), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL), interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
location_(location), named_btype_(NULL), dependencies_(), location_(location), named_btype_(NULL), dependencies_(),
is_visible_(true), is_error_(false), is_placeholder_(false), is_alias_(false), is_visible_(true), is_error_(false),
is_converted_(false), is_circular_(false), is_verified_(false), is_placeholder_(false), is_converted_(false), is_circular_(false),
seen_(false), seen_in_compare_is_identity_(false), is_verified_(false), seen_(false), seen_in_compare_is_identity_(false),
seen_in_get_backend_(false) seen_in_get_backend_(false), seen_alias_(false)
{ } { }
// Return the associated Named_object. This holds the actual name. // Return the associated Named_object. This holds the actual name.
...@@ -3082,6 +3082,17 @@ class Named_type : public Type ...@@ -3082,6 +3082,17 @@ class Named_type : public Type
set_named_object(Named_object* no) set_named_object(Named_object* no)
{ this->named_object_ = no; } { this->named_object_ = no; }
// Whether this is an alias (type T1 = T2) rather than an ordinary
// named type (type T1 T2).
bool
is_alias() const
{ return this->is_alias_; }
// Record that this type is an alias.
void
set_is_alias()
{ this->is_alias_ = true; }
// Return the function in which this type is defined. This will // Return the function in which this type is defined. This will
// return NULL for a type defined in global scope. // return NULL for a type defined in global scope.
const Named_object* const Named_object*
...@@ -3143,11 +3154,6 @@ class Named_type : public Type ...@@ -3143,11 +3154,6 @@ class Named_type : public Type
is_builtin() const is_builtin() const
{ return Linemap::is_predeclared_location(this->location_); } { return Linemap::is_predeclared_location(this->location_); }
// Whether this is an alias. There are currently two aliases: byte
// and rune.
bool
is_alias() const;
// Whether this named type is valid. A recursive named type is invalid. // Whether this named type is valid. A recursive named type is invalid.
bool bool
is_valid() const is_valid() const
...@@ -3195,8 +3201,7 @@ class Named_type : public Type ...@@ -3195,8 +3201,7 @@ class Named_type : public Type
// Return the list of local methods. // Return the list of local methods.
const Bindings* const Bindings*
local_methods() const local_methods() const;
{ return this->local_methods_; }
// Build the complete list of methods, including those from // Build the complete list of methods, including those from
// anonymous fields, and build method stubs if needed. // anonymous fields, and build method stubs if needed.
...@@ -3206,14 +3211,12 @@ class Named_type : public Type ...@@ -3206,14 +3211,12 @@ class Named_type : public Type
// Return whether this type has any methods. This should only be // Return whether this type has any methods. This should only be
// called after the finalize_methods pass. // called after the finalize_methods pass.
bool bool
has_any_methods() const has_any_methods() const;
{ return this->all_methods_ != NULL; }
// Return the methods for this type. This should only be called // Return the methods for this type. This should only be called
// after the finalized_methods pass. // after the finalized_methods pass.
const Methods* const Methods*
methods() const methods() const;
{ return this->all_methods_; }
// Return the method to use for NAME. This returns NULL if there is // Return the method to use for NAME. This returns NULL if there is
// no such method or if the method is ambiguous. When it returns // no such method or if the method is ambiguous. When it returns
...@@ -3246,6 +3249,16 @@ class Named_type : public Type ...@@ -3246,6 +3249,16 @@ class Named_type : public Type
is_named_backend_type_size_known() const is_named_backend_type_size_known() const
{ return this->named_btype_ != NULL && !this->is_placeholder_; } { return this->named_btype_ != NULL && !this->is_placeholder_; }
// Add to the reflection string as for Type::append_reflection, but
// if USE_ALIAS use the alias name rather than the alias target.
void
append_reflection_type_name(Gogo*, bool use_alias, std::string*) const;
// Append the mangled type name as for Type::append_mangled_name,
// but if USE_ALIAS use the alias name rather than the alias target.
void
append_mangled_type_name(Gogo*, bool use_alias, std::string*) const;
// Export the type. // Export the type.
void void
export_named_type(Export*, const std::string& name) const; export_named_type(Export*, const std::string& name) const;
...@@ -3340,6 +3353,8 @@ class Named_type : public Type ...@@ -3340,6 +3353,8 @@ class Named_type : public Type
// where we can't convert S2 to the backend representation unless we // where we can't convert S2 to the backend representation unless we
// have converted S1. // have converted S1.
std::vector<Named_type*> dependencies_; std::vector<Named_type*> dependencies_;
// Whether this is an alias type.
bool is_alias_;
// Whether this type is visible. This is false if this type was // Whether this type is visible. This is false if this type was
// created because it was referenced by an imported object, but the // created because it was referenced by an imported object, but the
// type itself was not exported. This will always be true for types // type itself was not exported. This will always be true for types
...@@ -3367,6 +3382,8 @@ class Named_type : public Type ...@@ -3367,6 +3382,8 @@ class Named_type : public Type
bool seen_in_compare_is_identity_; bool seen_in_compare_is_identity_;
// Like seen_, but used only by do_get_backend. // Like seen_, but used only by do_get_backend.
bool seen_in_get_backend_; bool seen_in_get_backend_;
// Like seen_, but used when resolving aliases.
mutable bool seen_alias_;
}; };
// A forward declaration. This handles a type which has been declared // A forward declaration. This handles a type which has been declared
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment