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
merge done from the gofrontend repository.
......@@ -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);
......
......@@ -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)
......
......@@ -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());
......
......@@ -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
......
......@@ -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
......
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