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:
parent
8f91e6e0ef
commit
b45285fc2e
4 changed files with 116 additions and 74 deletions
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue