Patchwork [gccgo] Permit omitting types in a composite literal

login
register
mail settings
Submitter Ian Taylor
Date Oct. 22, 2010, 9:33 p.m.
Message ID <mcrlj5px696.fsf@google.com>
Download mbox | patch
Permalink /patch/68972/
State New
Headers show

Comments

Ian Taylor - Oct. 22, 2010, 9:33 p.m.
The Go language was changed to permit omitting some redundant types in
nested composite literals.  Now instead of
  [][]int{[]int{1}, []int{2}}
you can write
  [][]int{{1}, {2}}

This patch implements that in gccgo.  Committed to gccgo branch.

Ian

Patch

diff -r e852fb180b3f go/expressions.cc
--- a/go/expressions.cc	Fri Oct 22 12:33:37 2010 -0700
+++ b/go/expressions.cc	Fri Oct 22 14:27:38 2010 -0700
@@ -2937,8 +2937,8 @@ 
 		    }
 		}
 
-	      return Expression::make_composite_literal(type, false, vals,
-							location);
+	      return Expression::make_slice_composite_literal(type, vals,
+							      location);
 	    }
 	}
     }
@@ -7823,14 +7823,19 @@ 
 	      vals->push_back(*pa);
 	    }
 
-	  Type* ctype;
+	  Expression* val;
 	  if (element_type == NULL)
-	    ctype = Type::make_struct_type(fields, loc);
+	    {
+	      Type* ctype = Type::make_struct_type(fields, loc);
+	      val = Expression::make_struct_composite_literal(ctype, vals, loc);
+	    }
 	  else
-	    ctype = Type::make_array_type(element_type, NULL);
-
-	  new_args->push_back(Expression::make_composite_literal(ctype, false,
-								 vals, loc));
+	    {
+	      Type* ctype = Type::make_array_type(element_type, NULL);
+	      val = Expression::make_slice_composite_literal(ctype, vals, loc);
+	    }
+
+	  new_args->push_back(val);
 	}
     }
 
@@ -7842,9 +7847,9 @@ 
 	{
 	  Struct_field_list* fields = new Struct_field_list();
 	  Type* param_type = Type::make_struct_type(fields, loc);
-	  new_args->push_back(Expression::make_composite_literal(param_type,
-								 false, NULL,
-								 loc));
+	  Expression* v = Expression::make_struct_composite_literal(param_type,
+								    NULL, loc);
+	  new_args->push_back(v);
 	}
     }
 
@@ -10962,10 +10967,10 @@ 
 class Composite_literal_expression : public Parser_expression
 {
  public:
-  Composite_literal_expression(Type* type, bool has_keys,
+  Composite_literal_expression(Type* type, int depth, bool has_keys,
 			       Expression_list* vals, source_location location)
     : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
-      type_(type), vals_(vals), has_keys_(has_keys)
+      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys)
   { }
 
  protected:
@@ -10978,7 +10983,8 @@ 
   Expression*
   do_copy()
   {
-    return new Composite_literal_expression(this->type_, this->has_keys_,
+    return new Composite_literal_expression(this->type_, this->depth_,
+					    this->has_keys_,
 					    (this->vals_ == NULL
 					     ? NULL
 					     : this->vals_->copy()),
@@ -10987,19 +10993,22 @@ 
 
  private:
   Expression*
-  lower_struct();
+  lower_struct(Type*);
 
   Expression*
-  lower_array();
+  lower_array(Type*);
 
   Expression*
-  make_array(Expression_list*);
+  make_array(Type*, Expression_list*);
 
   Expression*
-  lower_map();
+  lower_map(Type*);
 
   // The type of the composite literal.
   Type* type_;
+  // The depth within a list of composite literals within a composite
+  // literal, when the type is omitted.
+  int depth_;
   // The values to put in the composite literal.
   Expression_list* vals_;
   // If this is true, then VALS_ is a list of pairs: a key and a
@@ -11025,18 +11034,36 @@ 
 Composite_literal_expression::do_lower(Gogo*, Named_object*, int)
 {
   Type* type = this->type_;
+
+  for (int depth = this->depth_; depth > 0; --depth)
+    {
+      if (type->array_type() != NULL)
+	type = type->array_type()->element_type();
+      else if (type->map_type() != NULL)
+	type = type->map_type()->val_type();
+      else
+	{
+	  if (!type->is_error_type())
+	    error_at(this->location(),
+		     ("may only omit types within composite literals "
+		      "of slice, array, or map type"));
+	  return Expression::make_error(this->location());
+	}
+    }
+
   if (type->is_error_type())
     return Expression::make_error(this->location());
   else if (type->struct_type() != NULL)
-    return this->lower_struct();
+    return this->lower_struct(type);
   else if (type->array_type() != NULL)
-    return this->lower_array();
+    return this->lower_array(type);
   else if (type->map_type() != NULL)
-    return this->lower_map();
+    return this->lower_map(type);
   else
     {
       error_at(this->location(),
-	       "expected struct, array, or map type for composite literal");
+	       ("expected struct, slice, array, or map type "
+		"for composite literal"));
       return Expression::make_error(this->location());
     }
 }
@@ -11044,13 +11071,12 @@ 
 // Lower a struct composite literal.
 
 Expression*
-Composite_literal_expression::lower_struct()
+Composite_literal_expression::lower_struct(Type* type)
 {
   source_location location = this->location();
-  Struct_type* st = this->type_->struct_type();
+  Struct_type* st = type->struct_type();
   if (this->vals_ == NULL || !this->has_keys_)
-    return new Struct_construction_expression(this->type_, this->vals_,
-					      location);
+    return new Struct_construction_expression(type, this->vals_, location);
 
   size_t field_count = st->field_count();
   std::vector<Expression*> vals(field_count);
@@ -11153,8 +11179,8 @@ 
 	{
 	  error_at(name_expr->location(), "unknown field %qs in %qs",
 		   Gogo::unpack_hidden_name(name).c_str(),
-		   (this->type_->named_type() != NULL
-		    ? this->type_->named_type()->message_name().c_str()
+		   (type->named_type() != NULL
+		    ? type->named_type()->message_name().c_str()
 		    : "unnamed struct"));
 	  return Expression::make_error(location);
 	}
@@ -11163,8 +11189,8 @@ 
 	  error_at(name_expr->location(),
 		   "duplicate value for field %qs in %qs",
 		   Gogo::unpack_hidden_name(name).c_str(),
-		   (this->type_->named_type() != NULL
-		    ? this->type_->named_type()->message_name().c_str()
+		   (type->named_type() != NULL
+		    ? type->named_type()->message_name().c_str()
 		    : "unnamed struct"));
 	  return Expression::make_error(location);
 	}
@@ -11177,17 +11203,17 @@ 
   for (size_t i = 0; i < field_count; ++i)
     list->push_back(vals[i]);
 
-  return new Struct_construction_expression(this->type_, list, location);
+  return new Struct_construction_expression(type, list, location);
 }
 
 // Lower an array composite literal.
 
 Expression*
-Composite_literal_expression::lower_array()
+Composite_literal_expression::lower_array(Type* type)
 {
   source_location location = this->location();
   if (this->vals_ == NULL || !this->has_keys_)
-    return this->make_array(this->vals_);
+    return this->make_array(type, this->vals_);
 
   std::vector<Expression*> vals;
   vals.reserve(this->vals_->size());
@@ -11261,17 +11287,17 @@ 
   for (size_t i = 0; i < size; ++i)
     list->push_back(vals[i]);
 
-  return this->make_array(list);
+  return this->make_array(type, list);
 }
 
 // Actually build the array composite literal. This handles
 // [...]{...}.
 
 Expression*
-Composite_literal_expression::make_array(Expression_list* vals)
+Composite_literal_expression::make_array(Type* type, Expression_list* vals)
 {
   source_location location = this->location();
-  Array_type* at = this->type_->array_type();
+  Array_type* at = type->array_type();
   if (at->length() != NULL && at->length()->is_nil_expression())
     {
       size_t size = vals == NULL ? 0 : vals->size();
@@ -11280,18 +11306,18 @@ 
       Expression* elen = Expression::make_integer(&vlen, NULL, location);
       mpz_clear(vlen);
       at = Type::make_array_type(at->element_type(), elen);
-      this->type_ = at;
+      type = at;
     }
   if (at->length() != NULL)
-    return new Fixed_array_construction_expression(this->type_, vals, location);
+    return new Fixed_array_construction_expression(type, vals, location);
   else
-    return new Open_array_construction_expression(this->type_, vals, location);
+    return new Open_array_construction_expression(type, vals, location);
 }
 
 // Lower a map composite literal.
 
 Expression*
-Composite_literal_expression::lower_map()
+Composite_literal_expression::lower_map(Type* type)
 {
   source_location location = this->location();
   if (this->vals_ != NULL)
@@ -11316,17 +11342,18 @@ 
 	}
     }
 
-  return new Map_construction_expression(this->type_, this->vals_, location);
+  return new Map_construction_expression(type, this->vals_, location);
 }
 
 // Make a composite literal expression.
 
 Expression*
-Expression::make_composite_literal(Type* type, bool has_keys,
+Expression::make_composite_literal(Type* type, int depth, bool has_keys,
 				   Expression_list* vals,
 				   source_location location)
 {
-  return new Composite_literal_expression(type, has_keys, vals, location);
+  return new Composite_literal_expression(type, depth, has_keys, vals,
+					  location);
 }
 
 // Return whether this expression is a composite literal.
diff -r e852fb180b3f go/expressions.h
--- a/go/expressions.h	Fri Oct 22 12:33:37 2010 -0700
+++ b/go/expressions.h	Fri Oct 22 14:27:38 2010 -0700
@@ -248,9 +248,10 @@ 
   static Expression*
   make_cast(Type*, Expression*, source_location);
 
-  // Make a composite literal.
+  // Make a composite literal.  The DEPTH parameter is how far down we
+  // are in a list of composite literals with omitted types.
   static Expression*
-  make_composite_literal(Type*, bool has_keys, Expression_list*,
+  make_composite_literal(Type*, int depth, bool has_keys, Expression_list*,
 			 source_location);
 
   // Make a struct composite literal.
diff -r e852fb180b3f go/parse.cc
--- a/go/parse.cc	Fri Oct 22 12:33:37 2010 -0700
+++ b/go/parse.cc	Fri Oct 22 14:27:38 2010 -0700
@@ -2314,19 +2314,25 @@ 
   return e;
 }
 
-// CompositeLit  = LiteralType "{" [ ElementList ] "}" .
+// CompositeLit  = LiteralType LiteralValue .
 // LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
 //                 SliceType | MapType | TypeName .
-// ElementList   = Element { "," Element } [ "," ] .
+// LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
+// ElementList   = Element { "," Element } .
 // Element       = [ Key ":" ] Value .
 // Key           = Expression .
-// Value         = Expression .
-
-// We have already seen the type.  The case "[" "..." "]" ElementType
-// will be seen here as an array type whose length is "nil".
+// Value         = Expression | LiteralValue .
+
+// We have already seen the type if there is one, and we are now
+// looking at the LiteralValue.  The case "[" "..."  "]" ElementType
+// will be seen here as an array type whose length is "nil".  The
+// DEPTH parameter is non-zero if this is an embedded composite
+// literal and the type was omitted.  It gives the number of steps up
+// to the type which was provided.  E.g., in [][]int{{1}} it will be
+// 1.  In [][][]int{{{1}}} it will be 2.
 
 Expression*
-Parse::composite_lit(Type* type, source_location location)
+Parse::composite_lit(Type* type, int depth, source_location location)
 {
   gcc_assert(this->peek_token()->is_op(OPERATOR_LCURLY));
   this->advance_token();
@@ -2334,16 +2340,30 @@ 
   if (this->peek_token()->is_op(OPERATOR_RCURLY))
     {
       this->advance_token();
-      return Expression::make_composite_literal(type, false, NULL, location);
+      return Expression::make_composite_literal(type, depth, false, NULL,
+						location);
     }
 
   bool has_keys = false;
   Expression_list* vals = new Expression_list;
   while (true)
     {
-      Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+      Expression* val;
+      bool is_type_omitted = false;
 
       const Token* token = this->peek_token();
+
+      if (!token->is_op(OPERATOR_LCURLY))
+	val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+      else
+	{
+	  // This must be a composite literal inside another composite
+	  // literal, with the type omitted for the inner one.
+	  val = this->composite_lit(type, depth + 1, token->location());
+	  is_type_omitted = true;
+	}
+
+      token = this->peek_token();
       if (!token->is_op(OPERATOR_COLON))
 	{
 	  if (has_keys)
@@ -2351,6 +2371,12 @@ 
 	}
       else
 	{
+	  if (is_type_omitted && !val->is_error_expression())
+	    {
+	      this->error("unexpected %<:%>");
+	      val = Expression::make_error(this->location());
+	    }
+
 	  this->advance_token();
 
 	  if (!has_keys && !vals->empty())
@@ -2414,7 +2440,8 @@ 
 	}
     }
 
-  return Expression::make_composite_literal(type, has_keys, vals, location);
+  return Expression::make_composite_literal(type, depth, has_keys, vals,
+					    location);
 }
 
 // FunctionLit = "func" Signature Block .
@@ -2540,7 +2567,7 @@ 
 	  if (is_parenthesized)
 	    error_at(start_loc,
 		     "cannot parenthesize type in composite literal");
-	  ret = this->composite_lit(ret->type(), ret->location());
+	  ret = this->composite_lit(ret->type(), 0, ret->location());
 	}
       else if (this->peek_token()->is_op(OPERATOR_LPAREN))
 	{
diff -r e852fb180b3f go/parse.h
--- a/go/parse.h	Fri Oct 22 12:33:37 2010 -0700
+++ b/go/parse.h	Fri Oct 22 14:27:38 2010 -0700
@@ -206,7 +206,7 @@ 
   Expression* operand(bool may_be_sink);
   Expression* enclosing_var_reference(Named_object*, Named_object*,
 				      source_location);
-  Expression* composite_lit(Type*, source_location);
+  Expression* composite_lit(Type*, int depth, source_location);
   Expression* function_lit();
   Expression* create_closure(Named_object* function, Enclosing_vars*,
 			     source_location);