diff mbox

[gccgo] Update gccgo to current type rules

Message ID mcreideg13r.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Aug. 31, 2010, 5:10 p.m. UTC
The Go rules for type assignability and convertibility were simplified a
couple of months ago.  This patch updates gccgo to use the new rules.
It also includes a few library changes to correspond to the new rules,
in that the address of an array may no longer be assigned to a slice.
Committed to gccgo branch.

Ian
diff mbox

Patch

diff -r b0b47113eebd go/expressions.cc
--- a/go/expressions.cc	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/expressions.cc	Tue Aug 31 10:02:07 2010 -0700
@@ -1356,7 +1356,7 @@ 
  public:
   Boolean_expression(bool val, source_location location)
     : Expression(EXPRESSION_BOOLEAN, location),
-      val_(val)
+      val_(val), type_(NULL)
   { }
 
   static Expression*
@@ -1368,12 +1368,10 @@ 
   { return true; }
 
   Type*
-  do_type()
-  { return Type::make_boolean_type(); }
+  do_type();
 
   void
-  do_determine_type(const Type_context*)
-  { }
+  do_determine_type(const Type_context*);
 
   Expression*
   do_copy()
@@ -1388,9 +1386,35 @@ 
   { exp->write_c_string(this->val_ ? "true" : "false"); }
 
  private:
+  // The constant.
   bool val_;
+  // The type as determined by context.
+  Type* type_;
 };
 
+// Get the type.
+
+Type*
+Boolean_expression::do_type()
+{
+  if (this->type_ == NULL)
+    this->type_ = Type::make_boolean_type();
+  return this->type_;
+}
+
+// Set the type from the context.
+
+void
+Boolean_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL && context->type->is_boolean_type())
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_bool_type();
+}
+
 // Import a boolean constant.
 
 Expression*
@@ -1418,12 +1442,27 @@ 
 
 // Class String_expression.
 
-// The type of a string expression.
+// Get the type.
 
 Type*
 String_expression::do_type()
 {
-  return Type::make_string_type();
+  if (this->type_ == NULL)
+    this->type_ = Type::make_string_type();
+  return this->type_;
+}
+
+// Set the type from the context.
+
+void
+String_expression::do_determine_type(const Type_context* context)
+{
+  if (this->type_ != NULL && !this->type_->is_abstract())
+    ;
+  else if (context->type != NULL && context->type->is_string_type())
+    this->type_ = context->type;
+  else if (!context->may_be_abstract)
+    this->type_ = Type::lookup_string_type();
 }
 
 // Build a string constant.
@@ -2502,20 +2541,32 @@ 
 Const_expression::do_determine_type(const Type_context* context)
 {
   Type* ctype = this->constant_->const_value()->type();
+  Type* cetype = (ctype != NULL
+		  ? ctype
+		  : this->constant_->const_value()->expr()->type());
   if (ctype != NULL && !ctype->is_abstract())
     ;
   else if (context->type != NULL
 	   && (context->type->integer_type() != NULL
 	       || context->type->float_type() != NULL
-	       || context->type->complex_type() != NULL))
+	       || context->type->complex_type() != NULL)
+	   && (cetype->integer_type() != NULL
+	       || cetype->float_type() != NULL
+	       || cetype->complex_type() != NULL))
+    this->type_ = context->type;
+  else if (context->type != NULL
+	   && context->type->is_string_type()
+	   && cetype->is_string_type())
+    this->type_ = context->type;
+  else if (context->type != NULL
+	   && context->type->is_boolean_type()
+	   && cetype->is_boolean_type())
     this->type_ = context->type;
   else if (!context->may_be_abstract)
     {
-      if (ctype == NULL)
-	ctype = this->constant_->const_value()->expr()->type();
-      if (ctype->is_abstract())
-	ctype = ctype->make_non_abstract_type();
-      this->type_ = ctype;
+      if (cetype->is_abstract())
+	cetype = cetype->make_non_abstract_type();
+      this->type_ = cetype;
     }
 }
 
@@ -3120,73 +3171,11 @@ 
   Type* expr_type = this->expr_->type();
   std::string reason;
 
-  if (Type::are_compatible_for_conversion(type, expr_type, &reason))
+  if (Type::are_convertible(type, expr_type, &reason))
     return;
 
-  bool ok = false;
-  if ((type->integer_type() != NULL || type->float_type() != NULL)
-      && (expr_type->integer_type() != NULL
-	  || expr_type->float_type() != NULL))
-    ok = true;
-  else if (type->complex_type() != NULL
-	   && expr_type->complex_type() != NULL)
-    ok = true;
-  else if (type->is_string_type())
-    {
-      if (expr_type->integer_type() != NULL)
-	ok = true;
-      else
-	{
-	  Type* t = expr_type->deref();
-	  if (t->array_type() != NULL)
-	    {
-	      Type* e = t->array_type()->element_type()->forwarded();
-	      if (e->integer_type() != NULL
-		  && (e == Type::lookup_integer_type("uint8")
-		      || e == Type::lookup_integer_type("int")))
-		ok = true;
-	    }
-	}
-    }
-  else if (type->is_open_array_type() && expr_type->is_string_type())
-    {
-      Type* e = type->array_type()->element_type()->forwarded();
-      if (e->integer_type() != NULL
-	  && (e == Type::lookup_integer_type("uint8")
-	      || e == Type::lookup_integer_type("int")))
-	ok = true;
-    }
-  else if ((type->is_unsafe_pointer_type()
-	    && (expr_type->points_to() != NULL
-		|| (expr_type->integer_type() != NULL
-		    && (expr_type->integer_type()->bits()
-			== static_cast<int>(POINTER_SIZE))
-		    && expr_type->integer_type()->is_unsigned())))
-	   || (expr_type->is_unsafe_pointer_type()
-	       && (type->points_to() != NULL
-		   || (type->integer_type() != NULL
-		       && (type->integer_type()->bits()
-			   == static_cast<int>(POINTER_SIZE))
-		       && type->integer_type()->is_unsigned()))))
-    {
-      // Conversions between unsafe pointers and other pointers or
-      // integers of appropriate size are permitted.
-      ok = true;
-    }
-
-  // FIXME: Conversions between interfaces and pointers are supported.
-
-  if (!ok)
-    {
-      if (reason.empty())
-	this->report_error(_("invalid type conversion"));
-      else
-	{
-	  error_at(this->location(), "invalid type conversion (%s)",
-		   reason.c_str());
-	  this->set_is_error();
-	}
-    }
+  error_at(this->location(), reason.c_str());
+  this->set_is_error();
 }
 
 // Get a tree for a type conversion.
@@ -6081,7 +6070,7 @@ 
 		     ? this->expr_type_
 		     : this->expr_->type());
       etype = etype->deref();
-      if (!Type::are_identical(rtype, etype))
+      if (!Type::are_identical(rtype, etype, NULL))
 	this->report_error(_("method type does not match object type"));
     }
 }
@@ -6703,7 +6692,7 @@ 
       bool ret = false;
       Type* itype;
       if (args->back()->float_constant_value(i, &itype)
-	  && Type::are_identical(rtype, itype))
+	  && Type::are_identical(rtype, itype, NULL))
 	{
 	  mpfr_set(real, r, GMP_RNDN);
 	  mpfr_set(imag, i, GMP_RNDN);
@@ -6865,6 +6854,10 @@ 
 		    want_type = Type::lookup_float_type("float64");
 		  else if (atype->complex_type() != NULL)
 		    want_type = Type::lookup_complex_type("complex128");
+		  else if (atype->is_abstract_string_type())
+		    want_type = Type::lookup_string_type();
+		  else if (atype->is_abstract_boolean_type())
+		    want_type = Type::lookup_bool_type();
 		  else
 		    gcc_unreachable();
 		  subcontext.type = want_type;
@@ -7062,7 +7055,7 @@ 
 	    break;
 	  }
 
-	if (!Type::are_identical(e1, e2))
+	if (!Type::are_identical(e1, e2, NULL))
 	  this->report_error(_("element types must be the same"));
       }
       break;
@@ -7089,7 +7082,7 @@ 
 		 || args->back()->type()->is_error_type())
 	  this->set_is_error();
 	else if (!Type::are_identical(args->front()->type(),
-				      args->back()->type()))
+				      args->back()->type(), NULL))
 	  this->report_error(_("arguments must have identical types"));
 	else if (args->front()->type()->float_type() == NULL)
 	  this->report_error(_("arguments must have floating-point type"));
@@ -7911,7 +7904,7 @@ 
       Array_type* param_at = param_type->array_type();
       if (param_at != NULL
 	  && Type::are_identical(var_at->element_type(),
-				 param_at->element_type()))
+				 param_at->element_type(), NULL))
 	return true;
       error_at(arg->location(), "... mismatch: passing ...T as ...");
       return false;
@@ -8036,7 +8029,7 @@ 
 				     source_location argument_location)
 {
   std::string reason;
-  if (!Type::are_compatible_for_assign(parameter_type, argument_type, &reason))
+  if (!Type::are_assignable(parameter_type, argument_type, &reason))
     {
       if (reason.empty())
 	error_at(argument_location, "argument %d has incompatible type", i);
@@ -8078,8 +8071,8 @@ 
 	  // When passing a value, we need to check that we are
 	  // permitted to copy it.
 	  std::string reason;
-	  if (!Type::are_compatible_for_assign(fntype->receiver()->type(),
-					       first_arg_type, &reason))
+	  if (!Type::are_assignable(fntype->receiver()->type(),
+				    first_arg_type, &reason))
 	    {
 	      if (reason.empty())
 		this->report_error("incompatible type for receiver");
@@ -9208,9 +9201,8 @@ 
 Map_index_expression::do_check_types(Gogo*)
 {
   std::string reason;
-  if (!Type::are_compatible_for_assign(this->get_map_type()->key_type(),
-				       this->index_->type(),
-				       &reason))
+  if (!Type::are_assignable(this->get_map_type()->key_type(),
+			    this->index_->type(), &reason))
     {
       if (reason.empty())
 	this->report_error(_("incompatible type for map index"));
@@ -10072,8 +10064,7 @@ 
 	continue;
 
       std::string reason;
-      if (!Type::are_compatible_for_assign(pf->type(), (*pv)->type(),
-					   &reason))
+      if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason))
 	{
 	  if (reason.empty())
 	    error_at((*pv)->location(),
@@ -10311,8 +10302,7 @@ 
        ++pv, ++i)
     {
       if (*pv != NULL
-	  && !Type::are_compatible_for_assign(element_type, (*pv)->type(),
-					      NULL))
+	  && !Type::are_assignable(element_type, (*pv)->type(), NULL))
 	{
 	  error_at((*pv)->location(),
 		   "incompatible type for element %d in composite literal",
@@ -10688,7 +10678,7 @@ 
        pv != this->vals_->end();
        ++pv, ++i)
     {
-      if (!Type::are_compatible_for_assign(key_type, (*pv)->type(), NULL))
+      if (!Type::are_assignable(key_type, (*pv)->type(), NULL))
 	{
 	  error_at((*pv)->location(),
 		   "incompatible type for element %d key in map construction",
@@ -10696,7 +10686,7 @@ 
 	  this->set_is_error();
 	}
       ++pv;
-      if (!Type::are_compatible_for_assign(val_type, (*pv)->type(), NULL))
+      if (!Type::are_assignable(val_type, (*pv)->type(), NULL))
 	{
 	  error_at((*pv)->location(),
 		   ("incompatible type for element %d value "
@@ -11583,8 +11573,7 @@ 
     }
   Type* element_type = channel_type->element_type();
   if (element_type != NULL
-      && !Type::are_compatible_for_assign(element_type, this->val_->type(),
-					  NULL))
+      && !Type::are_assignable(element_type, this->val_->type(), NULL))
     {
       this->report_error(_("incompatible types in send"));
       return;
diff -r b0b47113eebd go/expressions.h
--- a/go/expressions.h	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/expressions.h	Tue Aug 31 10:02:07 2010 -0700
@@ -958,7 +958,7 @@ 
  public:
   String_expression(const std::string& val, source_location location)
     : Expression(EXPRESSION_STRING, location),
-      val_(val)
+      val_(val), type_(NULL)
   { }
 
   const std::string&
@@ -984,8 +984,7 @@ 
   do_type();
 
   void
-  do_determine_type(const Type_context*)
-  { }
+  do_determine_type(const Type_context*);
 
   Expression*
   do_copy()
@@ -1000,6 +999,8 @@ 
  private:
   // The string value.  This is immutable.
   const std::string val_;
+  // The type as determined by context.
+  Type* type_;
 };
 
 // A binary expression.
diff -r b0b47113eebd go/gogo.cc
--- a/go/gogo.cc	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/gogo.cc	Tue Aug 31 10:02:07 2010 -0700
@@ -1402,8 +1402,7 @@ 
       Expression* init = var->init();
       std::string reason;
       if (init != NULL
-	  && !Type::are_compatible_for_assign(var->type(), init->type(),
-					      &reason))
+	  && !Type::are_assignable(var->type(), init->type(), &reason))
 	{
 	  if (reason.empty())
 	    error_at(var->location(), "incompatible type in initialization");
@@ -1438,8 +1437,8 @@ 
       error_at(constant->expr()->location(), "expression is not constant");
       constant->set_error();
     }
-  else if (!Type::are_compatible_for_assign(constant->type(),
-					    constant->expr()->type(), NULL))
+  else if (!Type::are_assignable(constant->type(), constant->expr()->type(),
+				 NULL))
     {
       error_at(constant->location(),
 	       "initialization expression has wrong type");
diff -r b0b47113eebd go/statements.cc
--- a/go/statements.cc	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/statements.cc	Tue Aug 31 10:02:07 2010 -0700
@@ -345,9 +345,7 @@ 
 Temporary_statement::do_check_types(Gogo*)
 {
   if (this->type_ != NULL && this->init_ != NULL)
-    gcc_assert(Type::are_compatible_for_assign(this->type_,
-					       this->init_->type(),
-					       NULL));
+    gcc_assert(Type::are_assignable(this->type_, this->init_->type(), NULL));
 }
 
 // Return a tree.
@@ -485,7 +483,7 @@ 
   Type* lhs_type = this->lhs_->type();
   Type* rhs_type = this->rhs_->type();
   std::string reason;
-  if (!Type::are_compatible_for_assign(lhs_type, rhs_type, &reason))
+  if (!Type::are_assignable(lhs_type, rhs_type, &reason))
     {
       if (reason.empty())
 	error_at(this->location(), "incompatible types in assignment");
@@ -2412,7 +2410,7 @@ 
       e->determine_type(&type_context);
 
       std::string reason;
-      if (Type::are_compatible_for_assign(rvtype, e->type(), &reason))
+      if (Type::are_assignable(rvtype, e->type(), &reason))
 	{
 	  Expression* ve = Expression::make_var_reference(rv, e->location());
 	  lhs->push_back(ve);
@@ -2503,7 +2501,7 @@ 
 	  return;
 	}
       std::string reason;
-      if (!Type::are_compatible_for_assign(pt->type(), (*pe)->type(), &reason))
+      if (!Type::are_assignable(pt->type(), (*pe)->type(), &reason))
 	{
 	  if (reason.empty())
 	    error_at(this->location(),
diff -r b0b47113eebd go/types.cc
--- a/go/types.cc	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/types.cc	Tue Aug 31 10:02:07 2010 -0700
@@ -172,6 +172,10 @@ 
       return this->float_type()->is_abstract();
     case TYPE_COMPLEX:
       return this->complex_type()->is_abstract();
+    case TYPE_STRING:
+      return this->is_abstract_string_type();
+    case TYPE_BOOLEAN:
+      return this->is_abstract_boolean_type();
     default:
       return false;
     }
@@ -191,6 +195,10 @@ 
       return Type::lookup_float_type("float");
     case TYPE_COMPLEX:
       return Type::lookup_complex_type("complex");
+    case TYPE_STRING:
+      return Type::lookup_string_type();
+    case TYPE_BOOLEAN:
+      return Type::lookup_bool_type();
     default:
       gcc_unreachable();
     }
@@ -291,13 +299,11 @@ 
   return TRAVERSE_CONTINUE;
 }
 
-// Return true if two types are compatible according to COMPATIBLE.
-// If REASON is not NULL, optionally set *REASON to the reason the
-// types are incompatible.
+// Return whether two types are identical.  If REASON is not NULL,
+// optionally set *REASON to the reason the types are not identical.
 
 bool
-Type::are_compatible_for(const Type* t1, const Type* t2,
-			 Type_compatible compatible, std::string* reason)
+Type::are_identical(const Type* t1, const Type* t2, std::string* reason)
 {
   if (t1 == NULL || t2 == NULL)
     {
@@ -323,8 +329,7 @@ 
     return true;
 
   // Get a good reason for the sink type.  Note that the sink type on
-  // the left hand side of an assignment is handled in
-  // are_compatible_for_assign.
+  // the left hand side of an assignment is handled in are_assignable.
   if (t1->is_sink_type() || t2->is_sink_type())
     {
       if (reason != NULL)
@@ -332,76 +337,78 @@ 
       return false;
     }
 
-  // Cut off infinite recursion by using a flag on a named type.
-  const Named_type* nt1 = t1->named_type();
-  if (nt1 != NULL)
-    return nt1->is_compatible(t2, compatible, reason);
-
-  const Type* t1base = t1->base();
-  const Type* t2base = t2->base();
-
-  if (t1base->classification_ != t2base->classification_)
+  // A named type is only identical to itself.
+  if (t1->named_type() != NULL || t2->named_type() != NULL)
     return false;
 
-  switch (t1base->classification_)
+  // Check type shapes.
+  if (t1->classification() != t2->classification())
+    return false;
+
+  switch (t1->classification())
     {
     case TYPE_VOID:
     case TYPE_BOOLEAN:
     case TYPE_STRING:
     case TYPE_NIL:
-      // These types are always compatible with themselves.
+      // These types are always identical.
       return true;
 
     case TYPE_INTEGER:
-      return t1base->integer_type()->is_compatible(t2base->integer_type());
+      return t1->integer_type()->is_identical(t2->integer_type());
 
     case TYPE_FLOAT:
-      return t1base->float_type()->is_compatible(t2base->float_type());
+      return t1->float_type()->is_identical(t2->float_type());
 
     case TYPE_COMPLEX:
-      return t1base->complex_type()->is_compatible(t2base->complex_type());
+      return t1->complex_type()->is_identical(t2->complex_type());
 
     case TYPE_FUNCTION:
-      return t1base->function_type()->is_compatible(t2base->function_type(),
-						    compatible,
-						    false,
-						    reason);
+      return t1->function_type()->is_identical(t2->function_type(),
+					       false,
+					       reason);
 
     case TYPE_POINTER:
-      return Type::are_compatible_for(t1base->points_to(), t2base->points_to(),
-				      compatible, reason);
+      return Type::are_identical(t1->points_to(), t2->points_to(), reason);
 
     case TYPE_STRUCT:
-      return t1base->struct_type()->is_compatible(t2base->struct_type(),
-						  compatible);
+      return t1->struct_type()->is_identical(t2->struct_type());
 
     case TYPE_ARRAY:
-      return t1base->array_type()->is_compatible(t2base->array_type(),
-						 compatible);
+      return t1->array_type()->is_identical(t2->array_type());
 
     case TYPE_MAP:
-      return t1base->map_type()->is_compatible(t2base->map_type(),
-					       compatible);
+      return t1->map_type()->is_identical(t2->map_type());
 
     case TYPE_CHANNEL:
-      return t1base->channel_type()->is_compatible(t2base->channel_type(),
-						   compatible);
+      return t1->channel_type()->is_identical(t2->channel_type());
 
     case TYPE_INTERFACE:
-      return t1base->interface_type()->is_compatible(t2base->interface_type(),
-						     compatible);
+      return t1->interface_type()->is_identical(t2->interface_type());
 
     default:
       gcc_unreachable();
     }
 }
 
-// Return true if it's OK to have a binary operation with types LHS and RHS.
+// Return true if it's OK to have a binary operation with types LHS
+// and RHS.  This is not used for shifts.
 
 bool
 Type::are_compatible_for_binop(const Type* lhs, const Type* rhs)
 {
-  if (Type::are_compatible(lhs, rhs))
+  if (Type::are_identical(lhs, rhs, NULL))
+    return true;
+
+  // A constant of abstract bool type may be mixed with any bool type.
+  if ((rhs->is_abstract_boolean_type() && lhs->is_boolean_type())
+      || (lhs->is_abstract_boolean_type() && rhs->is_boolean_type()))
+    return true;
+
+  // A constant of abstract string type may be mixed with any string
+  // type.
+  if ((rhs->is_abstract_string_type() && lhs->is_string_type())
+      || (lhs->is_abstract_string_type() && rhs->is_string_type()))
     return true;
 
   lhs = lhs->base();
@@ -410,10 +417,16 @@ 
   // A constant of abstract integer, float, or complex type may be
   // mixed with an integer, float, or complex type.
   if ((rhs->is_abstract()
+       && (rhs->integer_type() != NULL
+	   || rhs->float_type() != NULL
+	   || rhs->complex_type() != NULL)
        && (lhs->integer_type() != NULL
 	   || lhs->float_type() != NULL
 	   || lhs->complex_type() != NULL))
       || (lhs->is_abstract()
+	  && (lhs->integer_type() != NULL
+	      || lhs->float_type() != NULL
+	      || lhs->complex_type() != NULL)
 	  && (rhs->integer_type() != NULL
 	      || rhs->float_type() != NULL
 	      || rhs->complex_type() != NULL)))
@@ -441,23 +454,22 @@ 
   return false;
 }
 
-
-// Return true if a value with type RHS may be assigned to a value
-// with type LHS.  IS_CONVERSION is true to check for conversion
-// compatibility rather than assignment compatibility.
+// Return true if a value with type RHS may be assigned to a variable
+// with type LHS.  If REASON is not NULL, set *REASON to the reason
+// the types are not assignable.
 
 bool
-Type::are_assignment_compatible(const Type* lhs, const Type* rhs,
-				bool is_conversion, std::string* reason)
-{
-  // Any value may be assigned to the blank identifier.  Make sure
-  // that types are reasonable before calling base().
+Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
+{
+  // Do some checks first.  Make sure the types are defined.
   if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL)
     {
-      if (!is_conversion && lhs->is_sink_type())
+      // Any value may be assigned to the blank identifier.
+      if (lhs->is_sink_type())
 	return true;
 
-      // Check for hidden fields before checking for compatibility.
+      // All fields of a struct must be exported, or the assignment
+      // must be in the same package.
       if (rhs != NULL && rhs->forwarded()->forward_declaration_type() == NULL)
 	{
 	  if (lhs->has_hidden_fields(NULL, reason)
@@ -466,89 +478,63 @@ 
 	}
     }
 
-  if (Type::are_compatible_for(lhs, rhs,
-			       (is_conversion
-				? COMPATIBLE_FOR_CONVERSION
-				: COMPATIBLE_COMPATIBLE),
-			       reason))
+  // Identical types are assignable.
+  if (Type::are_identical(lhs, rhs, reason))
     return true;
 
-  const Type* orig_lhs = lhs;
-  lhs = lhs->base();
-  const Type* orig_rhs = rhs;
-  rhs = rhs->base();
-
-  // Any type may be assigned to an interface type if it implements
-  // the required methods.  Note that we must pass ORIG_RHS here, not
-  // RHS, since the methods will be attached to ORIG_RHS.
-  if (lhs->interface_type() != NULL
-      && lhs->interface_type()->implements_interface(orig_rhs, reason))
+  // The types are assignable if they have identical underlying types
+  // and either LHS or RHS is not a named type.
+  if (((lhs->named_type() != NULL && rhs->named_type() == NULL)
+       || (rhs->named_type() != NULL && lhs->named_type() == NULL))
+      && Type::are_identical(lhs->base(), rhs->base(), reason))
     return true;
 
-  // Interface assignment is permitted if RHS is known to implement
-  // all the methods in LHS.
-  if (lhs->interface_type() != NULL
-      && rhs->interface_type() != NULL
-      && lhs->interface_type()->is_compatible_for_assign(rhs->interface_type(),
-							 reason))
-    return true;
-
-  // Other than the cases checked above, two different named types may
-  // be compatible for conversion, but are never compatible for
-  // assignment.
-  if (!is_conversion
-      && orig_lhs->named_type() != NULL
-      && orig_rhs->named_type() != NULL)
-    return false;
-
-  // The compatibility level to check for when checking subtypes.
-  Type_compatible pass = (is_conversion
-			  ? COMPATIBLE_FOR_CONVERSION
-			  : COMPATIBLE_COMPATIBLE);
-
-  // A pointer to an array may be assigned to a slice of the
-  // same element type.
-  if (lhs->is_open_array_type()
-      && rhs->points_to() != NULL
-      && rhs->points_to()->array_type() != NULL
-      && !rhs->is_open_array_type())
-    {
-      Type* e1 = lhs->array_type()->element_type();
-      Type* e2 = rhs->points_to()->array_type()->element_type();
-      if (Type::are_compatible_for(e1, e2, pass, reason))
+  // The types are assignable if LHS is an interface type and RHS
+  // implements the required methods.
+  const Interface_type* lhs_interface_type = lhs->interface_type();
+  if (lhs_interface_type != NULL)
+    {
+      if (lhs_interface_type->implements_interface(rhs, reason))
 	return true;
-    }
-
-  // We can assign a bidirectional channel to a uni-directional
-  // channel.
+      const Interface_type* rhs_interface_type = rhs->interface_type();
+      if (rhs_interface_type != NULL
+	  && lhs_interface_type->is_compatible_for_assign(rhs_interface_type,
+							  reason))
+	return true;
+    }
+
+  // The type are assignable if RHS is a bidirectional channel type,
+  // LHS is a channel type, they have identical element types, and
+  // either LHS or RHS is not a named type.
   if (lhs->channel_type() != NULL
       && rhs->channel_type() != NULL
       && rhs->channel_type()->may_send()
       && rhs->channel_type()->may_receive()
-      && Type::are_compatible_for(lhs->channel_type()->element_type(),
-				  rhs->channel_type()->element_type(),
-				  pass, reason))
+      && (lhs->named_type() == NULL || rhs->named_type() == NULL)
+      && Type::are_identical(lhs->channel_type()->element_type(),
+			     rhs->channel_type()->element_type(),
+			     reason))
     return true;
 
-  // A constant of abstract integer or float type may be assigned to
-  // integer, float, or complex type.
+  // The nil type may be assigned to a pointer, function, slice, map,
+  // channel, or interface type.
+  if (rhs->is_nil_type()
+      && (lhs->points_to() != NULL
+	  || lhs->function_type() != NULL
+	  || lhs->is_open_array_type()
+	  || lhs->map_type() != NULL
+	  || lhs->channel_type() != NULL
+	  || lhs->interface_type() != NULL))
+    return true;
+
+  // An untyped constant may be assigned to a numeric type if it is
+  // representable in that type.
   if (rhs->is_abstract()
       && (lhs->integer_type() != NULL
 	  || lhs->float_type() != NULL
 	  || lhs->complex_type() != NULL))
     return true;
 
-  // The nil type may be assigned to a pointer type, an interface
-  // type, a slice type, a map type, a channel type, or a function
-  // type.
-  if (rhs->is_nil_type()
-      && (lhs->points_to() != NULL
-	  || lhs->interface_type() != NULL
-	  || lhs->is_open_array_type()
-	  || lhs->map_type() != NULL
-	  || lhs->channel_type() != NULL
-	  || lhs->function_type() != NULL))
-    return true;
 
   // Give some better error messages.
   if (reason != NULL && reason->empty())
@@ -558,6 +544,112 @@ 
       else if (rhs->is_call_multiple_result_type())
 	reason->assign(_("multiple value function call in "
 			 "single value context"));
+      else if (lhs->named_type() != NULL && rhs->named_type() != NULL)
+	{
+	  size_t len = (lhs->named_type()->name().length()
+			+ rhs->named_type()->name().length()
+			+ 100);
+	  char* buf = new char[len];
+	  snprintf(buf, len, _("cannot use type %s as type %s"),
+		   rhs->named_type()->message_name().c_str(),
+		   lhs->named_type()->message_name().c_str());
+	  reason->assign(buf);
+	  delete[] buf;
+	}
+    }
+
+  return false;
+}
+
+// Return true if a value with type RHS may be converted to type LHS.
+// If REASON is not NULL, set *REASON to the reason the types are not
+// convertible.
+
+bool
+Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason)
+{
+  // The types are convertible if they are assignable.
+  if (Type::are_assignable(lhs, rhs, reason))
+    return true;
+
+  // The types are convertible if they have identical underlying
+  // types.
+  if ((lhs->named_type() != NULL || rhs->named_type() != NULL)
+      && Type::are_identical(lhs->base(), rhs->base(), reason))
+    return true;
+
+  // The types are convertible if they are both unnamed pointer types
+  // and their pointer base types have identical underlying types.
+  if (lhs->named_type() == NULL
+      && rhs->named_type() == NULL
+      && lhs->points_to() != NULL
+      && rhs->points_to() != NULL
+      && (lhs->points_to()->named_type() != NULL
+	  || rhs->points_to()->named_type() != NULL)
+      && Type::are_identical(lhs->points_to()->base(),
+			     rhs->points_to()->base(),
+			     reason))
+    return true;
+
+  // Integer and floating point types are convertible to each other.
+  if ((lhs->integer_type() != NULL || lhs->float_type() != NULL)
+      && (rhs->integer_type() != NULL || rhs->float_type() != NULL))
+    return true;
+
+  // Complex types are convertible to each other.
+  if (lhs->complex_type() != NULL && rhs->complex_type() != NULL)
+    return true;
+
+  // An integer, or []byte, or []int, may be converted to a string.
+  if (lhs->is_string_type())
+    {
+      if (rhs->integer_type() != NULL)
+	return true;
+      if (rhs->is_open_array_type())
+	{
+	  const Type* e = rhs->array_type()->element_type()->forwarded();
+	  if (e->integer_type() != NULL
+	      && (e == Type::lookup_integer_type("uint8")
+		  || e == Type::lookup_integer_type("int")))
+	    return true;
+	}
+    }
+
+  // A string may be converted to []byte or []int.
+  if (rhs->is_string_type() && lhs->is_open_array_type())
+    {
+      const Type* e = lhs->array_type()->element_type()->forwarded();
+      if (e->integer_type() != NULL
+	  && (e == Type::lookup_integer_type("uint8")
+	      || e == Type::lookup_integer_type("int")))
+	return true;
+    }
+
+  // An unsafe.Pointer type may be converted to any pointer type or to
+  // uintptr, and vice-versa.
+  if (lhs->is_unsafe_pointer_type()
+      && (rhs->points_to() != NULL
+	  || (rhs->integer_type() != NULL
+	      && rhs->forwarded() == Type::lookup_integer_type("uintptr"))))
+    return true;
+  if (rhs->is_unsafe_pointer_type()
+      && (lhs->points_to() != NULL
+	  || (lhs->integer_type() != NULL
+	      && lhs->forwarded() == Type::lookup_integer_type("uintptr"))))
+    return true;
+
+  // Give a better error message.
+  if (reason != NULL)
+    {
+      if (reason->empty())
+	*reason = "invalid type conversion";
+      else
+	{
+	  std::string s = "invalid type conversion (";
+	  s += *reason;
+	  s += ')';
+	  *reason = s;
+	}
     }
 
   return false;
@@ -1016,7 +1108,7 @@ 
 // Integer type compatibility.
 
 bool
-Integer_type::is_compatible(const Integer_type* t) const
+Integer_type::is_identical(const Integer_type* t) const
 {
   if (this->is_unsigned_ != t->is_unsigned_ || this->bits_ != t->bits_)
     return false;
@@ -1179,10 +1271,10 @@ 
   return abstract_type;
 }
 
-// Whether this type is compatible with T.
+// Whether this type is identical with T.
 
 bool
-Float_type::is_compatible(const Float_type* t) const
+Float_type::is_identical(const Float_type* t) const
 {
   if (this->bits_ != t->bits_)
     return false;
@@ -1337,10 +1429,10 @@ 
   return abstract_type;
 }
 
-// Whether this type is compatible with T.
+// Whether this type is identical with T.
 
 bool
-Complex_type::is_compatible(const Complex_type *t) const
+Complex_type::is_identical(const Complex_type *t) const
 {
   if (this->bits_ != t->bits_)
     return false;
@@ -1657,7 +1749,7 @@ 
 Function_type::is_valid_redeclaration(const Function_type* t,
 				      std::string* reason) const
 {
-  if (!this->is_compatible(t, COMPATIBLE_IDENTICAL, false, reason))
+  if (!this->is_identical(t, false, reason))
     return false;
 
   // A redeclaration of a function is required to use the same names
@@ -1691,8 +1783,7 @@ 
 	    }
 
 	  // This is called at parse time, so we may have unknown
-	  // types.  They will appear compatible according to
-	  // Type::is_compatible.
+	  // types.
 	  Type* t1 = p1->type()->forwarded();
 	  Type* t2 = p2->type()->forwarded();
 	  if (t1 != t2
@@ -1723,8 +1814,7 @@ 
 	    }
 
 	  // This is called at parse time, so we may have unknown
-	  // types.  They will appear compatible according to
-	  // Type::is_compatible.
+	  // types.
 	  Type* t1 = res1->type()->forwarded();
 	  Type* t2 = res2->type()->forwarded();
 	  if (t1 != t2
@@ -1742,10 +1832,8 @@ 
 // Check whether T is the same as this type.
 
 bool
-Function_type::is_compatible(const Function_type* t,
-			     Type_compatible compatible,
-			     bool ignore_receiver,
-			     std::string* reason) const
+Function_type::is_identical(const Function_type* t, bool ignore_receiver,
+			    std::string* reason) const
 {
   if (!ignore_receiver)
     {
@@ -1759,8 +1847,7 @@ 
 	}
       if (r1 != NULL)
 	{
-	  if (!Type::are_compatible_for(r1->type(), r2->type(), compatible,
-					reason))
+	  if (!Type::are_identical(r1->type(), r2->type(), reason))
 	    {
 	      if (reason != NULL && !reason->empty())
 		*reason = "receiver: " + *reason;
@@ -1791,8 +1878,7 @@ 
 	      return false;
 	    }
 
-	  if (!Type::are_compatible_for(p1->type(), p2->type(), compatible,
-					NULL))
+	  if (!Type::are_identical(p1->type(), p2->type(), NULL))
 	    {
 	      if (reason != NULL)
 		*reason = _("different parameter types");
@@ -1836,8 +1922,7 @@ 
 	      return false;
 	    }
 
-	  if (!Type::are_compatible_for(res1->type(), res2->type(), compatible,
-					NULL))
+	  if (!Type::are_identical(res1->type(), res2->type(), NULL))
 	    {
 	      if (reason != NULL)
 		*reason = _("different result types");
@@ -2643,11 +2728,10 @@ 
   return false;
 }
 
-// Whether this type is compatible with T.
+// Whether this type is identical to T.
 
 bool
-Struct_type::is_compatible(const Struct_type* t,
-			   Type_compatible compatible) const
+Struct_type::is_identical(const Struct_type* t) const
 {
   const Struct_field_list* fields1 = this->fields();
   const Struct_field_list* fields2 = t->fields();
@@ -2660,27 +2744,22 @@ 
     {
       if (pf2 == fields2->end())
 	return false;
-      if (compatible == COMPATIBLE_IDENTICAL
-	  && pf1->field_name() != pf2->field_name())
+      if (pf1->field_name() != pf2->field_name())
 	return false;
       if (pf1->is_anonymous() != pf2->is_anonymous()
-	  || !Type::are_compatible_for(pf1->type(), pf2->type(), compatible,
-				       NULL))
+	  || !Type::are_identical(pf1->type(), pf2->type(), NULL))
 	return false;
-      if (compatible == COMPATIBLE_IDENTICAL)
+      if (!pf1->has_tag())
 	{
-	  if (!pf1->has_tag())
-	    {
-	      if (pf2->has_tag())
-		return false;
-	    }
-	  else
-	    {
-	      if (!pf2->has_tag())
-		return false;
-	      if (pf1->tag() != pf2->tag())
-		return false;
-	    }
+	  if (pf2->has_tag())
+	    return false;
+	}
+      else
+	{
+	  if (!pf2->has_tag())
+	    return false;
+	  if (pf1->tag() != pf2->tag())
+	    return false;
 	}
     }
   if (pf2 != fields2->end())
@@ -3225,25 +3304,23 @@ 
 
 Array_type::Array_trees Array_type::array_trees;
 
-// Whether two array types are compatible.
+// Whether two array types are identical.
 
 bool
-Array_type::is_compatible(const Array_type* t,
-			  Type_compatible compatible) const
-{
-  if (!Type::are_compatible_for(this->element_type(), t->element_type(),
-				compatible, NULL))
+Array_type::is_identical(const Array_type* t) const
+{
+  if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
     return false;
 
   Expression* l1 = this->length();
   Expression* l2 = t->length();
 
-  // Open arrays of the same element type are identical.
+  // Slices of the same element type are identical.
   if (l1 == NULL && l2 == NULL)
     return true;
 
-  // Fixed arrays of the same element type are identical if they have
-  // the same length.
+  // Arrays of the same element type are identical if they have the
+  // same length.
   if (l1 != NULL && l2 != NULL)
     {
       if (l1 == l2)
@@ -3793,15 +3870,13 @@ 
   return true;
 }
 
-// Whether two map types are compatible.
+// Whether two map types are identical.
 
 bool
-Map_type::is_compatible(const Map_type* t, Type_compatible compatible) const
-{
-  return (Type::are_compatible_for(this->key_type(), t->key_type(),
-				   compatible, NULL)
-	  && Type::are_compatible_for(this->val_type(), t->val_type(),
-				      compatible, NULL));
+Map_type::is_identical(const Map_type* t) const
+{
+  return (Type::are_identical(this->key_type(), t->key_type(), NULL)
+	  && Type::are_identical(this->val_type(), t->val_type(), NULL));
 }
 
 // Hash code.
@@ -4016,11 +4091,9 @@ 
 // Whether this type is the same as T.
 
 bool
-Channel_type::is_compatible(const Channel_type* t,
-			    Type_compatible compatible) const
-{
-  if (!Type::are_compatible_for(this->element_type(), t->element_type(),
-				compatible, NULL))
+Channel_type::is_identical(const Channel_type* t) const
+{
+  if (!Type::are_identical(this->element_type(), t->element_type(), NULL))
     return false;
   return (this->may_send_ == t->may_send_
 	  && this->may_receive_ == t->may_receive_);
@@ -4334,11 +4407,10 @@ 
   return false;
 }
 
-// Whether this type is compatible with T.
+// Whether this type is identical with T.
 
 bool
-Interface_type::is_compatible(const Interface_type* t,
-			      Type_compatible compatible) const
+Interface_type::is_identical(const Interface_type* t) const
 {
   // We require the same methods with the same types.  The methods
   // have already been sorted.
@@ -4353,8 +4425,7 @@ 
       if (p1 == this->methods()->end())
 	return false;
       if (p1->name() != p2->name()
-	  || !Type::are_compatible_for(p1->type(), p2->type(), compatible,
-				       NULL))
+	  || !Type::are_identical(p1->type(), p2->type(), NULL))
 	return false;
     }
   if (p1 != this->methods()->end())
@@ -4363,7 +4434,7 @@ 
 }
 
 // Whether we can assign the interface type T to this type.  The types
-// are known to not be compatible.  An interface assignment is only
+// are known to not be identical.  An interface assignment is only
 // permitted if T is known to implement all methods in THIS.
 // Otherwise a type guard is required.
 
@@ -4394,8 +4465,7 @@ 
 	}
 
       std::string subreason;
-      if (!Type::are_compatible_for(p->type(), m->type(), COMPATIBLE_COMPATIBLE,
-				    &subreason))
+      if (!Type::are_identical(p->type(), m->type(), &subreason))
 	{
 	  if (reason != NULL)
 	    {
@@ -4522,8 +4592,7 @@ 
       Function_type* m_fn_type = m->type()->function_type();
       gcc_assert(p_fn_type != NULL && m_fn_type != NULL);
       std::string subreason;
-      if (!p_fn_type->is_compatible(m_fn_type, COMPATIBLE_COMPATIBLE, true,
-				    &subreason))
+      if (!p_fn_type->is_identical(m_fn_type, true, &subreason))
 	{
 	  if (reason != NULL)
 	    {
@@ -5255,44 +5324,6 @@ 
   return build_fold_addr_expr(decl);
 }
 
-// Whether this type is compatible with T.
-
-bool
-Named_type::is_compatible(const Type* t, Type_compatible compatible,
-			  std::string* reason) const
-{
-  if (compatible == COMPATIBLE_IDENTICAL)
-    return this == t;
-
-  // In general, different named types are not compatible other than
-  // for type conversion.  An exception is assigning to an variable
-  // with interface type.
-  if (t->named_type() != NULL && compatible != COMPATIBLE_FOR_CONVERSION)
-    {
-      if (reason != NULL)
-	{
-	  size_t len = (this->name().length()
-			+ t->named_type()->name().length()
-			+ 100);
-	  char* buf = new char[len];
-	  snprintf(buf, len, _("cannot use type %s as type %s"),
-		   t->named_type()->message_name().c_str(),
-		   this->message_name().c_str());
-	  reason->assign(buf);
-	  delete[] buf;
-	}
-      return false;
-    }
-
-  // We use the seen_ flag to cut off recursion.
-  if (this->seen_)
-    return this->type_->base() == t->base();
-  this->seen_ = true;
-  bool ret = Type::are_compatible_for(this->type_, t, compatible, reason);
-  this->seen_ = false;
-  return ret;
-}
-
 // Return whether a named type has any hidden fields.
 
 bool
diff -r b0b47113eebd go/types.h
--- a/go/types.h	Fri Aug 27 19:29:10 2010 -0700
+++ b/go/types.h	Tue Aug 31 10:02:07 2010 -0700
@@ -495,40 +495,27 @@ 
   verify()
   { return this->do_verify(); }
 
+  // Return true if two types are identical.  If this returns false,
+  // and REASON is not NULL, it may set *REASON.
+  static bool
+  are_identical(const Type* lhs, const Type* rhs, std::string* reason);
+
   // Return true if two types are compatible for use in a binary
   // operation.  This is an equivalence relation.
   static bool
   are_compatible_for_binop(const Type* t1, const Type* t2);
 
-  // Return true if a value with type RHS may be assigned to a value
-  // with type LHS.  This also controls whether a value with type RHS
-  // may be passed to a function which expects type LHS, and whether a
-  // value with type RHS may be returned from a function which returns
-  // type LHS.  This is not an equivalence relation.  If this returns
-  // false, and REASON is not NULL, it sets *REASON to an optional
-  // reason.
+  // Return true if a value with type RHS is assignable to a variable
+  // with type LHS.  This is not an equivalence relation.  If this
+  // returns false, and REASON is not NULL, it sets *REASON.
   static bool
-  are_compatible_for_assign(const Type* lhs, const Type* rhs,
-			    std::string* reason)
-  { return Type::are_assignment_compatible(lhs, rhs, false, reason); }
-
-  // Return true if a value with type RHS may be converted to a
-  // valuewith type LHS.  If this returns false, and REASON is not
-  // NULL, it sets *REASON to an optional reason.
+  are_assignable(const Type* lhs, const Type* rhs, std::string* reason);
+
+  // Return true if a value with type RHS may be converted to type
+  // LHS.  If this returns false, and REASON is not NULL, it sets
+  // *REASON.
   static bool
-  are_compatible_for_conversion(const Type* lhs, const Type* rhs,
-				std::string* reason)
-  { return Type::are_assignment_compatible(lhs, rhs, true, reason); }
-
-  // Return true if two types are compatible.
-  static bool
-  are_compatible(const Type* lhs, const Type* rhs)
-  { return Type::are_compatible_for(lhs, rhs, COMPATIBLE_COMPATIBLE, NULL); }
-
-  // Return true if two types are identical.
-  static bool
-  are_identical(const Type* lhs, const Type* rhs)
-  { return Type::are_compatible_for(lhs, rhs, COMPATIBLE_IDENTICAL, NULL); }
+  are_convertible(const Type* lhs, const Type* rhs, std::string* reason);
 
   // Whether this type has any hidden fields which are not visible in
   // the current compilation, such as a field whose name begins with a
@@ -538,8 +525,8 @@ 
   has_hidden_fields(const Named_type* within, std::string* reason) const;
 
   // Return a hash code for this type for the method hash table.
-  // Types which are equivalent according to are_compatible_for_method
-  // will have the same hash code.
+  // Types which are equivalent according to are_identical will have
+  // the same hash code.
   unsigned int
   hash_for_method(Gogo*) const;
 
@@ -635,11 +622,21 @@ 
   is_boolean_type() const
   { return this->base()->classification_ == TYPE_BOOLEAN; }
 
+  // Return true if this is an abstract boolean type.
+  bool
+  is_abstract_boolean_type() const
+  { return this->classification_ == TYPE_BOOLEAN; }
+
   // Return true if this is a string type.
   bool
   is_string_type() const
   { return this->base()->classification_ == TYPE_STRING; }
 
+  // Return true if this is an abstract string type.
+  bool
+  is_abstract_string_type() const
+  { return this->classification_ == TYPE_STRING; }
+
   // Return true if this is the sink type.  This is the type of the
   // blank identifier _.
   bool
@@ -818,8 +815,8 @@ 
   reflection(Gogo*) const;
 
   // Return a mangled name for the type.  This is a name which can be
-  // used in assembler code.  Types which compare as equal according
-  // to COMPATIBLE_SAME should have the same manged name.
+  // used in assembler code.  Identical types should have the same
+  // manged name.
   std::string
   mangled_name(Gogo*) const;
 
@@ -835,27 +832,6 @@ 
  protected:
   Type(Type_classification);
 
-  // Different sorts of type compatibility.
-  enum Type_compatible
-  {
-    // Identical types.
-    COMPATIBLE_IDENTICAL,
-    // Compatible types.
-    COMPATIBLE_COMPATIBLE,
-    // Compatible for conversion.
-    COMPATIBLE_FOR_CONVERSION
-  };
-
-  // Return whether types are compatible.
-  static bool
-  are_compatible_for(const Type*, const Type*, Type_compatible,
-		     std::string* reason);
-
-  // Return whether types are assignment compatible.
-  static bool
-  are_assignment_compatible(const Type*, const Type*, bool is_conversion,
-			    std::string* reason);
-
   // Functions implemented by the child class.
 
   // Traverse the subtypes.
@@ -1058,7 +1034,7 @@ 
  public:
   bool
   operator()(const Type* t1, const Type* t2) const
-  { return Type::are_identical(t1, t2); }
+  { return Type::are_identical(t1, t2, NULL); }
 };
 
 // An identifier with a type.
@@ -1246,7 +1222,7 @@ 
 
   // Whether this type is the same as T.
   bool
-  is_compatible(const Integer_type* t) const;
+  is_identical(const Integer_type* t) const;
 
  protected:
   unsigned int
@@ -1318,7 +1294,7 @@ 
 
   // Whether this type is the same as T.
   bool
-  is_compatible(const Float_type* t) const;
+  is_identical(const Float_type* t) const;
 
   // Return a tree for this type without using a Gogo*.
   tree
@@ -1390,7 +1366,7 @@ 
 
   // Whether this type is the same as T.
   bool
-  is_compatible(const Complex_type* t) const;
+  is_identical(const Complex_type* t) const;
 
   // Return a tree for this type without using a Gogo*.
   tree
@@ -1530,8 +1506,8 @@ 
 
   // Whether this type is the same as T.
   bool
-  is_compatible(const Function_type* t, Type_compatible,
-		bool ignore_receiver, std::string*) const;
+  is_identical(const Function_type* t, bool ignore_receiver,
+	       std::string*) const;
 
   // Record that this is a varargs function.
   void
@@ -1826,9 +1802,9 @@ 
   unsigned int
   total_field_count() const;
 
-  // Whether this type is compatible with T.
+  // Whether this type is identical with T.
   bool
-  is_compatible(const Struct_type* t, Type_compatible) const;
+  is_identical(const Struct_type* t) const;
 
   // Whether this struct type has any hidden fields.  This returns
   // true if any fields have hidden names, or if any non-pointer
@@ -1938,9 +1914,9 @@ 
   length() const
   { return this->length_; }
 
-  // Whether this type is compatible with T.
+  // Whether this type is identical with T.
   bool
-  is_compatible(const Array_type* t, Type_compatible) const;
+  is_identical(const Array_type* t) const;
 
   // Whether this type has any hidden fields.
   bool
@@ -2040,9 +2016,9 @@ 
   val_type() const
   { return this->val_type_; }
 
-  // Whether this type is compatible with T.
+  // Whether this type is identical with T.
   bool
-  is_compatible(const Map_type* t, Type_compatible) const;
+  is_identical(const Map_type* t) const;
 
   // Import a map type.
   static Map_type*
@@ -2123,9 +2099,9 @@ 
   element_type() const
   { return this->element_type_; }
 
-  // Whether this type is compatible with T.
+  // Whether this type is identical with T.
   bool
-  is_compatible(const Channel_type* t, Type_compatible) const;
+  is_identical(const Channel_type* t) const;
 
   // Import a channel type.
   static Channel_type*
@@ -2222,12 +2198,12 @@ 
   bool
   implements_interface(const Type* t, std::string* reason) const;
 
-  // Whether this type is compatible with T.  REASON is as in
+  // Whether this type is identical with T.  REASON is as in
   // implements_interface.
   bool
-  is_compatible(const Interface_type* t, Type_compatible) const;
-
-  // Whether we can assign T to this type.  is_compatible is known to
+  is_identical(const Interface_type* t) const;
+
+  // Whether we can assign T to this type.  is_identical is known to
   // be false.
   bool
   is_compatible_for_assign(const Interface_type*, std::string* reason) const;
@@ -2424,10 +2400,6 @@ 
   interface_method_table(Gogo*, const Interface_type* interface,
 			 bool is_pointer);
 
-  // Whether this type is compatible with T.
-  bool
-  is_compatible(const Type* t, Type_compatible, std::string* reason) const;
-
   // Whether this type has any hidden fields.
   bool
   named_type_has_hidden_fields(std::string* reason) const;
@@ -2518,10 +2490,10 @@ 
   bool is_visible_;
   // Whether this type is erroneous.
   bool is_error_;
-  // In a recursive operation such as is_compatible, this flag is used
-  // to prevent infinite recursion when a type refers to itself.  This
-  // is mutable because it is always reset to false when the function
-  // exits.
+  // In a recursive operation such as has_hidden_fields, this flag is
+  // used to prevent infinite recursion when a type refers to itself.
+  // This is mutable because it is always reset to false when the
+  // function exits.
   mutable bool seen_;
 };
 
diff -r b0b47113eebd libgo/go/debug/proc/regs_linux_amd64.go
--- a/libgo/go/debug/proc/regs_linux_amd64.go	Fri Aug 27 19:29:10 2010 -0700
+++ b/libgo/go/debug/proc/regs_linux_amd64.go	Tue Aug 31 10:02:07 2010 -0700
@@ -71,7 +71,7 @@ 
 	return r.setter(&r.PtraceRegs)
 }
 
-func (r *amd64Regs) Names() []string { return &names }
+func (r *amd64Regs) Names() []string { return names[0:] }
 
 func (r *amd64Regs) Get(i int) Word {
 	switch i {
diff -r b0b47113eebd libgo/go/exp/eval/eval_test.go
--- a/libgo/go/exp/eval/eval_test.go	Fri Aug 27 19:29:10 2010 -0700
+++ b/libgo/go/exp/eval/eval_test.go	Tue Aug 31 10:02:07 2010 -0700
@@ -205,7 +205,7 @@ 
 
 type testFunc struct{}
 
-func (*testFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} }
+func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
 
 func (*testFunc) Call(t *Thread) {
 	n := t.f.Vars[0].(IntValue).Get(t)
@@ -217,7 +217,7 @@ 
 
 type oneTwoFunc struct{}
 
-func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} }
+func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
 
 func (*oneTwoFunc) Call(t *Thread) {
 	t.f.Vars[0].(IntValue).Set(t, 1)
diff -r b0b47113eebd libgo/go/os/dir.go
--- a/libgo/go/os/dir.go	Fri Aug 27 19:29:10 2010 -0700
+++ b/libgo/go/os/dir.go	Tue Aug 31 10:02:07 2010 -0700
@@ -62,7 +62,7 @@ 
 		if result == nil {
 			break
 		}
-		var name = string(result.Name[0:clen(&result.Name)])
+		var name = string(result.Name[0:clen(result.Name[0:])])
 		if name == "." || name == ".." {	// Useless names
 			continue
 		}
diff -r b0b47113eebd libgo/syscalls/exec.go
--- a/libgo/syscalls/exec.go	Fri Aug 27 19:29:10 2010 -0700
+++ b/libgo/syscalls/exec.go	Tue Aug 31 10:02:07 2010 -0700
@@ -162,7 +162,7 @@ 
 	ForkLock.Lock();
 
 	// Allocate child status pipe close on exec.
-	if err = Pipe(&p); err != 0 {
+	if err = Pipe(p[0:]); err != 0 {
 		goto error;
 	}
 	var val int;
diff -r b0b47113eebd libgo/syscalls/syscall_linux.go
--- a/libgo/syscalls/syscall_linux.go	Fri Aug 27 19:29:10 2010 -0700
+++ b/libgo/syscalls/syscall_linux.go	Tue Aug 31 10:02:07 2010 -0700
@@ -13,17 +13,6 @@ 
 var dummy *byte
 const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
 
-// See bytes.Copy.
-func bytesCopy(dst, src []byte) int {
-	if len(src) > len(dst) {
-		src = src[0:len(dst)];
-	}
-	for i, x := range src {
-		dst[i] = x
-	}
-	return len(src)
-}
-
 func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
 	// The peek requests are machine-size oriented, so we wrap it
 	// to retrieve arbitrary-length data.
@@ -43,8 +32,8 @@ 
 			return 0, errno;
 		}
 		*(*_C_long)(unsafe.Pointer(&buf[0])) = val;
-		n += bytesCopy(out, buf[addr%sizeofPtr:len(buf)]);
-		out = out[n:len(out)];
+		n += copy(out, buf[addr%sizeofPtr:]);
+		out = out[n:];
 	}
 
 	// Remainder.
@@ -57,9 +46,9 @@ 
 			return n, errno;
 		}
 		*(*_C_long)(unsafe.Pointer(&buf[0])) = val;
-		copied := bytesCopy(out, &buf);
+		copied := copy(out, buf[0:]);
 		n += copied;
-		out = out[copied:len(out)];
+		out = out[copied:];
 	}
 
 	return n, 0;
@@ -84,7 +73,7 @@ 
 		if libc_ptrace(peekReq, Pid_t(pid), addr - addr%sizeofPtr, &buf[0]) < 0 {
 			return 0, GetErrno();
 		}
-		n += bytesCopy(buf[addr%sizeofPtr:len(buf)], data);
+		n += copy(buf[addr%sizeofPtr:], data);
 		word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
 		if libc_ptrace(pokeReq, Pid_t(pid), addr - addr%sizeofPtr, word) < 0 {
 			return 0, GetErrno();
@@ -108,7 +97,7 @@ 
 		if libc_ptrace(peekReq, Pid_t(pid), addr+uintptr(n), &buf[0]) < 0 {
 			return n, GetErrno();
 		}
-		bytesCopy(&buf, data);
+		copy(buf[0:], data);
 		word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0])))));
 		if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 {
 			return n, GetErrno();