Skip to content

Commit

Permalink
compiler: implement type aliases
Browse files Browse the repository at this point in the history
    
    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
  • Loading branch information
ian committed Jan 14, 2017
1 parent 929468b commit 9c164db
Show file tree
Hide file tree
Showing 7 changed files with 406 additions and 54 deletions.
2 changes: 1 addition & 1 deletion 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.
3 changes: 3 additions & 0 deletions gcc/go/gofrontend/export.cc
Expand Up @@ -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);
Expand Down
38 changes: 37 additions & 1 deletion gcc/go/gofrontend/gogo.cc
Expand Up @@ -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());
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions gcc/go/gofrontend/import.cc
Expand Up @@ -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.
Expand Down Expand Up @@ -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());

Expand Down
21 changes: 15 additions & 6 deletions gcc/go/gofrontend/parse.cc
Expand Up @@ -1515,7 +1515,7 @@ Parse::type_decl()
this->decl(&Parse::type_spec, NULL);
}

// TypeSpec = identifier Type .
// TypeSpec = identifier ["="] Type .

void
Parse::type_spec(void*)
Expand All @@ -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.
Expand All @@ -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
{
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9c164db

Please sign in to comment.