// ExpressionList = Expression { "," Expression } .
+// If MAY_BE_COMPOSITE_LIT is true, an expression may be a composite
+// literal.
+
// If MAY_BE_SINK is true, the expressions in the list may be "_".
Expression_list*
-Parse::expression_list(Expression* first, bool may_be_sink)
+Parse::expression_list(Expression* first, bool may_be_sink,
+ bool may_be_composite_lit)
{
Expression_list* ret = new Expression_list();
if (first != NULL)
ret->push_back(first);
while (true)
{
- ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink, true,
- NULL));
+ ret->push_back(this->expression(PRECEDENCE_NORMAL, may_be_sink,
+ may_be_composite_lit, NULL));
const Token* token = this->peek_token();
if (!token->is_op(OPERATOR_COMMA))
&& package->name() != this->gogo_->package_name())
{
// Check whether the name is there but hidden.
- std::string s = ('.' + package->package_value()->unique_prefix()
- + '.' + package->package_value()->name()
+ std::string s = ('.' + package->package_value()->pkgpath()
+ '.' + name);
named_object = package->package_value()->lookup(s);
if (named_object != NULL)
{
- const std::string& packname(package->package_value()->name());
+ Package* p = package->package_value();
+ const std::string& packname(p->package_name());
error_at(location, "invalid reference to hidden type %<%s.%s%>",
Gogo::message_name(packname).c_str(),
Gogo::message_name(name).c_str());
named_object = this->gogo_->add_unknown_name(name, location);
else
{
- const std::string& packname(package->package_value()->name());
+ const std::string& packname(package->package_value()->package_name());
error_at(location, "reference to undefined identifier %<%s.%s%>",
Gogo::message_name(packname).c_str(),
Gogo::message_name(name).c_str());
else
{
this->advance_token();
- expr_list = this->expression_list(NULL, false);
+ expr_list = this->expression_list(NULL, false, true);
*last_type = type;
if (*last_expr_list != NULL)
delete *last_expr_list;
if (this->peek_token()->is_op(OPERATOR_EQ))
{
this->advance_token();
- init = this->expression_list(NULL, false);
+ init = this->expression_list(NULL, false, true);
}
}
else
{
this->advance_token();
- init = this->expression_list(NULL, false);
+ init = this->expression_list(NULL, false, true);
}
this->init_vars(&til, type, init, false, location);
// 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)
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;
}
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
// the right number of values, but it might. Declare the variables,
// and then assign the results of the call to them.
+ 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);
- this->init_var(*pv, type, init, is_coloneq, false, &any_new);
+ Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
+ &any_new, ivars, ivals);
+
+ if (this->gogo_->in_global_scope() && no->is_variable())
+ {
+ if (first_var == NULL)
+ first_var = no;
+ else
+ {
+ // The subsequent vars have an implicit dependency on
+ // the first one, so that everything gets initialized in
+ // the right order and so that we detect cycles
+ // correctly.
+ this->gogo_->record_var_depends_on(no->var_value(), first_var);
+ }
+ }
}
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
+ this->finish_init_vars(ivars, ivals, location);
+
return true;
}
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);
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)
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);
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)
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;
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();
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();
// 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;
}
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.
// In order to support both "a, b := 1, 0" and "a, b = 1, 0" we accept
// tuple assignments here as well.
+// If MAY_BE_COMPOSITE_LIT is true, the expression on the right hand
+// side may be a composite literal.
+
// If P_RANGE_CLAUSE is not NULL, then this will recognize a
// RangeClause.
void
Parse::simple_var_decl_or_assignment(const std::string& name,
Location location,
+ bool may_be_composite_lit,
Range_clause* p_range_clause,
Type_switch* p_type_switch)
{
exprs->push_back(this->id_to_expression(p->name(),
p->location()));
- Expression_list* more_exprs = this->expression_list(NULL, true);
+ Expression_list* more_exprs =
+ this->expression_list(NULL, true, may_be_composite_lit);
for (Expression_list::const_iterator p = more_exprs->begin();
p != more_exprs->end();
++p)
exprs->push_back(*p);
delete more_exprs;
- this->tuple_assignment(exprs, p_range_clause);
+ this->tuple_assignment(exprs, may_be_composite_lit, p_range_clause);
return;
}
}
Expression_list* init;
if (p_type_switch == NULL)
- init = this->expression_list(NULL, false);
+ init = this->expression_list(NULL, false, may_be_composite_lit);
else
{
bool is_type_switch = false;
- Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
+ Expression* expr = this->expression(PRECEDENCE_NORMAL, false,
+ may_be_composite_lit,
&is_type_switch);
if (is_type_switch)
{
else
{
this->advance_token();
- init = this->expression_list(expr, false);
+ init = this->expression_list(expr, false, may_be_composite_lit);
}
}
// FunctionDecl = "func" identifier Signature [ Block ] .
// MethodDecl = "func" Receiver identifier Signature [ Block ] .
-// gcc extension:
+// Deprecated gcc extension:
// FunctionDecl = "func" identifier Signature
// __asm__ "(" string_lit ")" .
// This extension means a function whose real name is the identifier
-// inside the asm.
+// inside the asm. This extension will be removed at some future
+// date. It has been replaced with //extern comments.
void
Parse::function_decl()
{
go_assert(this->peek_token()->is_keyword(KEYWORD_FUNC));
Location location = this->location();
+ std::string extern_name = this->lex_->extern_name();
const Token* token = this->advance_token();
Typed_identifier* rec = NULL;
{
if (named_object == NULL && !Gogo::is_sink_name(name))
{
- if (fntype != NULL)
- this->gogo_->declare_function(name, fntype, location);
- else
+ if (fntype == NULL)
this->gogo_->add_erroneous_name(name);
+ else
+ {
+ named_object = this->gogo_->declare_function(name, fntype,
+ location);
+ if (!extern_name.empty()
+ && named_object->is_function_declaration())
+ {
+ Function_declaration* fd =
+ named_object->func_declaration_value();
+ fd->set_asm_name(extern_name);
+ }
+ }
}
}
else
{
go_assert(package != NULL);
error_at(location, "invalid reference to hidden type %<%s.%s%>",
- Gogo::message_name(package->name()).c_str(),
+ Gogo::message_name(package->package_name()).c_str(),
Gogo::message_name(id).c_str());
return Expression::make_error(location);
}
{
if (package != NULL)
{
- std::string n1 = Gogo::message_name(package->name());
+ std::string n1 = Gogo::message_name(package->package_name());
std::string n2 = Gogo::message_name(id);
if (!is_exported)
error_at(location,
if (token->is_op(OPERATOR_LPAREN))
{
this->advance_token();
- ret = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL);
if (!this->peek_token()->is_op(OPERATOR_RPAREN))
error_at(this->location(), "missing %<)%>");
else
}
else
{
- error_at(this->location(), "expected %<,%> or %<}%>");
+ if (token->is_op(OPERATOR_SEMICOLON))
+ error_at(this->location(),
+ "need trailing comma before newline in composite literal");
+ else
+ error_at(this->location(), "expected %<,%> or %<}%>");
this->gogo_->mark_locals_used();
int depth = 0;
{
if (this->peek_token()->is_op(OPERATOR_LCURLY))
{
- if (is_parenthesized)
+ if (!may_be_composite_lit)
+ {
+ Type* t = ret->type();
+ if (t->named_type() != NULL
+ || t->forward_declaration_type() != NULL)
+ error_at(start_loc,
+ _("parentheses required around this composite literal"
+ "to avoid parsing ambiguity"));
+ }
+ else if (is_parenthesized)
error_at(start_loc,
"cannot parenthesize type in composite literal");
ret = this->composite_lit(ret->type(), 0, ret->location());
const Token* token = this->advance_token();
if (!token->is_op(OPERATOR_RPAREN))
{
- args = this->expression_list(NULL, false);
+ args = this->expression_list(NULL, false, true);
token = this->peek_token();
if (token->is_op(OPERATOR_ELLIPSIS))
{
bool* is_type_switch)
{
const Token* token = this->peek_token();
+
+ // There is a complex parse for <- chan. The choices are
+ // Convert x to type <- chan int:
+ // (<- chan int)(x)
+ // Receive from (x converted to type chan <- chan int):
+ // (<- chan <- chan int (x))
+ // Convert x to type <- chan (<- chan int).
+ // (<- chan <- chan int)(x)
+ if (token->is_op(OPERATOR_CHANOP))
+ {
+ Location location = token->location();
+ if (this->advance_token()->is_keyword(KEYWORD_CHAN))
+ {
+ Expression* expr = this->primary_expr(false, may_be_composite_lit,
+ NULL);
+ if (expr->is_error_expression())
+ return expr;
+ else if (!expr->is_type_expression())
+ return Expression::make_receive(expr, location);
+ else
+ {
+ if (expr->type()->is_error_type())
+ return expr;
+
+ // We picked up "chan TYPE", but it is not a type
+ // conversion.
+ Channel_type* ct = expr->type()->channel_type();
+ if (ct == NULL)
+ {
+ // This is probably impossible.
+ error_at(location, "expected channel type");
+ return Expression::make_error(location);
+ }
+ else if (ct->may_receive())
+ {
+ // <- chan TYPE.
+ Type* t = Type::make_channel_type(false, true,
+ ct->element_type());
+ return Expression::make_type(t, location);
+ }
+ else
+ {
+ // <- chan <- TYPE. Because we skipped the leading
+ // <-, we parsed this as chan <- TYPE. With the
+ // leading <-, we parse it as <- chan (<- TYPE).
+ Type *t = this->reassociate_chan_direction(ct, location);
+ return Expression::make_type(t, location);
+ }
+ }
+ }
+
+ this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
+ token = this->peek_token();
+ }
+
if (token->is_op(OPERATOR_PLUS)
|| token->is_op(OPERATOR_MINUS)
|| token->is_op(OPERATOR_NOT)
Operator op = token->op();
this->advance_token();
- if (op == OPERATOR_CHANOP
- && this->peek_token()->is_keyword(KEYWORD_CHAN))
- {
- // This is "<- chan" which must be the start of a type.
- this->unget_token(Token::make_operator_token(op, location));
- return Expression::make_type(this->type(), location);
- }
-
Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
if (expr->is_error_expression())
;
is_type_switch);
}
+// This is called for the obscure case of
+// (<- chan <- chan int)(x)
+// In unary_expr we remove the leading <- and parse the remainder,
+// which gives us
+// chan <- (chan int)
+// When we add the leading <- back in, we really want
+// <- chan (<- chan int)
+// This means that we need to reassociate.
+
+Type*
+Parse::reassociate_chan_direction(Channel_type *ct, Location location)
+{
+ Channel_type* ele = ct->element_type()->channel_type();
+ if (ele == NULL)
+ {
+ error_at(location, "parse error");
+ return Type::make_error_type();
+ }
+ Type* sub = ele;
+ if (ele->may_send())
+ sub = Type::make_channel_type(false, true, ele->element_type());
+ else
+ sub = this->reassociate_chan_direction(ele, location);
+ return Type::make_channel_type(false, true, sub);
+}
+
// Statement =
// Declaration | LabeledStmt | SimpleStmt |
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
{
identifier = this->gogo_->pack_hidden_name(identifier, is_exported);
this->simple_var_decl_or_assignment(identifier, location,
+ may_be_composite_lit,
p_range_clause,
(token->is_op(OPERATOR_COLONEQ)
? p_type_switch
this->inc_dec_stat(this->verify_not_sink(exp));
else if (token->is_op(OPERATOR_COMMA)
|| token->is_op(OPERATOR_EQ))
- this->assignment(exp, p_range_clause);
+ this->assignment(exp, may_be_composite_lit, p_range_clause);
else if (token->is_op(OPERATOR_PLUSEQ)
|| token->is_op(OPERATOR_MINUSEQ)
|| token->is_op(OPERATOR_OREQ)
|| token->is_op(OPERATOR_RSHIFTEQ)
|| token->is_op(OPERATOR_ANDEQ)
|| token->is_op(OPERATOR_BITCLEAREQ))
- this->assignment(this->verify_not_sink(exp), p_range_clause);
+ this->assignment(this->verify_not_sink(exp), may_be_composite_lit,
+ p_range_clause);
else if (return_exp != NULL)
return this->verify_not_sink(exp);
else
// EXP is an expression that we have already parsed.
+// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand
+// side may be a composite literal.
+
// If RANGE_CLAUSE is not NULL, then this will recognize a
// RangeClause.
void
-Parse::assignment(Expression* expr, Range_clause* p_range_clause)
+Parse::assignment(Expression* expr, bool may_be_composite_lit,
+ Range_clause* p_range_clause)
{
Expression_list* vars;
if (!this->peek_token()->is_op(OPERATOR_COMMA))
else
{
this->advance_token();
- vars = this->expression_list(expr, true);
+ vars = this->expression_list(expr, true, may_be_composite_lit);
}
- this->tuple_assignment(vars, p_range_clause);
+ this->tuple_assignment(vars, may_be_composite_lit, p_range_clause);
}
// An assignment statement. LHS is the list of expressions which
// appear on the left hand side.
+// If MAY_BE_COMPOSITE_LIT is true, an expression on the right hand
+// side may be a composite literal.
+
// If RANGE_CLAUSE is not NULL, then this will recognize a
// RangeClause.
void
-Parse::tuple_assignment(Expression_list* lhs, Range_clause* p_range_clause)
+Parse::tuple_assignment(Expression_list* lhs, bool may_be_composite_lit,
+ Range_clause* p_range_clause)
{
const Token* token = this->peek_token();
if (!token->is_op(OPERATOR_EQ)
return;
}
- Expression_list* vals = this->expression_list(NULL, false);
+ Expression_list* vals = this->expression_list(NULL, false,
+ may_be_composite_lit);
// We've parsed everything; check for errors.
if (lhs == NULL || vals == NULL)
this->advance_token();
Expression_list* vals = NULL;
if (this->expression_may_start_here())
- vals = this->expression_list(NULL, false);
+ vals = this->expression_list(NULL, false, true);
this->gogo_->add_statement(Statement::make_return_statement(vals, location));
if (vals == NULL
++p)
{
Named_object* no = this->gogo_->lookup((*p)->name(), NULL);
- go_assert(no != NULL);
- if (!no->is_result_variable())
+ if (no == NULL)
+ go_assert(saw_errors());
+ else if (!no->is_result_variable())
error_at(location, "%qs is shadowed during return",
(*p)->message_name().c_str());
}
bool saw_simple_stat = false;
Expression* cond = NULL;
- bool saw_send_stmt;
+ bool saw_send_stmt = false;
if (this->simple_stat_may_start_here())
{
cond = this->simple_stat(false, &saw_send_stmt, NULL, NULL);
Expression* switch_val = NULL;
bool saw_send_stmt;
Type_switch type_switch;
+ bool have_type_switch_block = false;
if (this->simple_stat_may_start_here())
{
switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
id_loc));
if (is_coloneq)
{
- // This must be a TypeSwitchGuard.
+ // This must be a TypeSwitchGuard. It is in a
+ // different block from any initial SimpleStat.
+ if (saw_simple_stat)
+ {
+ this->gogo_->start_block(id_loc);
+ have_type_switch_block = true;
+ }
+
switch_val = this->simple_stat(false, &saw_send_stmt, NULL,
&type_switch);
if (!type_switch.found)
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
this->advance_token();
if (!this->peek_token()->is_op(OPERATOR_LCURLY))
- return;
+ {
+ if (have_type_switch_block)
+ this->gogo_->add_block(this->gogo_->finish_block(location),
+ location);
+ this->gogo_->add_block(this->gogo_->finish_block(location),
+ location);
+ return;
+ }
if (type_switch.found)
type_switch.expr = Expression::make_error(location);
}
else
{
error_at(this->location(), "expected %<{%>");
+ if (have_type_switch_block)
+ this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+ location);
this->gogo_->add_block(this->gogo_->finish_block(this->location()),
location);
return;
if (statement != NULL)
this->gogo_->add_statement(statement);
+ if (have_type_switch_block)
+ this->gogo_->add_block(this->gogo_->finish_block(this->location()),
+ location);
+
this->gogo_->add_block(this->gogo_->finish_block(this->location()),
location);
}
if (token->is_keyword(KEYWORD_CASE))
{
this->advance_token();
- return this->expression_list(NULL, false);
+ return this->expression_list(NULL, false, true);
}
else if (token->is_keyword(KEYWORD_DEFAULT))
{
Named_object* switch_no = NULL;
if (!type_switch.name.empty())
{
- Variable* switch_var = new Variable(NULL, type_switch.expr, false, false,
- false, type_switch.location);
- switch_no = this->gogo_->add_variable(type_switch.name, switch_var);
+ if (Gogo::is_sink_name(type_switch.name))
+ error_at(type_switch.location,
+ "no new variables on left side of %<:=%>");
+ else
+ {
+ Variable* switch_var = new Variable(NULL, type_switch.expr, false,
+ false, false,
+ type_switch.location);
+ switch_no = this->gogo_->add_variable(type_switch.name, switch_var);
+ }
}
Type_switch_statement* statement =
if (token->is_op(OPERATOR_COLONEQ))
{
// case rv := <-c:
- if (!this->advance_token()->is_op(OPERATOR_CHANOP))
+ this->advance_token();
+ Expression* e = this->expression(PRECEDENCE_NORMAL, false, false,
+ NULL);
+ Receive_expression* re = e->receive_expression();
+ if (re == NULL)
{
- error_at(this->location(), "expected %<<-%>");
+ if (!e->is_error_expression())
+ error_at(this->location(), "expected receive expression");
return false;
}
if (recv_var == "_")
}
*is_send = false;
*varname = gogo->pack_hidden_name(recv_var, is_rv_exported);
- this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
+ *channel = re->channel();
return true;
}
else if (token->is_op(OPERATOR_COMMA))
if (token->is_op(OPERATOR_COLONEQ))
{
// case rv, rc := <-c:
- if (!this->advance_token()->is_op(OPERATOR_CHANOP))
+ this->advance_token();
+ Expression* e = this->expression(PRECEDENCE_NORMAL, false,
+ false, NULL);
+ Receive_expression* re = e->receive_expression();
+ if (re == NULL)
{
- error_at(this->location(), "expected %<<-%>");
+ if (!e->is_error_expression())
+ error_at(this->location(),
+ "expected receive expression");
return false;
}
if (recv_var == "_" && recv_closed == "_")
if (recv_closed != "_")
*closedname = gogo->pack_hidden_name(recv_closed,
is_rc_exported);
- this->advance_token();
- *channel = this->expression(PRECEDENCE_NORMAL, false, true,
- NULL);
+ *channel = re->channel();
return true;
}
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);
{
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)
if (!token->is_string())
{
- error_at(this->location(), "missing import package name");
+ error_at(this->location(), "import statement not a string");
+ this->advance_token();
return;
}