Commit b45285fc by Ian Lance Taylor

compiler: Accept map composite literals with omitted key types.

    compiler: Copy key_path_ when copying a Composite_literal_expression.
    
    Fixes golang/go#10263.
    
    Reviewed-on: https://go-review.googlesource.com/14299
    Reviewed-on: https://go-review.googlesource.com/18988

From-SVN: r232892
parent 8f91e6e0
9e68d67d65fd72b9b4f163f2f26e15cd0d3e2cd2 8dce33f24dd3a34e3574c1d2604428586b63c1aa
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -12583,69 +12583,7 @@ Map_construction_expression::do_dump_expression( ...@@ -12583,69 +12583,7 @@ Map_construction_expression::do_dump_expression(
ast_dump_context->ostream() << "}"; ast_dump_context->ostream() << "}";
} }
// A general composite literal. This is lowered to a type specific // Class Composite_literal_expression.
// 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_;
};
// Traversal. // Traversal.
...@@ -12664,12 +12602,17 @@ Composite_literal_expression::do_traverse(Traverse* traverse) ...@@ -12664,12 +12602,17 @@ Composite_literal_expression::do_traverse(Traverse* traverse)
// The type may not be resolvable at this point. // The type may not be resolvable at this point.
Type* type = this->type_; 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) if (type->array_type() != NULL)
type = type->array_type()->element_type(); type = type->array_type()->element_type();
else if (type->map_type() != NULL) 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 else
{ {
// This error will be reported during lowering. // This error will be reported during lowering.
...@@ -12723,12 +12666,17 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, ...@@ -12723,12 +12666,17 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
{ {
Type* type = this->type_; 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) if (type->array_type() != NULL)
type = type->array_type()->element_type(); type = type->array_type()->element_type();
else if (type->map_type() != NULL) 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 else
{ {
if (!type->is_error()) if (!type->is_error())
......
...@@ -47,6 +47,7 @@ class Bound_method_expression; ...@@ -47,6 +47,7 @@ class Bound_method_expression;
class Field_reference_expression; class Field_reference_expression;
class Interface_field_reference_expression; class Interface_field_reference_expression;
class Allocation_expression; class Allocation_expression;
class Composite_literal_expression;
class Struct_construction_expression; class Struct_construction_expression;
class Array_construction_expression; class Array_construction_expression;
class Fixed_array_construction_expression; class Fixed_array_construction_expression;
...@@ -691,6 +692,15 @@ class Expression ...@@ -691,6 +692,15 @@ class Expression
allocation_expression() allocation_expression()
{ return this->convert<Allocation_expression, EXPRESSION_ALLOCATION>(); } { 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 // If this is a struct composite literal, return the
// Struct_construction_expression structure. Otherwise, return NULL. // Struct_construction_expression structure. Otherwise, return NULL.
Struct_construction_expression* Struct_construction_expression*
...@@ -2890,6 +2900,87 @@ class Allocation_expression : public Expression ...@@ -2890,6 +2900,87 @@ class Allocation_expression : public Expression
bool allocate_on_stack_; 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. // Construct a struct.
class Struct_construction_expression : public Expression class Struct_construction_expression : public Expression
......
...@@ -2739,7 +2739,7 @@ Parse::composite_lit(Type* type, int depth, Location location) ...@@ -2739,7 +2739,7 @@ Parse::composite_lit(Type* type, int depth, Location location)
// This must be a composite literal inside another composite // This must be a composite literal inside another composite
// literal, with the type omitted for the inner one. // literal, with the type omitted for the inner one.
val = this->composite_lit(type, depth + 1, token->location()); val = this->composite_lit(type, depth + 1, token->location());
is_type_omitted = true; is_type_omitted = true;
} }
token = this->peek_token(); token = this->peek_token();
...@@ -2751,11 +2751,14 @@ Parse::composite_lit(Type* type, int depth, Location location) ...@@ -2751,11 +2751,14 @@ Parse::composite_lit(Type* type, int depth, Location location)
} }
else else
{ {
if (is_type_omitted && !val->is_error_expression()) if (is_type_omitted)
{ {
error_at(this->location(), "unexpected %<:%>"); // VAL is a nested composite literal with an omitted type being
val = Expression::make_error(this->location()); // 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(); this->advance_token();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment