From 9c164db9de0066ad818d63393025570081bb2019 Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 14 Jan 2017 01:50:31 +0000 Subject: [PATCH] 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 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244460 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 3 + gcc/go/gofrontend/gogo.cc | 38 +++- gcc/go/gofrontend/import.cc | 10 ++ gcc/go/gofrontend/parse.cc | 21 ++- gcc/go/gofrontend/types.cc | 339 ++++++++++++++++++++++++++++++++---- gcc/go/gofrontend/types.h | 47 +++-- 7 files changed, 406 insertions(+), 54 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index d594ded36b34e..61359d33d484e 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0ba4563a4b0dec4c01b90d7b3c9e2ce2cd58a96f +ea73a80a6047f477d92fccc7de143a3ee1021c65 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index bec4c7ff978e1..6e085991a23ad 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -608,6 +608,9 @@ Export::write_type(const Type* type) // definition of the type may refer to the named type via a // pointer. this->type_refs_[type] = index; + + if (named_type != NULL && named_type->is_alias()) + this->write_c_string("= "); } type->export_type(this); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 34346a76a0f65..ad2541c6eee9a 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -108,12 +108,14 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) uint8_type->integer_type()->set_is_byte(); Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type, loc); + byte_type->type_value()->set_is_alias(); this->add_named_type(byte_type->type_value()); // "rune" is an alias for "int32". int32_type->integer_type()->set_is_rune(); Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type, loc); + rune_type->type_value()->set_is_alias(); this->add_named_type(rune_type->type_value()); this->add_named_type(Type::make_named_bool_type()); @@ -1775,6 +1777,10 @@ Gogo::start_function(const std::string& name, Function_type* type, if (rtype->classification() == Type::TYPE_POINTER) 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()) ret = Named_object::make_function(name, NULL, function); else if (rtype->named_type() != NULL) @@ -6865,7 +6871,7 @@ Type_declaration::add_method_declaration(const std::string& name, return ret; } -// Return whether any methods ere defined. +// Return whether any methods are defined. bool Type_declaration::has_methods() const @@ -6878,6 +6884,36 @@ Type_declaration::has_methods() const void 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::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::const_iterator p = this->methods_.begin(); p != this->methods_.end(); ++p) diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 2694cea479730..f6b4e0c0566a3 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -737,6 +737,13 @@ Import::read_type() 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 clause of that package. The type name will include // the pkgpath, which may be different. @@ -810,6 +817,9 @@ Import::read_type() // This type has not yet been imported. ntype->clear_is_visible(); + if (is_alias) + ntype->set_is_alias(); + if (!type->is_undefined() && type->interface_type() != NULL) this->gogo_->record_interface_type(type->interface_type()); diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 34a7765418db9..84840fb79c17c 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1515,7 +1515,7 @@ Parse::type_decl() this->decl(&Parse::type_spec, NULL); } -// TypeSpec = identifier Type . +// TypeSpec = identifier ["="] Type . void Parse::type_spec(void*) @@ -1531,6 +1531,13 @@ Parse::type_spec(void*) Location location = token->location(); 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 // identifier appears in the source code. We implement this by // declaring the type before we read the type definition. @@ -1542,13 +1549,13 @@ Parse::type_spec(void*) } 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 // to record an interface with a blank type name. type = this->interface_type(false); } - else if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) + else if (!token->is_op(OPERATOR_SEMICOLON)) type = this->type(); else { @@ -1579,9 +1586,11 @@ Parse::type_spec(void*) type = Type::make_error_type(); } - this->gogo_->define_type(named_type, - Type::make_named_type(named_type, type, - location)); + Named_type* nt = Type::make_named_type(named_type, type, location); + if (is_alias) + nt->set_is_alias(); + + this->gogo_->define_type(named_type, nt); go_assert(named_type->package() == NULL); } else diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0d14adf65b5f6..296e8e51ee0f9 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -328,10 +328,10 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, t2 = t2->forwarded(); // Ignore aliases for purposes of type identity. - if (t1->named_type() != NULL && t1->named_type()->is_alias()) - t1 = t1->named_type()->real_type(); - if (t2->named_type() != NULL && t2->named_type()->is_alias()) - t2 = t2->named_type()->real_type(); + while (t1->named_type() != NULL && t1->named_type()->is_alias()) + t1 = t1->named_type()->real_type()->forwarded(); + while (t2->named_type() != NULL && t2->named_type()->is_alias()) + t2 = t2->named_type()->real_type()->forwarded(); if (t1 == t2) return true; @@ -822,6 +822,8 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) unsigned int 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; if (this->classification_ != TYPE_FORWARD) ret += this->classification_; @@ -1165,8 +1167,8 @@ Bexpression* Type::type_descriptor_pointer(Gogo* gogo, Location location) { Type* t = this->forwarded(); - if (t->named_type() != NULL && t->named_type()->is_alias()) - t = t->named_type()->real_type(); + while (t->named_type() != NULL && t->named_type()->is_alias()) + t = t->named_type()->real_type()->forwarded(); if (t->type_descriptor_var_ == NULL) { t->make_type_descriptor_var(gogo); @@ -1585,6 +1587,9 @@ Type::make_type_descriptor_ptr_type() bool 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()) return false; if (!this->compare_is_identity(gogo)) @@ -1593,7 +1598,6 @@ Type::needs_specific_type_functions(Gogo* gogo) // We create a few predeclared types for type descriptors; they are // really just for the backend and don't need hash or equality // functions. - Named_type* nt = this->named_type(); if (nt != NULL && Linemap::is_predeclared_location(nt->location())) return false; @@ -1634,6 +1638,11 @@ Type::type_functions(Gogo* gogo, Named_type* name, Function_type* hash_fntype, Function_type* equal_fntype, Named_object** hash_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()) { *hash_fn = NULL; @@ -2164,6 +2173,11 @@ Type::write_named_hash(Gogo* gogo, Named_type* name, Location bloc = Linemap::predeclared_location(); 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); // The pointer to the type we are going to hash. This is an @@ -2371,8 +2385,8 @@ Bexpression* Type::gc_symbol_pointer(Gogo* gogo) { Type* t = this->forwarded(); - if (t->named_type() != NULL && t->named_type()->is_alias()) - t = t->named_type()->real_type(); + while (t->named_type() != NULL && t->named_type()->is_alias()) + t = t->named_type()->real_type()->forwarded(); if (t->gc_symbol_var_ == NULL) { t->make_gc_symbol_var(gogo); @@ -4857,7 +4871,10 @@ Struct_field::field_name() const if (dt->forward_declaration_type() != NULL) return dt->forward_declaration_type()->name(); 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()) { static const std::string error_string = "*error*"; @@ -5786,7 +5803,12 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const else ret->append(Gogo::unpack_hidden_name(p->field_name())); 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()) { @@ -5866,7 +5888,15 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const ret->append(buf); 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()) { const std::string& tag(p->tag()); @@ -9313,18 +9343,6 @@ Named_type::message_name() const 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 // 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 Named_object* Named_type::add_method(const std::string& name, Function* function) { + go_assert(!this->is_alias_); if (this->local_methods_ == NULL) this->local_methods_ = new Bindings(NULL); return this->local_methods_->add_function(name, NULL, function); @@ -9396,6 +9415,7 @@ Named_type::add_method_declaration(const std::string& name, Package* package, Function_type* type, Location location) { + go_assert(!this->is_alias_); if (this->local_methods_ == NULL) this->local_methods_ = new Bindings(NULL); 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, void Named_type::add_existing_method(Named_object* no) { + go_assert(!this->is_alias_); if (this->local_methods_ == NULL) this->local_methods_ = new Bindings(NULL); this->local_methods_->add_named_object(no); @@ -9418,11 +9439,51 @@ Named_type::add_existing_method(Named_object* no) Named_object* 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) return NULL; 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 // error reporting. @@ -9430,6 +9491,22 @@ bool Named_type::is_unexported_local_method(Gogo* gogo, 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_; if (methods != NULL) { @@ -9454,6 +9531,8 @@ Named_type::is_unexported_local_method(Gogo* gogo, void Named_type::finalize_methods(Gogo* gogo) { + if (this->is_alias_) + return; if (this->all_methods_ != NULL) return; @@ -9474,6 +9553,56 @@ Named_type::finalize_methods(Gogo* gogo) 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 // ambiguous. Set *IS_AMBIGUOUS if the method exists but is // ambiguous. @@ -9481,6 +9610,26 @@ Named_type::finalize_methods(Gogo* gogo) Method* 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); } @@ -9491,6 +9640,25 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const Expression* 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, &this->interface_method_tables_, &this->pointer_interface_method_tables_); @@ -9609,6 +9777,55 @@ Find_type_use::type(Type* type) 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. bool @@ -9618,6 +9835,22 @@ Named_type::do_verify() return 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); Type::traverse(this->type_, &find); if (find.found()) @@ -9718,8 +9951,11 @@ Named_type::do_needs_key_update() unsigned int Named_type::do_hash_for_method(Gogo* gogo) const { - if (this->is_alias()) - return this->type_->named_type()->do_hash_for_method(gogo); + if (this->is_error_) + return 0; + + // Aliases are handled in Type::hash_for_method. + go_assert(!this->is_alias_); const std::string& name(this->named_object()->name()); unsigned int ret = Type::hash_string(name, 0); @@ -10089,8 +10325,17 @@ Named_type::do_get_backend(Gogo* gogo) Expression* Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - if (name == NULL && this->is_alias()) - return this->type_->type_descriptor(gogo, this->type_); + if (this->is_error_) + 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 // descriptor for this type; we want the descriptor for the @@ -10106,9 +10351,25 @@ Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) void 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->seen_alias_ = false; return; } if (!this->is_builtin()) @@ -10173,9 +10434,25 @@ Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals, void 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->seen_alias_ = false; return; } Named_object* no = this->named_object_; @@ -11392,7 +11669,7 @@ Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name) if (name != NULL) return this->named_type_descriptor(gogo, t, name); else - return Expression::make_type_descriptor(t, ploc); + return Expression::make_error(this->named_object_->location()); } } diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index e9c31628ec13c..a2a6e611cc8df 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -3061,10 +3061,10 @@ class Named_type : public Type type_(type), local_methods_(NULL), all_methods_(NULL), interface_method_tables_(NULL), pointer_interface_method_tables_(NULL), location_(location), named_btype_(NULL), dependencies_(), - is_visible_(true), is_error_(false), is_placeholder_(false), - is_converted_(false), is_circular_(false), is_verified_(false), - seen_(false), seen_in_compare_is_identity_(false), - seen_in_get_backend_(false) + is_alias_(false), is_visible_(true), is_error_(false), + is_placeholder_(false), is_converted_(false), is_circular_(false), + is_verified_(false), seen_(false), seen_in_compare_is_identity_(false), + seen_in_get_backend_(false), seen_alias_(false) { } // Return the associated Named_object. This holds the actual name. @@ -3082,6 +3082,17 @@ class Named_type : public Type set_named_object(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 NULL for a type defined in global scope. const Named_object* @@ -3143,11 +3154,6 @@ class Named_type : public Type is_builtin() const { 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. bool is_valid() const @@ -3195,8 +3201,7 @@ class Named_type : public Type // Return the list of local methods. const Bindings* - local_methods() const - { return this->local_methods_; } + local_methods() const; // Build the complete list of methods, including those from // anonymous fields, and build method stubs if needed. @@ -3206,14 +3211,12 @@ class Named_type : public Type // Return whether this type has any methods. This should only be // called after the finalize_methods pass. bool - has_any_methods() const - { return this->all_methods_ != NULL; } + has_any_methods() const; // Return the methods for this type. This should only be called // after the finalized_methods pass. const Methods* - methods() const - { return this->all_methods_; } + methods() const; // 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 @@ -3246,6 +3249,16 @@ class Named_type : public Type is_named_backend_type_size_known() const { 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. void export_named_type(Export*, const std::string& name) const; @@ -3340,6 +3353,8 @@ class Named_type : public Type // where we can't convert S2 to the backend representation unless we // have converted S1. std::vector dependencies_; + // Whether this is an alias type. + bool is_alias_; // Whether this type is visible. This is false if this type was // created because it was referenced by an imported object, but the // type itself was not exported. This will always be true for types @@ -3367,6 +3382,8 @@ class Named_type : public Type bool seen_in_compare_is_identity_; // Like seen_, but used only by do_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