compiler: implement type aliases
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 14 Jan 2017 01:50:31 +0000 (01:50 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 14 Jan 2017 01:50:31 +0000 (01:50 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/export.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/import.cc
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index d594ded36b34e172700e7f0a1fcca00a5ee29cc8..61359d33d484e1e73910dda297cfbb24ec3fcd8a 100644 (file)
@@ -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.
index bec4c7ff978e1dde8d201f4181c882bc135e3c1a..6e085991a23ad76bb3796c1f66450b9f40bda5a4 100644 (file)
@@ -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);
index 34346a76a0f657925b9bcae1827384bc4aafc383..ad2541c6eee9ae3c6384b788b04b1591fd852636 100644 (file)
@@ -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<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();
        p != this->methods_.end();
        ++p)
index 2694cea4797309e2b29e508b3e8182b2e3d3bccf..f6b4e0c0566a346552662ec707334d5617628dd3 100644 (file)
@@ -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());
 
index 34a7765418db9e71a766450bb43a62c54258af77..84840fb79c17cf986d2d0583797bf8df86f19279 100644 (file)
@@ -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
index 0d14adf65b5f63f60f1a5dd205069643706fbfe4..296e8e51ee0f9c6cadec6ec037c6eefc153f72e4 100644 (file)
@@ -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());
     }
 }
 
index e9c31628ec13cf83723cdfd08c0d5417982cee7f..a2a6e611cc8df5060688a18fde4fd7e797b90c20 100644 (file)
@@ -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<Named_type*> 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