This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gccgo] Permit unnamed structs to have methods


I didn't quite realized that it is possible for unnamed types to have
methods.  A struct with no name can have methods if it has anonymous
fields which have methods.  I committed this patch to the gccgo branch
to implement that.  This is a relatively large patch because I moved a
bunch of code being specific to Named_type to being general for any
Type, although only invoked for Named_type or Struct_type.

Ian


diff -r 5a0e1b402d81 go/expressions.cc
--- a/go/expressions.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/expressions.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -8295,75 +8295,11 @@
 Expression*
 Selector_expression::do_lower(Gogo* gogo, Named_object*, int)
 {
-  source_location location = this->location();
   Expression* left = this->left_;
-  const std::string& name(this->name_);
-
   if (left->is_type_expression())
     return this->lower_method_expression(gogo);
-
-  Type* type = left->type();
-  Type* ptype = type->deref();
-  Struct_type* struct_type = ptype->struct_type();
-  Interface_type* interface_type = ptype->interface_type();
-  Named_type* named_type = type->named_type();
-  if (named_type == NULL && type != ptype)
-    named_type = ptype->named_type();
-
-  if (type->is_error_type())
-    return Expression::make_error(location);
-  else if (struct_type != NULL && named_type == NULL)
-    {
-      Expression* ret = struct_type->field_reference(left, name, location);
-      if (ret != NULL)
-	return ret;
-    }
-  else if (interface_type != NULL && interface_type->find_method(name) != NULL)
-    return Expression::make_interface_field_reference(left, name, location);
-
-  if (named_type != NULL)
-    {
-      bool found_pointer_method;
-      Expression* ret = named_type->bind_field_or_method(left, name, location,
-							 &found_pointer_method);
-      if (ret != NULL)
-	return ret;
-      if (found_pointer_method)
-	{
-	  error_at(location, "method requires a pointer");
-	  return Expression::make_error(location);
-	}
-    }
-
-  if (struct_type == NULL && interface_type == NULL && named_type == NULL)
-    error_at(location,
-	     "request for %qs in something which has no fields or methods",
-	     Gogo::unpack_hidden_name(name).c_str());
-  else
-    {
-      bool is_unexported;
-      std::string unpacked = Gogo::unpack_hidden_name(name);
-      if (!Gogo::is_hidden_name(name))
-	is_unexported = false;
-      else
-	{
-	  if (named_type != NULL)
-	    is_unexported = named_type->is_unexported_field_or_method(unpacked);
-	  else if (struct_type != NULL)
-	    is_unexported = struct_type->is_unexported_field(unpacked);
-	  else if (interface_type != NULL)
-	    is_unexported = interface_type->is_unexported_method(unpacked);
-	  else
-	    is_unexported = false;
-	}
-      if (is_unexported)
-	error_at(location, "reference to unexported field or method %qs",
-		 unpacked.c_str());
-      else
-	error_at(location, "reference to undefined field or method %qs",
-		 unpacked.c_str());
-    }
-  return Expression::make_error(location);
+  return Type::bind_field_or_method(left->type(), left, this->name_,
+				    this->location());
 }
 
 // Lower a method expression T.M or (*T).M.  We turn this into a
@@ -8457,9 +8393,8 @@
   Named_object* vno = gogo->lookup(receiver_name, NULL);
   gcc_assert(vno != NULL);
   Expression* ve = Expression::make_var_reference(vno, location);
-  bool dummy;
-  Expression* bm = nt->bind_field_or_method(ve, name, location, &dummy);
-  gcc_assert(bm != NULL);
+  Expression* bm = Type::bind_field_or_method(nt, ve, name, location);
+  gcc_assert(bm != NULL && !bm->is_error_expression());
 
   Expression_list* args;
   if (method_parameters == NULL)
diff -r 5a0e1b402d81 go/gogo-tree.cc
--- a/go/gogo-tree.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/gogo-tree.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -2389,16 +2389,14 @@
 
 // Build a method table for a type descriptor.  METHOD_TYPE_TREE is
 // the type of the method table, and should be the type of a slice.
-// METHODS_TYPE is the type which gives the methods.  If
-// ONLY_VALUE_METHODS is true, then only value methods are used.  This
-// returns a constructor for a slice.
+// METHODS is the list of methods.  If ONLY_VALUE_METHODS is true,
+// then only value methods are used.  This returns a constructor for a
+// slice.
 
 tree
-Gogo::type_method_table(tree method_type_tree, Named_type* methods_type,
+Gogo::type_method_table(tree method_type_tree, const Methods* methods,
 			bool only_value_methods)
 {
-  const Methods* methods = methods_type->methods();
-
   std::vector<std::pair<std::string, const Method*> > smethods;
   if (methods != NULL)
     {
@@ -2440,15 +2438,15 @@
 // Build a decl for uncommon type information for a type descriptor.
 // UNCOMMON_TYPE_TREE is the type of the uncommon type struct--struct
 // __go_uncommon_type in libgo/runtime/go-type.h.  If NAME is not
-// NULL, it is the name of the type.  If METHODS_TYPE is NULL, then
-// NAME must not be NULL, and the methods are the value methods of
-// NAME.  If METHODS_TYPE is not NULL, then NAME may be NULL, and the
-// methods are all the methods of METHODS_TYPE.  This returns a
-// pointer to the decl that it builds.
+// NULL, it is the name of the type.  If METHODS is not NULL, it is
+// the list of methods.  ONLY_VALUE_METHODS is true if only value
+// methods should be included.  At least one of NAME and METHODS must
+// not be NULL.  This returns a pointer to the decl that it builds.
 
 tree
 Gogo::uncommon_type_information(tree uncommon_type_tree, Named_type* name,
-				Named_type* methods_type)
+				const Methods* methods,
+				bool only_value_methods)
 {
   gcc_assert(TREE_CODE(uncommon_type_tree) == RECORD_TYPE);
 
@@ -2508,11 +2506,8 @@
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
   elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
-  elt->value = this->type_method_table(TREE_TYPE(field),
-				       (methods_type != NULL
-					? methods_type
-					: name),
-				       methods_type == NULL);
+  elt->value = this->type_method_table(TREE_TYPE(field), methods,
+				       only_value_methods);
 
   tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, create_tmp_var_name("U"),
 			 uncommon_type_tree);
@@ -2531,14 +2526,15 @@
 
 // Build a constructor for the basic type descriptor struct for TYPE.
 // RUNTIME_TYPE_CODE is the value to store in the __code field.  If
-// NAME is not NULL, it is the name to use.  If METHODS_TYPE is NULL,
-// then if NAME is NULL there are no methods, and if NAME is not NULL
-// then we use the value methods for NAME.  If METHODS_TYPE is not
-// NULL, then we use all the methods from METHODS_TYPE.
+// NAME is not NULL, it is the name to use.  If METHODS is not NULL,
+// it is the list of methods to use.  If METHODS is NULL, then we get
+// the methods from NAME.  ONLY_VALUE_METHODS is true if only value
+// methods should be included.
 
 tree
 Gogo::type_descriptor_constructor(int runtime_type_code, Type* type,
-				  Named_type* name, Named_type* methods_type)
+				  Named_type* name, const Methods* methods,
+				  bool only_value_methods)
 {
   tree type_descriptor_type_tree = this->type_descriptor_type_tree();
   tree type_tree = type->get_tree(this);
@@ -2617,12 +2613,16 @@
   elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
 
-  if (name == NULL
-      && (methods_type == NULL || !methods_type->has_any_methods()))
+  if (name == NULL && methods == NULL)
     elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
   else
-    elt->value = this->uncommon_type_information(TREE_TYPE(TREE_TYPE(field)),
-						 name, methods_type);
+    {
+      if (methods == NULL)
+	methods = name->methods();
+      elt->value = this->uncommon_type_information(TREE_TYPE(TREE_TYPE(field)),
+						   name, methods,
+						   only_value_methods);
+    }
 
   tree ret = build_constructor(type_descriptor_type_tree, init);
   TREE_CONSTANT(ret) = 1;
@@ -2806,7 +2806,8 @@
     return;
 
   tree constructor = this->type_descriptor_constructor(runtime_type_code,
-						       type, name, NULL);
+						       type, name, NULL,
+						       true);
 
   this->finish_type_descriptor_decl(pdecl, type, name, constructor);
 }
@@ -2863,15 +2864,23 @@
 					name, pdecl))
     return;
 
+  const Methods* methods;
+  Type* deref = type->points_to();
+  if (deref->named_type() != NULL)
+    methods = deref->named_type()->methods();
+  else if (deref->struct_type() != NULL)
+    methods = deref->struct_type()->methods();
+  else
+    methods = NULL;
+
   VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
 
   tree field = TYPE_FIELDS(type_descriptor_type_tree);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__common") == 0);
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
-  Named_type* method_type = type->points_to()->named_type();
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_PTR, type,
-						 name, method_type);
+						 name, methods, false);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
@@ -2973,7 +2982,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_FUNC, type,
-						 name, NULL);
+						 name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__dotdotdot") == 0);
@@ -3143,6 +3152,11 @@
 					name, pdecl))
     return;
 
+  const Methods* methods = type->methods();
+  // A named struct should not have methods--the methods should attach
+  // to the named type.
+  gcc_assert(methods == NULL || name == NULL);
+
   VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2);
 
   tree field = TYPE_FIELDS(type_descriptor_type_tree);
@@ -3150,7 +3164,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_STRUCT,
-						 type, name, NULL);
+						 type, name, methods, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__fields") == 0);
@@ -3209,7 +3223,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_ARRAY,
-						 type, name, NULL);
+						 type, name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
@@ -3271,7 +3285,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_SLICE,
-						 type, name, NULL);
+						 type, name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
@@ -3327,7 +3341,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_MAP,
-						 type, name, NULL);
+						 type, name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__key_type") == 0);
@@ -3392,7 +3406,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_CHAN,
-						 type, name, NULL);
+						 type, name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
@@ -3549,7 +3563,7 @@
   constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
   elt->index = field;
   elt->value = this->type_descriptor_constructor(RUNTIME_TYPE_CODE_INTERFACE,
-						 type, name, NULL);
+						 type, name, NULL, true);
 
   field = TREE_CHAIN(field);
   gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
diff -r 5a0e1b402d81 go/gogo.cc
--- a/go/gogo.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/gogo.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -1224,12 +1224,16 @@
 class Finalize_methods : public Traverse
 {
  public:
-  Finalize_methods()
-    : Traverse(traverse_types)
+  Finalize_methods(Gogo* gogo)
+    : Traverse(traverse_types),
+      gogo_(gogo)
   { }
 
   int
   type(Type*);
+
+ private:
+  Gogo* gogo_;
 };
 
 // Finalize the methods of an interface type.
@@ -1239,47 +1243,53 @@
 {
   // Check the classification so that we don't finalize the methods
   // twice for a named interface type.
-  if (t->classification() == Type::TYPE_INTERFACE)
-    t->interface_type()->finalize_methods();
+  switch (t->classification())
+    {
+    case Type::TYPE_INTERFACE:
+      t->interface_type()->finalize_methods();
+      break;
+
+    case Type::TYPE_NAMED:
+      {
+	// We have to finalize the methods of the real type first.
+	// But if the real type is a struct type, then we only want to
+	// finalize the methods of the field types, not of the struct
+	// type itself.  We don't want to add methods to the struct,
+	// since it has a name.
+	Type* rt = t->named_type()->real_type();
+	if (rt->classification() != Type::TYPE_STRUCT)
+	  {
+	    if (Type::traverse(rt, this) == TRAVERSE_EXIT)
+	      return TRAVERSE_EXIT;
+	  }
+	else
+	  {
+	    if (rt->struct_type()->traverse_field_types(this) == TRAVERSE_EXIT)
+	      return TRAVERSE_EXIT;
+	  }
+
+	t->named_type()->finalize_methods(this->gogo_);
+
+	return TRAVERSE_SKIP_COMPONENTS;
+      }
+
+    case Type::TYPE_STRUCT:
+      t->struct_type()->finalize_methods(this->gogo_);
+      break;
+
+    default:
+      break;
+    }
+
   return TRAVERSE_CONTINUE;
 }
 
-// Finalize method lists and build stub methods for named types.
+// Finalize method lists and build stub methods for types.
 
 void
 Gogo::finalize_methods()
 {
-  // Finalizing methods can add new definitions, so gather the types
-  // first.
-  std::vector<Named_type*> types;
-  for (Packages::const_iterator p = this->packages_.begin();
-       p != this->packages_.end();
-       ++p)
-    {
-      Bindings* bindings = p->second->bindings();
-      for (Bindings::const_definitions_iterator pd =
-	     bindings->begin_definitions();
-	   pd != bindings->end_definitions();
-	   ++pd)
-	{
-	  if (p->second == this->package_ && (*pd)->package() != NULL)
-	    {
-	      // This was brought in via 'import . "pkg"'.  We will
-	      // pick it up when we look at its original package.
-	      continue;
-	    }
-
-	  if ((*pd)->is_type())
-	    types.push_back((*pd)->type_value());
-	}
-    }
-
-  for (std::vector<Named_type*>::const_iterator p = types.begin();
-       p != types.end();
-       ++p)
-    (*p)->finalize_methods(this);
-
-  Finalize_methods finalize;
+  Finalize_methods finalize(this);
   this->traverse(&finalize);
 }
 
diff -r 5a0e1b402d81 go/gogo.h
--- a/go/gogo.h	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/gogo.h	Fri Feb 12 23:56:51 2010 -0800
@@ -631,18 +631,19 @@
 
   // Return the method table for a type.
   tree
-  type_method_table(tree method_type_tree, Named_type*,
+  type_method_table(tree method_type_tree, const Methods*,
 		    bool only_value_methods);
 
   // Return the uncommon type information for a type descriptor.
   tree
   uncommon_type_information(tree uncommon_type_tree, Named_type* name,
-			    Named_type* methods_type);
+			    const Methods*, bool only_value_methods);
 
   // Return a constructor for the basic type descriptor for TYPE.
   tree
   type_descriptor_constructor(int runtime_type_code, Type* type,
-			      Named_type* name, Named_type* methods_type);
+			      Named_type* name, const Methods*,
+			      bool only_value_methods);
 
   // Where a type descriptor should be defined.
   enum Type_descriptor_location
@@ -1845,11 +1846,6 @@
   source_location
   location() const;
 
-  // Set the package where the object is defined.
-  void
-  set_package(const Package* package)
-  { this->package_ = package; }
-
   // Return a tree for the external identifier for this object.
   tree
   get_id(Gogo*);
diff -r 5a0e1b402d81 go/parse.cc
--- a/go/parse.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/parse.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -1383,7 +1383,7 @@
 	  this->gogo_->define_type(named_type,
 				   Type::make_named_type(named_type, type,
 							 location));
-	  named_type->set_package(NULL);
+	  gcc_assert(named_type->package() == NULL);
 	}
       else
 	{
@@ -1954,11 +1954,9 @@
     }
   else
     {
-      named_object = this->gogo_->start_function(name, fntype, true, location);
+      this->gogo_->start_function(name, fntype, true, location);
       source_location end_loc = this->block();
       this->gogo_->finish_function(end_loc);
-      if (named_object != NULL)
-	named_object->set_package(NULL);
     }
 }
 
diff -r 5a0e1b402d81 go/types.cc
--- a/go/types.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/types.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -2063,6 +2063,28 @@
   return ret;
 }
 
+// Make a copy of a function type without a receiver.
+
+Function_type*
+Function_type::copy_without_receiver() const
+{
+  gcc_assert(this->is_method());
+  return Type::make_function_type(NULL, this->parameters_, this->results_,
+				  this->location_);
+}
+
+// Make a copy of a function type with a receiver.
+
+Function_type*
+Function_type::copy_with_receiver(Type* receiver_type) const
+{
+  gcc_assert(!this->is_method());
+  Typed_identifier* receiver = new Typed_identifier("", receiver_type,
+						    this->location_);
+  return Type::make_function_type(receiver, this->parameters_,
+				  this->results_, this->location_);
+}
+
 // Make a function type.
 
 Function_type*
@@ -2602,9 +2624,9 @@
 
   // Look for an anonymous field which contains a field with this
   // name.
+  unsigned int found_depth = 0;
   Field_reference_expression* ret = NULL;
   const Struct_field* parent = NULL;
-  unsigned int retdepth = 0;
   i = 0;
   for (Struct_field_list::const_iterator pf = fields->begin();
        pf != fields->end();
@@ -2627,13 +2649,13 @@
       if (sub == NULL)
 	continue;
 
-      if (ret == NULL || subdepth < retdepth)
+      if (ret == NULL || subdepth < found_depth)
 	{
 	  if (ret != NULL)
 	    delete ret;
 	  ret = sub;
 	  parent = &*pf;
-	  retdepth = subdepth;
+	  found_depth = subdepth;
 	  Expression* here = Expression::make_field_reference(struct_expr, i,
 							      location);
 	  while (sub->expr() != NULL)
@@ -2643,18 +2665,21 @@
 	    }
 	  sub->set_struct_expression(here);
 	}
-      else if (subdepth > retdepth)
+      else if (subdepth > found_depth)
 	delete sub;
       else
 	{
-	  error_at(location, "field %<%s%> is ambiguous via %<%s%> and %<%s%>",
-		   name.c_str(), parent->field_name().c_str(),
-		   pf->field_name().c_str());
+	  // We do not handle ambiguity here--it should be handled by
+	  // Type::bind_field_or_method.
 	  delete sub;
-	}
-    }
-
-  *depth = retdepth + 1;
+	  found_depth = 0;
+	  ret = NULL;
+	}
+    }
+
+  if (ret != NULL)
+    *depth = found_depth + 1;
+
   return ret;
 }
 
@@ -2681,29 +2706,42 @@
 // Return whether NAME is an unexported field, for better error reporting.
 
 bool
-Struct_type::is_unexported_field(const std::string& name) const
+Struct_type::is_unexported_local_field(const std::string& name) const
 {
   const Struct_field_list* fields = this->fields_;
-  if (fields == NULL)
-    return false;
-  for (Struct_field_list::const_iterator pf = fields->begin();
-       pf != fields->end();
-       ++pf)
-    {
-      const std::string& field_name(pf->field_name());
-      if (Gogo::is_hidden_name(field_name)
-	  && name == Gogo::unpack_hidden_name(field_name))
-	return true;
-      if (pf->is_anonymous())
-	{
-	  Struct_type* st = pf->type()->deref()->struct_type();
-	  if (st != NULL && st->is_unexported_field(name))
+  if (fields != NULL)
+    {
+      for (Struct_field_list::const_iterator pf = fields->begin();
+	   pf != fields->end();
+	   ++pf)
+	{
+	  const std::string& field_name(pf->field_name());
+	  if (Gogo::is_hidden_name(field_name)
+	      && name == Gogo::unpack_hidden_name(field_name))
 	    return true;
 	}
     }
   return false;
 }
 
+// Finalize the methods of an unnamed struct.
+
+void
+Struct_type::finalize_methods(Gogo* gogo)
+{
+  Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
+}
+
+// Return the method NAME, or NULL if there isn't one or if it is
+// ambiguous.  Set *IS_AMBIGUOUS if the method exists but is
+// ambiguous.
+
+Method*
+Struct_type::method_function(const std::string& name) const
+{
+  return Type::method_function(this->all_methods_, name, NULL);
+}
+
 // Get the tree for a struct type.
 
 tree
@@ -4914,211 +4952,29 @@
   this->local_methods_->add_named_object(no);
 }
 
-// Return whether NO is a method for which the receiver is a pointer.
-
-bool
-Named_type::method_expects_pointer(const Named_object* no)
-{
-  const Function_type *fntype;
-  if (no->is_function())
-    fntype = no->func_value()->type();
-  else if (no->is_function_declaration())
-    fntype = no->func_declaration_value()->type();
-  else
-    gcc_unreachable();
-  return fntype->receiver()->type()->points_to() != NULL;
-}
-
-// Look for field or method NAME associated with this type at parse
-// time.  Return an Expression for the field or method bound to EXPR,
-// or NULL if there is no such field or method.  When returning NULL,
-// this sets *FOUND_POINTER_METHOD if we found a method we couldn't
-// use because it requires a pointer.
-
-Expression*
-Named_type::bind_field_or_method(Expression* expr, const std::string& name,
-				 source_location location,
-				 bool *found_pointer_method) const
-{
-  *found_pointer_method = false;
-
-  const Struct_type* st = this->deref()->struct_type();
-  if (st != NULL)
-    {
-      unsigned int index = 0;
-      const Struct_field* sf = st->find_local_field(name, &index);
-      if (sf != NULL)
-	return Expression::make_field_reference(expr, index, location);
-    }
-
-  if (this->local_methods_ != NULL)
-    {
-      Named_object* no = this->local_methods_->lookup(name);
-      if (no != NULL)
-	{
-	  // Take the address of the expression if necessary.
-	  if (expr->type()->points_to() == NULL
-	      && Named_type::method_expects_pointer(no))
-	    {
-	      if (expr->is_lvalue())
-		expr = Expression::make_unary(OPERATOR_AND, expr, location);
-	      else
-		{
-		  *found_pointer_method = true;
-		  return NULL;
-		}
-	    }
-	  Expression* func = Expression::make_func_reference(no, NULL,
-							     location);
-	  return Expression::make_bound_method(expr, func, location);
-	}
-    }
-
-  bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
-				  || expr->is_lvalue());
-  bool is_method;
-  if (this->find_field_or_method(name, receiver_can_be_pointer, NULL,
-				 &is_method, found_pointer_method))
-    {
-      if (is_method)
-	{
-	  bool is_ambiguous;
-	  Method* m = this->method_function(name, &is_ambiguous);
-	  if (m == NULL)
-	    {
-	      // We just found the method, so this can only fail if it
-	      // is ambiguous.
-	      gcc_assert(is_ambiguous);
-	      error_at(location, "reference to method %qs is ambiguous",
-		       Gogo::unpack_hidden_name(name).c_str());
-	      return Expression::make_error(location);
-	    }
-	  if (!m->is_value_method() && expr->type()->points_to() == NULL)
-	    expr = Expression::make_unary(OPERATOR_AND, expr, location);
-	  return m->bind_method(expr, location);
-	}
-      else
-	{
-	  // This is a field in an embedded struct.  We look it up
-	  // again, looking only at fields this time.  This is simpler
-	  // than building the subexpression we need as we go along.
-	  gcc_assert(this->struct_type() != NULL);
-	  Expression* ret = this->struct_type()->field_reference(expr, name,
-								 location);
-	  gcc_assert(ret != NULL);
-	  return ret;
-	}
-    }
-
-  return NULL;
-}
-
-// Look for a field or method named NAME, returning whether one is
-// found.  This looks through embedded anonymous fields and handles
-// ambiguity.  If a method is found, set *IS_METHOD to true;
-// otherwise, if a field is found, set it to false.  If
-// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
-// whose address can not be taken.  When returning false, this sets
-// *FOUND_POINTER_METHOD if we found a method we couldn't use because
-// it requires a pointer.  LEVEL is used for recursive calls.
-
-bool
-Named_type::find_field_or_method(const std::string& name,
-				 bool receiver_can_be_pointer,
-				 int* level,
-				 bool* is_method,
-				 bool* found_pointer_method) const
-{
-  if (this->local_methods_ != NULL)
-    {
-      Named_object* no = this->local_methods_->lookup(name);
-      if (no != NULL)
-	{
-	  if (!receiver_can_be_pointer
-	      && Named_type::method_expects_pointer(no))
-	    *found_pointer_method = true;
-	  else
-	    {
-	      *is_method = true;
-	      return true;
-	    }
-	}
-    }
-
-  const Interface_type* it = this->interface_type();
-  if (it != NULL)
-    {
-      const Typed_identifier* tid = it->find_method(name);
-      if (tid == NULL)
-	return false;
-      *is_method = true;
-      return true;
-    }
-
-  const Struct_type* st = this->struct_type();
-  if (st == NULL)
-    return false;
-
-  const Struct_field_list* fields = st->fields();
-  if (fields == NULL)
-    return false;
-
-  bool found = false;
-  bool found_is_method = false;
-  int found_level = 0;
-  for (Struct_field_list::const_iterator pf = fields->begin();
-       pf != fields->end();
-       ++pf)
-    {
-      if (pf->field_name() == name)
-	{
-	  *is_method = false;
-	  return true;
-	}
-
-      if (!pf->is_anonymous())
-	continue;
-
-      Named_type* fntype = pf->type()->deref()->named_type();
-      gcc_assert(fntype != NULL);
-
-      int sublevel = level == NULL ? 1 : *level + 1;
-      bool sub_is_method;
-      bool subfound = fntype->find_field_or_method(name,
-						   receiver_can_be_pointer,
-						   &sublevel,
-						   &sub_is_method,
-						   found_pointer_method);
-      if (subfound && (!found || sublevel < found_level))
-	{
-	  found = true;
-	  found_is_method = sub_is_method;
-	  found_level = sublevel;
-	}
-    }
-
-  if (found)
-    {
-      if (level != NULL)
-	*level = found_level;
-      *is_method = found_is_method;
-      return true;
-    }
-
-  return false;
+// Look for a local method NAME, and returns its named object, or NULL
+// if not there.
+
+Named_object*
+Named_type::find_local_method(const std::string& name) const
+{
+  if (this->local_methods_ == NULL)
+    return NULL;
+  return this->local_methods_->lookup(name);
 }
 
 // Return whether NAME is an unexported field or method, for better
 // error reporting.
 
 bool
-Named_type::is_unexported_field_or_method(const std::string& name) const
-{
-  if (this->local_methods_ != NULL)
+Named_type::is_unexported_local_method(const std::string& name) const
+{
+  Bindings* methods = this->local_methods_;
+  if (methods != NULL)
     {
       for (Bindings::const_declarations_iterator p =
-	     this->local_methods_->begin_declarations();
-	   p != this->local_methods_->end_declarations();
+	     methods->begin_declarations();
+	   p != methods->end_declarations();
 	   ++p)
 	{
 	  if (Gogo::is_hidden_name(p->first)
@@ -5126,34 +4982,6 @@
 	    return true;
 	}
     }
-
-  const Interface_type* it = this->interface_type();
-  if (it != NULL && it->is_unexported_method(name))
-    return true;
-
-  const Struct_type* st = this->deref()->struct_type();
-  if (st == NULL)
-    return false;
-  if (st->is_unexported_field(name))
-    return true;
-
-  const Struct_field_list* fields = st->fields();
-  if (fields == NULL)
-    return false;
-
-  for (Struct_field_list::const_iterator pf = fields->begin();
-       pf != fields->end();
-       ++pf)
-    {
-      if (pf->is_anonymous())
-	{
-	  Named_type* subtype = pf->type()->deref()->named_type();
-	  gcc_assert(subtype != NULL);
-	  if (subtype->is_unexported_field_or_method(name))
-	    return true;
-	}
-    }
-
   return false;
 }
 
@@ -5164,402 +4992,21 @@
 void
 Named_type::finalize_methods(Gogo* gogo)
 {
-  if (this->local_methods_ != NULL && this->points_to() != NULL)
+  if (this->local_methods_ != NULL
+      && (this->points_to() != NULL || this->interface_type() != NULL))
     {
       const Bindings* lm = this->local_methods_;
       for (Bindings::const_declarations_iterator p = lm->begin_declarations();
 	   p != lm->end_declarations();
 	   ++p)
-	error_at(p->second->location(), "invalid pointer receiver type");
+	error_at(p->second->location(),
+		 "invalid pointer or interface receiver type");
       delete this->local_methods_;
       this->local_methods_ = NULL;
       return;
     }
 
-  Types_seen types_seen;
-  this->add_methods_for_type(this, NULL, 0, false, false, &types_seen);
-
-  this->build_stub_methods(gogo);
-}
-
-// Add the method for TYPE to the methods for THIS.  FIELD_INDEX is
-// the index of the field.  FIELD_INDEX will be -1U when TYPE == THIS.
-// Otherwise TYPE is the type of an anonymous field.  DEPTH is the
-// depth of the field within THIS.  IS_EMBEDDED_POINTER is true if we
-// are adding these methods for an anonymous field with pointer type.
-// NEEDS_STUB_METHOD is true if we need to use a stub method which
-// calls the real method.  TYPES_SEEN is used to avoid infinite
-// recursion.  This returns true if any methods were added.
-
-bool
-Named_type::add_methods_for_type(const Named_type* type,
-				 const Method::Field_indexes* field_indexes,
-				 unsigned int depth,
-				 bool is_embedded_pointer,
-				 bool needs_stub_method,
-				 Types_seen* types_seen)
-{
-  // Pointer types may not have methods.
-  if (type->points_to() != NULL)
-    return false;
-
-  std::pair<Types_seen::iterator, bool> ins = types_seen->insert(type);
-  if (!ins.second)
-    return false;
-
-  bool ret = false;
-
-  if (this->add_local_methods_for_type(type, field_indexes, depth,
-				       is_embedded_pointer, needs_stub_method))
-    ret = true;
-
-  if (this->add_embedded_methods_for_type(type, field_indexes, depth,
-					  is_embedded_pointer,
-					  needs_stub_method,
-					  types_seen))
-    ret = true;
-
-  // If we are called with depth > 0, then we are looking at an
-  // anonymous field of a struct.  If such a field has interface type,
-  // then we need to add the interface methods.
-  if (depth > 0)
-    {
-      if (this->add_interface_methods_for_type(type, field_indexes, depth))
-	ret = true;
-    }
-
-  return ret;
-}
-
-// Add the local methods for TYPE to this type.  The parameters and
-// return value are as for add_methods_for_type.
-
-bool
-Named_type::add_local_methods_for_type(
-    const Named_type* type,
-    const Method::Field_indexes* field_indexes,
-    unsigned int depth,
-    bool is_embedded_pointer,
-    bool needs_stub_method)
-{
-  if (type->local_methods_ == NULL)
-    return false;
-
-  if (this->all_methods_ == NULL)
-    this->all_methods_ = new Methods();
-
-  bool ret = false;
-  const Bindings* lm = type->local_methods_;
-  for (Bindings::const_declarations_iterator p = lm->begin_declarations();
-       p != lm->end_declarations();
-       ++p)
-    {
-      Named_object* no = p->second;
-      bool is_value_method = (is_embedded_pointer
-			      || !Named_type::method_expects_pointer(no));
-      Method* m = new Named_method(no, field_indexes, depth, is_value_method,
-				   (needs_stub_method
-				    || (depth > 0 && is_value_method)));
-      if (this->all_methods_->insert(no->name(), m))
-	ret = true;
-      else
-	delete m;
-    }
-
-  return ret;
-}
-
-// Add the embedded methods for TYPE to this type.  These are the
-// methods attached to anonymous fields.  The parameters and return
-// value are as for add_methods_for_type.
-
-bool
-Named_type::add_embedded_methods_for_type(
-    const Named_type* type,
-    const Method::Field_indexes* field_indexes,
-    unsigned int depth,
-    bool is_embedded_pointer,
-    bool needs_stub_method,
-    Types_seen* types_seen)
-{
-  // Look for anonymous fields in TYPE.  TYPE has fields if it is a
-  // struct.
-  const Struct_type* st = type->struct_type();
-  if (st == NULL)
-    return false;
-
-  const Struct_field_list* fields = st->fields();
-  if (fields == NULL)
-    {
-      // Having an incomplete type is most likely an error which will
-      // be reported elsewhere.  Here we just avoid a crash.
-      return false;
-    }
-
-  bool ret = false;
-  unsigned int i = 0;
-  for (Struct_field_list::const_iterator pf = fields->begin();
-       pf != fields->end();
-       ++pf, ++i)
-    {
-      if (!pf->is_anonymous())
-	continue;
-
-      Type* ftype = pf->type();
-      bool is_pointer = false;
-      if (ftype->points_to() != NULL)
-	{
-	  ftype = ftype->points_to();
-	  is_pointer = true;
-	}
-      Named_type* fntype = ftype->named_type();
-      if (fntype == NULL)
-	{
-	  Forward_declaration_type *fdtype = ftype->forward_declaration_type();
-	  gcc_assert(fdtype != NULL);
-	  Type* t = fdtype->real_type();
-	  gcc_assert(t->is_error_type());
-	  continue;
-	}
-
-      Method::Field_indexes* sub_field_indexes = new Method::Field_indexes();
-      sub_field_indexes->next = field_indexes;
-      sub_field_indexes->field_index = i;
-
-      if (this->add_methods_for_type(fntype, sub_field_indexes, depth + 1,
-				     (is_embedded_pointer || is_pointer),
-				     (needs_stub_method
-				      || is_pointer
-				      || i > 0),
-				     types_seen))
-	ret = true;
-      else
-	delete sub_field_indexes;
-    }
-
-  return ret;
-}
-
-// If TYPE is an interface type, then add its methods to this type.
-// This is for interface methods attached to an anonymous field.  The
-// parameters and return value are as for add_methods_for_type, except
-// that the boolean parameters are unnecessary.
-
-bool
-Named_type::add_interface_methods_for_type(
-    const Named_type* type,
-    const Method::Field_indexes* field_indexes,
-    unsigned int depth)
-{
-  const Interface_type* it = type->interface_type();
-  if (it == NULL)
-    return false;
-
-  const Typed_identifier_list* methods = it->methods();
-  if (methods == NULL)
-    return false;
-
-  if (this->all_methods_ == NULL)
-    this->all_methods_ = new Methods();
-
-  bool ret = false;
-  for (Typed_identifier_list::const_iterator pm = methods->begin();
-       pm != methods->end();
-       ++pm)
-    {
-      Function_type *fntype = pm->type()->function_type();
-      gcc_assert(fntype != NULL);
-      Method* m = new Interface_method(pm->name(), pm->location(), fntype,
-				       field_indexes, depth);
-      if (this->all_methods_->insert(pm->name(), m))
-	ret = true;
-      else
-	delete m;
-    }
-
-  return ret;
-}
-
-// The name we use for the receiver of a stub method.
-
-const char* const Named_type::receiver_name = "__this";
-
-// Build stub methods as needed.  A stub method may be needed when we
-// inherit a method from an anonymous field.  When we need the address
-// of the method, as in a type descriptor, we need to build a little
-// stub which does the required field dereferences and jumps to the
-// real method.
-
-void
-Named_type::build_stub_methods(Gogo* gogo)
-{
-  if (this->all_methods_ == NULL)
-    return;
-  for (Methods::const_iterator p = this->all_methods_->begin();
-       p != this->all_methods_->end();
-       ++p)
-    {
-      Method* m = p->second;
-      if (m->is_ambiguous() || !m->needs_stub_method())
-	continue;
-
-      const std::string& name(p->first);
-
-      // Build a stub method.
-
-      const Function_type* fntype = m->type();
-
-      static int counter;
-      char buf[100];
-      snprintf(buf, sizeof buf, "%s%d", Named_type::receiver_name, counter);
-      ++counter;
-
-      Type* receiver_type = this;
-      if (!m->is_value_method())
-	receiver_type = Type::make_pointer_type(receiver_type);
-      source_location receiver_location = m->receiver_location();
-      Typed_identifier* receiver = new Typed_identifier(buf, receiver_type,
-							receiver_location);
-
-      const Typed_identifier_list* fnparams = fntype->parameters();
-      Typed_identifier_list* stub_params;
-      if (fnparams == NULL)
-	stub_params = NULL;
-      else
-	{
-	  // We give each stub parameter we create a unique name.
-	  static unsigned int count;
-	  stub_params = new Typed_identifier_list;
-	  for (Typed_identifier_list::const_iterator p = fnparams->begin();
-	       p != fnparams->end();
-	       ++p, ++count)
-	    {
-	      char buf[100];
-	      snprintf(buf, sizeof buf, "p%u", count);
-	      stub_params->push_back(Typed_identifier(buf, p->type(),
-						      p->location()));
-	    }
-	}
-
-      const Typed_identifier_list* fnresults = fntype->results();
-      Typed_identifier_list* stub_results;
-      if (fnresults == NULL)
-	stub_results = NULL;
-      else
-	{
-	  // We create the result parameters without any names, since
-	  // we won't refer to them.
-	  stub_results = new Typed_identifier_list;
-	  for (Typed_identifier_list::const_iterator p = fnresults->begin();
-	       p != fnresults->end();
-	       ++p)
-	    stub_results->push_back(Typed_identifier("", p->type(),
-						     p->location()));
-	}
-
-      Function_type* stub_type = Type::make_function_type(receiver,
-							  stub_params,
-							  stub_results,
-							  fntype->location());
-      if (fntype->is_varargs())
-	stub_type->set_is_varargs();
-
-      // We only create the function in the source file which creates
-      // the type.
-      Named_object* stub;
-      if (this->named_object_->package() != NULL)
-	{
-	  stub = gogo->declare_function(name, stub_type,
-					fntype->location());
-	  stub->set_package(this->named_object_->package());
-	}
-      else
-	{
-	  stub = gogo->start_function(name, stub_type, false,
-				      fntype->location());
-	  this->build_one_stub_method(gogo, m, buf, stub_params);
-	  gogo->finish_function(fntype->location());
-	}
-
-      m->set_stub_object(stub);
-    }
-}
-
-// Build a stub method which adjusts the receiver according to
-// FIELD_INDEXES and calls METHOD.  PARAMS is the list of function
-// parameters.
-
-void
-Named_type::build_one_stub_method(Gogo* gogo, Method* method,
-				  const char* receiver_name,
-				  const Typed_identifier_list* params)
-{
-  // FIXME: Using a predetermined name is a hack.
-  Named_object* this_object = gogo->lookup(receiver_name, NULL);
-  gcc_assert(this_object != NULL);
-
-  source_location location = this->location_;
-  Expression* expr = Expression::make_var_reference(this_object, location);
-
-  expr = this->apply_field_indexes(expr, method->field_indexes());
-  if (expr->type()->points_to() == NULL)
-    expr = Expression::make_unary(OPERATOR_AND, expr, location);
-
-  Expression_list* arguments;
-  if (params == NULL)
-    arguments = NULL;
-  else
-    {
-      arguments = new Expression_list;
-      for (Typed_identifier_list::const_iterator p = params->begin();
-	   p != params->end();
-	   ++p)
-	{
-	  Named_object* param = gogo->lookup(p->name(), NULL);
-	  gcc_assert(param != NULL);
-	  Expression* param_ref = Expression::make_var_reference(param,
-								 location);
-	  arguments->push_back(param_ref);
-	}
-    }
-
-  Expression* func = method->bind_method(expr, location);
-  Call_expression* call = Expression::make_call(func, arguments, location);
-  size_t count = call->result_count();
-  if (count == 0)
-    gogo->add_statement(Statement::make_statement(call));
-  else
-    {
-      Expression_list* retvals = new Expression_list();
-      if (count <= 1)
-	retvals->push_back(call);
-      else
-	{
-	  for (size_t i = 0; i < count; ++i)
-	    retvals->push_back(Expression::make_call_result(call, i));
-	}
-      const Function* function = gogo->current_function()->func_value();
-      Statement* retstat = Statement::make_return_statement(function, retvals,
-							    location);
-      gogo->add_statement(retstat);
-    }
-}
-
-// Apply FIELD_INDEXES to EXPR.  The field indexes have to be applied
-// in reverse order.
-
-Expression*
-Named_type::apply_field_indexes(Expression* expr,
-				const Method::Field_indexes* field_indexes)
-{
-  if (field_indexes == NULL)
-    return expr;
-  expr = this->apply_field_indexes(expr, field_indexes->next);
-  Struct_type* stype = expr->type()->deref()->struct_type();
-  gcc_assert(stype != NULL
-	     && field_indexes->field_index < stype->field_count());
-  return Expression::make_field_reference(expr, field_indexes->field_index,
-					  this->location_);
+  Type::finalize_methods(gogo, this, this->location_, &this->all_methods_);
 }
 
 // Return the method NAME, or NULL if there isn't one or if it is
@@ -5569,19 +5016,7 @@
 Method*
 Named_type::method_function(const std::string& name, bool* is_ambiguous) const
 {
-  *is_ambiguous = false;
-  if (this->all_methods_ == NULL)
-    return NULL;
-  Methods::const_iterator p = this->all_methods_->find(name);
-  if (p == this->all_methods_->end())
-    return NULL;
-  Method* m = p->second;
-  if (m->is_ambiguous())
-    {
-      *is_ambiguous = true;
-      return NULL;
-    }
-  return m;
+  return Type::method_function(this->all_methods_, name, is_ambiguous);
 }
 
 // Return a pointer to the interface method table for this type for
@@ -6029,6 +5464,720 @@
   return new Named_type(named_object, type, location);
 }
 
+// Finalize the methods for TYPE.  It will be a named type or a struct
+// type.  This sets *ALL_METHODS to the list of methods, and builds
+// all required stubs.
+
+void
+Type::finalize_methods(Gogo* gogo, const Type* type, source_location location,
+		       Methods** all_methods)
+{
+  *all_methods = NULL;
+  Types_seen types_seen;
+  Type::add_methods_for_type(type, NULL, 0, false, false, &types_seen,
+			     all_methods);
+  Type::build_stub_methods(gogo, type, *all_methods, location);
+}
+
+// Add the methods for TYPE to *METHODS.  FIELD_INDEXES is used to
+// build up the struct field indexes as we go.  DEPTH is the depth of
+// the field within TYPE.  IS_EMBEDDED_POINTER is true if we are
+// adding these methods for an anonymous field with pointer type.
+// NEEDS_STUB_METHOD is true if we need to use a stub method which
+// calls the real method.  TYPES_SEEN is used to avoid infinite
+// recursion.
+
+void
+Type::add_methods_for_type(const Type* type,
+			   const Method::Field_indexes* field_indexes,
+			   unsigned int depth,
+			   bool is_embedded_pointer,
+			   bool needs_stub_method,
+			   Types_seen* types_seen,
+			   Methods** methods)
+{
+  // Pointer types may not have methods.
+  if (type->points_to() != NULL)
+    return;
+
+  const Named_type* nt = type->named_type();
+  if (nt != NULL)
+    {
+      std::pair<Types_seen::iterator, bool> ins = types_seen->insert(nt);
+      if (!ins.second)
+	return;
+    }
+
+  if (nt != NULL)
+    Type::add_local_methods_for_type(nt, field_indexes, depth,
+				     is_embedded_pointer, needs_stub_method,
+				     methods);
+
+  Type::add_embedded_methods_for_type(type, field_indexes, depth,
+				      is_embedded_pointer, needs_stub_method,
+				      types_seen, methods);
+
+  // If we are called with depth > 0, then we are looking at an
+  // anonymous field of a struct.  If such a field has interface type,
+  // then we need to add the interface methods.  We don't want to add
+  // them when depth == 0, because we will already handle them
+  // following the usual rules for an interface type.
+  if (depth > 0)
+    Type::add_interface_methods_for_type(type, field_indexes, depth, methods);
+}
+
+// Add the local methods for the named type NT to *METHODS.  The
+// parameters are as for add_methods_to_type.
+
+void
+Type::add_local_methods_for_type(const Named_type* nt,
+				 const Method::Field_indexes* field_indexes,
+				 unsigned int depth,
+				 bool is_embedded_pointer,
+				 bool needs_stub_method,
+				 Methods** methods)
+{
+  const Bindings* local_methods = nt->local_methods();
+  if (local_methods == NULL)
+    return;
+
+  if (*methods == NULL)
+    *methods = new Methods();
+
+  for (Bindings::const_declarations_iterator p =
+	 local_methods->begin_declarations();
+       p != local_methods->end_declarations();
+       ++p)
+    {
+      Named_object* no = p->second;
+      bool is_value_method = (is_embedded_pointer
+			      || !Type::method_expects_pointer(no));
+      Method* m = new Named_method(no, field_indexes, depth, is_value_method,
+				   (needs_stub_method
+				    || (depth > 0 && is_value_method)));
+      if (!(*methods)->insert(no->name(), m))
+	delete m;
+    }
+}
+
+// Add the embedded methods for TYPE to *METHODS.  These are the
+// methods attached to anonymous fields.  The parameters are as for
+// add_methods_to_type.
+
+void
+Type::add_embedded_methods_for_type(const Type* type,
+				    const Method::Field_indexes* field_indexes,
+				    unsigned int depth,
+				    bool is_embedded_pointer,
+				    bool needs_stub_method,
+				    Types_seen* types_seen,
+				    Methods** methods)
+{
+  // Look for anonymous fields in TYPE.  TYPE has fields if it is a
+  // struct.
+  const Struct_type* st = type->struct_type();
+  if (st == NULL)
+    return;
+
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return;
+
+  unsigned int i = 0;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf, ++i)
+    {
+      if (!pf->is_anonymous())
+	continue;
+
+      Type* ftype = pf->type();
+      bool is_pointer = false;
+      if (ftype->points_to() != NULL)
+	{
+	  ftype = ftype->points_to();
+	  is_pointer = true;
+	}
+      Named_type* fnt = ftype->named_type();
+      if (fnt == NULL)
+	{
+	  // This is an error, but it will be diagnosed elsewhere.
+	  continue;
+	}
+
+      Method::Field_indexes* sub_field_indexes = new Method::Field_indexes();
+      sub_field_indexes->next = field_indexes;
+      sub_field_indexes->field_index = i;
+
+      Type::add_methods_for_type(fnt, sub_field_indexes, depth + 1,
+				 (is_embedded_pointer || is_pointer),
+				 (needs_stub_method
+				  || is_pointer
+				  || i > 0),
+				 types_seen,
+				 methods);
+    }
+}
+
+// If TYPE is an interface type, then add its method to *METHODS.
+// This is for interface methods attached to an anonymous field.  The
+// parameters are as for add_methods_for_type.
+
+void
+Type::add_interface_methods_for_type(const Type* type,
+				     const Method::Field_indexes* field_indexes,
+				     unsigned int depth,
+				     Methods** methods)
+{
+  const Interface_type* it = type->interface_type();
+  if (it == NULL)
+    return;
+
+  const Typed_identifier_list* imethods = it->methods();
+  if (imethods == NULL)
+    return;
+
+  if (*methods == NULL)
+    *methods = new Methods();
+
+  for (Typed_identifier_list::const_iterator pm = imethods->begin();
+       pm != imethods->end();
+       ++pm)
+    {
+      Function_type* fntype = pm->type()->function_type();
+      gcc_assert(fntype != NULL && !fntype->is_method());
+      fntype = fntype->copy_with_receiver(const_cast<Type*>(type));
+      Method* m = new Interface_method(pm->name(), pm->location(), fntype,
+				       field_indexes, depth);
+      if (!(*methods)->insert(pm->name(), m))
+	delete m;
+    }
+}
+
+// Build stub methods for TYPE as needed.  METHODS is the set of
+// methods for the type.  A stub method may be needed when a type
+// inherits a method from an anonymous field.  When we need the
+// address of the method, as in a type descriptor, we need to build a
+// little stub which does the required field dereferences and jumps to
+// the real method.  LOCATION is the location of the type definition.
+
+void
+Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
+			 source_location location)
+{
+  if (methods == NULL)
+    return;
+  for (Methods::const_iterator p = methods->begin();
+       p != methods->end();
+       ++p)
+    {
+      Method* m = p->second;
+      if (m->is_ambiguous() || !m->needs_stub_method())
+	continue;
+
+      const std::string& name(p->first);
+
+      // Build a stub method.
+
+      const Function_type* fntype = m->type();
+
+      static unsigned int counter;
+      char buf[100];
+      snprintf(buf, sizeof buf, "$this%u", counter);
+      ++counter;
+
+      Type* receiver_type = const_cast<Type*>(type);
+      if (!m->is_value_method())
+	receiver_type = Type::make_pointer_type(receiver_type);
+      source_location receiver_location = m->receiver_location();
+      Typed_identifier* receiver = new Typed_identifier(buf, receiver_type,
+							receiver_location);
+
+      const Typed_identifier_list* fnparams = fntype->parameters();
+      Typed_identifier_list* stub_params;
+      if (fnparams == NULL || fnparams->empty())
+	stub_params = NULL;
+      else
+	{
+	  // We give each stub parameter a unique name.
+	  stub_params = new Typed_identifier_list();
+	  for (Typed_identifier_list::const_iterator pp = fnparams->begin();
+	       pp != fnparams->end();
+	       ++pp)
+	    {
+	      char pbuf[100];
+	      snprintf(pbuf, sizeof pbuf, "$p%u", counter);
+	      stub_params->push_back(Typed_identifier(pbuf, pp->type(),
+						      pp->location()));
+	      ++counter;
+	    }
+	}
+
+      const Typed_identifier_list* fnresults = fntype->results();
+      Typed_identifier_list* stub_results;
+      if (fnresults == NULL || fnresults->empty())
+	stub_results = NULL;
+      else
+	{
+	  // We create the result parameters without any names, since
+	  // we won't refer to them.
+	  stub_results = new Typed_identifier_list();
+	  for (Typed_identifier_list::const_iterator pr = fnresults->begin();
+	       pr != fnresults->end();
+	       ++pr)
+	    stub_results->push_back(Typed_identifier("", pr->type(),
+						     pr->location()));
+	}
+
+      Function_type* stub_type = Type::make_function_type(receiver,
+							  stub_params,
+							  stub_results,
+							  fntype->location());
+      if (fntype->is_varargs())
+	stub_type->set_is_varargs();
+
+      // We only create the function in the package which creates the
+      // type.
+      const Package* package;
+      if (type->named_type() == NULL)
+	package = NULL;
+      else
+	package = type->named_type()->named_object()->package();
+      Named_object* stub;
+      if (package != NULL)
+	stub = Named_object::make_function_declaration(name, package,
+						       stub_type, location);
+      else
+	{
+	  stub = gogo->start_function(name, stub_type, false,
+				      fntype->location());
+	  Type::build_one_stub_method(gogo, m, buf, stub_params, location);
+	  gogo->finish_function(fntype->location());
+	}
+
+      m->set_stub_object(stub);
+    }
+}
+
+// Build a stub method which adjusts the receiver as required to call
+// METHOD.  RECEIVER_NAME is the name we used for the receiver.
+// PARAMS is the list of function parameters.
+
+void
+Type::build_one_stub_method(Gogo* gogo, Method* method,
+			    const char* receiver_name,
+			    const Typed_identifier_list* params,
+			    source_location location)
+{
+  Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
+  gcc_assert(receiver_object != NULL);
+
+  Expression* expr = Expression::make_var_reference(receiver_object, location);
+  expr = Type::apply_field_indexes(expr, method->field_indexes(), location);
+  if (expr->type()->points_to() == NULL)
+    expr = Expression::make_unary(OPERATOR_AND, expr, location);
+
+  Expression_list* arguments;
+  if (params == NULL || params->empty())
+    arguments = NULL;
+  else
+    {
+      arguments = new Expression_list();
+      for (Typed_identifier_list::const_iterator p = params->begin();
+	   p != params->end();
+	   ++p)
+	{
+	  Named_object* param = gogo->lookup(p->name(), NULL);
+	  gcc_assert(param != NULL);
+	  Expression* param_ref = Expression::make_var_reference(param,
+								 location);
+	  arguments->push_back(param_ref);
+	}
+    }
+
+  Expression* func = method->bind_method(expr, location);
+  gcc_assert(func != NULL);
+  Call_expression* call = Expression::make_call(func, arguments, location);
+  size_t count = call->result_count();
+  if (count == 0)
+    gogo->add_statement(Statement::make_statement(call));
+  else
+    {
+      Expression_list* retvals = new Expression_list();
+      if (count <= 1)
+	retvals->push_back(call);
+      else
+	{
+	  for (size_t i = 0; i < count; ++i)
+	    retvals->push_back(Expression::make_call_result(call, i));
+	}
+      const Function* function = gogo->current_function()->func_value();
+      Statement* retstat = Statement::make_return_statement(function, retvals,
+							    location);
+      gogo->add_statement(retstat);
+    }
+}
+
+// Apply FIELD_INDEXES to EXPR.  The field indexes have to be applied
+// in reverse order.
+
+Expression*
+Type::apply_field_indexes(Expression* expr,
+			  const Method::Field_indexes* field_indexes,
+			  source_location location)
+{
+  if (field_indexes == NULL)
+    return expr;
+  expr = Type::apply_field_indexes(expr, field_indexes->next, location);
+  Struct_type* stype = expr->type()->deref()->struct_type();
+  gcc_assert(stype != NULL
+	     && field_indexes->field_index < stype->field_count());
+  return Expression::make_field_reference(expr, field_indexes->field_index,
+					  location);
+}
+
+// Return whether NO is a method for which the receiver is a pointer.
+
+bool
+Type::method_expects_pointer(const Named_object* no)
+{
+  const Function_type *fntype;
+  if (no->is_function())
+    fntype = no->func_value()->type();
+  else if (no->is_function_declaration())
+    fntype = no->func_declaration_value()->type();
+  else
+    gcc_unreachable();
+  return fntype->receiver()->type()->points_to() != NULL;
+}
+
+// Given a set of methods for a type, METHODS, return the method NAME,
+// or NULL if there isn't one or if it is ambiguous.  If IS_AMBIGUOUS
+// is not NULL, then set *IS_AMBIGUOUS to true if the method exists
+// but is ambiguous (and return NULL).
+
+Method*
+Type::method_function(const Methods* methods, const std::string& name,
+		      bool* is_ambiguous)
+{
+  if (is_ambiguous != NULL)
+    *is_ambiguous = false;
+  if (methods == NULL)
+    return NULL;
+  Methods::const_iterator p = methods->find(name);
+  if (p == methods->end())
+    return NULL;
+  Method* m = p->second;
+  if (m->is_ambiguous())
+    {
+      if (is_ambiguous != NULL)
+	*is_ambiguous = true;
+      return NULL;
+    }
+  return m;
+}
+
+// Look for field or method NAME for TYPE.  Return an Expression for
+// the field or method bound to EXPR.  If there is no such field or
+// method, give an appropriate error and return an error expression.
+
+Expression*
+Type::bind_field_or_method(const Type* type, Expression* expr,
+			   const std::string& name,
+			   source_location location)
+{
+  if (type->is_error_type())
+    return Expression::make_error(location);
+
+  const Named_type* nt = type->named_type();
+  if (nt == NULL)
+    nt = type->deref()->named_type();
+  const Struct_type* st = type->deref()->struct_type();
+  const Interface_type* it = type->deref()->interface_type();
+
+  bool receiver_can_be_pointer = (expr->type()->points_to() != NULL
+				  || expr->is_lvalue());
+  bool is_method = false;
+  bool found_pointer_method = false;
+  std::string ambig1;
+  std::string ambig2;
+  if (Type::find_field_or_method(type, name, receiver_can_be_pointer, NULL,
+				 &is_method, &found_pointer_method,
+				 &ambig1, &ambig2))
+    {
+      Expression* ret;
+      if (!is_method)
+	{
+	  gcc_assert(st != NULL);
+	  ret = st->field_reference(expr, name, location);
+	}
+      else if (it != NULL && it->find_method(name) != NULL)
+	ret = Expression::make_interface_field_reference(expr, name,
+							 location);
+      else
+	{
+	  Method* m;
+	  if (nt != NULL)
+	    m = nt->method_function(name, NULL);
+	  else if (st != NULL)
+	    m = st->method_function(name);
+	  else
+	    gcc_unreachable();
+	  gcc_assert(m != NULL);
+	  if (!m->is_value_method() && expr->type()->points_to() == NULL)
+	    expr = Expression::make_unary(OPERATOR_AND, expr, location);
+	  ret = m->bind_method(expr, location);
+	}
+      gcc_assert(ret != NULL);
+      return ret;
+    }
+  else
+    {
+      if (!ambig1.empty())
+	error_at(location, "%qs is ambiguous via %qs and %qs",
+		 Gogo::unpack_hidden_name(name).c_str(),
+		 ambig1.c_str(), ambig2.c_str());
+      else if (found_pointer_method)
+	error_at(location, "method requires a pointer");
+      else if (nt == NULL && st == NULL && it == NULL)
+	error_at(location,
+		 ("reference to field %qs in object which "
+		  "has no fields or methods"),
+		 name.c_str());
+      else
+	{
+	  bool is_unexported;
+	  std::string unpacked = Gogo::unpack_hidden_name(name);
+	  if (!Gogo::is_hidden_name(name))
+	    is_unexported = false;
+	  else
+	    is_unexported = Type::is_unexported_field_or_method(type, name);
+	  if (is_unexported)
+	    error_at(location, "reference to unexported field or method %qs",
+		     unpacked.c_str());
+	  else
+	    error_at(location, "reference to undefined field or method %qs",
+		     unpacked.c_str());
+	}
+      return Expression::make_error(location);
+    }
+}
+
+// Look in TYPE for a field or method named NAME, return true if one
+// is found.  This looks through embedded anonymous fields and handles
+// ambiguity.  If a method is found, sets *IS_METHOD to true;
+// otherwise, if a field is found, set it to false.  If
+// RECEIVER_CAN_BE_POINTER is false, then the receiver is a value
+// whose address can not be taken.  When returning false, this sets
+// *FOUND_POINTER_METHOD if we found a method we couldn't use because
+// it requires a pointer.  LEVEL is used for recursive calls, and can
+// be NULL for a non-recursive call.  When this function returns false
+// because it finds that the name is ambiguous, it will store a path
+// to the ambiguous names in *AMBIG1 and *AMBIG2.  If the name is not
+// found at all, *AMBIG1 and *AMBIG2 will be unchanged.
+
+// This function just returns whether or not there is a field or
+// method, and whether it is a field or method.  It doesn't build an
+// expression to refer to it.  If it is a method, we then look in the
+// list of all methods for the type.  If it is a field, the search has
+// to be done again, looking only for fields, and building up the
+// expression as we go.
+
+bool
+Type::find_field_or_method(const Type* type,
+			   const std::string& name,
+			   bool receiver_can_be_pointer,
+			   int* level,
+			   bool* is_method,
+			   bool* found_pointer_method,
+			   std::string* ambig1,
+			   std::string* ambig2)
+{
+  // Named types can have locally defined methods.
+  const Named_type* nt = type->named_type();
+  if (nt == NULL && type->points_to() != NULL)
+    nt = type->points_to()->named_type();
+  if (nt != NULL)
+    {
+      Named_object* no = nt->find_local_method(name);
+      if (no != NULL)
+	{
+	  if (receiver_can_be_pointer || !Type::method_expects_pointer(no))
+	    {
+	      *is_method = true;
+	      return true;
+	    }
+
+	  // Record that we have found a pointer method in order to
+	  // give a better error message if we don't find anything
+	  // else.
+	  *found_pointer_method = true;
+	}
+    }
+
+  // Interface types can have methods.
+  const Interface_type* it = type->deref()->interface_type();
+  if (it != NULL && it->find_method(name) != NULL)
+    {
+      *is_method = true;
+      return true;
+    }
+
+  // Struct types can have fields.  They can also inherit fields and
+  // methods from anonymous fields.
+  const Struct_type* st = type->deref()->struct_type();
+  if (st == NULL)
+    return false;
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return false;
+
+  int found_level = 0;
+  bool found_is_method = false;
+  std::string found_ambig1;
+  std::string found_ambig2;
+  const Struct_field* found_parent = NULL;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      if (pf->field_name() == name)
+	{
+	  *is_method = false;
+	  return true;
+	}
+
+      if (!pf->is_anonymous())
+	continue;
+
+      Named_type* fnt = pf->type()->deref()->named_type();
+      gcc_assert(fnt != NULL);
+
+      int sublevel = level == NULL ? 1 : *level + 1;
+      bool sub_is_method;
+      std::string subambig1;
+      std::string subambig2;
+      bool subfound = Type::find_field_or_method(fnt,
+						 name,
+						 receiver_can_be_pointer,
+						 &sublevel,
+						 &sub_is_method,
+						 found_pointer_method,
+						 &subambig1,
+						 &subambig2);
+      if (!subfound)
+	{
+	  if (!subambig1.empty())
+	    {
+	      // The name was found via this field, but is ambiguous.
+	      // if the ambiguity is lower or at the same level as
+	      // anything else we have already found, then we want to
+	      // pass the ambiguity back to the caller.
+	      if (found_level == 0 || sublevel <= found_level)
+		{
+		  found_ambig1 = pf->field_name() + '.' + subambig1;
+		  found_ambig2 = pf->field_name() + '.' + subambig2;
+		  found_level = sublevel;
+		}
+	    }
+	}
+      else
+	{
+	  // The name was found via this field.  Use the level to see
+	  // if we want to use this one, or whether it introduces an
+	  // ambiguity.
+	  if (found_level == 0 || sublevel < found_level)
+	    {
+	      found_level = sublevel;
+	      found_is_method = sub_is_method;
+	      found_ambig1.clear();
+	      found_ambig2.clear();
+	      found_parent = &*pf;
+	    }
+	  else if (sublevel > found_level)
+	    ;
+	  else if (found_ambig1.empty())
+	    {
+	      // We found an ambiguity.
+	      gcc_assert(found_parent != NULL);
+	      found_ambig1 = found_parent->field_name();
+	      found_ambig2 = pf->field_name();
+	    }
+	  else
+	    {
+	      // We found an ambiguity, but we already know of one.
+	      // Just report the earlier one.
+	    }
+	}
+    }
+
+  // Here if we didn't find anything FOUND_LEVEL is 0.  If we found
+  // something ambiguous, FOUND_LEVEL is not 0 and FOUND_AMBIG1 and
+  // FOUND_AMBIG2 are not empty.  If we found the field, FOUND_LEVEL
+  // is not 0 and FOUND_AMBIG1 and FOUND_AMBIG2 are empty.
+
+  if (found_level == 0)
+    return false;
+  else if (!found_ambig1.empty())
+    {
+      gcc_assert(!found_ambig1.empty());
+      ambig1->assign(found_ambig1);
+      ambig2->assign(found_ambig2);
+      if (level != NULL)
+	*level = found_level;
+      return false;
+    }
+  else
+    {
+      if (level != NULL)
+	*level = found_level;
+      *is_method = found_is_method;
+      return true;
+    }
+}
+
+// Return whether NAME is an unexported field or method for TYPE.
+
+bool
+Type::is_unexported_field_or_method(const Type* type, const std::string& name)
+{
+  type = type->deref();
+
+  const Named_type* nt = type->named_type();
+  if (nt != NULL && nt->is_unexported_local_method(name))
+    return true;
+
+  const Interface_type* it = type->interface_type();
+  if (it != NULL && it->is_unexported_method(name))
+    return true;
+
+  const Struct_type* st = type->struct_type();
+  if (st != NULL && st->is_unexported_local_field(name))
+    return true;
+
+  if (st == NULL)
+    return false;
+
+  const Struct_field_list* fields = st->fields();
+  if (fields == NULL)
+    return false;
+
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
+    {
+      if (pf->is_anonymous())
+	{
+	  Named_type* subtype = pf->type()->deref()->named_type();
+	  gcc_assert(subtype != NULL);
+	  if (Type::is_unexported_field_or_method(subtype, name))
+	    return true;
+	}
+    }
+
+  return false;
+}
+
 // Class Forward_declaration.
 
 Forward_declaration_type::Forward_declaration_type(Named_object* named_object)
diff -r 5a0e1b402d81 go/types.h
--- a/go/types.h	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/types.h	Fri Feb 12 23:56:51 2010 -0800
@@ -29,6 +29,10 @@
 class Interface_type;
 class Named_type;
 class Forward_declaration_type;
+class Method;
+class Methods;
+class Type_hash_identical;
+class Type_identical;
 class Expression;
 class Expression_list;
 class Call_expression;
@@ -72,6 +76,262 @@
 static const int RUNTIME_TYPE_CODE_PTR = 23;
 static const int RUNTIME_TYPE_CODE_STRUCT = 24;
 
+// To build the complete list of methods for a named type we need to
+// gather all methods from anonymous fields.  Those methods may
+// require an arbitrary set of indirections and field offsets.  There
+// is also the possibility of ambiguous methods, which we could ignore
+// except that we want to give a better error message for that case.
+// This is a base class.  There are two types of methods: named
+// methods, and methods which are inherited from an anonymous field of
+// interface type.
+
+class Method
+{
+ public:
+  // For methods in anonymous types we need to know the sequence of
+  // field references used to extract the pointer to pass to the
+  // method.  Since each method for a particular anonymous field will
+  // have the sequence of field indexes, and since the indexes can be
+  // shared going down the chain, we use a manually managed linked
+  // list.  The first entry in the list is the field index for the
+  // last field, the one passed to the method.
+
+  struct Field_indexes
+  {
+    const Field_indexes* next;
+    unsigned int field_index;
+  };
+
+  virtual ~Method()
+  { }
+
+  // Get the list of field indexes.
+  const Field_indexes*
+  field_indexes() const
+  { return this->field_indexes_; }
+
+  // Get the depth.
+  unsigned int
+  depth() const
+  { return this->depth_; }
+
+  // Return whether this is a value method--a method which does not
+  // require a pointer expression.
+  bool
+  is_value_method() const
+  { return this->is_value_method_; }
+
+  // Return whether we need a stub method--this is true if we can't
+  // just pass the main object to the method.
+  bool
+  needs_stub_method() const
+  { return this->needs_stub_method_; }
+
+  // Return whether this is an ambiguous method name.
+  bool
+  is_ambiguous() const
+  { return this->is_ambiguous_; }
+
+  // Note that this method is ambiguous.
+  void
+  set_is_ambiguous()
+  { this->is_ambiguous_ = true; }
+
+  // Return the type of the method.
+  Function_type*
+  type() const
+  { return this->do_type(); }
+
+  // Return the location of the method receiver.
+  source_location
+  receiver_location() const
+  { return this->do_receiver_location(); }
+
+  // Return an expression which binds this method to EXPR.  This is
+  // something which can be used with a function call.
+  Expression*
+  bind_method(Expression* expr, source_location location) const;
+
+  // Return the named object for this method.  This may only be called
+  // after methods are finalized.
+  Named_object*
+  named_object() const;
+
+  // Set the stub object.
+  void
+  set_stub_object(Named_object* no)
+  {
+    gcc_assert(this->stub_ == NULL);
+    this->stub_ = no;
+  }
+
+ protected:
+  // These objects are only built by the child classes.
+  Method(const Field_indexes* field_indexes, unsigned int depth,
+	 bool is_value_method, bool needs_stub_method)
+    : field_indexes_(field_indexes), depth_(depth), stub_(NULL),
+      is_value_method_(is_value_method), needs_stub_method_(needs_stub_method),
+      is_ambiguous_(false)
+  { }
+
+  // The named object for this method.
+  virtual Named_object*
+  do_named_object() const = 0;
+
+  // The type of the method.
+  virtual Function_type*
+  do_type() const = 0;
+
+  // Return the location of the method receiver.
+  virtual source_location
+  do_receiver_location() const = 0;
+
+  // Bind a method to an object.
+  virtual Expression*
+  do_bind_method(Expression* expr, source_location location) const = 0;
+
+ private:
+  // The sequence of field indexes used for this method.  If this is
+  // NULL, then the method is defined for the current type.
+  const Field_indexes* field_indexes_;
+  // The depth at which this method was found.
+  unsigned int depth_;
+  // If a stub method is required, this is its object.  This is only
+  // set after stub methods are built in finalize_methods.
+  Named_object* stub_;
+  // Whether this is a value method--a method that does not require a
+  // pointer.
+  bool is_value_method_;
+  // Whether a stub method is required.
+  bool needs_stub_method_;
+  // Whether this method is ambiguous.
+  bool is_ambiguous_;
+};
+
+// A named method.  This is what you get with a method declaration,
+// either directly on the type, or inherited from some anonymous
+// embedded field.
+
+class Named_method : public Method
+{
+ public:
+  Named_method(Named_object* named_object, const Field_indexes* field_indexes,
+	       unsigned int depth, bool is_value_method,
+	       bool needs_stub_method)
+    : Method(field_indexes, depth, is_value_method, needs_stub_method),
+      named_object_(named_object)
+  { }
+
+ protected:
+  // Get the Named_object for the method.
+  Named_object*
+  do_named_object() const
+  { return this->named_object_; }
+
+  // The type of the method.
+  Function_type*
+  do_type() const;
+
+  // Return the location of the method receiver.
+  source_location
+  do_receiver_location() const;
+
+  // Bind a method to an object.
+  Expression*
+  do_bind_method(Expression* expr, source_location location) const;
+
+ private:
+  // The method itself.  For a method which needs a stub, this starts
+  // out as the underlying method, and is later replaced with the stub
+  // method.
+  Named_object* named_object_;
+};
+
+// An interface method.  This is used when an interface appears as an
+// anonymous field in a named struct.
+
+class Interface_method : public Method
+{
+ public:
+  Interface_method(const std::string& name, source_location location,
+		   Function_type* fntype, const Field_indexes* field_indexes,
+		   unsigned int depth)
+    : Method(field_indexes, depth, true, true),
+      name_(name), location_(location), fntype_(fntype)
+  { }
+
+ protected:
+  // Get the Named_object for the method.  This should never be
+  // called, as we always create a stub.
+  Named_object*
+  do_named_object() const
+  { gcc_unreachable(); }
+
+  // The type of the method.
+  Function_type*
+  do_type() const
+  { return this->fntype_; }
+
+  // Return the location of the method receiver.
+  source_location
+  do_receiver_location() const
+  { return this->location_; }
+
+  // Bind a method to an object.
+  Expression*
+  do_bind_method(Expression* expr, source_location location) const;
+
+ private:
+  // The name of the interface method to call.
+  std::string name_;
+  // The location of the definition of the interface method.
+  source_location location_;
+  // The type of the interface method.
+  Function_type* fntype_;
+};
+
+// A mapping from method name to Method.  This is a wrapper around a
+// hash table.
+
+class Methods
+{
+ private:
+  typedef std::tr1::unordered_map<std::string, Method*> Method_map;
+
+ public:
+  typedef Method_map::const_iterator const_iterator;
+
+  Methods()
+    : methods_()
+  { }
+
+  // Insert a new method.  Returns true if it was inserted, false if
+  // it was overidden or ambiguous.
+  bool
+  insert(const std::string& name, Method* m);
+
+  // The number of (unambiguous) methods.
+  size_t
+  count() const;
+
+  // Iterate.
+  const_iterator
+  begin() const
+  { return this->methods_.begin(); }
+
+  const_iterator
+  end() const
+  { return this->methods_.end(); }
+
+  // Lookup.
+  const_iterator
+  find(const std::string& name) const
+  { return this->methods_.find(name); }
+
+ private:
+  Method_map methods_;
+};
+
 // The base class for all types.
 
 class Type
@@ -499,6 +759,16 @@
   is_unsafe_pointer_type() const
   { return this->points_to() != NULL && this->points_to()->is_void_type(); }
 
+  // Look for field or method NAME for TYPE.  Return an expression for
+  // it, bound to EXPR.
+  static Expression*
+  bind_field_or_method(const Type* type, Expression* expr,
+		       const std::string& name, source_location);
+
+  // Return true if NAME is an unexported field or method of TYPE.
+  static bool
+  is_unexported_field_or_method(const Type*, const std::string&);
+
   // This type was passed to the builtin function make.  ARGS are the
   // arguments passed to make after the type; this may be NULL if
   // there were none.  Issue any required errors.
@@ -633,6 +903,19 @@
   virtual void
   do_export(Export*) const;
 
+  // Return whether a method expects a pointer as the receiver.
+  static bool
+  method_expects_pointer(const Named_object*);
+
+  // Finalize the methods for a type.
+  static void
+  finalize_methods(Gogo*, const Type*, source_location, Methods**);
+
+  // Return a method from a set of methods.
+  static Method*
+  method_function(const Methods*, const std::string& name,
+		  bool* is_ambiguous);
+
   // Build a type descriptor entry for TYPE, using NAME as the name of
   // the type.  PACKAGE is the package where TYPE is defined, or NULL
   // if defined in the package currently being compiled.  Store the
@@ -706,6 +989,53 @@
   inc_or_dec_refcount(Gogo* gogo, tree expr_tree, source_location,
 		      bool is_local, bool is_increment);
 
+  // A hash table we use to avoid infinite recursion.
+  typedef std::tr1::unordered_set<const Named_type*, Type_hash_identical,
+				  Type_identical> Types_seen;
+
+  // Add all methods for TYPE to the list of methods for THIS.
+  static void
+  add_methods_for_type(const Type* type, const Method::Field_indexes*,
+		       unsigned int depth, bool, bool, Types_seen*,
+		       Methods**);
+
+  static void
+  add_local_methods_for_type(const Named_type* type,
+			     const Method::Field_indexes*,
+			     unsigned int depth, bool, bool, Methods**);
+
+  static void
+  add_embedded_methods_for_type(const Type* type,
+				const Method::Field_indexes*,
+				unsigned int depth, bool, bool, Types_seen*,
+				Methods**);
+
+  static void
+  add_interface_methods_for_type(const Type* type,
+				 const Method::Field_indexes*,
+				 unsigned int depth, Methods**);
+
+  // Build stub methods for a type.
+  static void
+  build_stub_methods(Gogo*, const Type* type, const Methods* methods,
+		     source_location);
+
+  static void
+  build_one_stub_method(Gogo*, Method*, const char* receiver_name,
+			const Typed_identifier_list*, source_location);
+
+  static Expression*
+  apply_field_indexes(Expression*, const Method::Field_indexes*,
+		      source_location);
+
+  // Look for a field or method named NAME in TYPE.
+  static bool
+  find_field_or_method(const Type* type, const std::string& name,
+		       bool receiver_can_be_pointer,
+		       int* level, bool* is_method,
+		       bool* found_pointer_method,
+		       std::string* ambig1, std::string* ambig2);
+
   // The type classification.
   Type_classification classification_;
   // The tree representation of the type, once it has been determined.
@@ -1147,6 +1477,16 @@
   static Function_type*
   do_import(Import*);
 
+  // Return a copy of this type without a receiver.  This is only
+  // valid for a method type.
+  Function_type*
+  copy_without_receiver() const;
+
+  // Return a copy of this type with a receiver.  This is used when an
+  // interface method is attached to a named or struct type.
+  Function_type*
+  copy_with_receiver(Type*) const;
+
  protected:
   int
   do_traverse(Traverse*);
@@ -1374,7 +1714,7 @@
  public:
   Struct_type(Struct_field_list* fields, source_location location)
     : Type(TYPE_STRUCT),
-      fields_(fields), location_(location)
+      fields_(fields), location_(location), all_methods_(NULL)
   { }
 
   // Return the field NAME.  This only looks at local fields, not at
@@ -1427,10 +1767,38 @@
   bool
   struct_has_hidden_fields(const Named_type* within, std::string*) const;
 
-  // Return whether NAME is a field which is not exported.  This is
-  // only used for better error reporting.
+  // Return whether NAME is a local field which is not exported.  This
+  // is only used for better error reporting.
   bool
-  is_unexported_field(const std::string& name) const;
+  is_unexported_local_field(const std::string& name) const;
+
+  // If this is an unnamed struct, build the complete list of methods,
+  // including those from anonymous fields, and build methods stubs if
+  // needed.
+  void
+  finalize_methods(Gogo*);
+
+  // Return whether this type has any methods.  This should only be
+  // called after the finalize_methods pass.
+  bool
+  has_any_methods() const
+  { return this->all_methods_ != NULL; }
+
+  // Return the methods for tihs type.  This should only be called
+  // after the finalize_methods pass.
+  const Methods*
+  methods() const
+  { return this->all_methods_; }
+
+  // Return the method to use for NAME.  This returns NULL if there is
+  // no such method or if the method is ambiguous.
+  Method*
+  method_function(const std::string& name) const;
+
+  // Traverse just the field types of a struct type.
+  int
+  traverse_field_types(Traverse* traverse)
+  { return this->do_traverse(traverse); }
 
   // Import a struct type.
   static Struct_type*
@@ -1483,6 +1851,8 @@
   Struct_field_list* fields_;
   // The place where the struct was declared.
   source_location location_;
+  // If this struct is unnamed, a list of methods.
+  Methods* all_methods_;
 };
 
 // The type of an array.
@@ -1845,262 +2215,6 @@
   source_location location_;
 };
 
-// To build the complete list of methods for a named type we need to
-// gather all methods from anonymous fields.  Those methods may
-// require an arbitrary set of indirections and field offsets.  There
-// is also the possibility of ambiguous methods, which we could ignore
-// except that we want to give a better error message for that case.
-// This is a base class.  There are two types of methods: named
-// methods, and methods which are inherited from an anonymous field of
-// interface type.
-
-class Method
-{
- public:
-  // For methods in anonymous types we need to know the sequence of
-  // field references used to extract the pointer to pass to the
-  // method.  Since each method for a particular anonymous field will
-  // have the sequence of field indexes, and since the indexes can be
-  // shared going down the chain, we use a manually managed linked
-  // list.  The first entry in the list is the field index for the
-  // last field, the one passed to the method.
-
-  struct Field_indexes
-  {
-    const Field_indexes* next;
-    unsigned int field_index;
-  };
-
-  virtual ~Method()
-  { }
-
-  // Get the list of field indexes.
-  const Field_indexes*
-  field_indexes() const
-  { return this->field_indexes_; }
-
-  // Get the depth.
-  unsigned int
-  depth() const
-  { return this->depth_; }
-
-  // Return whether this is a value method--a method which does not
-  // require a pointer expression.
-  bool
-  is_value_method() const
-  { return this->is_value_method_; }
-
-  // Return whether we need a stub method--this is true if we can't
-  // just pass the main object to the method.
-  bool
-  needs_stub_method() const
-  { return this->needs_stub_method_; }
-
-  // Return whether this is an ambiguous method name.
-  bool
-  is_ambiguous() const
-  { return this->is_ambiguous_; }
-
-  // Note that this method is ambiguous.
-  void
-  set_is_ambiguous()
-  { this->is_ambiguous_ = true; }
-
-  // Return the type of the method.
-  Function_type*
-  type() const
-  { return this->do_type(); }
-
-  // Return the location of the method receiver.
-  source_location
-  receiver_location() const
-  { return this->do_receiver_location(); }
-
-  // Return an expression which binds this method to EXPR.  This is
-  // something which can be used with a function call.
-  Expression*
-  bind_method(Expression* expr, source_location location) const;
-
-  // Return the named object for this method.  This may only be called
-  // after methods are finalized.
-  Named_object*
-  named_object() const;
-
-  // Set the stub object.
-  void
-  set_stub_object(Named_object* no)
-  {
-    gcc_assert(this->stub_ == NULL);
-    this->stub_ = no;
-  }
-
- protected:
-  // These objects are only built by the child classes.
-  Method(const Field_indexes* field_indexes, unsigned int depth,
-	 bool is_value_method, bool needs_stub_method)
-    : field_indexes_(field_indexes), depth_(depth), stub_(NULL),
-      is_value_method_(is_value_method), needs_stub_method_(needs_stub_method),
-      is_ambiguous_(false)
-  { }
-
-  // The named object for this method.
-  virtual Named_object*
-  do_named_object() const = 0;
-
-  // The type of the method.
-  virtual Function_type*
-  do_type() const = 0;
-
-  // Return the location of the method receiver.
-  virtual source_location
-  do_receiver_location() const = 0;
-
-  // Bind a method to an object.
-  virtual Expression*
-  do_bind_method(Expression* expr, source_location location) const = 0;
-
- private:
-  // The sequence of field indexes used for this method.  If this is
-  // NULL, then the method is defined for the current type.
-  const Field_indexes* field_indexes_;
-  // The depth at which this method was found.
-  unsigned int depth_;
-  // If a stub method is required, this is its object.  This is only
-  // set after stub methods are built in finalize_methods.
-  Named_object* stub_;
-  // Whether this is a value method--a method that does not require a
-  // pointer.
-  bool is_value_method_;
-  // Whether a stub method is required.
-  bool needs_stub_method_;
-  // Whether this method is ambiguous.
-  bool is_ambiguous_;
-};
-
-// A named method.  This is what you get with a method declaration,
-// either directly on the type, or inherited from some anonymous
-// embedded field.
-
-class Named_method : public Method
-{
- public:
-  Named_method(Named_object* named_object, const Field_indexes* field_indexes,
-	       unsigned int depth, bool is_value_method,
-	       bool needs_stub_method)
-    : Method(field_indexes, depth, is_value_method, needs_stub_method),
-      named_object_(named_object)
-  { }
-
- protected:
-  // Get the Named_object for the method.
-  Named_object*
-  do_named_object() const
-  { return this->named_object_; }
-
-  // The type of the method.
-  Function_type*
-  do_type() const;
-
-  // Return the location of the method receiver.
-  source_location
-  do_receiver_location() const;
-
-  // Bind a method to an object.
-  Expression*
-  do_bind_method(Expression* expr, source_location location) const;
-
- private:
-  // The method itself.  For a method which needs a stub, this starts
-  // out as the underlying method, and is later replaced with the stub
-  // method.
-  Named_object* named_object_;
-};
-
-// An interface method.  This is used when an interface appears as an
-// anonymous field in a named struct.
-
-class Interface_method : public Method
-{
- public:
-  Interface_method(const std::string& name, source_location location,
-		   Function_type* fntype, const Field_indexes* field_indexes,
-		   unsigned int depth)
-    : Method(field_indexes, depth, true, true),
-      name_(name), location_(location), fntype_(fntype)
-  { }
-
- protected:
-  // Get the Named_object for the method.  This should never be
-  // called, as we always create a stub.
-  Named_object*
-  do_named_object() const
-  { gcc_unreachable(); }
-
-  // The type of the method.
-  Function_type*
-  do_type() const
-  { return this->fntype_; }
-
-  // Return the location of the method receiver.
-  source_location
-  do_receiver_location() const
-  { return this->location_; }
-
-  // Bind a method to an object.
-  Expression*
-  do_bind_method(Expression* expr, source_location location) const;
-
- private:
-  // The name of the interface method to call.
-  std::string name_;
-  // The location of the definition of the interface method.
-  source_location location_;
-  // The type of the interface method.
-  Function_type* fntype_;
-};
-
-// A mapping from method name to Method.  This is a wrapper around a
-// hash table.
-
-class Methods
-{
- private:
-  typedef std::tr1::unordered_map<std::string, Method*> Method_map;
-
- public:
-  typedef Method_map::const_iterator const_iterator;
-
-  Methods()
-    : methods_()
-  { }
-
-  // Insert a new method.  Returns true if it was inserted, false if
-  // it was overidden or ambiguous.
-  bool
-  insert(const std::string& name, Method* m);
-
-  // The number of (unambiguous) methods.
-  size_t
-  count() const;
-
-  // Iterate.
-  const_iterator
-  begin() const
-  { return this->methods_.begin(); }
-
-  const_iterator
-  end() const
-  { return this->methods_.end(); }
-
-  // Lookup.
-  const_iterator
-  find(const std::string& name) const
-  { return this->methods_.find(name); }
-
- private:
-  Method_map methods_;
-};
-
 // The value we keep for a named type.  This lets us get the right
 // name when we convert to trees.  Note that we don't actually keep
 // the name here; the name is in the Named_object which points to
@@ -2202,6 +2316,15 @@
   void
   add_existing_method(Named_object*);
 
+  // Look up a local method.
+  Named_object*
+  find_local_method(const std::string& name) const;
+
+  // Return the list of local methods.
+  const Bindings*
+  local_methods() const
+  { return this->local_methods_; }
+
   // Build the complete list of methods, including those from
   // anonymous fields, and build method stubs if needed.
   void
@@ -2219,16 +2342,6 @@
   methods() const
   { return this->all_methods_; }
 
-  // EXPR has this type.  Look for field or method NAME associated
-  // with this type.  Return a Field_reference_expression or
-  // Bound_method_expression for the field or method bound to EXPR.
-  // Return NULL if there is no such field or method.  If this returns
-  // NULL, it sets *FOUND_POINTER_METHOD if a method was found which
-  // takes a pointer but EXPR is value whose address can not be taken.
-  Expression*
-  bind_field_or_method(Expression* expr, const std::string& name,
-		       source_location, bool *found_pointer_method) const;
-
   // Return the method to use for NAME.  This returns NULL if there is
   // no such method or if the method is ambiguous.  When it returns
   // NULL, this sets *IS_AMBIGUOUS if the method name is ambiguous.
@@ -2238,7 +2351,7 @@
   // Return whether NAME is a known field or method which is not
   // exported.  This is only used for better error reporting.
   bool
-  is_unexported_field_or_method(const std::string& name) const;
+  is_unexported_local_method(const std::string& name) const;
 
   // Return a pointer to the interface method table for this type for
   // the interface INTERFACE.
@@ -2325,53 +2438,6 @@
 				  Type_hash_identical,
 				  Type_identical> Interface_method_tables;
 
-  static const char* const receiver_name;
-
-  // Return whether a method expects a pointer as the receiver.
-  static bool
-  method_expects_pointer(const Named_object*);
-
-  // Look for a field or method named NAME.
-  bool
-  find_field_or_method(const std::string& name, bool receiver_can_be_pointer,
-		       int* level, bool* is_method,
-		       bool* found_pointer_method) const;
-
-  // A hash table we use to avoid infinite recursion.
-  typedef std::tr1::unordered_set<const Named_type*, Type_hash_identical,
-				  Type_identical> Types_seen;
-
-  // Add all methods for TYPE to the list of methods for THIS.
-  bool
-  add_methods_for_type(const Named_type* type, const Method::Field_indexes*,
-		       unsigned int depth, bool, bool, Types_seen*);
-
-  bool
-  add_local_methods_for_type(const Named_type* type,
-			     const Method::Field_indexes*,
-			     unsigned int depth, bool, bool);
-
-  bool
-  add_embedded_methods_for_type(const Named_type* type,
-				const Method::Field_indexes*,
-				unsigned int depth, bool, bool, Types_seen*);
-
-  bool
-  add_interface_methods_for_type(const Named_type* type,
-				 const Method::Field_indexes*,
-				 unsigned int depth);
-
-  // Build stub methods.
-  void
-  build_stub_methods(Gogo*);
-
-  void
-  build_one_stub_method(Gogo*, Method*, const char* receiver_name,
-			const Typed_identifier_list*);
-
-  Expression*
-  apply_field_indexes(Expression*, const Method::Field_indexes*);
-
   // A pointer back to the Named_object for this type.
   Named_object* named_object_;
   // If this type is defined in a function, a pointer back to the
diff -r 5a0e1b402d81 go/unsafe.cc
--- a/go/unsafe.cc	Mon Feb 08 14:36:27 2010 -0800
+++ b/go/unsafe.cc	Fri Feb 12 23:56:51 2010 -0800
@@ -36,7 +36,6 @@
     {
       Type* type = Type::make_pointer_type(Type::make_void_type());
       no = bindings->add_type("Pointer", package, type, UNKNOWN_LOCATION);
-      no->set_package(package);
     }
   else
     {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]