#include "backend.h"
#include "types.h"
+// Forward declarations so that we don't have to make types.h #include
+// backend.h.
+
+static void
+get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
+ bool use_placeholder,
+ std::vector<Backend::Btyped_identifier>* bfields);
+
+static void
+get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
+ std::vector<Backend::Btyped_identifier>* bfields);
+
+static void
+get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+ bool use_placeholder,
+ std::vector<Backend::Btyped_identifier>* bfields);
+
// Class Type.
Type::Type(Type_classification classification)
- : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
+ : classification_(classification), btype_is_placeholder_(false),
+ btype_(NULL), type_descriptor_var_(NULL)
{
}
switch (this->classification())
{
case TYPE_INTEGER:
- return Type::lookup_integer_type("int");
+ if (this->integer_type()->is_rune())
+ return Type::lookup_integer_type("int32");
+ else
+ return Type::lookup_integer_type("int");
case TYPE_FLOAT:
return Type::lookup_float_type("float64");
case TYPE_COMPLEX:
t1 = t1->forwarded();
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();
+
if (t1 == t2)
return true;
Type::get_backend(Gogo* gogo)
{
if (this->btype_ != NULL)
- return this->btype_;
+ {
+ if (this->btype_is_placeholder_ && gogo->named_types_are_converted())
+ this->finish_backend(gogo);
+ return this->btype_;
+ }
if (this->forward_declaration_type() != NULL
|| this->named_type() != NULL)
return this->btype_;
}
+// Get the backend representation of a type without forcing the
+// creation of the backend representation of all supporting types.
+// This will return a backend type that has the correct size but may
+// be incomplete. E.g., a pointer will just be a placeholder pointer,
+// and will not contain the final representation of the type to which
+// it points. This is used while converting all named types to the
+// backend representation, to avoid problems with indirect references
+// to types which are not yet complete. When this is called, the
+// sizes of all direct references (e.g., a struct field) should be
+// known, but the sizes of indirect references (e.g., the type to
+// which a pointer points) may not.
+
+Btype*
+Type::get_backend_placeholder(Gogo* gogo)
+{
+ if (gogo->named_types_are_converted())
+ return this->get_backend(gogo);
+ if (this->btype_ != NULL)
+ return this->btype_;
+
+ Btype* bt;
+ switch (this->classification_)
+ {
+ case TYPE_ERROR:
+ case TYPE_VOID:
+ case TYPE_BOOLEAN:
+ case TYPE_INTEGER:
+ case TYPE_FLOAT:
+ case TYPE_COMPLEX:
+ case TYPE_STRING:
+ case TYPE_NIL:
+ // These are simple types that can just be created directly.
+ return this->get_backend(gogo);
+
+ case TYPE_FUNCTION:
+ {
+ Location loc = this->function_type()->location();
+ bt = gogo->backend()->placeholder_pointer_type("", loc, true);
+ }
+ break;
+
+ case TYPE_POINTER:
+ {
+ Location loc = Linemap::unknown_location();
+ bt = gogo->backend()->placeholder_pointer_type("", loc, false);
+ }
+ break;
+
+ case TYPE_STRUCT:
+ // We don't have to make the struct itself be a placeholder. We
+ // are promised that we know the sizes of the struct fields.
+ // But we may have to use a placeholder for any particular
+ // struct field.
+ {
+ std::vector<Backend::Btyped_identifier> bfields;
+ get_backend_struct_fields(gogo, this->struct_type()->fields(),
+ true, &bfields);
+ bt = gogo->backend()->struct_type(bfields);
+ }
+ break;
+
+ case TYPE_ARRAY:
+ if (this->is_slice_type())
+ {
+ std::vector<Backend::Btyped_identifier> bfields;
+ get_backend_slice_fields(gogo, this->array_type(), true, &bfields);
+ bt = gogo->backend()->struct_type(bfields);
+ }
+ else
+ {
+ Btype* element = this->array_type()->get_backend_element(gogo, true);
+ Bexpression* len = this->array_type()->get_backend_length(gogo);
+ bt = gogo->backend()->array_type(element, len);
+ }
+ break;
+
+ case TYPE_MAP:
+ case TYPE_CHANNEL:
+ // All maps and channels have the same backend representation.
+ return this->get_backend(gogo);
+
+ case TYPE_INTERFACE:
+ if (this->interface_type()->is_empty())
+ return Interface_type::get_backend_empty_interface_type(gogo);
+ else
+ {
+ std::vector<Backend::Btyped_identifier> bfields;
+ get_backend_interface_fields(gogo, this->interface_type(), true,
+ &bfields);
+ bt = gogo->backend()->struct_type(bfields);
+ }
+ break;
+
+ case TYPE_NAMED:
+ case TYPE_FORWARD:
+ // Named types keep track of their own dependencies and manage
+ // their own placeholders.
+ return this->get_backend(gogo);
+
+ case TYPE_SINK:
+ case TYPE_CALL_MULTIPLE_RESULT:
+ default:
+ go_unreachable();
+ }
+
+ this->btype_ = bt;
+ this->btype_is_placeholder_ = true;
+ return bt;
+}
+
+// Complete the backend representation. This is called for a type
+// using a placeholder type.
+
+void
+Type::finish_backend(Gogo* gogo)
+{
+ go_assert(this->btype_ != NULL);
+ if (!this->btype_is_placeholder_)
+ return;
+
+ switch (this->classification_)
+ {
+ case TYPE_ERROR:
+ case TYPE_VOID:
+ case TYPE_BOOLEAN:
+ case TYPE_INTEGER:
+ case TYPE_FLOAT:
+ case TYPE_COMPLEX:
+ case TYPE_STRING:
+ case TYPE_NIL:
+ go_unreachable();
+
+ case TYPE_FUNCTION:
+ {
+ Btype* bt = this->do_get_backend(gogo);
+ if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt))
+ go_assert(saw_errors());
+ }
+ break;
+
+ case TYPE_POINTER:
+ {
+ Btype* bt = this->do_get_backend(gogo);
+ if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt))
+ go_assert(saw_errors());
+ }
+ break;
+
+ case TYPE_STRUCT:
+ // The struct type itself is done, but we have to make sure that
+ // all the field types are converted.
+ this->struct_type()->finish_backend_fields(gogo);
+ break;
+
+ case TYPE_ARRAY:
+ // The array type itself is done, but make sure the element type
+ // is converted.
+ this->array_type()->finish_backend_element(gogo);
+ break;
+
+ case TYPE_MAP:
+ case TYPE_CHANNEL:
+ go_unreachable();
+
+ case TYPE_INTERFACE:
+ // The interface type itself is done, but make sure the method
+ // types are converted.
+ this->interface_type()->finish_backend_methods(gogo);
+ break;
+
+ case TYPE_NAMED:
+ case TYPE_FORWARD:
+ go_unreachable();
+
+ case TYPE_SINK:
+ case TYPE_CALL_MULTIPLE_RESULT:
+ default:
+ go_unreachable();
+ }
+
+ this->btype_is_placeholder_ = false;
+}
+
// Return a pointer to the type descriptor for this type.
tree
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();
if (t->type_descriptor_var_ == NULL)
{
t->make_type_descriptor_var(gogo);
++p;
go_assert(p->is_field_name("hash"));
- mpz_set_ui(iv, this->hash_for_method(gogo));
+ unsigned int h;
+ if (name != NULL)
+ h = name->hash_for_method(gogo);
+ else
+ h = this->hash_for_method(gogo);
+ mpz_set_ui(iv, h);
vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
++p;
{
if (!this->is_backend_type_size_known(gogo))
return false;
- size_t size = gogo->backend()->type_size(this->get_backend(gogo));
+ Btype* bt = this->get_backend_placeholder(gogo);
+ size_t size = gogo->backend()->type_size(bt);
*psize = static_cast<unsigned int>(size);
if (*psize != size)
return false;
{
if (!this->is_backend_type_size_known(gogo))
return false;
- size_t align = gogo->backend()->type_alignment(this->get_backend(gogo));
+ Btype* bt = this->get_backend_placeholder(gogo);
+ size_t align = gogo->backend()->type_alignment(bt);
*palign = static_cast<unsigned int>(align);
if (*palign != align)
return false;
{
if (!this->is_backend_type_size_known(gogo))
return false;
- size_t a = gogo->backend()->type_field_alignment(this->get_backend(gogo));
+ Btype* bt = this->get_backend_placeholder(gogo);
+ size_t a = gogo->backend()->type_field_alignment(bt);
*palign = static_cast<unsigned int>(a);
if (*palign != a)
return false;
return abstract_type;
}
+// Create a new abstract character type.
+
+Integer_type*
+Integer_type::create_abstract_character_type()
+{
+ static Integer_type* abstract_type;
+ if (abstract_type == NULL)
+ {
+ abstract_type = new Integer_type(true, false, 32,
+ RUNTIME_TYPE_KIND_INT32);
+ abstract_type->set_is_rune();
+ }
+ return abstract_type;
+}
+
// Integer type compatibility.
bool
Expression*
Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name)
{
- go_assert(name != NULL);
+ go_assert(name != NULL || saw_errors());
return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
}
return Integer_type::create_abstract_integer_type();
}
+// Make an abstract character type.
+
+Integer_type*
+Type::make_abstract_character_type()
+{
+ return Integer_type::create_abstract_character_type();
+}
+
// Look up an integer type.
Named_type*
Expression*
Float_type::do_type_descriptor(Gogo* gogo, Named_type* name)
{
- go_assert(name != NULL);
+ go_assert(name != NULL || saw_errors());
return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
}
Expression*
Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name)
{
- go_assert(name != NULL);
+ go_assert(name != NULL || saw_errors());
return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name);
}
Type* b = gogo->lookup_global("byte")->type_value();
Type* pb = Type::make_pointer_type(b);
+
+ // We aren't going to get back to this field to finish the
+ // backend representation, so force it to be finished now.
+ if (!gogo->named_types_are_converted())
+ {
+ pb->get_backend_placeholder(gogo);
+ pb->finish_backend(gogo);
+ }
+
fields[0].name = "__data";
fields[0].btype = pb->get_backend(gogo);
fields[0].location = Linemap::predeclared_location();
// Get the backend representation for a function type.
Btype*
-Function_type::get_function_backend(Gogo* gogo)
+Function_type::do_get_backend(Gogo* gogo)
{
Backend::Btyped_identifier breceiver;
if (this->receiver_ != NULL)
this->location());
}
-// A hash table mapping function types to their backend placeholders.
-
-Function_type::Placeholders Function_type::placeholders;
-
-// Get the backend representation for a function type. If we are
-// still converting types, and this types has multiple results, return
-// a placeholder instead. We do this because for multiple results we
-// build a struct, and we need to make sure that all the types in the
-// struct are valid before we create the struct.
-
-Btype*
-Function_type::do_get_backend(Gogo* gogo)
-{
- if (!gogo->named_types_are_converted()
- && this->results_ != NULL
- && this->results_->size() > 1)
- {
- Btype* placeholder =
- gogo->backend()->placeholder_pointer_type("", this->location(), true);
- Function_type::placeholders.push_back(std::make_pair(this, placeholder));
- return placeholder;
- }
- return this->get_function_backend(gogo);
-}
-
-// Convert function types after all named types are converted.
-
-void
-Function_type::convert_types(Gogo* gogo)
-{
- for (Placeholders::const_iterator p = Function_type::placeholders.begin();
- p != Function_type::placeholders.end();
- ++p)
- {
- Btype* bt = p->first->get_function_backend(gogo);
- if (!gogo->backend()->set_placeholder_function_type(p->second, bt))
- go_assert(saw_errors());
- }
-}
-
// The type of a function type descriptor.
Type*
return this->to_type_->hash_for_method(gogo) << 4;
}
-// The tree for a pointer type.
+// Get the backend representation for a pointer type.
Btype*
Pointer_type::do_get_backend(Gogo* gogo)
static void
get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields,
+ bool use_placeholder,
std::vector<Backend::Btyped_identifier>* bfields)
{
bfields->resize(fields->size());
++p, ++i)
{
(*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name());
- (*bfields)[i].btype = p->type()->get_backend(gogo);
+ (*bfields)[i].btype = (use_placeholder
+ ? p->type()->get_backend_placeholder(gogo)
+ : p->type()->get_backend(gogo));
(*bfields)[i].location = p->location();
}
go_assert(i == fields->size());
Struct_type::do_get_backend(Gogo* gogo)
{
std::vector<Backend::Btyped_identifier> bfields;
- get_backend_struct_fields(gogo, this->fields_, &bfields);
+ get_backend_struct_fields(gogo, this->fields_, false, &bfields);
return gogo->backend()->struct_type(bfields);
}
+// Finish the backend representation of the fields of a struct.
+
+void
+Struct_type::finish_backend_fields(Gogo* gogo)
+{
+ const Struct_field_list* fields = this->fields_;
+ if (fields != NULL)
+ {
+ for (Struct_field_list::const_iterator p = fields->begin();
+ p != fields->end();
+ ++p)
+ p->type()->get_backend(gogo);
+ }
+}
+
// The type of a struct type descriptor.
Type*
{
if (!this->is_backend_type_size_known(gogo))
return false;
- size_t offset = gogo->backend()->type_field_offset(this->get_backend(gogo),
- index);
+ Btype* bt = this->get_backend_placeholder(gogo);
+ size_t offset = gogo->backend()->type_field_offset(bt, index);
*poffset = static_cast<unsigned int>(offset);
if (*poffset != offset)
return false;
// size which does not fit in int.
static void
-get_backend_slice_fields(Gogo* gogo, Array_type* type,
+get_backend_slice_fields(Gogo* gogo, Array_type* type, bool use_placeholder,
std::vector<Backend::Btyped_identifier>* bfields)
{
bfields->resize(3);
Type* pet = Type::make_pointer_type(type->element_type());
- Btype* pbet = pet->get_backend(gogo);
+ Btype* pbet = (use_placeholder
+ ? pet->get_backend_placeholder(gogo)
+ : pet->get_backend(gogo));
Location ploc = Linemap::predeclared_location();
Backend::Btyped_identifier* p = &(*bfields)[0];
if (this->length_ == NULL)
{
std::vector<Backend::Btyped_identifier> bfields;
- get_backend_slice_fields(gogo, this, &bfields);
+ get_backend_slice_fields(gogo, this, false, &bfields);
return gogo->backend()->struct_type(bfields);
}
else
{
- Btype* element = this->get_backend_element(gogo);
+ Btype* element = this->get_backend_element(gogo, false);
Bexpression* len = this->get_backend_length(gogo);
return gogo->backend()->array_type(element, len);
}
}
// Return the backend representation of the element type.
+
Btype*
-Array_type::get_backend_element(Gogo* gogo)
+Array_type::get_backend_element(Gogo* gogo, bool use_placeholder)
{
- return this->element_type_->get_backend(gogo);
+ if (use_placeholder)
+ return this->element_type_->get_backend_placeholder(gogo);
+ else
+ return this->element_type_->get_backend(gogo);
}
// Return the backend representation of the length.
return tree_to_expr(this->get_length_tree(gogo));
}
+// Finish backend representation of the array.
+
+void
+Array_type::finish_backend_element(Gogo* gogo)
+{
+ Type* et = this->array_type()->element_type();
+ et->get_backend(gogo);
+ if (this->is_slice_type())
+ {
+ // This relies on the fact that we always use the same
+ // structure for a pointer to any given type.
+ Type* pet = Type::make_pointer_type(et);
+ pet->get_backend(gogo);
+ }
+}
+
// Return a tree for a pointer to the values in ARRAY.
tree
Array_type::capacity_tree(Gogo* gogo, tree array)
{
if (this->length_ != NULL)
- return omit_one_operand(sizetype, this->get_length_tree(gogo), array);
+ return omit_one_operand(integer_type_node, this->get_length_tree(gogo),
+ array);
// This is an open array. We need to read the capacity field.
int
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 this->methods_->traverse(traverse);
+ return methods->traverse(traverse);
}
// Finalize the methods. This handles interface inheritance.
void
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;
+
+ 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;
- bool is_recursive = false;
- size_t from = 0;
- size_t to = 0;
- while (from < this->methods_->size())
+ seen.reserve(inherit.size());
+ bool issued_recursive_error = false;
+ while (!inherit.empty())
{
- 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;
- }
+ Type* t = inherit.back().type();
+ Location tl = inherit.back().location();
+ inherit.pop_back();
- Interface_type* it = p->type()->interface_type();
+ Interface_type* it = t->interface_type();
if (it == NULL)
{
- error_at(p->location(), "interface contains embedded non-interface");
- ++from;
+ if (!t->is_error())
+ error_at(tl, "interface contains embedded non-interface");
continue;
}
if (it == this)
{
- if (!is_recursive)
+ if (!issued_recursive_error)
{
- error_at(p->location(), "invalid recursive interface");
- is_recursive = true;
+ error_at(tl, "invalid recursive interface");
+ issued_recursive_error = true;
}
- ++from;
continue;
}
- Named_type* nt = p->type()->named_type();
+ Named_type* nt = t->named_type();
if (nt != NULL)
{
std::vector<Named_type*>::const_iterator q;
{
if (*q == nt)
{
- error_at(p->location(), "inherited interface loop");
+ error_at(tl, "inherited interface loop");
break;
}
}
if (q != seen.end())
- {
- ++from;
- continue;
- }
+ continue;
seen.push_back(nt);
}
- const Typed_identifier_list* methods = it->methods();
- if (methods == NULL)
- {
- ++from;
- continue;
- }
- for (Typed_identifier_list::const_iterator q = methods->begin();
- q != methods->end();
+ const Typed_identifier_list* imethods = it->parse_methods_;
+ if (imethods == NULL)
+ continue;
+ for (Typed_identifier_list::const_iterator q = imethods->begin();
+ q != imethods->end();
++q)
{
if (q->name().empty())
- {
- 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()));
- }
- }
+ inherit.push_back(*q);
else if (this->find_method(q->name()) == NULL)
- this->methods_->push_back(Typed_identifier(q->name(), q->type(),
- p->location()));
+ this->all_methods_->push_back(Typed_identifier(q->name(),
+ q->type(), tl));
else
- {
- if (!is_recursive)
- error_at(p->location(), "inherited method %qs is ambiguous",
- Gogo::message_name(q->name()).c_str());
- }
+ error_at(tl, "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
{
- this->methods_->resize(to);
- this->methods_->sort_by_name();
+ delete this->all_methods_;
+ this->all_methods_ = NULL;
}
}
const Typed_identifier*
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;
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p)
if (p->name() == name)
return &*p;
size_t
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;
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p, ++ret)
if (p->name() == name)
return ret;
bool
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;
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p)
{
const std::string& method_name(p->name());
Interface_type::is_identical(const Interface_type* t,
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
// have already been sorted.
- if (this->methods() == NULL || t->methods() == NULL)
- return this->methods() == t->methods();
+ if (this->all_methods_ == NULL || t->all_methods_ == NULL)
+ return this->all_methods_ == t->all_methods_;
+
+ if (this->assume_identical(this, t) || t->assume_identical(t, this))
+ return true;
- Typed_identifier_list::const_iterator p1 = this->methods()->begin();
- for (Typed_identifier_list::const_iterator p2 = t->methods()->begin();
- 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())
- return false;
+ if (p1 == this->all_methods_->end())
+ break;
if (p1->name() != p2->name()
|| !Type::are_identical(p1->type(), p2->type(),
errors_are_identical, NULL))
- return false;
+ break;
}
- if (p1 != this->methods()->end())
- return false;
- return true;
+
+ this->assume_identical_ = hold_ai;
+
+ 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
Interface_type::is_compatible_for_assign(const Interface_type* t,
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;
- for (Typed_identifier_list::const_iterator p = this->methods()->begin();
- p != this->methods()->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p)
{
const Typed_identifier* m = t->find_method(p->name());
// Hash code.
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;
- if (this->methods_ != NULL)
+ if (this->all_methods_ != NULL)
{
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p =
+ this->all_methods_->begin();
+ p != this->all_methods_->end();
++p)
{
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;
}
}
bool
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;
bool is_pointer = false;
return false;
}
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p)
{
bool is_ambiguous = false;
static void
get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+ bool use_placeholder,
std::vector<Backend::Btyped_identifier>* bfields)
{
Location loc = type->location();
p != type->methods()->end();
++p, ++i)
{
+ // The type of the method in Go only includes the parameters.
+ // The actual method also has a receiver, which is always a
+ // pointer. We need to add that pointer type here in order to
+ // generate the correct type for the backend.
+ Function_type* ft = p->type()->function_type();
+ go_assert(ft->receiver() == NULL);
+
+ const Typed_identifier_list* params = ft->parameters();
+ Typed_identifier_list* mparams = new Typed_identifier_list();
+ if (params != NULL)
+ mparams->reserve(params->size() + 1);
+ Type* vt = Type::make_pointer_type(Type::make_void_type());
+ mparams->push_back(Typed_identifier("", vt, ft->location()));
+ if (params != NULL)
+ {
+ for (Typed_identifier_list::const_iterator pp = params->begin();
+ pp != params->end();
+ ++pp)
+ mparams->push_back(*pp);
+ }
+
+ Typed_identifier_list* mresults = (ft->results() == NULL
+ ? NULL
+ : ft->results()->copy());
+ Function_type* mft = Type::make_function_type(NULL, mparams, mresults,
+ ft->location());
+
mfields[i].name = Gogo::unpack_hidden_name(p->name());
- mfields[i].btype = p->type()->get_backend(gogo);
+ mfields[i].btype = (use_placeholder
+ ? mft->get_backend_placeholder(gogo)
+ : mft->get_backend(gogo));
mfields[i].location = loc;
// Sanity check: the names should be sorted.
go_assert(p->name() > last_name);
Btype*
Interface_type::do_get_backend(Gogo* gogo)
{
- if (this->methods_ == NULL)
+ if (this->is_empty())
return Interface_type::get_backend_empty_interface_type(gogo);
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;
- get_backend_interface_fields(gogo, this, &bfields);
- return gogo->backend()->struct_type(bfields);
+ get_backend_interface_fields(gogo, this, false, &bfields);
+ if (!gogo->backend()->set_placeholder_struct_type(this->interface_btype_,
+ bfields))
+ this->interface_btype_ = gogo->backend()->error_type();
+ return this->interface_btype_;
+ }
+}
+
+// Finish the backend representation of the methods.
+
+void
+Interface_type::finish_backend_methods(Gogo* gogo)
+{
+ if (!this->interface_type()->is_empty())
+ {
+ const Typed_identifier_list* methods = this->methods();
+ if (methods != NULL)
+ {
+ for (Typed_identifier_list::const_iterator p = methods->begin();
+ p != methods->end();
+ ++p)
+ p->type()->get_backend(gogo);
+ }
}
}
go_assert(pif->is_field_name("methods"));
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();
- methods->reserve(this->methods_->size());
- for (Typed_identifier_list::const_iterator pm = this->methods_->begin();
- pm != this->methods_->end();
+ methods->reserve(this->all_methods_->size());
+ for (Typed_identifier_list::const_iterator pm =
+ this->all_methods_->begin();
+ pm != this->all_methods_->end();
++pm)
{
const Struct_field_list* mfields = elemtype->struct_type()->fields();
Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
{
ret->append("interface {");
- if (this->methods_ != NULL)
+ const Typed_identifier_list* methods = this->parse_methods_;
+ if (methods != NULL)
{
ret->push_back(' ');
- for (Typed_identifier_list::const_iterator p = this->methods_->begin();
- p != this->methods_->end();
+ for (Typed_identifier_list::const_iterator p = methods->begin();
+ p != methods->end();
++p)
{
- if (p != this->methods_->begin())
+ if (p != methods->begin())
ret->append("; ");
- if (!Gogo::is_hidden_name(p->name()))
- ret->append(p->name());
+ if (p->name().empty())
+ this->append_reflection(p->type(), gogo, ret);
else
{
- // 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()));
+ if (!Gogo::is_hidden_name(p->name()))
+ ret->append(p->name());
+ else
+ {
+ // 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(' ');
}
void
Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
+ go_assert(this->methods_are_finalized_);
+
ret->push_back('I');
- const Typed_identifier_list* methods = this->methods_;
- if (methods != NULL)
+ const Typed_identifier_list* methods = this->all_methods_;
+ if (methods != NULL && !this->seen_)
{
+ this->seen_ = true;
for (Typed_identifier_list::const_iterator p = methods->begin();
p != methods->end();
++p)
{
- std::string n = Gogo::unpack_hidden_name(p->name());
- char buf[20];
- snprintf(buf, sizeof buf, "%u_",
- static_cast<unsigned int>(n.length()));
- ret->append(buf);
- ret->append(n);
+ if (!p->name().empty())
+ {
+ std::string n = Gogo::unpack_hidden_name(p->name());
+ char buf[20];
+ snprintf(buf, sizeof buf, "%u_",
+ static_cast<unsigned int>(n.length()));
+ ret->append(buf);
+ ret->append(n);
+ }
this->append_mangled_name(p->type(), gogo, ret);
}
+ this->seen_ = false;
}
ret->push_back('e');
{
exp->write_c_string("interface { ");
- const Typed_identifier_list* methods = this->methods_;
+ const Typed_identifier_list* methods = this->parse_methods_;
if (methods != NULL)
{
for (Typed_identifier_list::const_iterator pm = methods->begin();
pm != methods->end();
++pm)
{
- exp->write_string(pm->name());
- 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)
+ if (pm->name().empty())
{
- bool is_varargs = fntype->is_varargs();
- for (Typed_identifier_list::const_iterator pp =
- 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());
- }
- }
+ exp->write_c_string("$ ");
+ exp->write_type(pm->type());
}
+ else
+ {
+ exp->write_string(pm->name());
+ exp->write_c_string(" (");
- exp->write_c_string(")");
+ const Function_type* fntype = pm->type()->function_type();
- 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
+ bool first = true;
+ const Typed_identifier_list* parameters = fntype->parameters();
+ if (parameters != NULL)
{
- first = true;
- exp->write_c_string("(");
- for (Typed_identifier_list::const_iterator p =
- results->begin();
- p != results->end();
- ++p)
+ bool is_varargs = fntype->is_varargs();
+ for (Typed_identifier_list::const_iterator pp =
+ parameters->begin();
+ pp != parameters->end();
+ ++pp)
{
if (first)
first = false;
else
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(")");
}
}
while (imp->peek_char() != '}')
{
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(" (");
Typed_identifier_list* parameters;
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.
// Bind a method to an object.
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.
this->find_type_->add_dependency(type->named_type());
break;
+ case Type::TYPE_NAMED:
+ case Type::TYPE_FORWARD:
+ go_assert(saw_errors());
+ break;
+
case Type::TYPE_VOID:
case Type::TYPE_SINK:
case Type::TYPE_FUNCTION:
case Type::TYPE_MAP:
case Type::TYPE_CHANNEL:
case Type::TYPE_INTERFACE:
- case Type::TYPE_NAMED:
- case Type::TYPE_FORWARD:
default:
go_unreachable();
}
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);
+
const std::string& name(this->named_object()->name());
unsigned int ret = Type::hash_string(name, 0);
{
std::vector<Backend::Btyped_identifier> bfields;
get_backend_struct_fields(gogo, base->struct_type()->fields(),
- &bfields);
+ true, &bfields);
if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
bt = gogo->backend()->error_type();
}
// Slice types were completed in create_placeholder.
if (!base->is_slice_type())
{
- Btype* bet = base->array_type()->get_backend_element(gogo);
+ Btype* bet = base->array_type()->get_backend_element(gogo, true);
Bexpression* blen = base->array_type()->get_backend_length(gogo);
if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen))
bt = gogo->backend()->error_type();
// because we can fill them in completely here with the final
// size.
std::vector<Backend::Btyped_identifier> bfields;
- get_backend_slice_fields(gogo, base->array_type(), &bfields);
+ get_backend_slice_fields(gogo, base->array_type(), true, &bfields);
if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
this->named_btype_ = gogo->backend()->error_type();
}
// because we can fill them in completely here with the final
// size.
std::vector<Backend::Btyped_identifier> bfields;
- get_backend_interface_fields(gogo, base->interface_type(), &bfields);
+ get_backend_interface_fields(gogo, base->interface_type(), true,
+ &bfields);
if (!gogo->backend()->set_placeholder_struct_type(bt, bfields))
this->named_btype_ = gogo->backend()->error_type();
}
case TYPE_NIL:
case TYPE_MAP:
case TYPE_CHANNEL:
+ return bt;
+
case TYPE_STRUCT:
+ if (!this->seen_in_get_backend_)
+ {
+ this->seen_in_get_backend_ = true;
+ base->struct_type()->finish_backend_fields(gogo);
+ this->seen_in_get_backend_ = false;
+ }
+ return bt;
+
case TYPE_ARRAY:
+ if (!this->seen_in_get_backend_)
+ {
+ this->seen_in_get_backend_ = true;
+ base->array_type()->finish_backend_element(gogo);
+ this->seen_in_get_backend_ = false;
+ }
+ return bt;
+
case TYPE_INTERFACE:
+ if (!this->seen_in_get_backend_)
+ {
+ this->seen_in_get_backend_ = true;
+ base->interface_type()->finish_backend_methods(gogo);
+ this->seen_in_get_backend_ = false;
+ }
return bt;
case TYPE_FUNCTION:
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 NAME is not NULL, then we don't really want the type
// descriptor for this type; we want the descriptor for the
// underlying type, giving it the name NAME.
void
Named_type::do_reflection(Gogo* gogo, std::string* ret) const
{
- if (!Linemap::is_predeclared_location(this->location()))
+ if (this->is_alias())
+ {
+ this->append_reflection(this->type_, gogo, ret);
+ return;
+ }
+ if (!this->is_builtin())
{
const Package* package = this->named_object_->package();
if (package != NULL)
void
Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
+ if (this->is_alias())
+ {
+ this->append_mangled_name(this->type_, gogo, ret);
+ return;
+ }
Named_object* no = this->named_object_;
std::string name;
- if (Linemap::is_predeclared_location(this->location()))
+ if (this->is_builtin())
go_assert(this->in_function_ == NULL);
else
{
// If this is a pointer to a pointer, then it is possible that the
// pointed-to type has methods.
+ bool dereferenced = false;
if (nt == NULL
&& st == NULL
&& it == NULL
return Expression::make_error(location);
nt = type->points_to()->named_type();
st = type->points_to()->struct_type();
+ dereferenced = true;
}
bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
else
go_unreachable();
go_assert(m != NULL);
+ if (dereferenced && m->is_value_method())
+ {
+ error_at(location,
+ "calling value method requires explicit dereference");
+ return Expression::make_error(location);
+ }
if (!m->is_value_method() && expr->type()->points_to() == NULL)
expr = Expression::make_unary(OPERATOR_AND, expr, location);
ret = m->bind_method(expr, location);
Named_object*
Forward_declaration_type::add_method_declaration(const std::string& name,
+ Package* package,
Function_type* type,
Location location)
{
if (no->is_unknown())
no->declare_as_type();
Type_declaration* td = no->type_declaration_value();
- return td->add_method_declaration(name, type, location);
+ return td->add_method_declaration(name, package, type, location);
}
// Traversal.
{
Location ploc = Linemap::predeclared_location();
if (!this->is_defined())
- return Expression::make_nil(ploc);
+ return Expression::make_error(ploc);
else
{
Type* t = this->real_type();