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
This commit is contained in:
Ian Lance Taylor 2016-01-27 18:51:58 +00:00
parent 8f91e6e0ef
commit b45285fc2e
4 changed files with 116 additions and 74 deletions

View File

@ -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.

View File

@ -12583,69 +12583,7 @@ Map_construction_expression::do_dump_expression(
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_traverse(Traverse* traverse)
// 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(Gogo* gogo, Named_object* function,
{
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())

View File

@ -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 Expression
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

View File

@ -2739,7 +2739,7 @@ Parse::composite_lit(Type* type, int depth, Location location)
// 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 depth, Location location)
}
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();