compiler: finalize methods for type aliases of struct types

Previously we would finalize the methods of the alias type itself, but
since its a type alias we really need to finalize the methods of the
aliased type.

Also, handle method expressions of unnamed struct types.

Test case is https://golang.org/cl/251168.

Fixes golang/go#38125

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/251279
This commit is contained in:
Ian Lance Taylor 2020-08-27 22:18:45 -07:00
parent 1e19ecd79b
commit 27edc6c3e2
3 changed files with 35 additions and 21 deletions

View File

@ -1,4 +1,4 @@
6f309797e4f7eed635950687e902a294126e6fc6
a59167c29d6ad2ddf533b3a12b365f72df0e1476
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -14529,21 +14529,19 @@ Selector_expression::lower_method_expression(Gogo* gogo)
is_pointer = true;
type = type->points_to();
}
Named_type* nt = type->named_type();
if (nt == NULL)
{
go_error_at(location,
("method expression requires named type or "
"pointer to named type"));
return Expression::make_error(location);
}
Named_type* nt = type->named_type();
Struct_type* st = type->struct_type();
bool is_ambiguous;
Method* method = nt->method_function(name, &is_ambiguous);
Method* method = NULL;
if (nt != NULL)
method = nt->method_function(name, &is_ambiguous);
else if (st != NULL)
method = st->method_function(name, &is_ambiguous);
const Typed_identifier* imethod = NULL;
if (method == NULL && !is_pointer)
{
Interface_type* it = nt->interface_type();
Interface_type* it = type->interface_type();
if (it != NULL)
imethod = it->find_method(name);
}
@ -14551,16 +14549,28 @@ Selector_expression::lower_method_expression(Gogo* gogo)
if ((method == NULL && imethod == NULL)
|| (left_type->named_type() != NULL && left_type->points_to() != NULL))
{
if (!is_ambiguous)
go_error_at(location, "type %<%s%s%> has no method %<%s%>",
is_pointer ? "*" : "",
nt->message_name().c_str(),
Gogo::message_name(name).c_str());
if (nt != NULL)
{
if (!is_ambiguous)
go_error_at(location, "type %<%s%s%> has no method %<%s%>",
is_pointer ? "*" : "",
nt->message_name().c_str(),
Gogo::message_name(name).c_str());
else
go_error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>",
Gogo::message_name(name).c_str(),
is_pointer ? "*" : "",
nt->message_name().c_str());
}
else
go_error_at(location, "method %<%s%s%> is ambiguous in type %<%s%>",
Gogo::message_name(name).c_str(),
is_pointer ? "*" : "",
nt->message_name().c_str());
{
if (!is_ambiguous)
go_error_at(location, "type has no method %<%s%>",
Gogo::message_name(name).c_str());
else
go_error_at(location, "method %<%s%> is ambiguous",
Gogo::message_name(name).c_str());
}
return Expression::make_error(location);
}
@ -14657,7 +14667,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
Expression* ve = Expression::make_var_reference(vno, location);
Expression* bm;
if (method != NULL)
bm = Type::bind_field_or_method(gogo, nt, ve, name, location);
bm = Type::bind_field_or_method(gogo, type, ve, name, location);
else
bm = Expression::make_interface_field_reference(ve, name, location);

View File

@ -3508,6 +3508,10 @@ Finalize_methods::type(Type* t)
case Type::TYPE_NAMED:
{
Named_type* nt = t->named_type();
if (nt->is_alias())
return TRAVERSE_CONTINUE;
Type* rt = nt->real_type();
if (rt->classification() != Type::TYPE_STRUCT)
{