compiler: Fix a, b, c := b, a, 1 when a and b already exist.
From-SVN: r192022
This commit is contained in:
parent
e1d90a813c
commit
bed6238ce6
2 changed files with 60 additions and 16 deletions
|
@ -1631,12 +1631,16 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
|
|||
|
||||
// Note that INIT was already parsed with the old name bindings, so
|
||||
// we don't have to worry that it will accidentally refer to the
|
||||
// newly declared variables.
|
||||
// newly declared variables. But we do have to worry about a mix of
|
||||
// newly declared variables and old variables if the old variables
|
||||
// appear in the initializations.
|
||||
|
||||
Expression_list::const_iterator pexpr;
|
||||
if (init != NULL)
|
||||
pexpr = init->begin();
|
||||
bool any_new = false;
|
||||
Expression_list* vars = new Expression_list();
|
||||
Expression_list* vals = new Expression_list();
|
||||
for (Typed_identifier_list::const_iterator p = til->begin();
|
||||
p != til->end();
|
||||
++p)
|
||||
|
@ -1644,7 +1648,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
|
|||
if (init != NULL)
|
||||
go_assert(pexpr != init->end());
|
||||
this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
|
||||
false, &any_new);
|
||||
false, &any_new, vars, vals);
|
||||
if (init != NULL)
|
||||
++pexpr;
|
||||
}
|
||||
|
@ -1652,6 +1656,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
|
|||
go_assert(pexpr == init->end());
|
||||
if (is_coloneq && !any_new)
|
||||
error_at(location, "variables redeclared but no variable is new");
|
||||
this->finish_init_vars(vars, vals, location);
|
||||
}
|
||||
|
||||
// See if we need to initialize a list of variables from a function
|
||||
|
@ -1674,13 +1679,15 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
|
|||
Named_object* first_var = NULL;
|
||||
unsigned int index = 0;
|
||||
bool any_new = false;
|
||||
Expression_list* ivars = new Expression_list();
|
||||
Expression_list* ivals = new Expression_list();
|
||||
for (Typed_identifier_list::const_iterator pv = vars->begin();
|
||||
pv != vars->end();
|
||||
++pv, ++index)
|
||||
{
|
||||
Expression* init = Expression::make_call_result(call, index);
|
||||
Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
|
||||
&any_new);
|
||||
&any_new, ivars, ivals);
|
||||
|
||||
if (this->gogo_->in_global_scope() && no->is_variable())
|
||||
{
|
||||
|
@ -1700,6 +1707,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
|
|||
if (is_coloneq && !any_new)
|
||||
error_at(location, "variables redeclared but no variable is new");
|
||||
|
||||
this->finish_init_vars(ivars, ivals, location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1725,7 +1734,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
|
|||
Typed_identifier_list::const_iterator p = vars->begin();
|
||||
Expression* init = type == NULL ? index : NULL;
|
||||
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
|
||||
type == NULL, &any_new);
|
||||
type == NULL, &any_new, NULL, NULL);
|
||||
if (type == NULL && any_new && val_no->is_variable())
|
||||
val_no->var_value()->set_type_from_init_tuple();
|
||||
Expression* val_var = Expression::make_var_reference(val_no, location);
|
||||
|
@ -1735,7 +1744,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
|
|||
if (var_type == NULL)
|
||||
var_type = Type::lookup_bool_type();
|
||||
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
|
||||
&any_new);
|
||||
&any_new, NULL, NULL);
|
||||
Expression* present_var = Expression::make_var_reference(no, location);
|
||||
|
||||
if (is_coloneq && !any_new)
|
||||
|
@ -1790,7 +1799,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
|
|||
Typed_identifier_list::const_iterator p = vars->begin();
|
||||
Expression* init = type == NULL ? receive : NULL;
|
||||
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
|
||||
type == NULL, &any_new);
|
||||
type == NULL, &any_new, NULL, NULL);
|
||||
if (type == NULL && any_new && val_no->is_variable())
|
||||
val_no->var_value()->set_type_from_init_tuple();
|
||||
Expression* val_var = Expression::make_var_reference(val_no, location);
|
||||
|
@ -1800,7 +1809,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
|
|||
if (var_type == NULL)
|
||||
var_type = Type::lookup_bool_type();
|
||||
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
|
||||
&any_new);
|
||||
&any_new, NULL, NULL);
|
||||
Expression* received_var = Expression::make_var_reference(no, location);
|
||||
|
||||
if (is_coloneq && !any_new)
|
||||
|
@ -1857,7 +1866,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
|
|||
if (var_type == NULL)
|
||||
var_type = type_guard->type();
|
||||
Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false,
|
||||
&any_new);
|
||||
&any_new, NULL, NULL);
|
||||
Expression* val_var = Expression::make_var_reference(val_no, location);
|
||||
|
||||
++p;
|
||||
|
@ -1865,7 +1874,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
|
|||
if (var_type == NULL)
|
||||
var_type = Type::lookup_bool_type();
|
||||
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
|
||||
&any_new);
|
||||
&any_new, NULL, NULL);
|
||||
Expression* ok_var = Expression::make_var_reference(no, location);
|
||||
|
||||
Expression* texpr = type_guard->expr();
|
||||
|
@ -1904,7 +1913,8 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
|
|||
|
||||
Named_object*
|
||||
Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
|
||||
bool is_coloneq, bool type_from_init, bool* is_new)
|
||||
bool is_coloneq, bool type_from_init, bool* is_new,
|
||||
Expression_list* vars, Expression_list* vals)
|
||||
{
|
||||
Location location = tid.location();
|
||||
|
||||
|
@ -1946,9 +1956,9 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
|
|||
// like v, ok := x.(int).
|
||||
if (!type_from_init && init != NULL)
|
||||
{
|
||||
Expression *v = Expression::make_var_reference(no, location);
|
||||
Statement *s = Statement::make_assignment(v, init, location);
|
||||
this->gogo_->add_statement(s);
|
||||
go_assert(vars != NULL && vals != NULL);
|
||||
vars->push_back(Expression::make_var_reference(no, location));
|
||||
vals->push_back(init);
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
@ -1983,6 +1993,36 @@ Parse::create_dummy_global(Type* type, Expression* init,
|
|||
return this->gogo_->add_variable(buf, var);
|
||||
}
|
||||
|
||||
// Finish the variable initialization by executing any assignments to
|
||||
// existing variables when using :=. These must be done as a tuple
|
||||
// assignment in case of something like n, a, b := 1, b, a.
|
||||
|
||||
void
|
||||
Parse::finish_init_vars(Expression_list* vars, Expression_list* vals,
|
||||
Location location)
|
||||
{
|
||||
if (vars->empty())
|
||||
{
|
||||
delete vars;
|
||||
delete vals;
|
||||
}
|
||||
else if (vars->size() == 1)
|
||||
{
|
||||
go_assert(!this->gogo_->in_global_scope());
|
||||
this->gogo_->add_statement(Statement::make_assignment(vars->front(),
|
||||
vals->front(),
|
||||
location));
|
||||
delete vars;
|
||||
delete vals;
|
||||
}
|
||||
else
|
||||
{
|
||||
go_assert(!this->gogo_->in_global_scope());
|
||||
this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals,
|
||||
location));
|
||||
}
|
||||
}
|
||||
|
||||
// SimpleVarDecl = identifier ":=" Expression .
|
||||
|
||||
// We've already seen the identifier.
|
||||
|
@ -5113,7 +5153,8 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
|
|||
bool any_new = false;
|
||||
|
||||
const Typed_identifier* pti = &til->front();
|
||||
Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new);
|
||||
Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new,
|
||||
NULL, NULL);
|
||||
if (any_new && no->is_variable())
|
||||
no->var_value()->set_type_from_range_index();
|
||||
p_range_clause->index = Expression::make_var_reference(no, location);
|
||||
|
@ -5124,7 +5165,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
|
|||
{
|
||||
pti = &til->back();
|
||||
bool is_new = false;
|
||||
no = this->init_var(*pti, NULL, expr, true, true, &is_new);
|
||||
no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL);
|
||||
if (is_new && no->is_variable())
|
||||
no->var_value()->set_type_from_range_value();
|
||||
if (is_new)
|
||||
|
|
|
@ -206,8 +206,11 @@ class Parse
|
|||
Expression*, bool is_coloneq,
|
||||
Location);
|
||||
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
|
||||
bool is_coloneq, bool type_from_init, bool* is_new);
|
||||
bool is_coloneq, bool type_from_init, bool* is_new,
|
||||
Expression_list* vars, Expression_list* vals);
|
||||
Named_object* create_dummy_global(Type*, Expression*, Location);
|
||||
void finish_init_vars(Expression_list* vars, Expression_list* vals,
|
||||
Location);
|
||||
void simple_var_decl_or_assignment(const std::string&, Location,
|
||||
bool may_be_composite_lit,
|
||||
Range_clause*, Type_switch*);
|
||||
|
|
Loading…
Add table
Reference in a new issue