diff mbox

Go patch committed: Accept map composite literals with omitted key types

Message ID CAOyqgcWAd4VF3rt7Nfz6mFTNDC5cnN3Ey5kjqEL3vC7YDZ7O0g@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Jan. 27, 2016, 6:52 p.m. UTC
In the Go 1.5 release, the language was changed slightly to permit
omitting the type of a key in a composite literal of map type.  This
patch by Chris Manghane implements that in gccgo.  This fixes
https://golang.org/issue/10263 .  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 232858)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-9e68d67d65fd72b9b4f163f2f26e15cd0d3e2cd2
+8dce33f24dd3a34e3574c1d2604428586b63c1aa
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 232239)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -12583,69 +12583,7 @@  Map_construction_expression::do_dump_exp
   ast_dump_context->ostream() << "}";
 }
 
-// A general composite literal.  This is lowered to a type specific
-// version.
-
-class Composite_literal_expression : public Parser_expression
-{
- public:
-  Composite_literal_expression(Type* type, int depth, bool has_keys,
-			       Expression_list* vals, bool all_are_names,
-			       Location location)
-    : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
-      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys),
-      all_are_names_(all_are_names)
-  { }
-
- protected:
-  int
-  do_traverse(Traverse* traverse);
-
-  Expression*
-  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
-  Expression*
-  do_copy()
-  {
-    return new Composite_literal_expression(this->type_, this->depth_,
-					    this->has_keys_,
-					    (this->vals_ == NULL
-					     ? NULL
-					     : this->vals_->copy()),
-					    this->all_are_names_,
-					    this->location());
-  }
-
-  void
-  do_dump_expression(Ast_dump_context*) const;
-  
- private:
-  Expression*
-  lower_struct(Gogo*, Type*);
-
-  Expression*
-  lower_array(Type*);
-
-  Expression*
-  make_array(Type*, const std::vector<unsigned long>*, Expression_list*);
-
-  Expression*
-  lower_map(Gogo*, Named_object*, Statement_inserter*, 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
-  // value.  In an array initializer, a missing key will be NULL.
-  bool has_keys_;
-  // If this is true, then HAS_KEYS_ is true, and every key is a
-  // simple identifier.
-  bool all_are_names_;
-};
+// Class Composite_literal_expression.
 
 // Traversal.
 
@@ -12664,12 +12602,17 @@  Composite_literal_expression::do_travers
       // The type may not be resolvable at this point.
       Type* type = this->type_;
 
-      for (int depth = this->depth_; depth > 0; --depth)
+      for (int depth = 0; depth < this->depth_; ++depth)
         {
           if (type->array_type() != NULL)
             type = type->array_type()->element_type();
           else if (type->map_type() != NULL)
-            type = type->map_type()->val_type();
+            {
+              if (this->key_path_[depth])
+                type = type->map_type()->key_type();
+              else
+                type = type->map_type()->val_type();
+            }
           else
             {
               // This error will be reported during lowering.
@@ -12723,12 +12666,17 @@  Composite_literal_expression::do_lower(G
 {
   Type* type = this->type_;
 
-  for (int depth = this->depth_; depth > 0; --depth)
+  for (int depth = 0; depth < this->depth_; ++depth)
     {
       if (type->array_type() != NULL)
 	type = type->array_type()->element_type();
       else if (type->map_type() != NULL)
-	type = type->map_type()->val_type();
+        {
+          if (this->key_path_[depth])
+            type = type->map_type()->key_type();
+          else
+            type = type->map_type()->val_type();
+        }
       else
 	{
 	  if (!type->is_error())
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 232239)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -47,6 +47,7 @@  class Bound_method_expression;
 class Field_reference_expression;
 class Interface_field_reference_expression;
 class Allocation_expression;
+class Composite_literal_expression;
 class Struct_construction_expression;
 class Array_construction_expression;
 class Fixed_array_construction_expression;
@@ -691,6 +692,15 @@  class Expression
   allocation_expression()
   { return this->convert<Allocation_expression, EXPRESSION_ALLOCATION>(); }
 
+  // If this is a general composite literal, return the
+  // Composite_literal_expression structure.  Otherwise, return NULL.
+  Composite_literal_expression*
+  complit()
+  {
+    return this->convert<Composite_literal_expression,
+			 EXPRESSION_COMPOSITE_LITERAL>();
+  }
+
   // If this is a struct composite literal, return the
   // Struct_construction_expression structure.  Otherwise, return NULL.
   Struct_construction_expression*
@@ -2890,6 +2900,87 @@  class Allocation_expression : public Exp
   bool allocate_on_stack_;
 };
 
+// A general composite literal.  This is lowered to a type specific
+// version.
+
+class Composite_literal_expression : public Parser_expression
+{
+ public:
+  Composite_literal_expression(Type* type, int depth, bool has_keys,
+			       Expression_list* vals, bool all_are_names,
+			       Location location)
+    : Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
+      type_(type), depth_(depth), vals_(vals), has_keys_(has_keys),
+      all_are_names_(all_are_names), key_path_(std::vector<bool>(depth))
+  {}
+
+
+  // Mark the DEPTH entry of KEY_PATH as containing a key.
+  void
+  update_key_path(size_t depth)
+  {
+    go_assert(depth < this->key_path_.size());
+    this->key_path_[depth] = true;
+  }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Expression*
+  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+
+  Expression*
+  do_copy()
+  {
+    Composite_literal_expression *ret =
+      new Composite_literal_expression(this->type_, this->depth_,
+				       this->has_keys_,
+				       (this->vals_ == NULL
+					? NULL
+					: this->vals_->copy()),
+				       this->all_are_names_,
+				       this->location());
+    ret->key_path_ = this->key_path_;
+    return ret;
+  }
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  Expression*
+  lower_struct(Gogo*, Type*);
+
+  Expression*
+  lower_array(Type*);
+
+  Expression*
+  make_array(Type*, const std::vector<unsigned long>*, Expression_list*);
+
+  Expression*
+  lower_map(Gogo*, Named_object*, Statement_inserter*, 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
+  // value.  In an array initializer, a missing key will be NULL.
+  bool has_keys_;
+  // If this is true, then HAS_KEYS_ is true, and every key is a
+  // simple identifier.
+  bool all_are_names_;
+  // A complement to DEPTH that indicates for each level starting from 0 to
+  // DEPTH-1 whether or not this composite literal is nested inside of key or
+  // a value.  This is used to decide which type to use when given a map literal
+  // with omitted key types.
+  std::vector<bool> key_path_;
+};
+
 // Construct a struct.
 
 class Struct_construction_expression : public Expression
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc	(revision 232858)
+++ gcc/go/gofrontend/parse.cc	(working copy)
@@ -2739,7 +2739,7 @@  Parse::composite_lit(Type* type, int dep
 	  // 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;
+          is_type_omitted = true;
 	}
 
       token = this->peek_token();
@@ -2751,11 +2751,14 @@  Parse::composite_lit(Type* type, int dep
 	}
       else
 	{
-	  if (is_type_omitted && !val->is_error_expression())
-	    {
-	      error_at(this->location(), "unexpected %<:%>");
-	      val = Expression::make_error(this->location());
-	    }
+          if (is_type_omitted)
+            {
+              // VAL is a nested composite literal with an omitted type being
+              // used a key.  Record this information in VAL so that the correct
+              // type is associated with the literal value if VAL is a
+              // map literal.
+              val->complit()->update_key_path(depth);
+            }
 
 	  this->advance_token();