compiler: Handle recursive interfaces.
* go-gcc.cc (Gcc_backend::placeholder_struct_type): Permit name to be empty. (Gcc_backend::set_placeholder_struct_type): Likewise. From-SVN: r183340
This commit is contained in:
parent
0ab6e1eceb
commit
7c0434e577
@ -1,3 +1,9 @@
|
|||||||
|
2012-01-20 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
|
* go-gcc.cc (Gcc_backend::placeholder_struct_type): Permit name to
|
||||||
|
be empty.
|
||||||
|
(Gcc_backend::set_placeholder_struct_type): Likewise.
|
||||||
|
|
||||||
2012-01-17 Ian Lance Taylor <iant@google.com>
|
2012-01-17 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
* gospec.c (lang_specific_driver): If we see -S without -o, add -o
|
* gospec.c (lang_specific_driver): If we see -S without -o, add -o
|
||||||
|
@ -656,10 +656,13 @@ Gcc_backend::placeholder_struct_type(const std::string& name,
|
|||||||
Location location)
|
Location location)
|
||||||
{
|
{
|
||||||
tree ret = make_node(RECORD_TYPE);
|
tree ret = make_node(RECORD_TYPE);
|
||||||
tree decl = build_decl(location.gcc_location(), TYPE_DECL,
|
if (!name.empty())
|
||||||
get_identifier_from_string(name),
|
{
|
||||||
ret);
|
tree decl = build_decl(location.gcc_location(), TYPE_DECL,
|
||||||
TYPE_NAME(ret) = decl;
|
get_identifier_from_string(name),
|
||||||
|
ret);
|
||||||
|
TYPE_NAME(ret) = decl;
|
||||||
|
}
|
||||||
return this->make_type(ret);
|
return this->make_type(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,10 +677,13 @@ Gcc_backend::set_placeholder_struct_type(
|
|||||||
gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE);
|
gcc_assert(TREE_CODE(t) == RECORD_TYPE && TYPE_FIELDS(t) == NULL_TREE);
|
||||||
Btype* r = this->fill_in_struct(placeholder, fields);
|
Btype* r = this->fill_in_struct(placeholder, fields);
|
||||||
|
|
||||||
// Build the data structure gcc wants to see for a typedef.
|
if (TYPE_NAME(t) != NULL_TREE)
|
||||||
tree copy = build_distinct_type_copy(t);
|
{
|
||||||
TYPE_NAME(copy) = NULL_TREE;
|
// Build the data structure gcc wants to see for a typedef.
|
||||||
DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy;
|
tree copy = build_distinct_type_copy(t);
|
||||||
|
TYPE_NAME(copy) = NULL_TREE;
|
||||||
|
DECL_ORIGINAL_TYPE(TYPE_NAME(t)) = copy;
|
||||||
|
}
|
||||||
|
|
||||||
return r->get_tree() != error_mark_node;
|
return r->get_tree() != error_mark_node;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,8 @@ class Backend
|
|||||||
set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0;
|
set_placeholder_function_type(Btype* placeholder, Btype* ft) = 0;
|
||||||
|
|
||||||
// Create a placeholder struct type. This is used for a named
|
// Create a placeholder struct type. This is used for a named
|
||||||
// struct type, as with placeholder_pointer_type.
|
// struct type, as with placeholder_pointer_type. It is also used
|
||||||
|
// for interface types, in which case NAME will be the empty string.
|
||||||
virtual Btype*
|
virtual Btype*
|
||||||
placeholder_struct_type(const std::string& name, Location) = 0;
|
placeholder_struct_type(const std::string& name, Location) = 0;
|
||||||
|
|
||||||
|
@ -7566,7 +7566,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
|||||||
{
|
{
|
||||||
// Calling recover outside of a function always returns the
|
// Calling recover outside of a function always returns the
|
||||||
// nil empty interface.
|
// nil empty interface.
|
||||||
Type* eface = Type::make_interface_type(NULL, loc);
|
Type* eface = Type::make_empty_interface_type(loc);
|
||||||
return Expression::make_cast(eface, Expression::make_nil(loc), loc);
|
return Expression::make_cast(eface, Expression::make_nil(loc), loc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -8189,7 +8189,7 @@ Builtin_call_expression::do_type()
|
|||||||
return Type::make_void_type();
|
return Type::make_void_type();
|
||||||
|
|
||||||
case BUILTIN_RECOVER:
|
case BUILTIN_RECOVER:
|
||||||
return Type::make_interface_type(NULL, Linemap::predeclared_location());
|
return Type::make_empty_interface_type(Linemap::predeclared_location());
|
||||||
|
|
||||||
case BUILTIN_APPEND:
|
case BUILTIN_APPEND:
|
||||||
{
|
{
|
||||||
@ -8883,7 +8883,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
|
|||||||
if (arg_tree == error_mark_node)
|
if (arg_tree == error_mark_node)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
Type *empty =
|
Type *empty =
|
||||||
Type::make_interface_type(NULL, Linemap::predeclared_location());
|
Type::make_empty_interface_type(Linemap::predeclared_location());
|
||||||
arg_tree = Expression::convert_for_assignment(context, empty,
|
arg_tree = Expression::convert_for_assignment(context, empty,
|
||||||
arg->type(),
|
arg->type(),
|
||||||
arg_tree, location);
|
arg_tree, location);
|
||||||
@ -8916,7 +8916,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
|
|||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
Type *empty =
|
Type *empty =
|
||||||
Type::make_interface_type(NULL, Linemap::predeclared_location());
|
Type::make_empty_interface_type(Linemap::predeclared_location());
|
||||||
tree empty_tree = type_to_tree(empty->get_backend(context->gogo()));
|
tree empty_tree = type_to_tree(empty->get_backend(context->gogo()));
|
||||||
|
|
||||||
Type* nil_type = Type::make_nil_type();
|
Type* nil_type = Type::make_nil_type();
|
||||||
|
@ -110,7 +110,8 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
|
|||||||
results->push_back(Typed_identifier("", Type::lookup_string_type(), loc));
|
results->push_back(Typed_identifier("", Type::lookup_string_type(), loc));
|
||||||
Type *method_type = Type::make_function_type(NULL, NULL, results, loc);
|
Type *method_type = Type::make_function_type(NULL, NULL, results, loc);
|
||||||
methods->push_back(Typed_identifier("Error", method_type, loc));
|
methods->push_back(Typed_identifier("Error", method_type, loc));
|
||||||
Type *error_iface = Type::make_interface_type(methods, loc);
|
Interface_type *error_iface = Type::make_interface_type(methods, loc);
|
||||||
|
error_iface->finalize_methods();
|
||||||
Named_type *error_type = Named_object::make_type("error", NULL, error_iface, loc)->type_value();
|
Named_type *error_type = Named_object::make_type("error", NULL, error_iface, loc)->type_value();
|
||||||
this->add_named_type(error_type);
|
this->add_named_type(error_type);
|
||||||
}
|
}
|
||||||
@ -175,7 +176,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
|
|||||||
print_type->set_is_builtin();
|
print_type->set_is_builtin();
|
||||||
this->globals_->add_function_declaration("println", NULL, print_type, loc);
|
this->globals_->add_function_declaration("println", NULL, print_type, loc);
|
||||||
|
|
||||||
Type *empty = Type::make_interface_type(NULL, loc);
|
Type *empty = Type::make_empty_interface_type(loc);
|
||||||
Typed_identifier_list* panic_parms = new Typed_identifier_list();
|
Typed_identifier_list* panic_parms = new Typed_identifier_list();
|
||||||
panic_parms->push_back(Typed_identifier("e", empty, loc));
|
panic_parms->push_back(Typed_identifier("e", empty, loc));
|
||||||
Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
|
Function_type *panic_type = Type::make_function_type(NULL, panic_parms,
|
||||||
@ -1564,7 +1565,8 @@ Finalize_methods::type(Type* t)
|
|||||||
// finalize the methods of the field types, not of the struct
|
// finalize the methods of the field types, not of the struct
|
||||||
// type itself. We don't want to add methods to the struct,
|
// type itself. We don't want to add methods to the struct,
|
||||||
// since it has a name.
|
// since it has a name.
|
||||||
Type* rt = t->named_type()->real_type();
|
Named_type* nt = t->named_type();
|
||||||
|
Type* rt = nt->real_type();
|
||||||
if (rt->classification() != Type::TYPE_STRUCT)
|
if (rt->classification() != Type::TYPE_STRUCT)
|
||||||
{
|
{
|
||||||
if (Type::traverse(rt, this) == TRAVERSE_EXIT)
|
if (Type::traverse(rt, this) == TRAVERSE_EXIT)
|
||||||
@ -1576,7 +1578,21 @@ Finalize_methods::type(Type* t)
|
|||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->named_type()->finalize_methods(this->gogo_);
|
nt->finalize_methods(this->gogo_);
|
||||||
|
|
||||||
|
// If this type is defined in a different package, then finalize the
|
||||||
|
// types of all the methods, since we won't see them otherwise.
|
||||||
|
if (nt->named_object()->package() != NULL && nt->has_any_methods())
|
||||||
|
{
|
||||||
|
const Methods* methods = nt->methods();
|
||||||
|
for (Methods::const_iterator p = methods->begin();
|
||||||
|
p != methods->end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (Type::traverse(p->second->type(), this) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRAVERSE_SKIP_COMPONENTS;
|
return TRAVERSE_SKIP_COMPONENTS;
|
||||||
}
|
}
|
||||||
@ -2622,6 +2638,9 @@ class Build_method_tables : public Traverse
|
|||||||
void
|
void
|
||||||
Gogo::build_interface_method_tables()
|
Gogo::build_interface_method_tables()
|
||||||
{
|
{
|
||||||
|
if (saw_errors())
|
||||||
|
return;
|
||||||
|
|
||||||
std::vector<Interface_type*> hidden_interfaces;
|
std::vector<Interface_type*> hidden_interfaces;
|
||||||
hidden_interfaces.reserve(this->interface_types_.size());
|
hidden_interfaces.reserve(this->interface_types_.size());
|
||||||
for (std::vector<Interface_type*>::const_iterator pi =
|
for (std::vector<Interface_type*>::const_iterator pi =
|
||||||
@ -4922,10 +4941,7 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
|||||||
| Traverse::traverse_statements
|
| Traverse::traverse_statements
|
||||||
| Traverse::traverse_expressions
|
| Traverse::traverse_expressions
|
||||||
| Traverse::traverse_types)) != 0)
|
| Traverse::traverse_types)) != 0)
|
||||||
{
|
t = p->func_value()->traverse(traverse);
|
||||||
if (p->func_value()->traverse(traverse) == TRAVERSE_EXIT)
|
|
||||||
return TRAVERSE_EXIT;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Named_object::NAMED_OBJECT_PACKAGE:
|
case Named_object::NAMED_OBJECT_PACKAGE:
|
||||||
@ -4952,6 +4968,26 @@ Bindings::traverse(Traverse* traverse, bool is_global)
|
|||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we need to traverse types, check the function declarations,
|
||||||
|
// which have types. We don't need to check the type declarations,
|
||||||
|
// as those are just names.
|
||||||
|
if ((traverse_mask & e_or_t) != 0)
|
||||||
|
{
|
||||||
|
for (Bindings::const_declarations_iterator p =
|
||||||
|
this->begin_declarations();
|
||||||
|
p != this->end_declarations();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (p->second->is_function_declaration())
|
||||||
|
{
|
||||||
|
if (Type::traverse(p->second->func_declaration_value()->type(),
|
||||||
|
traverse)
|
||||||
|
== TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5090,9 +5126,12 @@ Traverse::remember_type(const Type* type)
|
|||||||
return true;
|
return true;
|
||||||
go_assert((this->traverse_mask() & traverse_types) != 0
|
go_assert((this->traverse_mask() & traverse_types) != 0
|
||||||
|| (this->traverse_mask() & traverse_expressions) != 0);
|
|| (this->traverse_mask() & traverse_expressions) != 0);
|
||||||
// We only have to remember named types, as they are the only ones
|
// We mostly only have to remember named types. But it turns out
|
||||||
// we can see multiple times in a traversal.
|
// that an interface type can refer to itself without using a name
|
||||||
if (type->classification() != Type::TYPE_NAMED)
|
// by relying on interface inheritance, as in
|
||||||
|
// type I interface { F() interface{I} }
|
||||||
|
if (type->classification() != Type::TYPE_NAMED
|
||||||
|
&& type->classification() != Type::TYPE_INTERFACE)
|
||||||
return false;
|
return false;
|
||||||
if (this->types_seen_ == NULL)
|
if (this->types_seen_ == NULL)
|
||||||
this->types_seen_ = new Types_seen();
|
this->types_seen_ = new Types_seen();
|
||||||
|
@ -2578,8 +2578,13 @@ class Traverse
|
|||||||
type(Type*);
|
type(Type*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Unordered_set_hash(const Type*, Type_hash_identical,
|
// A hash table for types we have seen during this traversal. Note
|
||||||
Type_identical) Types_seen;
|
// that this uses the default hash functions for pointers rather
|
||||||
|
// than Type_hash_identical and Type_identical. This is because for
|
||||||
|
// traversal we care about seeing a specific type structure. If
|
||||||
|
// there are two separate instances of identical types, we want to
|
||||||
|
// traverse both.
|
||||||
|
typedef Unordered_set(const Type*) Types_seen;
|
||||||
|
|
||||||
typedef Unordered_set(const Expression*) Expressions_seen;
|
typedef Unordered_set(const Expression*) Expressions_seen;
|
||||||
|
|
||||||
|
@ -151,12 +151,14 @@ runtime_function_type(Runtime_function_type bft)
|
|||||||
Typed_identifier_list* methods = new Typed_identifier_list();
|
Typed_identifier_list* methods = new Typed_identifier_list();
|
||||||
Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
|
Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
|
||||||
methods->push_back(Typed_identifier("x", mtype, bloc));
|
methods->push_back(Typed_identifier("x", mtype, bloc));
|
||||||
t = Type::make_interface_type(methods, bloc);
|
Interface_type* it = Type::make_interface_type(methods, bloc);
|
||||||
|
it->finalize_methods();
|
||||||
|
t = it;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFT_EFACE:
|
case RFT_EFACE:
|
||||||
t = Type::make_interface_type(NULL, bloc);
|
t = Type::make_empty_interface_type(bloc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RFT_FUNC_PTR:
|
case RFT_FUNC_PTR:
|
||||||
|
@ -6148,9 +6148,12 @@ Type::make_channel_type(bool send, bool receive, Type* element_type)
|
|||||||
int
|
int
|
||||||
Interface_type::do_traverse(Traverse* traverse)
|
Interface_type::do_traverse(Traverse* traverse)
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
Typed_identifier_list* methods = (this->methods_are_finalized_
|
||||||
|
? this->all_methods_
|
||||||
|
: this->parse_methods_);
|
||||||
|
if (methods == NULL)
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
return this->methods_->traverse(traverse);
|
return methods->traverse(traverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the methods. This handles interface inheritance.
|
// Finalize the methods. This handles interface inheritance.
|
||||||
@ -6158,56 +6161,57 @@ Interface_type::do_traverse(Traverse* traverse)
|
|||||||
void
|
void
|
||||||
Interface_type::finalize_methods()
|
Interface_type::finalize_methods()
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
if (this->methods_are_finalized_)
|
||||||
|
return;
|
||||||
|
this->methods_are_finalized_ = true;
|
||||||
|
if (this->parse_methods_ == NULL)
|
||||||
return;
|
return;
|
||||||
std::vector<Named_type*> seen;
|
|
||||||
bool is_recursive = false;
|
|
||||||
size_t from = 0;
|
|
||||||
size_t to = 0;
|
|
||||||
while (from < this->methods_->size())
|
|
||||||
{
|
|
||||||
const Typed_identifier* p = &this->methods_->at(from);
|
|
||||||
if (!p->name().empty())
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < to; ++i)
|
|
||||||
{
|
|
||||||
if (this->methods_->at(i).name() == p->name())
|
|
||||||
{
|
|
||||||
error_at(p->location(), "duplicate method %qs",
|
|
||||||
Gogo::message_name(p->name()).c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == to)
|
|
||||||
{
|
|
||||||
if (from != to)
|
|
||||||
this->methods_->set(to, *p);
|
|
||||||
++to;
|
|
||||||
}
|
|
||||||
++from;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Interface_type* it = p->type()->interface_type();
|
this->all_methods_ = new Typed_identifier_list();
|
||||||
|
this->all_methods_->reserve(this->parse_methods_->size());
|
||||||
|
Typed_identifier_list inherit;
|
||||||
|
for (Typed_identifier_list::const_iterator pm =
|
||||||
|
this->parse_methods_->begin();
|
||||||
|
pm != this->parse_methods_->end();
|
||||||
|
++pm)
|
||||||
|
{
|
||||||
|
const Typed_identifier* p = &*pm;
|
||||||
|
if (p->name().empty())
|
||||||
|
inherit.push_back(*p);
|
||||||
|
else if (this->find_method(p->name()) == NULL)
|
||||||
|
this->all_methods_->push_back(*p);
|
||||||
|
else
|
||||||
|
error_at(p->location(), "duplicate method %qs",
|
||||||
|
Gogo::message_name(p->name()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Named_type*> seen;
|
||||||
|
seen.reserve(inherit.size());
|
||||||
|
bool issued_recursive_error = false;
|
||||||
|
while (!inherit.empty())
|
||||||
|
{
|
||||||
|
Type* t = inherit.back().type();
|
||||||
|
Location tl = inherit.back().location();
|
||||||
|
inherit.pop_back();
|
||||||
|
|
||||||
|
Interface_type* it = t->interface_type();
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
{
|
{
|
||||||
error_at(p->location(), "interface contains embedded non-interface");
|
if (!t->is_error())
|
||||||
++from;
|
error_at(tl, "interface contains embedded non-interface");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (it == this)
|
if (it == this)
|
||||||
{
|
{
|
||||||
if (!is_recursive)
|
if (!issued_recursive_error)
|
||||||
{
|
{
|
||||||
error_at(p->location(), "invalid recursive interface");
|
error_at(tl, "invalid recursive interface");
|
||||||
is_recursive = true;
|
issued_recursive_error = true;
|
||||||
}
|
}
|
||||||
++from;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Named_type* nt = p->type()->named_type();
|
Named_type* nt = t->named_type();
|
||||||
if (nt != NULL)
|
if (nt != NULL)
|
||||||
{
|
{
|
||||||
std::vector<Named_type*>::const_iterator q;
|
std::vector<Named_type*>::const_iterator q;
|
||||||
@ -6215,73 +6219,39 @@ Interface_type::finalize_methods()
|
|||||||
{
|
{
|
||||||
if (*q == nt)
|
if (*q == nt)
|
||||||
{
|
{
|
||||||
error_at(p->location(), "inherited interface loop");
|
error_at(tl, "inherited interface loop");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (q != seen.end())
|
if (q != seen.end())
|
||||||
{
|
continue;
|
||||||
++from;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
seen.push_back(nt);
|
seen.push_back(nt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Typed_identifier_list* methods = it->methods();
|
const Typed_identifier_list* imethods = it->parse_methods_;
|
||||||
if (methods == NULL)
|
if (imethods == NULL)
|
||||||
{
|
continue;
|
||||||
++from;
|
for (Typed_identifier_list::const_iterator q = imethods->begin();
|
||||||
continue;
|
q != imethods->end();
|
||||||
}
|
|
||||||
for (Typed_identifier_list::const_iterator q = methods->begin();
|
|
||||||
q != methods->end();
|
|
||||||
++q)
|
++q)
|
||||||
{
|
{
|
||||||
if (q->name().empty())
|
if (q->name().empty())
|
||||||
{
|
inherit.push_back(*q);
|
||||||
if (q->type()->forwarded() == p->type()->forwarded())
|
|
||||||
error_at(p->location(), "interface inheritance loop");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for (i = from + 1; i < this->methods_->size(); ++i)
|
|
||||||
{
|
|
||||||
const Typed_identifier* r = &this->methods_->at(i);
|
|
||||||
if (r->name().empty()
|
|
||||||
&& r->type()->forwarded() == q->type()->forwarded())
|
|
||||||
{
|
|
||||||
error_at(p->location(),
|
|
||||||
"inherited interface listed twice");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == this->methods_->size())
|
|
||||||
this->methods_->push_back(Typed_identifier(q->name(),
|
|
||||||
q->type(),
|
|
||||||
p->location()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (this->find_method(q->name()) == NULL)
|
else if (this->find_method(q->name()) == NULL)
|
||||||
this->methods_->push_back(Typed_identifier(q->name(), q->type(),
|
this->all_methods_->push_back(Typed_identifier(q->name(),
|
||||||
p->location()));
|
q->type(), tl));
|
||||||
else
|
else
|
||||||
{
|
error_at(tl, "inherited method %qs is ambiguous",
|
||||||
if (!is_recursive)
|
Gogo::message_name(q->name()).c_str());
|
||||||
error_at(p->location(), "inherited method %qs is ambiguous",
|
|
||||||
Gogo::message_name(q->name()).c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
++from;
|
|
||||||
}
|
|
||||||
if (to == 0)
|
|
||||||
{
|
|
||||||
delete this->methods_;
|
|
||||||
this->methods_ = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->all_methods_->empty())
|
||||||
|
this->all_methods_->sort_by_name();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->methods_->resize(to);
|
delete this->all_methods_;
|
||||||
this->methods_->sort_by_name();
|
this->all_methods_ = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6290,10 +6260,11 @@ Interface_type::finalize_methods()
|
|||||||
const Typed_identifier*
|
const Typed_identifier*
|
||||||
Interface_type::find_method(const std::string& name) const
|
Interface_type::find_method(const std::string& name) const
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
go_assert(this->methods_are_finalized_);
|
||||||
|
if (this->all_methods_ == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
|
||||||
p != this->methods_->end();
|
p != this->all_methods_->end();
|
||||||
++p)
|
++p)
|
||||||
if (p->name() == name)
|
if (p->name() == name)
|
||||||
return &*p;
|
return &*p;
|
||||||
@ -6305,10 +6276,10 @@ Interface_type::find_method(const std::string& name) const
|
|||||||
size_t
|
size_t
|
||||||
Interface_type::method_index(const std::string& name) const
|
Interface_type::method_index(const std::string& name) const
|
||||||
{
|
{
|
||||||
go_assert(this->methods_ != NULL);
|
go_assert(this->methods_are_finalized_ && this->all_methods_ != NULL);
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
|
||||||
p != this->methods_->end();
|
p != this->all_methods_->end();
|
||||||
++p, ++ret)
|
++p, ++ret)
|
||||||
if (p->name() == name)
|
if (p->name() == name)
|
||||||
return ret;
|
return ret;
|
||||||
@ -6321,10 +6292,11 @@ Interface_type::method_index(const std::string& name) const
|
|||||||
bool
|
bool
|
||||||
Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
|
Interface_type::is_unexported_method(Gogo* gogo, const std::string& name) const
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
go_assert(this->methods_are_finalized_);
|
||||||
|
if (this->all_methods_ == NULL)
|
||||||
return false;
|
return false;
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
|
||||||
p != this->methods_->end();
|
p != this->all_methods_->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
const std::string& method_name(p->name());
|
const std::string& method_name(p->name());
|
||||||
@ -6342,26 +6314,53 @@ bool
|
|||||||
Interface_type::is_identical(const Interface_type* t,
|
Interface_type::is_identical(const Interface_type* t,
|
||||||
bool errors_are_identical) const
|
bool errors_are_identical) const
|
||||||
{
|
{
|
||||||
|
go_assert(this->methods_are_finalized_ && t->methods_are_finalized_);
|
||||||
|
|
||||||
// We require the same methods with the same types. The methods
|
// We require the same methods with the same types. The methods
|
||||||
// have already been sorted.
|
// have already been sorted.
|
||||||
if (this->methods() == NULL || t->methods() == NULL)
|
if (this->all_methods_ == NULL || t->all_methods_ == NULL)
|
||||||
return this->methods() == t->methods();
|
return this->all_methods_ == t->all_methods_;
|
||||||
|
|
||||||
Typed_identifier_list::const_iterator p1 = this->methods()->begin();
|
if (this->assume_identical(this, t) || t->assume_identical(t, this))
|
||||||
for (Typed_identifier_list::const_iterator p2 = t->methods()->begin();
|
return true;
|
||||||
p2 != t->methods()->end();
|
|
||||||
++p1, ++p2)
|
Assume_identical* hold_ai = this->assume_identical_;
|
||||||
|
Assume_identical ai;
|
||||||
|
ai.t1 = this;
|
||||||
|
ai.t2 = t;
|
||||||
|
ai.next = hold_ai;
|
||||||
|
this->assume_identical_ = &ai;
|
||||||
|
|
||||||
|
Typed_identifier_list::const_iterator p1 = this->all_methods_->begin();
|
||||||
|
Typed_identifier_list::const_iterator p2;
|
||||||
|
for (p2 = t->all_methods_->begin(); p2 != t->all_methods_->end(); ++p1, ++p2)
|
||||||
{
|
{
|
||||||
if (p1 == this->methods()->end())
|
if (p1 == this->all_methods_->end())
|
||||||
return false;
|
break;
|
||||||
if (p1->name() != p2->name()
|
if (p1->name() != p2->name()
|
||||||
|| !Type::are_identical(p1->type(), p2->type(),
|
|| !Type::are_identical(p1->type(), p2->type(),
|
||||||
errors_are_identical, NULL))
|
errors_are_identical, NULL))
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
if (p1 != this->methods()->end())
|
|
||||||
return false;
|
this->assume_identical_ = hold_ai;
|
||||||
return true;
|
|
||||||
|
return p1 == this->all_methods_->end() && p2 == t->all_methods_->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if T1 and T2 are assumed to be identical during a type
|
||||||
|
// comparison.
|
||||||
|
|
||||||
|
bool
|
||||||
|
Interface_type::assume_identical(const Interface_type* t1,
|
||||||
|
const Interface_type* t2) const
|
||||||
|
{
|
||||||
|
for (Assume_identical* p = this->assume_identical_;
|
||||||
|
p != NULL;
|
||||||
|
p = p->next)
|
||||||
|
if ((p->t1 == t1 && p->t2 == t2) || (p->t1 == t2 && p->t2 == t1))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether we can assign the interface type T to this type. The types
|
// Whether we can assign the interface type T to this type. The types
|
||||||
@ -6373,10 +6372,11 @@ bool
|
|||||||
Interface_type::is_compatible_for_assign(const Interface_type* t,
|
Interface_type::is_compatible_for_assign(const Interface_type* t,
|
||||||
std::string* reason) const
|
std::string* reason) const
|
||||||
{
|
{
|
||||||
if (this->methods() == NULL)
|
go_assert(this->methods_are_finalized_ && t->methods_are_finalized_);
|
||||||
|
if (this->all_methods_ == NULL)
|
||||||
return true;
|
return true;
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods()->begin();
|
for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
|
||||||
p != this->methods()->end();
|
p != this->all_methods_->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
const Typed_identifier* m = t->find_method(p->name());
|
const Typed_identifier* m = t->find_method(p->name());
|
||||||
@ -6423,17 +6423,23 @@ Interface_type::is_compatible_for_assign(const Interface_type* t,
|
|||||||
// Hash code.
|
// Hash code.
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
Interface_type::do_hash_for_method(Gogo* gogo) const
|
Interface_type::do_hash_for_method(Gogo*) const
|
||||||
{
|
{
|
||||||
|
go_assert(this->methods_are_finalized_);
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
if (this->methods_ != NULL)
|
if (this->all_methods_ != NULL)
|
||||||
{
|
{
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p =
|
||||||
p != this->methods_->end();
|
this->all_methods_->begin();
|
||||||
|
p != this->all_methods_->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
ret = Type::hash_string(p->name(), ret);
|
ret = Type::hash_string(p->name(), ret);
|
||||||
ret += p->type()->hash_for_method(gogo);
|
// We don't use the method type in the hash, to avoid
|
||||||
|
// infinite recursion if an interface method uses a type
|
||||||
|
// which is an interface which inherits from the interface
|
||||||
|
// itself.
|
||||||
|
// type T interface { F() interface {T}}
|
||||||
ret <<= 1;
|
ret <<= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6446,7 +6452,8 @@ Interface_type::do_hash_for_method(Gogo* gogo) const
|
|||||||
bool
|
bool
|
||||||
Interface_type::implements_interface(const Type* t, std::string* reason) const
|
Interface_type::implements_interface(const Type* t, std::string* reason) const
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
go_assert(this->methods_are_finalized_);
|
||||||
|
if (this->all_methods_ == NULL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool is_pointer = false;
|
bool is_pointer = false;
|
||||||
@ -6499,8 +6506,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
|
||||||
p != this->methods_->end();
|
p != this->all_methods_->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
bool is_ambiguous = false;
|
bool is_ambiguous = false;
|
||||||
@ -6653,13 +6660,20 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
|
|||||||
Btype*
|
Btype*
|
||||||
Interface_type::do_get_backend(Gogo* gogo)
|
Interface_type::do_get_backend(Gogo* gogo)
|
||||||
{
|
{
|
||||||
if (this->methods_ == NULL)
|
if (this->is_empty())
|
||||||
return Interface_type::get_backend_empty_interface_type(gogo);
|
return Interface_type::get_backend_empty_interface_type(gogo);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (this->interface_btype_ != NULL)
|
||||||
|
return this->interface_btype_;
|
||||||
|
this->interface_btype_ =
|
||||||
|
gogo->backend()->placeholder_struct_type("", this->location_);
|
||||||
std::vector<Backend::Btyped_identifier> bfields;
|
std::vector<Backend::Btyped_identifier> bfields;
|
||||||
get_backend_interface_fields(gogo, this, &bfields);
|
get_backend_interface_fields(gogo, this, &bfields);
|
||||||
return gogo->backend()->struct_type(bfields);
|
if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_,
|
||||||
|
bfields))
|
||||||
|
this->interface_btype_ = gogo->backend()->error_type();
|
||||||
|
return this->interface_btype_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6721,13 +6735,14 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name)
|
|||||||
go_assert(pif->is_field_name("methods"));
|
go_assert(pif->is_field_name("methods"));
|
||||||
|
|
||||||
Expression_list* methods = new Expression_list();
|
Expression_list* methods = new Expression_list();
|
||||||
if (this->methods_ != NULL && !this->methods_->empty())
|
if (this->all_methods_ != NULL)
|
||||||
{
|
{
|
||||||
Type* elemtype = pif->type()->array_type()->element_type();
|
Type* elemtype = pif->type()->array_type()->element_type();
|
||||||
|
|
||||||
methods->reserve(this->methods_->size());
|
methods->reserve(this->all_methods_->size());
|
||||||
for (Typed_identifier_list::const_iterator pm = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator pm =
|
||||||
pm != this->methods_->end();
|
this->all_methods_->begin();
|
||||||
|
pm != this->all_methods_->end();
|
||||||
++pm)
|
++pm)
|
||||||
{
|
{
|
||||||
const Struct_field_list* mfields = elemtype->struct_type()->fields();
|
const Struct_field_list* mfields = elemtype->struct_type()->fields();
|
||||||
@ -6780,29 +6795,35 @@ void
|
|||||||
Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
|
Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
|
||||||
{
|
{
|
||||||
ret->append("interface {");
|
ret->append("interface {");
|
||||||
if (this->methods_ != NULL)
|
const Typed_identifier_list* methods = this->parse_methods_;
|
||||||
|
if (methods != NULL)
|
||||||
{
|
{
|
||||||
ret->push_back(' ');
|
ret->push_back(' ');
|
||||||
for (Typed_identifier_list::const_iterator p = this->methods_->begin();
|
for (Typed_identifier_list::const_iterator p = methods->begin();
|
||||||
p != this->methods_->end();
|
p != methods->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
if (p != this->methods_->begin())
|
if (p != methods->begin())
|
||||||
ret->append("; ");
|
ret->append("; ");
|
||||||
if (!Gogo::is_hidden_name(p->name()))
|
if (p->name().empty())
|
||||||
ret->append(p->name());
|
this->append_reflection(p->type(), gogo, ret);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This matches what the gc compiler does.
|
if (!Gogo::is_hidden_name(p->name()))
|
||||||
std::string prefix = Gogo::hidden_name_prefix(p->name());
|
ret->append(p->name());
|
||||||
ret->append(prefix.substr(prefix.find('.') + 1));
|
else
|
||||||
ret->push_back('.');
|
{
|
||||||
ret->append(Gogo::unpack_hidden_name(p->name()));
|
// This matches what the gc compiler does.
|
||||||
|
std::string prefix = Gogo::hidden_name_prefix(p->name());
|
||||||
|
ret->append(prefix.substr(prefix.find('.') + 1));
|
||||||
|
ret->push_back('.');
|
||||||
|
ret->append(Gogo::unpack_hidden_name(p->name()));
|
||||||
|
}
|
||||||
|
std::string sub = p->type()->reflection(gogo);
|
||||||
|
go_assert(sub.compare(0, 4, "func") == 0);
|
||||||
|
sub = sub.substr(4);
|
||||||
|
ret->append(sub);
|
||||||
}
|
}
|
||||||
std::string sub = p->type()->reflection(gogo);
|
|
||||||
go_assert(sub.compare(0, 4, "func") == 0);
|
|
||||||
sub = sub.substr(4);
|
|
||||||
ret->append(sub);
|
|
||||||
}
|
}
|
||||||
ret->push_back(' ');
|
ret->push_back(' ');
|
||||||
}
|
}
|
||||||
@ -6814,23 +6835,30 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
|
|||||||
void
|
void
|
||||||
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
|
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
|
||||||
{
|
{
|
||||||
|
go_assert(this->methods_are_finalized_);
|
||||||
|
|
||||||
ret->push_back('I');
|
ret->push_back('I');
|
||||||
|
|
||||||
const Typed_identifier_list* methods = this->methods_;
|
const Typed_identifier_list* methods = this->all_methods_;
|
||||||
if (methods != NULL)
|
if (methods != NULL && !this->seen_)
|
||||||
{
|
{
|
||||||
|
this->seen_ = true;
|
||||||
for (Typed_identifier_list::const_iterator p = methods->begin();
|
for (Typed_identifier_list::const_iterator p = methods->begin();
|
||||||
p != methods->end();
|
p != methods->end();
|
||||||
++p)
|
++p)
|
||||||
{
|
{
|
||||||
std::string n = Gogo::unpack_hidden_name(p->name());
|
if (!p->name().empty())
|
||||||
char buf[20];
|
{
|
||||||
snprintf(buf, sizeof buf, "%u_",
|
std::string n = Gogo::unpack_hidden_name(p->name());
|
||||||
static_cast<unsigned int>(n.length()));
|
char buf[20];
|
||||||
ret->append(buf);
|
snprintf(buf, sizeof buf, "%u_",
|
||||||
ret->append(n);
|
static_cast<unsigned int>(n.length()));
|
||||||
|
ret->append(buf);
|
||||||
|
ret->append(n);
|
||||||
|
}
|
||||||
this->append_mangled_name(p->type(), gogo, ret);
|
this->append_mangled_name(p->type(), gogo, ret);
|
||||||
}
|
}
|
||||||
|
this->seen_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret->push_back('e');
|
ret->push_back('e');
|
||||||
@ -6843,67 +6871,75 @@ Interface_type::do_export(Export* exp) const
|
|||||||
{
|
{
|
||||||
exp->write_c_string("interface { ");
|
exp->write_c_string("interface { ");
|
||||||
|
|
||||||
const Typed_identifier_list* methods = this->methods_;
|
const Typed_identifier_list* methods = this->parse_methods_;
|
||||||
if (methods != NULL)
|
if (methods != NULL)
|
||||||
{
|
{
|
||||||
for (Typed_identifier_list::const_iterator pm = methods->begin();
|
for (Typed_identifier_list::const_iterator pm = methods->begin();
|
||||||
pm != methods->end();
|
pm != methods->end();
|
||||||
++pm)
|
++pm)
|
||||||
{
|
{
|
||||||
exp->write_string(pm->name());
|
if (pm->name().empty())
|
||||||
exp->write_c_string(" (");
|
|
||||||
|
|
||||||
const Function_type* fntype = pm->type()->function_type();
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
const Typed_identifier_list* parameters = fntype->parameters();
|
|
||||||
if (parameters != NULL)
|
|
||||||
{
|
{
|
||||||
bool is_varargs = fntype->is_varargs();
|
exp->write_c_string("$ ");
|
||||||
for (Typed_identifier_list::const_iterator pp =
|
exp->write_type(pm->type());
|
||||||
parameters->begin();
|
|
||||||
pp != parameters->end();
|
|
||||||
++pp)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
first = false;
|
|
||||||
else
|
|
||||||
exp->write_c_string(", ");
|
|
||||||
if (!is_varargs || pp + 1 != parameters->end())
|
|
||||||
exp->write_type(pp->type());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exp->write_c_string("...");
|
|
||||||
Type *pptype = pp->type();
|
|
||||||
exp->write_type(pptype->array_type()->element_type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
exp->write_c_string(")");
|
|
||||||
|
|
||||||
const Typed_identifier_list* results = fntype->results();
|
|
||||||
if (results != NULL)
|
|
||||||
{
|
{
|
||||||
exp->write_c_string(" ");
|
exp->write_string(pm->name());
|
||||||
if (results->size() == 1)
|
exp->write_c_string(" (");
|
||||||
exp->write_type(results->begin()->type());
|
|
||||||
else
|
const Function_type* fntype = pm->type()->function_type();
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
const Typed_identifier_list* parameters = fntype->parameters();
|
||||||
|
if (parameters != NULL)
|
||||||
{
|
{
|
||||||
first = true;
|
bool is_varargs = fntype->is_varargs();
|
||||||
exp->write_c_string("(");
|
for (Typed_identifier_list::const_iterator pp =
|
||||||
for (Typed_identifier_list::const_iterator p =
|
parameters->begin();
|
||||||
results->begin();
|
pp != parameters->end();
|
||||||
p != results->end();
|
++pp)
|
||||||
++p)
|
|
||||||
{
|
{
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
exp->write_c_string(", ");
|
exp->write_c_string(", ");
|
||||||
exp->write_type(p->type());
|
if (!is_varargs || pp + 1 != parameters->end())
|
||||||
|
exp->write_type(pp->type());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exp->write_c_string("...");
|
||||||
|
Type *pptype = pp->type();
|
||||||
|
exp->write_type(pptype->array_type()->element_type());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exp->write_c_string(")");
|
||||||
|
|
||||||
|
const Typed_identifier_list* results = fntype->results();
|
||||||
|
if (results != NULL)
|
||||||
|
{
|
||||||
|
exp->write_c_string(" ");
|
||||||
|
if (results->size() == 1)
|
||||||
|
exp->write_type(results->begin()->type());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = true;
|
||||||
|
exp->write_c_string("(");
|
||||||
|
for (Typed_identifier_list::const_iterator p =
|
||||||
|
results->begin();
|
||||||
|
p != results->end();
|
||||||
|
++p)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
exp->write_c_string(", ");
|
||||||
|
exp->write_type(p->type());
|
||||||
|
}
|
||||||
|
exp->write_c_string(")");
|
||||||
}
|
}
|
||||||
exp->write_c_string(")");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6925,6 +6961,16 @@ Interface_type::do_import(Import* imp)
|
|||||||
while (imp->peek_char() != '}')
|
while (imp->peek_char() != '}')
|
||||||
{
|
{
|
||||||
std::string name = imp->read_identifier();
|
std::string name = imp->read_identifier();
|
||||||
|
|
||||||
|
if (name == "$")
|
||||||
|
{
|
||||||
|
imp->require_c_string(" ");
|
||||||
|
Type* t = imp->read_type();
|
||||||
|
methods->push_back(Typed_identifier("", t, imp->location()));
|
||||||
|
imp->require_c_string("; ");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
imp->require_c_string(" (");
|
imp->require_c_string(" (");
|
||||||
|
|
||||||
Typed_identifier_list* parameters;
|
Typed_identifier_list* parameters;
|
||||||
@ -7014,6 +7060,16 @@ Type::make_interface_type(Typed_identifier_list* methods,
|
|||||||
return new Interface_type(methods, location);
|
return new Interface_type(methods, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make an empty interface type.
|
||||||
|
|
||||||
|
Interface_type*
|
||||||
|
Type::make_empty_interface_type(Location location)
|
||||||
|
{
|
||||||
|
Interface_type* ret = new Interface_type(NULL, location);
|
||||||
|
ret->finalize_methods();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Class Method.
|
// Class Method.
|
||||||
|
|
||||||
// Bind a method to an object.
|
// Bind a method to an object.
|
||||||
|
@ -485,6 +485,9 @@ class Type
|
|||||||
static Interface_type*
|
static Interface_type*
|
||||||
make_interface_type(Typed_identifier_list* methods, Location);
|
make_interface_type(Typed_identifier_list* methods, Location);
|
||||||
|
|
||||||
|
static Interface_type*
|
||||||
|
make_empty_interface_type(Location);
|
||||||
|
|
||||||
static Type*
|
static Type*
|
||||||
make_type_descriptor_type();
|
make_type_descriptor_type();
|
||||||
|
|
||||||
@ -1319,6 +1322,10 @@ class Typed_identifier_list
|
|||||||
Linemap::unknown_location()));
|
Linemap::unknown_location()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reserve(size_t c)
|
||||||
|
{ this->entries_.reserve(c); }
|
||||||
|
|
||||||
// Iterators.
|
// Iterators.
|
||||||
|
|
||||||
typedef std::vector<Typed_identifier>::iterator iterator;
|
typedef std::vector<Typed_identifier>::iterator iterator;
|
||||||
@ -2429,7 +2436,9 @@ class Interface_type : public Type
|
|||||||
public:
|
public:
|
||||||
Interface_type(Typed_identifier_list* methods, Location location)
|
Interface_type(Typed_identifier_list* methods, Location location)
|
||||||
: Type(TYPE_INTERFACE),
|
: Type(TYPE_INTERFACE),
|
||||||
methods_(methods), location_(location)
|
parse_methods_(methods), all_methods_(NULL), location_(location),
|
||||||
|
interface_btype_(NULL), assume_identical_(NULL),
|
||||||
|
methods_are_finalized_(false), seen_(false)
|
||||||
{ go_assert(methods == NULL || !methods->empty()); }
|
{ go_assert(methods == NULL || !methods->empty()); }
|
||||||
|
|
||||||
// The location where the interface type was defined.
|
// The location where the interface type was defined.
|
||||||
@ -2440,18 +2449,27 @@ class Interface_type : public Type
|
|||||||
// Return whether this is an empty interface.
|
// Return whether this is an empty interface.
|
||||||
bool
|
bool
|
||||||
is_empty() const
|
is_empty() const
|
||||||
{ return this->methods_ == NULL; }
|
{
|
||||||
|
go_assert(this->methods_are_finalized_);
|
||||||
|
return this->all_methods_ == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the list of methods. This will return NULL for an empty
|
// Return the list of methods. This will return NULL for an empty
|
||||||
// interface.
|
// interface.
|
||||||
const Typed_identifier_list*
|
const Typed_identifier_list*
|
||||||
methods() const
|
methods() const
|
||||||
{ return this->methods_; }
|
{
|
||||||
|
go_assert(this->methods_are_finalized_);
|
||||||
|
return this->all_methods_;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the number of methods.
|
// Return the number of methods.
|
||||||
size_t
|
size_t
|
||||||
method_count() const
|
method_count() const
|
||||||
{ return this->methods_ == NULL ? 0 : this->methods_->size(); }
|
{
|
||||||
|
go_assert(this->methods_are_finalized_);
|
||||||
|
return this->all_methods_ == NULL ? 0 : this->all_methods_->size();
|
||||||
|
}
|
||||||
|
|
||||||
// Return the method NAME, or NULL.
|
// Return the method NAME, or NULL.
|
||||||
const Typed_identifier*
|
const Typed_identifier*
|
||||||
@ -2461,7 +2479,8 @@ class Interface_type : public Type
|
|||||||
size_t
|
size_t
|
||||||
method_index(const std::string& name) const;
|
method_index(const std::string& name) const;
|
||||||
|
|
||||||
// Finalize the methods. This handles interface inheritance.
|
// Finalize the methods. This sets all_methods_. This handles
|
||||||
|
// interface inheritance.
|
||||||
void
|
void
|
||||||
finalize_methods();
|
finalize_methods();
|
||||||
|
|
||||||
@ -2528,11 +2547,41 @@ class Interface_type : public Type
|
|||||||
do_export(Export*) const;
|
do_export(Export*) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The list of methods associated with the interface. This will be
|
// This type guards against infinite recursion when comparing
|
||||||
// NULL for the empty interface.
|
// interface types. We keep a list of interface types assumed to be
|
||||||
Typed_identifier_list* methods_;
|
// identical during comparison. We just keep the list on the stack.
|
||||||
|
// This permits us to compare cases like
|
||||||
|
// type I1 interface { F() interface{I1} }
|
||||||
|
// type I2 interface { F() interface{I2} }
|
||||||
|
struct Assume_identical
|
||||||
|
{
|
||||||
|
Assume_identical* next;
|
||||||
|
const Interface_type* t1;
|
||||||
|
const Interface_type* t2;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
assume_identical(const Interface_type*, const Interface_type*) const;
|
||||||
|
|
||||||
|
// The list of methods associated with the interface from the
|
||||||
|
// parser. This will be NULL for the empty interface. This may
|
||||||
|
// include unnamed interface types.
|
||||||
|
Typed_identifier_list* parse_methods_;
|
||||||
|
// The list of all methods associated with the interface. This
|
||||||
|
// expands any interface types listed in methods_. It is set by
|
||||||
|
// finalize_methods. This will be NULL for the empty interface.
|
||||||
|
Typed_identifier_list* all_methods_;
|
||||||
// The location where the interface was defined.
|
// The location where the interface was defined.
|
||||||
Location location_;
|
Location location_;
|
||||||
|
// The backend representation of this type during backend conversion.
|
||||||
|
Btype* interface_btype_;
|
||||||
|
// A list of interface types assumed to be identical during
|
||||||
|
// interface comparison.
|
||||||
|
mutable Assume_identical* assume_identical_;
|
||||||
|
// Whether the methods have been finalized.
|
||||||
|
bool methods_are_finalized_;
|
||||||
|
// Used to avoid endless recursion in do_mangled_name.
|
||||||
|
mutable bool seen_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The value we keep for a named type. This lets us get the right
|
// The value we keep for a named type. This lets us get the right
|
||||||
|
@ -87,7 +87,7 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
|
|||||||
this->add_named_object(no);
|
this->add_named_object(no);
|
||||||
|
|
||||||
// Typeof.
|
// Typeof.
|
||||||
Type* empty_interface = Type::make_interface_type(NULL, bloc);
|
Type* empty_interface = Type::make_empty_interface_type(bloc);
|
||||||
Typed_identifier_list* parameters = new Typed_identifier_list;
|
Typed_identifier_list* parameters = new Typed_identifier_list;
|
||||||
parameters->push_back(Typed_identifier("i", empty_interface, bloc));
|
parameters->push_back(Typed_identifier("i", empty_interface, bloc));
|
||||||
results = new Typed_identifier_list;
|
results = new Typed_identifier_list;
|
||||||
|
@ -23,5 +23,5 @@ type I5 interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type I6 interface {
|
type I6 interface {
|
||||||
I5 // GC_ERROR "interface"
|
I5 // ERROR "interface"
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ type I1 interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type I2 interface {
|
type I2 interface {
|
||||||
I1 // GC_ERROR "loop|interface"
|
I1 // ERROR "loop|interface"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user