diff options
author | Ian Lance Taylor <iant@golang.org> | 2023-10-19 19:34:31 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2023-12-18 17:30:56 -0800 |
commit | c20328e7cad2989bcdc9ff5003d6a16405c31ab5 (patch) | |
tree | 837db6d6d15e763947916017b122788e30ea1e59 /gcc/go/gofrontend/statements.cc | |
parent | 15cb5204e4c5f79d1b7179ae2590bb65e24b745f (diff) | |
download | gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.zip gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.gz gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.bz2 |
compiler: move lowering pass after check types pass
This change moves the lowering pass after the type determination and
the type checking passes. This lets us simplify some of the code that
determines the type of an expression, which previously had to work
correctly both before and after type determination.
I'm doing this to help with future generic support. For example, with
generics, we can see code like
func ident[T any](v T) T { return v }
func F() int32 {
s := int32(1)
return ident(s)
}
Before this change, we would type check return statements in the
lowering pass (see Return_statement::do_lower). With a generic
example like the above, that means we have to determine the type of s,
and use that to infer the type arguments passed to ident, and use that
to determine the result type of ident. That is too much to do at
lowering time. Of course we can change the way that return statements
work, but similar issues arise with index expressions, the types of
closures for function literals, and probably other cases as well.
Rather than try to deal with all those cases, we move the lowering
pass after type checking. This requires a bunch of changes, notably
for determining constant types. We have to add type checking for
various constructs that formerly disappeared in the lowering pass.
So it's a lot of shuffling. Sorry for the size of the patch.
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536643
Diffstat (limited to 'gcc/go/gofrontend/statements.cc')
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 1198 |
1 files changed, 893 insertions, 305 deletions
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 5d652a1..e9675eb 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -134,7 +134,7 @@ Statement::import_statement(Import_function_body* ifb, Location loc) // After lowering return statements have no expressions. The // return expressions are assigned to result parameters. ifb->advance(6); - return Statement::make_return_statement(NULL, loc); + return Statement::make_return_statement(ifb->function(), NULL, loc); } else if (ifb->match_c_string("var $t")) return Temporary_statement::do_import(ifb, loc); @@ -278,6 +278,12 @@ Variable_declaration_statement::do_traverse(Traverse*) return TRAVERSE_CONTINUE; } +void +Variable_declaration_statement::do_determine_types(Gogo* gogo) +{ + this->var_->var_value()->determine_type(gogo); +} + // Lower the variable's initialization expression. Statement* @@ -327,6 +333,8 @@ Variable_declaration_statement::do_add_conversions() Bstatement* Variable_declaration_statement::do_get_backend(Translate_context* context) { + if (this->var_->is_redefinition()) + return context->backend()->error_statement(); Bfunction* bfunction = context->function()->func_value()->get_decl(); Variable* var = this->var_->var_value(); Bvariable* bvar = this->var_->get_backend_variable(context->gogo(), @@ -969,7 +977,9 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED, loc); ref = Expression::make_temporary_reference(val_temp, loc); - b->add_statement(Statement::make_assignment(indir, ref, loc)); + Statement* s = Statement::make_assignment(indir, ref, loc); + s->determine_types(gogo); + b->add_statement(s); return Statement::make_block_statement(b, loc); } @@ -1017,45 +1027,59 @@ Assignment_statement::do_determine_types(Gogo* gogo) this->rhs_->determine_type(gogo, &context); } -// Check types for an assignment. +// Check types for an assignment from RHS to LHS. Returns true if the +// assignment is OK. -void -Assignment_statement::do_check_types(Gogo*) +bool +Assignment_statement::check_assignment_types(Expression* lhs, + Type* rhs_type, + Location loc) { // The left hand side must be either addressable, a map index // expression, or the blank identifier. - if (!this->lhs_->is_addressable() - && this->lhs_->map_index_expression() == NULL - && !this->lhs_->is_sink_expression()) + if (!lhs->is_addressable() + && !Index_expression::is_map_index(lhs) + && !lhs->is_sink_expression()) { - if (!this->lhs_->type()->is_error()) - this->report_error(_("invalid left hand side of assignment")); - return; + if (!lhs->type()->is_error()) + go_error_at(lhs->location(), "invalid left hand side of assignment"); + return false; } - Type* lhs_type = this->lhs_->type(); - Type* rhs_type = this->rhs_->type(); + Type* lhs_type = lhs->type(); - // Invalid assignment of nil to the blank identifier. - if (lhs_type->is_sink_type() - && rhs_type->is_nil_type()) + // Check for invalid assignment of nil to the blank identifier. + if (lhs_type->is_sink_type() && rhs_type->is_nil_type()) { - this->report_error(_("use of untyped nil")); - return; + go_error_at(loc, "use of untyped nil"); + return false; } std::string reason; if (!Type::are_assignable(lhs_type, rhs_type, &reason)) { if (reason.empty()) - go_error_at(this->location(), "incompatible types in assignment"); + go_error_at(loc, "incompatible types in assignment"); else - go_error_at(this->location(), "incompatible types in assignment (%s)", + go_error_at(loc, "incompatible types in assignment (%s)", reason.c_str()); - this->set_is_error(); + return false; } - if (lhs_type->is_error() || rhs_type->is_error()) + if (lhs_type->is_error_type() || rhs_type->is_error_type()) + return false; + + return true; +} + +// Check types for an assignment. + +void +Assignment_statement::do_check_types(Gogo*) +{ + if (!Assignment_statement::check_assignment_types(this->lhs_, + this->rhs_->type(), + this->location())) this->set_is_error(); } @@ -1173,6 +1197,12 @@ class Assignment_operation_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1184,6 +1214,9 @@ class Assignment_operation_statement : public Statement do_dump_statement(Ast_dump_context*) const; private: + Operator + get_binop(); + // The operator (OPERATOR_PLUSEQ, etc.). Operator op_; // Left hand side. @@ -1202,11 +1235,137 @@ Assignment_operation_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->rhs_); } +void +Assignment_operation_statement::do_determine_types(Gogo* gogo) +{ + this->lhs_->determine_type_no_context(gogo); + Type* rhs_context_type = this->lhs_->type(); + if (rhs_context_type->is_sink_type()) + rhs_context_type = NULL; + Type_context context(rhs_context_type, false); + this->rhs_->determine_type(gogo, &context); +} + +// Get the binary operator from the assignment operator. + +Operator +Assignment_operation_statement::get_binop() +{ + switch (this->op_) + { + case OPERATOR_PLUSEQ: + return OPERATOR_PLUS; + case OPERATOR_MINUSEQ: + return OPERATOR_MINUS; + case OPERATOR_OREQ: + return OPERATOR_OR; + case OPERATOR_XOREQ: + return OPERATOR_XOR; + case OPERATOR_MULTEQ: + return OPERATOR_MULT; + case OPERATOR_DIVEQ: + return OPERATOR_DIV; + case OPERATOR_MODEQ: + return OPERATOR_MOD; + case OPERATOR_LSHIFTEQ: + return OPERATOR_LSHIFT; + case OPERATOR_RSHIFTEQ: + return OPERATOR_RSHIFT; + case OPERATOR_ANDEQ: + return OPERATOR_AND; + case OPERATOR_BITCLEAREQ: + return OPERATOR_BITCLEAR; + default: + go_unreachable(); + } +} + +void +Assignment_operation_statement::do_check_types(Gogo*) +{ + if (this->lhs_->is_sink_expression()) + { + this->report_error(_("cannot use %<_%> as value")); + return; + } + + + Type* lhs_type = this->lhs_->type(); + Type* rhs_type = this->rhs_->type(); + + if (!this->lhs_->is_addressable() + && !Index_expression::is_map_index(this->lhs_)) + { + if (!lhs_type->is_error()) + this->report_error(_("invalid left hand side of assignment")); + this->set_is_error(); + return; + } + + if (this->op_ != OPERATOR_LSHIFTEQ && this->op_ != OPERATOR_RSHIFTEQ) + { + if (!Type::are_compatible_for_binop(lhs_type, rhs_type)) + { + this->report_error(_("incompatible type in binary expression")); + return; + } + if (!Binary_expression::check_operator_type(this->get_binop(), lhs_type, + rhs_type, this->location())) + { + this->set_is_error(); + return; + } + if (this->op_ == OPERATOR_DIVEQ || this->op_ == OPERATOR_MODEQ) + { + Numeric_constant rconst; + unsigned long rval; + if (lhs_type->integer_type() != NULL + && this->rhs_->numeric_constant_value(&rconst) + && rconst.to_unsigned_long(&rval) == Numeric_constant::NC_UL_VALID + && rval == 0) + { + this->report_error(_("integer division by zero")); + return; + } + } + } + else + { + if (lhs_type->integer_type() == NULL) + { + this->report_error(_("shift of non-integer operand")); + return; + } + + if (rhs_type->is_string_type() + || (!rhs_type->is_abstract() + && rhs_type->integer_type() == NULL)) + { + this->report_error(_("shift count not integer")); + return; + } + + Numeric_constant nc; + if (this->rhs_->numeric_constant_value(&nc)) + { + mpz_t val; + if (!nc.to_int(&val)) + { + this->report_error(_("shift count not integer")); + return; + } + if (mpz_sgn(val) < 0) + this->report_error(_("negative shift count")); + mpz_clear(val); + } + } +} + // Lower an assignment operation statement to a regular assignment // statement. Statement* -Assignment_operation_statement::do_lower(Gogo*, Named_object*, +Assignment_operation_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { Location loc = this->location(); @@ -1229,48 +1388,10 @@ Assignment_operation_statement::do_lower(Gogo*, Named_object*, Expression* lval = this->lhs_->copy(); - Operator op; - switch (this->op_) - { - case OPERATOR_PLUSEQ: - op = OPERATOR_PLUS; - break; - case OPERATOR_MINUSEQ: - op = OPERATOR_MINUS; - break; - case OPERATOR_OREQ: - op = OPERATOR_OR; - break; - case OPERATOR_XOREQ: - op = OPERATOR_XOR; - break; - case OPERATOR_MULTEQ: - op = OPERATOR_MULT; - break; - case OPERATOR_DIVEQ: - op = OPERATOR_DIV; - break; - case OPERATOR_MODEQ: - op = OPERATOR_MOD; - break; - case OPERATOR_LSHIFTEQ: - op = OPERATOR_LSHIFT; - break; - case OPERATOR_RSHIFTEQ: - op = OPERATOR_RSHIFT; - break; - case OPERATOR_ANDEQ: - op = OPERATOR_AND; - break; - case OPERATOR_BITCLEAREQ: - op = OPERATOR_BITCLEAR; - break; - default: - go_unreachable(); - } - - Expression* binop = Expression::make_binary(op, lval, this->rhs_, loc); + Expression* binop = Expression::make_binary(this->get_binop(), lval, + this->rhs_, loc); Statement* s = Statement::make_assignment(this->lhs_, binop, loc); + s->determine_types(gogo); if (b->statements()->empty()) { delete b; @@ -1322,6 +1443,12 @@ class Tuple_assignment_statement : public Statement int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1349,15 +1476,53 @@ Tuple_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression_list(traverse, this->rhs_); } +void +Tuple_assignment_statement::do_determine_types(Gogo* gogo) +{ + Expression_list::iterator pr = this->rhs_->begin(); + for (Expression_list::iterator pl = this->lhs_->begin(); + pl != this->lhs_->end(); + ++pl, ++pr) + { + go_assert(pr != this->rhs_->end()); + (*pl)->determine_type_no_context(gogo); + Type* rhs_context_type = (*pl)->type(); + if (rhs_context_type->is_sink_type()) + rhs_context_type = NULL; + Type_context context(rhs_context_type, false); + (*pr)->determine_type(gogo, &context); + } + go_assert(pr == this->rhs_->end()); +} + +void +Tuple_assignment_statement::do_check_types(Gogo*) +{ + Expression_list::iterator pr = this->rhs_->begin(); + for (Expression_list::iterator pl = this->lhs_->begin(); + pl != this->lhs_->end(); + ++pl, ++pr) + { + go_assert(pr != this->rhs_->end()); + if (!Assignment_statement::check_assignment_types(*pl, (*pr)->type(), + this->location())) + this->set_is_error(); + } + go_assert(pr == this->rhs_->end()); +} + // Lower a tuple assignment. We use temporary variables to split it // up into a set of single assignments. Statement* -Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, - Statement_inserter*) +Tuple_assignment_statement::do_lower(Gogo* gogo, Named_object*, + Block* enclosing, Statement_inserter*) { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Block* b = new Block(enclosing, loc); // First move out any subexpressions on the left hand side. The @@ -1417,7 +1582,9 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, continue; Expression* ref = Expression::make_temporary_reference(*ptemp, loc); - b->add_statement(Statement::make_assignment(*plhs, ref, loc)); + Statement* s = Statement::make_assignment(*plhs, ref, loc); + s->determine_types(gogo); + b->add_statement(s); ++ptemp; } go_assert(ptemp == temps.end() || saw_errors()); @@ -1464,6 +1631,12 @@ public: int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1494,6 +1667,45 @@ Tuple_map_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->map_index_); } +void +Tuple_map_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->present_->determine_type_no_context(gogo); + this->map_index_->determine_type_no_context(gogo); +} + +void +Tuple_map_assignment_statement::do_check_types(Gogo*) +{ + Expression* map_expr = this->map_index_; + Map_type* map_type; + if (map_expr->map_index_expression() != NULL) + map_type = map_expr->map_index_expression()->get_map_type(); + else if (map_expr->index_expression() != NULL) + map_type = map_expr->index_expression()->left()->type()->map_type(); + else + { + this->report_error(_("expected map index on right hand side")); + return; + } + if (map_type == NULL || map_type->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, + map_type->val_type(), + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->present_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower a tuple map assignment. Statement* @@ -1502,15 +1714,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Map_index_expression* map_index = this->map_index_->map_index_expression(); - if (map_index == NULL) - { - this->report_error(_("expected map index on right hand side")); - return Statement::make_error_statement(loc); - } + go_assert(map_index != NULL); Map_type* map_type = map_index->get_map_type(); - if (map_type == NULL) - return Statement::make_error_statement(loc); + go_assert(map_type != NULL); // Avoid copy for string([]byte) conversions used in map keys. // mapaccess doesn't keep the reference, so this is safe. @@ -1607,11 +1817,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* res = Expression::make_call_result(call, 0); res = Expression::make_unsafe_cast(val_ptr_type, res, loc); Statement* s = Statement::make_assignment(ref, res, loc); + s->determine_types(gogo); b->add_statement(s); ref = Expression::make_temporary_reference(present_temp, loc); ref->set_is_lvalue(); res = Expression::make_call_result(call, 1); s = Statement::make_assignment(ref, res, loc); + s->determine_types(gogo); b->add_statement(s); // val = *val__ptr_temp @@ -1619,11 +1831,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* ind = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc); s = Statement::make_assignment(this->val_, ind, loc); + s->determine_types(gogo); b->add_statement(s); // present = present_temp ref = Expression::make_temporary_reference(present_temp, loc); s = Statement::make_assignment(this->present_, ref, loc); + s->determine_types(gogo); b->add_statement(s); return Statement::make_block_statement(b, loc); @@ -1669,6 +1883,12 @@ class Tuple_receive_assignment_statement : public Statement int do_traverse(Traverse* traverse); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1699,6 +1919,39 @@ Tuple_receive_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->channel_); } +void +Tuple_receive_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->closed_->determine_type_no_context(gogo); + this->channel_->determine_type_no_context(gogo); +} + +void +Tuple_receive_assignment_statement::do_check_types(Gogo*) +{ + Channel_type* ct = this->channel_->type()->channel_type(); + if (ct == NULL) + { + this->report_error(_("expected channel")); + return; + } + if (!ct->may_receive()) + { + this->report_error(_("invalid receive on send-only channel")); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, + ct->element_type(), + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->closed_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower to a function call. Statement* @@ -1708,17 +1961,11 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Channel_type* channel_type = this->channel_->type()->channel_type(); - if (channel_type == NULL) - { - this->report_error(_("expected channel")); - return Statement::make_error_statement(loc); - } - if (!channel_type->may_receive()) - { - this->report_error(_("invalid receive on send-only channel")); - return Statement::make_error_statement(loc); - } + go_assert(channel_type != NULL && channel_type->may_receive()); Block* b = new Block(enclosing, loc); @@ -1750,16 +1997,19 @@ Tuple_receive_assignment_statement::do_lower(Gogo* gogo, Named_object*, ref = Expression::make_temporary_reference(closed_temp, loc); ref->set_is_lvalue(); Statement* s = Statement::make_assignment(ref, call, loc); + s->determine_types(gogo); b->add_statement(s); // val = val_temp ref = Expression::make_temporary_reference(val_temp, loc); s = Statement::make_assignment(this->val_, ref, loc); + s->determine_types(gogo); b->add_statement(s); // closed = closed_temp ref = Expression::make_temporary_reference(closed_temp, loc); s = Statement::make_assignment(this->closed_, ref, loc); + s->determine_types(gogo); b->add_statement(s); return Statement::make_block_statement(b, loc); @@ -1808,6 +2058,12 @@ class Tuple_type_guard_assignment_statement : public Statement int do_traverse(Traverse*); + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -1847,6 +2103,34 @@ Tuple_type_guard_assignment_statement::do_traverse(Traverse* traverse) return this->traverse_expression(traverse, &this->expr_); } +void +Tuple_type_guard_assignment_statement::do_determine_types(Gogo* gogo) +{ + this->val_->determine_type_no_context(gogo); + this->ok_->determine_type_no_context(gogo); + this->expr_->determine_type_no_context(gogo); +} + +void +Tuple_type_guard_assignment_statement::do_check_types(Gogo*) +{ + Type* expr_type = this->expr_->type(); + if (expr_type->interface_type() == NULL) + { + if (!expr_type->is_error() && !this->type_->is_error()) + this->report_error(_("type assertion only valid for interface types")); + return; + } + + if (!Assignment_statement::check_assignment_types(this->val_, this->type_, + this->location())) + this->set_is_error(); + if (!Assignment_statement::check_assignment_types(this->ok_, + Type::make_boolean_type(), + this->location())) + this->set_is_error(); +} + // Lower to a function call. Statement* @@ -1856,13 +2140,11 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*, { Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + Type* expr_type = this->expr_->type(); - if (expr_type->interface_type() == NULL) - { - if (!expr_type->is_error() && !this->type_->is_error()) - this->report_error(_("type assertion only valid for interface types")); - return Statement::make_error_statement(loc); - } + go_assert(expr_type->interface_type() != NULL); Block* b = new Block(enclosing, loc); @@ -1907,12 +2189,14 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo* gogo, Named_object*, Expression* res = Expression::make_call_result(call, 0); res = Expression::make_unsafe_cast(this->type_, res, loc); Statement* s = Statement::make_assignment(this->val_, res, loc); + s->determine_types(gogo); b->add_statement(s); res = Expression::make_call_result(call, 1); if (!this->ok_->type()->is_boolean_type()) res = Expression::make_cast(Type::lookup_bool_type(), res, loc); s = Statement::make_assignment(this->ok_, res, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -1971,11 +2255,13 @@ Tuple_type_guard_assignment_statement::lower_to_object_type( Expression* ok_ref = Expression::make_temporary_reference(ok_temp, loc); s = Statement::make_assignment(ok_ref, call, loc); } + s->determine_types(gogo); b->add_statement(s); // val = val_temp ref = Expression::make_temporary_reference(val_temp, loc); s = Statement::make_assignment(this->val_, ref, loc); + s->determine_types(gogo); b->add_statement(s); // ok = ok_temp @@ -1983,6 +2269,7 @@ Tuple_type_guard_assignment_statement::lower_to_object_type( { ref = Expression::make_temporary_reference(ok_temp, loc); s = Statement::make_assignment(this->ok_, ref, loc); + s->determine_types(gogo); b->add_statement(s); } } @@ -2050,35 +2337,12 @@ Expression_statement::do_check_types(Gogo*) bool Expression_statement::do_may_fall_through() const { + // The builtin function panic does not return. const Call_expression* call = this->expr_->call_expression(); - if (call != NULL) - { - const Expression* fn = call->fn(); - // panic is still an unknown named object. - const Unknown_expression* ue = fn->unknown_expression(); - if (ue != NULL) - { - Named_object* no = ue->named_object(); - - if (no->is_unknown()) - no = no->unknown_value()->real_named_object(); - if (no != NULL) - { - Function_type* fntype; - if (no->is_function()) - fntype = no->func_value()->type(); - else if (no->is_function_declaration()) - fntype = no->func_declaration_value()->type(); - else - fntype = NULL; - - // The builtin function panic does not return. - if (fntype != NULL && fntype->is_builtin() && no->name() == "panic") - return false; - } - } - } - return true; + if (call == NULL) + return true; + const Builtin_call_expression* bce = call->builtin_call_expression(); + return bce == NULL || bce->code() != Builtin_call_expression::BUILTIN_PANIC; } // Export an expression statement. @@ -2225,6 +2489,12 @@ class Inc_dec_statement : public Statement do_traverse(Traverse* traverse) { return this->traverse_expression(traverse, &this->expr_); } + void + do_determine_types(Gogo*); + + void + do_check_types(Gogo*); + Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); @@ -2242,17 +2512,36 @@ class Inc_dec_statement : public Statement bool is_inc_; }; +void +Inc_dec_statement::do_determine_types(Gogo* gogo) +{ + this->expr_->determine_type_no_context(gogo); +} + +void +Inc_dec_statement::do_check_types(Gogo*) +{ + if (!this->expr_->is_addressable() + && !Index_expression::is_map_index(this->expr_)) + { + if (!this->expr_->type()->is_error()) + this->report_error(_("invalid left hand side of assignment")); + this->set_is_error(); + return; + } + if (!this->expr_->type()->is_numeric_type()) + { + this->report_error(_("increment or decrement of non-numeric type")); + return; + } +} + // Lower to += or -=. Statement* Inc_dec_statement::do_lower(Gogo*, Named_object*, Block*, Statement_inserter*) { Location loc = this->location(); - if (!this->expr_->type()->is_numeric_type()) - { - this->report_error("increment or decrement of non-numeric type"); - return Statement::make_error_statement(loc); - } Expression* oexpr = Expression::make_integer_ul(1, this->expr_->type(), loc); Operator op = this->is_inc_ ? OPERATOR_PLUSEQ : OPERATOR_MINUSEQ; return Statement::make_assignment_operation(op, this->expr_, oexpr, loc); @@ -2370,12 +2659,16 @@ void Thunk_statement::do_check_types(Gogo*) { if (!this->call_->discarding_value()) - return; + { + this->set_is_error(); + return; + } Call_expression* ce = this->call_->call_expression(); if (ce == NULL) { if (!this->call_->is_error_expression()) this->report_error("expected call expression"); + this->set_is_error(); return; } } @@ -2888,6 +3181,7 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Statement* call_statement = Statement::make_statement(call, true); + call_statement->determine_types(gogo); gogo->add_statement(call_statement); // If this is a defer statement, the label comes immediately after @@ -2898,7 +3192,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, Expression_list* vals = new Expression_list(); vals->push_back(Expression::make_boolean(false, location)); - gogo->add_statement(Statement::make_return_statement(vals, location)); + Statement* s = Statement::make_return_statement(function, vals, + location); + s->determine_types(gogo); + gogo->add_statement(s); } Block* b = gogo->finish_block(location); @@ -2983,6 +3280,7 @@ Go_statement::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Expression* call = Runtime::make_call(gogo, Runtime::GO, this->location(), 2, fn, arg); + call->determine_type_no_context(gogo); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); return context->backend()->expression_statement(bfunction, bcall); @@ -3024,7 +3322,7 @@ Defer_statement::do_get_backend(Translate_context* context) Expression* call; if (this->on_stack_) { - if (context->gogo()->debug_optimization()) + if (gogo->debug_optimization()) go_debug(loc, "stack allocated defer"); Type* defer_type = Defer_statement::defer_struct_type(); @@ -3037,6 +3335,7 @@ Defer_statement::do_get_backend(Translate_context* context) else call = Runtime::make_call(gogo, Runtime::DEFERPROC, loc, 3, ds, fn, arg); + call->determine_type_no_context(gogo); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); return context->backend()->expression_statement(bfunction, bcall); @@ -3082,80 +3381,97 @@ Statement::make_defer_statement(Call_expression* call, // Class Return_statement. -// Lower a return statement. If we are returning a function call -// which returns multiple values which match the current function, -// split up the call's results. If the return statement lists -// explicit values, implement this statement by assigning the values -// to the result variables and change this statement to a naked -// return. This lets panic/recover work correctly. - -Statement* -Return_statement::do_lower(Gogo* gogo, Named_object* function, - Block* enclosing, Statement_inserter*) +void +Return_statement::do_determine_types(Gogo* gogo) { - if (this->is_lowered_) - return this; + if (this->types_are_determined_) + return; + this->types_are_determined_ = true; - Expression_list* vals = this->vals_; - this->vals_ = NULL; - this->is_lowered_ = true; + size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size(); + if (vals_count == 0) + return; - Location loc = this->location(); + Function::Results* results = + this->function_->func_value()->result_variables(); + size_t results_count = results == NULL ? 0 : results->size(); - size_t vals_count = vals == NULL ? 0 : vals->size(); - Function::Results* results = function->func_value()->result_variables(); + // If the current function has multiple return values, and we are + // returning a single call expression, split up the call expression. + if (results_count > 1 + && vals_count == 1 + && this->vals_->front()->call_expression() != NULL) + { + Call_expression* call = this->vals_->front()->call_expression(); + call->set_expected_result_count(results_count); + call->determine_type_no_context(gogo); + delete this->vals_; + this->vals_ = new Expression_list(); + for (size_t i = 0; i < results_count; ++i) + this->vals_->push_back(Expression::make_call_result(call, i)); + vals_count = results_count; + } + + if (vals_count != results_count) + { + // This is an error which we will report later. Determine all + // types to avoid knockon errors. + for (Expression_list::const_iterator pe = this->vals_->begin(); + pe != this->vals_->end(); + ++pe) + (*pe)->determine_type_no_context(gogo); + return; + } + + Expression_list::const_iterator pe = this->vals_->begin(); + for (Function::Results::const_iterator pr = results->begin(); + pr != results->end(); + ++pr, ++pe) + { + Type* rvtype = (*pr)->result_var_value()->type(); + Type_context context(rvtype, false); + (*pe)->determine_type(gogo, &context); + } +} + +void +Return_statement::do_check_types(Gogo*) +{ + size_t vals_count = this->vals_ == NULL ? 0 : this->vals_->size(); + Function::Results* results = + this->function_->func_value()->result_variables(); size_t results_count = results == NULL ? 0 : results->size(); if (vals_count == 0) { - if (results_count > 0 && !function->func_value()->results_are_named()) - { - this->report_error(_("not enough arguments to return")); - return this; - } - return this; + if (results_count > 0 + && !this->function_->func_value()->results_are_named()) + this->report_error(_("not enough arguments to return")); + return; } if (results_count == 0) { this->report_error(_("return with value in function " "with no return type")); - return this; - } - - // If the current function has multiple return values, and we are - // returning a single call expression, split up the call expression. - if (results_count > 1 - && vals->size() == 1 - && vals->front()->call_expression() != NULL) - { - Call_expression* call = vals->front()->call_expression(); - call->set_expected_result_count(results_count); - delete vals; - vals = new Expression_list; - for (size_t i = 0; i < results_count; ++i) - vals->push_back(Expression::make_call_result(call, i)); - vals_count = results_count; + delete this->vals_; + this->vals_ = NULL; + return; } if (vals_count < results_count) { this->report_error(_("not enough arguments to return")); - return this; + return; } if (vals_count > results_count) { this->report_error(_("too many values in return statement")); - return this; + return; } - Block* b = new Block(enclosing, loc); - - Expression_list* lhs = new Expression_list(); - Expression_list* rhs = new Expression_list(); - - Expression_list::const_iterator pe = vals->begin(); + Expression_list::const_iterator pe = this->vals_->begin(); int i = 1; for (Function::Results::const_iterator pr = results->begin(); pr != results->end(); @@ -3164,22 +3480,9 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function, Named_object* rv = *pr; Expression* e = *pe; - // Check types now so that we give a good error message. The - // result type is known. We determine the expression type - // early. - - Type *rvtype = rv->result_var_value()->type(); - Type_context type_context(rvtype, false); - e->determine_type(gogo, &type_context); - std::string reason; - if (Type::are_assignable(rvtype, e->type(), &reason)) - { - Expression* ve = Expression::make_var_reference(rv, e->location()); - lhs->push_back(ve); - rhs->push_back(e); - } - else + if (!Type::are_assignable(rv->result_var_value()->type(), e->type(), + &reason)) { if (reason.empty()) go_error_at(e->location(), @@ -3188,21 +3491,77 @@ Return_statement::do_lower(Gogo* gogo, Named_object* function, go_error_at(e->location(), "incompatible type for return value %d (%s)", i, reason.c_str()); + this->set_is_error(); } } - go_assert(lhs->size() == rhs->size()); +} + +// Lower a return statement. If we are returning a function call +// which returns multiple values which match the current function, +// split up the call's results. If the return statement lists +// explicit values, implement this statement by assigning the values +// to the result variables and change this statement to a naked +// return. This lets panic/recover work correctly. + +Statement* +Return_statement::do_lower(Gogo* gogo, Named_object*, + Block* enclosing, Statement_inserter*) +{ + Location loc = this->location(); + + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + + if (this->is_lowered_) + return this; + + Expression_list* vals = this->vals_; + this->vals_ = NULL; + this->is_lowered_ = true; + + size_t vals_count = vals == NULL ? 0 : vals->size(); + + if (vals_count == 0) + return this; + + Function::Results* results = + this->function_->func_value()->result_variables(); + size_t results_count = results == NULL ? 0 : results->size(); + + go_assert(vals_count == results_count); + + Block* b = new Block(enclosing, loc); + + Expression_list* lhs = new Expression_list(); + Expression_list* rhs = new Expression_list(); + + Expression_list::const_iterator pe = vals->begin(); + for (Function::Results::const_iterator pr = results->begin(); + pr != results->end(); + ++pr, ++pe) + { + Named_object* rv = *pr; + Expression* e = *pe; + Expression* ve = Expression::make_var_reference(rv, e->location()); + lhs->push_back(ve); + rhs->push_back(e); + } - if (lhs->empty()) - ; - else if (lhs->size() == 1) + if (lhs->size() == 1) { - b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(), - loc)); + Statement* s = Statement::make_assignment(lhs->front(), rhs->front(), + loc); + s->determine_types(gogo); + b->add_statement(s); delete lhs; delete rhs; } else - b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc)); + { + Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc); + s->determine_types(gogo); + b->add_statement(s); + } b->add_statement(this); @@ -3261,16 +3620,17 @@ Return_statement::do_dump_statement(Ast_dump_context* ast_dump_context) const // Make a return statement. Return_statement* -Statement::make_return_statement(Expression_list* vals, +Statement::make_return_statement(Named_object* function, Expression_list* vals, Location location) { - return new Return_statement(vals, location); + return new Return_statement(function, vals, location); } // Make a statement that returns the result of a call expression. Statement* -Statement::make_return_from_call(Call_expression* call, Location location) +Statement::make_return_from_call(Named_object* function, Call_expression* call, + Location location) { size_t rc = call->result_count(); if (rc == 0) @@ -3285,7 +3645,7 @@ Statement::make_return_from_call(Call_expression* call, Location location) for (size_t i = 0; i < rc; ++i) vals->push_back(Expression::make_call_result(call, i)); } - return Statement::make_return_statement(vals, location); + return Statement::make_return_statement(function, vals, location); } } @@ -3942,7 +4302,8 @@ Case_clauses::Case_clause::is_constant() const // test. We branch to FINISH_LABEL at the end of the statements. void -Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp, +Case_clauses::Case_clause::lower(Gogo* gogo, Block* b, + Temporary_statement* val_temp, Unnamed_label* start_label, Unnamed_label* finish_label) const { @@ -3980,6 +4341,7 @@ Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp, // if !COND { goto NEXT_CASE_LABEL } cond = Expression::make_unary(OPERATOR_NOT, cond, loc); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -4024,11 +4386,11 @@ Case_clauses::Case_clause::check_types(Type* type) p != this->cases_->end(); ++p) { - if (!Type::are_assignable(type, (*p)->type(), NULL) - && !Type::are_assignable((*p)->type(), type, NULL)) + std::string reason; + if (!Type::are_compatible_for_comparison(true, type, (*p)->type(), + &reason)) { - go_error_at((*p)->location(), - "type mismatch between switch value and case clause"); + go_error_at(this->location_, "%s", reason.c_str()); return false; } } @@ -4179,7 +4541,7 @@ Case_clauses::is_constant() const // Lower case clauses for a nonconstant switch. void -Case_clauses::lower(Block* b, Temporary_statement* val_temp, +Case_clauses::lower(Gogo* gogo, Block* b, Temporary_statement* val_temp, Unnamed_label* break_label) const { // The default case. @@ -4217,7 +4579,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp, } if (!p->is_default()) - p->lower(b, val_temp, start_label, finish_label); + p->lower(gogo, b, val_temp, start_label, finish_label); else { // We have to move the default case to the end, so that we @@ -4229,7 +4591,7 @@ Case_clauses::lower(Block* b, Temporary_statement* val_temp, } if (default_case != NULL) - default_case->lower(b, val_temp, default_start_label, + default_case->lower(gogo, b, val_temp, default_start_label, default_finish_label); } @@ -4341,12 +4703,6 @@ class Constant_switch_statement : public Statement int do_traverse(Traverse*); - void - do_determine_types(Gogo*); - - void - do_check_types(Gogo*); - Bstatement* do_get_backend(Translate_context*); @@ -4372,24 +4728,6 @@ Constant_switch_statement::do_traverse(Traverse* traverse) return this->clauses_->traverse(traverse); } -// Determine types. - -void -Constant_switch_statement::do_determine_types(Gogo* gogo) -{ - this->val_->determine_type_no_context(gogo); - this->clauses_->determine_types(gogo, this->val_->type()); -} - -// Check types. - -void -Constant_switch_statement::do_check_types(Gogo*) -{ - if (!this->clauses_->check_types(this->val_->type())) - this->set_is_error(); -} - // Convert to GENERIC. Bstatement* @@ -4452,11 +4790,50 @@ Switch_statement::do_traverse(Traverse* traverse) return this->clauses_->traverse(traverse); } +void +Switch_statement::do_determine_types(Gogo* gogo) +{ + if (this->val_ != NULL) + this->val_->determine_type_no_context(gogo); + this->clauses_->determine_types(gogo, + (this->val_ == NULL + ? NULL + : this->val_->type())); +} + +void +Switch_statement::do_check_types(Gogo*) +{ + if (this->val_ != NULL + && (this->val_->is_error_expression() + || this->val_->type()->is_error())) + return; + + if (this->val_ != NULL + && !this->val_->type()->is_comparable() + && !Type::are_compatible_for_comparison(true, this->val_->type(), + Type::make_nil_type(), NULL)) + { + go_error_at(this->val_->location(), + "cannot switch on value whose type may not be compared"); + this->set_is_error(); + return; + } + + Type* type; + if (this->val_ != NULL) + type = this->val_->type(); + else + type = Type::make_boolean_type(); + if (!this->clauses_->check_types(type)) + this->set_is_error(); +} + // Lower a Switch_statement to a Constant_switch_statement or a series // of if statements. Statement* -Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, +Switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { Location loc = this->location(); @@ -4476,16 +4853,6 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, return new Constant_switch_statement(this->val_, this->clauses_, this->break_label_, loc); - if (this->val_ != NULL - && !this->val_->type()->is_comparable() - && !Type::are_compatible_for_comparison(true, this->val_->type(), - Type::make_nil_type(), NULL)) - { - go_error_at(this->val_->location(), - "cannot switch on value whose type may not be compared"); - return Statement::make_error_statement(loc); - } - Block* b = new Block(enclosing, loc); if (this->clauses_->empty()) @@ -4507,7 +4874,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, Temporary_statement* val_temp = Statement::make_temporary(type, val, loc); b->add_statement(val_temp); - this->clauses_->lower(b, val_temp, this->break_label()); + this->clauses_->lower(gogo, b, val_temp, this->break_label()); Statement* s = Statement::make_unnamed_label_statement(this->break_label_); b->add_statement(s); @@ -4588,27 +4955,19 @@ Type_case_clauses::Type_case_clause::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Lower one clause in a type switch. Add statements to the block B. -// The type descriptor we are switching on is in DESCRIPTOR_TEMP. -// BREAK_LABEL is the label at the end of the type switch. -// *STMTS_LABEL, if not NULL, is a label to put at the start of the -// statements. - void -Type_case_clauses::Type_case_clause::lower(Gogo* gogo, - Type* switch_val_type, - Block* b, - Temporary_statement* descriptor_temp, - Unnamed_label* break_label, - Unnamed_label** stmts_label) const +Type_case_clauses::Type_case_clause::determine_types(Gogo* gogo) { - Location loc = this->location_; + if (this->statements_ != NULL) + this->statements_->determine_types(gogo); +} - Unnamed_label* next_case_label = NULL; +bool +Type_case_clauses::Type_case_clause::check_types(Type* switch_val_type) +{ if (!this->is_default_) { Type* type = this->type_; - std::string reason; if (switch_val_type->interface_type() != NULL && !type->is_nil_constant_as_type() @@ -4621,7 +4980,31 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo, else go_error_at(this->location_, "impossible type switch case (%s)", reason.c_str()); + return false; } + } + return true; +} + +// Lower one clause in a type switch. Add statements to the block B. +// The type descriptor we are switching on is in DESCRIPTOR_TEMP. +// BREAK_LABEL is the label at the end of the type switch. +// *STMTS_LABEL, if not NULL, is a label to put at the start of the +// statements. + +void +Type_case_clauses::Type_case_clause::lower(Gogo* gogo, + Block* b, + Temporary_statement* descriptor_temp, + Unnamed_label* break_label, + Unnamed_label** stmts_label) const +{ + Location loc = this->location_; + + Unnamed_label* next_case_label = NULL; + if (!this->is_default_) + { + Type* type = this->type_; Expression* ref = Expression::make_temporary_reference(descriptor_temp, loc); @@ -4670,6 +5053,7 @@ Type_case_clauses::Type_case_clause::lower(Gogo* gogo, Statement* s = Statement::make_goto_unnamed_statement(dest, loc); then_block->add_statement(s); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); b->add_statement(s); } @@ -4774,6 +5158,29 @@ Type_case_clauses::traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Type_case_clauses::determine_types(Gogo* gogo) +{ + for (Type_clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + p->determine_types(gogo); +} + +bool +Type_case_clauses::check_types(Type* switch_val_type) +{ + bool ret = true; + for (Type_clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + { + if (!p->check_types(switch_val_type)) + ret = false; + } + return ret; +} + // Check for duplicate types. void @@ -4802,8 +5209,7 @@ Type_case_clauses::check_duplicates() const // BREAK_LABEL is the label at the end of the type switch. void -Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, - Block* b, +Type_case_clauses::lower(Gogo* gogo, Block* b, Temporary_statement* descriptor_temp, Unnamed_label* break_label) const { @@ -4815,8 +5221,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, ++p) { if (!p->is_default()) - p->lower(gogo, switch_val_type, b, descriptor_temp, break_label, - &stmts_label); + p->lower(gogo, b, descriptor_temp, break_label, &stmts_label); else { // We are generating a series of tests, which means that we @@ -4827,8 +5232,7 @@ Type_case_clauses::lower(Gogo* gogo, Type* switch_val_type, go_assert(stmts_label == NULL); if (default_case != NULL) - default_case->lower(gogo, switch_val_type, b, descriptor_temp, break_label, - NULL); + default_case->lower(gogo, b, descriptor_temp, break_label, NULL); } // Return true if these clauses may fall through to the statements @@ -4875,6 +5279,31 @@ Type_switch_statement::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +void +Type_switch_statement::do_determine_types(Gogo* gogo) +{ + this->expr_->determine_type_no_context(gogo); + this->clauses_->determine_types(gogo); +} + +void +Type_switch_statement::do_check_types(Gogo*) +{ + if (this->clauses_ != NULL) + this->clauses_->check_duplicates(); + + Type* expr_type = this->expr_->type(); + if (expr_type->interface_type() == NULL) + { + if (!expr_type->is_error()) + this->report_error(_("cannot type switch on non-interface value")); + this->set_is_error(); + } + + if (!this->clauses_->check_types(expr_type)) + this->set_is_error(); +} + // Lower a type switch statement to a series of if statements. The gc // compiler is able to generate a table in some cases. However, that // does not work for us because we may have type descriptors in @@ -4887,19 +5316,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { const Location loc = this->location(); - if (this->clauses_ != NULL) - this->clauses_->check_duplicates(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); Block* b = new Block(enclosing, loc); - Type* val_type = this->expr_->type(); - if (val_type->interface_type() == NULL) - { - if (!val_type->is_error()) - this->report_error(_("cannot type switch on non-interface value")); - return Statement::make_error_statement(loc); - } - Temporary_statement* val_temp = Statement::make_temporary(NULL, this->expr_, loc); b->add_statement(val_temp); @@ -4917,10 +5338,11 @@ Type_switch_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Expression::make_temporary_reference(descriptor_temp, loc); lhs->set_is_lvalue(); Statement* s = Statement::make_assignment(lhs, td, loc); + s->determine_types(gogo); b->add_statement(s); if (this->clauses_ != NULL) - this->clauses_->lower(gogo, val_type, b, descriptor_temp, this->break_label()); + this->clauses_->lower(gogo, b, descriptor_temp, this->break_label()); s = Statement::make_unnamed_label_statement(this->break_label_); b->add_statement(s); @@ -5090,7 +5512,7 @@ Send_statement::do_get_backend(Translate_context* context) Channel_type* channel_type = this->channel_->type()->channel_type(); Type* element_type = channel_type->element_type(); - Expression* val = Expression::convert_for_assignment(context->gogo(), + Expression* val = Expression::convert_for_assignment(gogo, element_type, this->val_, loc); @@ -5159,8 +5581,8 @@ Send_statement::do_get_backend(Translate_context* context) Expression* call = Runtime::make_call(gogo, Runtime::CHANSEND, loc, 2, this->channel_, val); - - context->gogo()->lower_expression(context->function(), NULL, &call); + call->determine_type_no_context(gogo); + gogo->lower_expression(context->function(), NULL, &call); Bexpression* bcall = call->get_backend(context); Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* s = context->backend()->expression_statement(bfunction, bcall); @@ -5259,7 +5681,7 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, loc); if (this->is_send_) - this->lower_send(b, scase, chanref); + this->lower_send(gogo, b, scase, chanref); else this->lower_recv(gogo, function, b, scase, chanref, recvok); @@ -5272,7 +5694,8 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, // Lower a send clause in a select statement. void -Select_clauses::Select_clause::lower_send(Block* b, Expression* scase, +Select_clauses::Select_clause::lower_send(Gogo* gogo, Block* b, + Expression* scase, Expression* chanref) { Location loc = this->location_; @@ -5300,7 +5723,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr); + this->set_case(gogo, b, scase, chanref, valaddr); } // Lower a receive clause in a select statement. @@ -5326,7 +5749,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr); + this->set_case(gogo, b, scase, chanref, valaddr); // If the block of statements is executed, arrange for the received // value to move from VAL to the place where the statements expect @@ -5345,7 +5768,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, { init = new Block(b, loc); valref = Expression::make_temporary_reference(val, loc); - init->add_statement(Statement::make_assignment(this->val_, valref, loc)); + Statement* s = Statement::make_assignment(this->val_, valref, loc); + s->determine_types(gogo); + init->add_statement(s); } if (this->closedvar_ != NULL) @@ -5359,8 +5784,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, if (init == NULL) init = new Block(b, loc); Expression* cref = Expression::make_temporary_reference(recvok, loc); - init->add_statement(Statement::make_assignment(this->closed_, cref, - loc)); + Statement* s = Statement::make_assignment(this->closed_, cref, loc); + s->determine_types(gogo); + init->add_statement(s); } if (init != NULL) @@ -5378,7 +5804,8 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, // pass to the runtime function selectgo. void -Select_clauses::Select_clause::set_case(Block* b, +Select_clauses::Select_clause::set_case(Gogo* gogo, + Block* b, Expression* scase, Expression* chanref, Expression* elem) @@ -5392,6 +5819,7 @@ Select_clauses::Select_clause::set_case(Block* b, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); chanref = Expression::make_unsafe_cast(unsafe_pointer_type, chanref, loc); Statement* s = Statement::make_assignment(ref, chanref, loc); + s->determine_types(gogo); b->add_statement(s); if (elem != NULL) @@ -5400,6 +5828,7 @@ Select_clauses::Select_clause::set_case(Block* b, go_assert(scase_type->field(field_index)->is_field_name("elem")); ref = Expression::make_field_reference(scase->copy(), field_index, loc); s = Statement::make_assignment(ref, elem, loc); + s->determine_types(gogo); b->add_statement(s); } } @@ -5409,7 +5838,16 @@ Select_clauses::Select_clause::set_case(Block* b, void Select_clauses::Select_clause::determine_types(Gogo* gogo) { - go_assert(this->is_lowered_); + if (this->channel_ != NULL) + this->channel_->determine_type_no_context(gogo); + if (this->val_ != NULL) + this->val_->determine_type_no_context(gogo); + if (this->closed_ != NULL) + this->closed_->determine_type_no_context(gogo); + if (this->var_ != NULL && this->var_->is_variable()) + this->var_->var_value()->determine_type(gogo); + if (this->closedvar_ != NULL && this->closedvar_->is_variable()) + this->closedvar_->var_value()->determine_type(gogo); if (this->statements_ != NULL) this->statements_->determine_types(gogo); } @@ -5673,6 +6111,7 @@ Select_clauses::get_backend(Translate_context* context, Gogo* gogo = context->gogo(); Expression* crash = Runtime::make_call(gogo, Runtime::UNREACHABLE, location, 0); + crash->determine_type_no_context(gogo); Bexpression* bcrash = crash->get_backend(context); clauses[count] = context->backend()->expression_statement(bfunction, bcrash); @@ -5740,6 +6179,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, { Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0); Statement *s = Statement::make_statement(call, false); + s->determine_types(gogo); b->add_statement(s); this->is_lowered_ = true; return Statement::make_block_statement(b, loc); @@ -5823,11 +6263,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, Expression* result = Expression::make_call_result(call, 0); Expression* ref = Expression::make_temporary_reference(this->index_, loc); Statement* s = Statement::make_assignment(ref, result, loc); + s->determine_types(gogo); b->add_statement(s); result = Expression::make_call_result(call, 1); ref = Expression::make_temporary_reference(recvok, loc); s = Statement::make_assignment(ref, result, loc); + s->determine_types(gogo); b->add_statement(s); this->is_lowered_ = true; @@ -5857,8 +6299,10 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) Block* bnil = new Block(b, loc); Expression* call = Runtime::make_call(gogo, Runtime::BLOCK, loc, 0); Statement* s = Statement::make_statement(call, false); + s->determine_types(gogo); bnil->add_statement(s); Statement* ifs = Statement::make_if_statement(cond, bnil, NULL, loc); + ifs->determine_types(gogo); b->add_statement(ifs); chanref = chanref->copy(); @@ -5866,6 +6310,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) if (scase.is_send()) { s = Statement::make_send_statement(chanref, scase.val(), cloc); + s->determine_types(gogo); b->add_statement(s); } else @@ -5888,6 +6333,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) } else s = Statement::make_statement(recv, false); + s->determine_types(gogo); b->add_statement(s); } else @@ -5918,6 +6364,7 @@ Select_statement::lower_one_case(Gogo* gogo, Block* b) } s = Statement::make_tuple_receive_assignment(lhs, lhs2, chanref, cloc); + s->determine_types(gogo); b->add_statement(s); if (scase.var() != NULL) @@ -6000,12 +6447,14 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement::make_temporary(Type::make_boolean_type(), Expression::make_call_result(call, 0), loc); + selected_temp->determine_types(gogo); b->add_statement(selected_temp); Temporary_statement* ok_temp = Statement::make_temporary(Type::make_boolean_type(), Expression::make_call_result(call, 1), loc); + ok_temp->determine_types(gogo); b->add_statement(ok_temp); cond = Expression::make_temporary_reference(selected_temp, loc); @@ -6017,6 +6466,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement* as = Statement::make_assignment(chancase.val(), ref->copy(), cloc); + as->determine_types(gogo); bchan->add_statement(as); } else if (chancase.var() != NULL) @@ -6031,6 +6481,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) cloc); Statement* as = Statement::make_assignment(chancase.closed(), okref, cloc); + as->determine_types(gogo); bchan->add_statement(as); } else if (chancase.closedvar() != NULL) @@ -6047,6 +6498,7 @@ Select_statement::lower_two_case(Gogo* gogo, Block* b) Statement* ifs = Statement::make_if_statement(cond, bchan, defcase.statements(), loc); + ifs->determine_types(gogo); b->add_statement(ifs); Statement* label = @@ -6129,16 +6581,47 @@ For_statement::do_traverse(Traverse* traverse) return this->statements_->traverse(traverse); } +void +For_statement::do_determine_types(Gogo* gogo) +{ + if (this->init_ != NULL) + this->init_->determine_types(gogo); + if (this->cond_ != NULL) + this->cond_->determine_type_no_context(gogo); + if (this->post_ != NULL) + this->post_->determine_types(gogo); + this->statements_->determine_types(gogo); +} + +void +For_statement::do_check_types(Gogo*) +{ + if (this->cond_ != NULL) + { + Type* type = this->cond_->type(); + if (type->is_error()) + this->set_is_error(); + else if (!type->is_boolean_type()) + { + go_error_at(this->cond_->location(), "expected boolean expression"); + this->set_is_error(); + } + } +} + // Lower a For_statement into if statements and gotos. Getting rid of // complex statements make it easier to handle garbage collection. Statement* -For_statement::do_lower(Gogo*, Named_object*, Block* enclosing, +For_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, Statement_inserter*) { - Statement* s; Location loc = this->location(); + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(loc); + + Statement* s; Block* b = new Block(enclosing, this->location()); if (this->init_ != NULL) { @@ -6188,6 +6671,7 @@ For_statement::do_lower(Gogo*, Named_object*, Block* enclosing, then_block->add_statement(s); s = Statement::make_if_statement(this->cond_, then_block, NULL, cond_loc); + s->determine_types(gogo); b->add_statement(s); } @@ -6318,22 +6802,30 @@ For_range_statement::do_traverse(Traverse* traverse) return this->statements_->traverse(traverse); } -// Lower a for range statement. For simplicity we lower this into a -// for statement, which will then be lowered in turn to goto -// statements. +void +For_range_statement::do_determine_types(Gogo* gogo) +{ + if (this->index_var_ != NULL) + this->index_var_->determine_type_no_context(gogo); + if (this->value_var_ != NULL) + this->value_var_->determine_type_no_context(gogo); + this->range_->determine_type_no_context(gogo); + this->statements_->determine_types(gogo); +} -Statement* -For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, - Statement_inserter*) +void +For_range_statement::do_check_types(Gogo*) { Type* range_type = this->range_->type(); + + Type* index_type; + Type* value_type = NULL; + if (range_type->points_to() != NULL && range_type->points_to()->array_type() != NULL && !range_type->points_to()->is_slice_type()) range_type = range_type->points_to(); - Type* index_type; - Type* value_type = NULL; if (range_type->array_type() != NULL) { index_type = Type::lookup_integer_type("int"); @@ -6351,22 +6843,79 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, } else if (range_type->channel_type() != NULL) { + if (!range_type->channel_type()->may_receive()) + this->report_error(_("invalid receive on send-only channel")); index_type = range_type->channel_type()->element_type(); if (this->value_var_ != NULL) { if (!this->value_var_->type()->is_error()) this->report_error(_("too many variables for range clause " "with channel")); - return Statement::make_error_statement(this->location()); + this->set_is_error(); + return; } } else { this->report_error(_("range clause must have " "array, slice, string, map, or channel type")); - return Statement::make_error_statement(this->location()); + return; } + if (this->index_var_ != NULL + && !Assignment_statement::check_assignment_types(this->index_var_, + index_type, + this->location())) + this->set_is_error(); + if (this->value_var_ != NULL + && !Assignment_statement::check_assignment_types(this->value_var_, + value_type, + this->location())) + this->set_is_error(); +} + +// Lower a for range statement. For simplicity we lower this into a +// for statement, which will then be lowered in turn to goto +// statements. + +Statement* +For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, + Statement_inserter*) +{ + if (this->classification() == STATEMENT_ERROR) + return Statement::make_error_statement(this->location()); + + Type* range_type = this->range_->type(); + if (range_type->points_to() != NULL + && range_type->points_to()->array_type() != NULL + && !range_type->points_to()->is_slice_type()) + range_type = range_type->points_to(); + + Type* index_type; + Type* value_type = NULL; + if (range_type->array_type() != NULL) + { + index_type = Type::lookup_integer_type("int"); + value_type = range_type->array_type()->element_type(); + } + else if (range_type->is_string_type()) + { + index_type = Type::lookup_integer_type("int"); + value_type = Type::lookup_integer_type("rune"); + } + else if (range_type->map_type() != NULL) + { + index_type = range_type->map_type()->key_type(); + value_type = range_type->map_type()->val_type(); + } + else if (range_type->channel_type() != NULL) + { + index_type = range_type->channel_type()->element_type(); + go_assert(this->value_var_ == NULL); + } + else + go_unreachable(); + // If there is only one iteration variable, and len(this->range_) is // constant, then we do not evaluate the range variable. len(x) is // a contant if x is a string constant or if x is an array. If x is @@ -6412,6 +6961,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { if (gogo->debug_optimization()) go_debug(loc, "map range clear"); + clear->determine_types(gogo); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } @@ -6429,6 +6979,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, { if (gogo->debug_optimization()) go_debug(loc, "array range clear"); + clear->determine_types(gogo); temp_block->add_statement(clear); return Statement::make_block_statement(temp_block, loc); } @@ -6505,6 +7056,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, assign = Statement::make_tuple_assignment(lhs, rhs, loc); } + assign->determine_types(gogo); body->add_statement(assign); } @@ -6515,6 +7067,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, For_statement* loop = Statement::make_for_statement(init, cond, post, this->location()); loop->add_statements(body); + loop->determine_types(gogo); loop->set_break_continue_labels(this->break_label_, this->continue_label_); temp_block->add_statement(loop); @@ -6596,12 +7149,14 @@ For_range_statement::lower_range_array(Gogo* gogo, { Expression* ref = this->make_range_ref(range_object, range_temp, loc); range_temp = Statement::make_temporary(NULL, ref, loc); + range_temp->determine_types(gogo); init->add_statement(range_temp); len_arg = ref; } Expression* len_call = this->call_builtin(gogo, "len", len_arg, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), len_call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Expression* zexpr = Expression::make_integer_ul(0, NULL, loc); @@ -6610,6 +7165,7 @@ For_range_statement::lower_range_array(Gogo* gogo, Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); *pinit = init; @@ -6638,6 +7194,7 @@ For_range_statement::lower_range_array(Gogo* gogo, tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); s = Statement::make_assignment(tref, index, loc); + s->determine_types(gogo); iter_init->add_statement(s); } @@ -6650,6 +7207,7 @@ For_range_statement::lower_range_array(Gogo* gogo, tref = Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); s = Statement::make_inc_statement(tref); + s->determine_types(gogo); post->add_statement(s); *ppost = post; } @@ -6694,12 +7252,14 @@ For_range_statement::lower_range_slice(Gogo* gogo, Expression* ref = this->make_range_ref(range_object, range_temp, loc); Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc); + for_temp->determine_types(gogo); init->add_statement(for_temp); ref = Expression::make_temporary_reference(for_temp, loc); Expression* len_call = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), len_call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Expression* zexpr = Expression::make_integer_ul(0, NULL, loc); @@ -6708,6 +7268,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); Statement* s = Statement::make_assignment(tref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); *pinit = init; @@ -6736,6 +7297,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, tref = Expression::make_temporary_reference(value_temp, loc); tref->set_is_lvalue(); s = Statement::make_assignment(tref, index, loc); + s->determine_types(gogo); iter_init->add_statement(s); } @@ -6748,6 +7310,7 @@ For_range_statement::lower_range_slice(Gogo* gogo, tref = Expression::make_temporary_reference(index_temp, loc); tref->set_is_lvalue(); s = Statement::make_inc_statement(tref); + s->determine_types(gogo); post->add_statement(s); *ppost = post; } @@ -6796,6 +7359,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Call_expression* call = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), call, loc); + len_temp->determine_types(gogo); init->add_statement(len_temp); Temporary_statement* next_index_temp = @@ -6807,6 +7371,7 @@ For_range_statement::lower_range_string(Gogo* gogo, index_ref->set_is_lvalue(); Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc); Statement* s = Statement::make_assignment(index_ref, zexpr, loc); + s->determine_types(gogo); init->add_statement(s); Type* rune_type; @@ -6847,6 +7412,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Expression::make_temporary_reference(value_temp, loc); value_ref->set_is_lvalue(); s = Statement::make_assignment(value_ref, ref, loc); + s->determine_types(gogo); iter_init->add_statement(s); value_ref = Expression::make_temporary_reference(value_temp, loc); @@ -6864,6 +7430,7 @@ For_range_statement::lower_range_string(Gogo* gogo, Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one, loc); s = Statement::make_assignment(lhs, sum, loc); + s->determine_types(gogo); then_block->add_statement(s); Block* else_block = new Block(iter_init, loc); @@ -6876,15 +7443,18 @@ For_range_statement::lower_range_string(Gogo* gogo, value_ref->set_is_lvalue(); Expression* res = Expression::make_call_result(call, 0); s = Statement::make_assignment(value_ref, res, loc); + s->determine_types(gogo); else_block->add_statement(s); lhs = Expression::make_temporary_reference(next_index_temp, loc); lhs->set_is_lvalue(); res = Expression::make_call_result(call, 1); s = Statement::make_assignment(lhs, res, loc); + s->determine_types(gogo); else_block->add_statement(s); s = Statement::make_if_statement(cond, then_block, else_block, loc); + s->determine_types(gogo); iter_init->add_statement(s); *piter_init = iter_init; @@ -6898,6 +7468,7 @@ For_range_statement::lower_range_string(Gogo* gogo, index_ref->set_is_lvalue(); ref = Expression::make_temporary_reference(next_index_temp, loc); s = Statement::make_assignment(index_ref, ref, loc); + s->determine_types(gogo); post->add_statement(s); *ppost = post; @@ -6951,7 +7522,9 @@ For_range_statement::lower_range_map(Gogo* gogo, Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* call = Runtime::make_call(gogo, Runtime::MAPITERINIT, loc, 3, p1, p2, p3); - init->add_statement(Statement::make_statement(call, true)); + Statement* s = Statement::make_statement(call, true); + s->determine_types(gogo); + init->add_statement(s); *pinit = init; @@ -6977,6 +7550,7 @@ For_range_statement::lower_range_map(Gogo* gogo, rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc); Statement* set = Statement::make_assignment(lhs, rhs, loc); + set->determine_types(gogo); iter_init->add_statement(set); if (value_temp != NULL) @@ -6987,6 +7561,7 @@ For_range_statement::lower_range_map(Gogo* gogo, rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED, loc); set = Statement::make_assignment(lhs, rhs, loc); + set->determine_types(gogo); iter_init->add_statement(set); } @@ -7000,7 +7575,9 @@ For_range_statement::lower_range_map(Gogo* gogo, ref = Expression::make_temporary_reference(hiter, loc); p1 = Expression::make_unary(OPERATOR_AND, ref, loc); call = Runtime::make_call(gogo, Runtime::MAPITERNEXT, loc, 1, p1); - post->add_statement(Statement::make_statement(call, true)); + s = Statement::make_statement(call, true); + s->determine_types(gogo); + post->add_statement(s); *ppost = post; } @@ -7008,7 +7585,7 @@ For_range_statement::lower_range_map(Gogo* gogo, // Lower a for range over a channel. void -For_range_statement::lower_range_channel(Gogo*, +For_range_statement::lower_range_channel(Gogo* gogo, Block*, Block* body_block, Named_object* range_object, @@ -7061,6 +7638,7 @@ For_range_statement::lower_range_channel(Gogo*, oref->set_is_lvalue(); Statement* s = Statement::make_tuple_receive_assignment(iref, oref, cref, loc); + s->determine_types(gogo); iter_init->add_statement(s); Block* then_block = new Block(iter_init, loc); @@ -7070,6 +7648,7 @@ For_range_statement::lower_range_channel(Gogo*, oref = Expression::make_temporary_reference(ok_temp, loc); Expression* cond = Expression::make_unary(OPERATOR_NOT, oref, loc); s = Statement::make_if_statement(cond, then_block, NULL, loc); + s->determine_types(gogo); iter_init->add_statement(s); *piter_init = iter_init; @@ -7125,7 +7704,9 @@ For_range_statement::lower_map_range_clear(Gogo* gogo, Expression* e1 = Expression::make_type_descriptor(map_type, loc); Expression* e2 = this->make_range_ref(range_object, range_temp, loc); call = Runtime::make_call(gogo, Runtime::MAPCLEAR, loc, 2, e1, e2); - return Statement::make_statement(call, true); + Statement* s = Statement::make_statement(call, true); + s->determine_types(gogo); + return s; } // Match @@ -7193,6 +7774,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, ref = this->make_range_ref(range_object, range_temp, loc); Expression* len = this->call_builtin(gogo, "len", ref, loc); Temporary_statement* tslen = Statement::make_temporary(NULL, len, loc); + tslen->determine_types(gogo); temp_block->add_statement(tslen); Expression* zero = Expression::make_integer_ul(0, this->index_var_->type(), loc); @@ -7201,12 +7783,14 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, elem->array_index_expression()->set_needs_bounds_check(false); Expression* e1 = Expression::make_unary(OPERATOR_AND, elem, loc); Temporary_statement* ts1 = Statement::make_temporary(NULL, e1, loc); + ts1->determine_types(gogo); b->add_statement(ts1); len = Expression::make_temporary_reference(tslen, loc); Expression* sz = Expression::make_integer_int64(elme_sz, len->type(), loc); Expression* e2 = Expression::make_binary(OPERATOR_MULT, len, sz, loc); Temporary_statement* ts2 = Statement::make_temporary(NULL, e2, loc); + ts2->determine_types(gogo); b->add_statement(ts2); Expression* ptr_arg = Expression::make_temporary_reference(ts1, loc); @@ -7223,6 +7807,7 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, zero32, sz_arg); } Statement* cs3 = Statement::make_statement(call, true); + cs3->determine_types(gogo); b->add_statement(cs3); len = Expression::make_temporary_reference(tslen, loc); @@ -7230,12 +7815,15 @@ For_range_statement::lower_array_range_clear(Gogo* gogo, Expression* rhs = Expression::make_binary(OPERATOR_MINUS, len, one, loc); Expression* lhs = this->index_var_->copy(); Statement* as4 = Statement::make_assignment(lhs, rhs, loc); + as4->determine_types(gogo); b->add_statement(as4); len = Expression::make_temporary_reference(tslen, loc); zero = zero->copy(); Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, len, zero, loc); - return Statement::make_if_statement(cond, b, NULL, loc); + Statement* ret = Statement::make_if_statement(cond, b, NULL, loc); + ret->determine_types(gogo); + return ret; } // Return the break LABEL_EXPR. |