Commit 27a19c58 by Ian Lance Taylor

Change c <- v from an expression to a statement.

Don't do anything special if we don't use the value of <-c.
Fix sending an untyped constant in a select statement.

From-SVN: r171371
parent e110e232
...@@ -12357,103 +12357,6 @@ Expression::make_receive(Expression* channel, source_location location) ...@@ -12357,103 +12357,6 @@ Expression::make_receive(Expression* channel, source_location location)
return new Receive_expression(channel, location); return new Receive_expression(channel, location);
} }
// Class Send_expression.
// Traversal.
int
Send_expression::do_traverse(Traverse* traverse)
{
if (Expression::traverse(&this->channel_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return Expression::traverse(&this->val_, traverse);
}
// Get the type.
Type*
Send_expression::do_type()
{
if (this->is_value_discarded_)
return Type::make_void_type();
else
return Type::lookup_bool_type();
}
// Set types.
void
Send_expression::do_determine_type(const Type_context*)
{
this->channel_->determine_type_no_context();
Type* type = this->channel_->type();
Type_context subcontext;
if (type->channel_type() != NULL)
subcontext.type = type->channel_type()->element_type();
this->val_->determine_type(&subcontext);
}
// Check types.
void
Send_expression::do_check_types(Gogo*)
{
Type* type = this->channel_->type();
if (type->is_error_type())
{
this->set_is_error();
return;
}
Channel_type* channel_type = type->channel_type();
if (channel_type == NULL)
{
error_at(this->location(), "left operand of %<<-%> must be channel");
this->set_is_error();
return;
}
Type* element_type = channel_type->element_type();
if (element_type != NULL
&& !Type::are_assignable(element_type, this->val_->type(), NULL))
{
this->report_error(_("incompatible types in send"));
return;
}
if (!channel_type->may_send())
{
this->report_error(_("invalid send on receive-only channel"));
return;
}
}
// Get a tree for a send expression.
tree
Send_expression::do_get_tree(Translate_context* context)
{
tree channel = this->channel_->get_tree(context);
tree val = this->val_->get_tree(context);
if (channel == error_mark_node || val == error_mark_node)
return error_mark_node;
Channel_type* channel_type = this->channel_->type()->channel_type();
val = Expression::convert_for_assignment(context,
channel_type->element_type(),
this->val_->type(),
val,
this->location());
return Gogo::send_on_channel(channel, val, this->is_value_discarded_,
this->for_select_, this->location());
}
// Make a send expression
Send_expression*
Expression::make_send(Expression* channel, Expression* val,
source_location location)
{
return new Send_expression(channel, val, location);
}
// An expression which evaluates to a pointer to the type descriptor // An expression which evaluates to a pointer to the type descriptor
// of a type. // of a type.
......
...@@ -36,7 +36,6 @@ class Field_reference_expression; ...@@ -36,7 +36,6 @@ class Field_reference_expression;
class Interface_field_reference_expression; class Interface_field_reference_expression;
class Type_guard_expression; class Type_guard_expression;
class Receive_expression; class Receive_expression;
class Send_expression;
class Named_object; class Named_object;
class Export; class Export;
class Import; class Import;
...@@ -89,7 +88,6 @@ class Expression ...@@ -89,7 +88,6 @@ class Expression
EXPRESSION_COMPOSITE_LITERAL, EXPRESSION_COMPOSITE_LITERAL,
EXPRESSION_HEAP_COMPOSITE, EXPRESSION_HEAP_COMPOSITE,
EXPRESSION_RECEIVE, EXPRESSION_RECEIVE,
EXPRESSION_SEND,
EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_TYPE_INFO, EXPRESSION_TYPE_INFO,
EXPRESSION_STRUCT_FIELD_OFFSET, EXPRESSION_STRUCT_FIELD_OFFSET,
...@@ -271,10 +269,6 @@ class Expression ...@@ -271,10 +269,6 @@ class Expression
static Receive_expression* static Receive_expression*
make_receive(Expression* channel, source_location); make_receive(Expression* channel, source_location);
// Make a send expression.
static Send_expression*
make_send(Expression* channel, Expression* val, source_location);
// Make an expression which evaluates to the type descriptor of a // Make an expression which evaluates to the type descriptor of a
// type. // type.
static Expression* static Expression*
...@@ -356,8 +350,7 @@ class Expression ...@@ -356,8 +350,7 @@ class Expression
// This is called by the parser if the value of this expression is // This is called by the parser if the value of this expression is
// being discarded. This issues warnings about computed values // being discarded. This issues warnings about computed values
// being unused, and handles send expressions which act differently // being unused.
// depending upon whether the value is used.
void void
discarding_value() discarding_value()
{ this->do_discarding_value(); } { this->do_discarding_value(); }
...@@ -1807,7 +1800,7 @@ class Receive_expression : public Expression ...@@ -1807,7 +1800,7 @@ class Receive_expression : public Expression
public: public:
Receive_expression(Expression* channel, source_location location) Receive_expression(Expression* channel, source_location location)
: Expression(EXPRESSION_RECEIVE, location), : Expression(EXPRESSION_RECEIVE, location),
channel_(channel), is_value_discarded_(false), for_select_(false) channel_(channel), for_select_(false)
{ } { }
// Return the channel. // Return the channel.
...@@ -1827,7 +1820,7 @@ class Receive_expression : public Expression ...@@ -1827,7 +1820,7 @@ class Receive_expression : public Expression
void void
do_discarding_value() do_discarding_value()
{ this->is_value_discarded_ = true; } { }
Type* Type*
do_type(); do_type();
...@@ -1855,67 +1848,6 @@ class Receive_expression : public Expression ...@@ -1855,67 +1848,6 @@ class Receive_expression : public Expression
private: private:
// The channel from which we are receiving. // The channel from which we are receiving.
Expression* channel_; Expression* channel_;
// Whether the value is being discarded.
bool is_value_discarded_;
// Whether this is for a select statement.
bool for_select_;
};
// A send expression.
class Send_expression : public Expression
{
public:
Send_expression(Expression* channel, Expression* val,
source_location location)
: Expression(EXPRESSION_SEND, location),
channel_(channel), val_(val), is_value_discarded_(false),
for_select_(false)
{ }
// Note that this is for a select statement.
void
set_for_select()
{ this->for_select_ = true; }
protected:
int
do_traverse(Traverse* traverse);
void
do_discarding_value()
{ this->is_value_discarded_ = true; }
Type*
do_type();
void
do_determine_type(const Type_context*);
void
do_check_types(Gogo*);
Expression*
do_copy()
{
return Expression::make_send(this->channel_->copy(), this->val_->copy(),
this->location());
}
bool
do_must_eval_in_order() const
{ return true; }
tree
do_get_tree(Translate_context*);
private:
// The channel on which to send the value.
Expression* channel_;
// The value to send.
Expression* val_;
// Whether the value is being discarded.
bool is_value_discarded_;
// Whether this is for a select statement. // Whether this is for a select statement.
bool for_select_; bool for_select_;
}; };
......
...@@ -1926,14 +1926,6 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s) ...@@ -1926,14 +1926,6 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
{ {
Expression** pexpr = *p; Expression** pexpr = *p;
// If the last expression is a send or receive expression, we
// may be ignoring the value; we don't want to evaluate it
// early.
if (p + 1 == find_eval_ordering.end()
&& ((*pexpr)->classification() == Expression::EXPRESSION_SEND
|| (*pexpr)->classification() == Expression::EXPRESSION_RECEIVE))
break;
// The last expression in a thunk will be the call passed to go // The last expression in a thunk will be the call passed to go
// or defer, which we must not evaluate early. // or defer, which we must not evaluate early.
if (is_thunk && p + 1 == find_eval_ordering.end()) if (is_thunk && p + 1 == find_eval_ordering.end())
......
...@@ -2944,9 +2944,6 @@ Parse::expression(Precedence precedence, bool may_be_sink, ...@@ -2944,9 +2944,6 @@ Parse::expression(Precedence precedence, bool may_be_sink,
case OPERATOR_ANDAND: case OPERATOR_ANDAND:
right_precedence = PRECEDENCE_ANDAND; right_precedence = PRECEDENCE_ANDAND;
break; break;
case OPERATOR_CHANOP:
right_precedence = PRECEDENCE_CHANOP;
break;
case OPERATOR_EQEQ: case OPERATOR_EQEQ:
case OPERATOR_NOTEQ: case OPERATOR_NOTEQ:
case OPERATOR_LT: case OPERATOR_LT:
...@@ -2997,10 +2994,7 @@ Parse::expression(Precedence precedence, bool may_be_sink, ...@@ -2997,10 +2994,7 @@ Parse::expression(Precedence precedence, bool may_be_sink,
Expression* right = this->expression(right_precedence, false, Expression* right = this->expression(right_precedence, false,
may_be_composite_lit, may_be_composite_lit,
NULL); NULL);
if (op == OPERATOR_CHANOP) left = Expression::make_binary(op, left, right, binop_location);
left = Expression::make_send(left, right, binop_location);
else
left = Expression::make_binary(op, left, right, binop_location);
} }
} }
...@@ -3302,8 +3296,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location) ...@@ -3302,8 +3296,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location)
this->statement(label); this->statement(label);
} }
// SimpleStat = // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt |
// ExpressionStat | IncDecStat | Assignment | SimpleVarDecl . // Assignment | ShortVarDecl .
// EmptyStmt was handled in Parse::statement.
// In order to make this work for if and switch statements, if // In order to make this work for if and switch statements, if
// RETURN_EXP is true, and we see an ExpressionStat, we return the // RETURN_EXP is true, and we see an ExpressionStat, we return the
...@@ -3360,7 +3356,10 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp, ...@@ -3360,7 +3356,10 @@ Parse::simple_stat(bool may_be_composite_lit, bool return_exp,
return NULL; return NULL;
} }
token = this->peek_token(); token = this->peek_token();
if (token->is_op(OPERATOR_PLUSPLUS) || token->is_op(OPERATOR_MINUSMINUS)) if (token->is_op(OPERATOR_CHANOP))
this->send_stmt(this->verify_not_sink(exp));
else if (token->is_op(OPERATOR_PLUSPLUS)
|| token->is_op(OPERATOR_MINUSMINUS))
this->inc_dec_stat(this->verify_not_sink(exp)); this->inc_dec_stat(this->verify_not_sink(exp));
else if (token->is_op(OPERATOR_COMMA) else if (token->is_op(OPERATOR_COMMA)
|| token->is_op(OPERATOR_EQ)) || token->is_op(OPERATOR_EQ))
...@@ -3430,6 +3429,20 @@ Parse::expression_stat(Expression* exp) ...@@ -3430,6 +3429,20 @@ Parse::expression_stat(Expression* exp)
this->gogo_->add_statement(Statement::make_statement(exp)); this->gogo_->add_statement(Statement::make_statement(exp));
} }
// SendStmt = Channel "&lt;-" Expression .
// Channel = Expression .
void
Parse::send_stmt(Expression* channel)
{
gcc_assert(this->peek_token()->is_op(OPERATOR_CHANOP));
source_location loc = this->location();
this->advance_token();
Expression* val = this->expression(PRECEDENCE_NORMAL, false, true, NULL);
Statement* s = Statement::make_send_statement(channel, val, loc);
this->gogo_->add_statement(s);
}
// IncDecStat = Expression ( "++" | "--" ) . // IncDecStat = Expression ( "++" | "--" ) .
void void
...@@ -4159,7 +4172,7 @@ Parse::select_stat(const Label* label) ...@@ -4159,7 +4172,7 @@ Parse::select_stat(const Label* label)
this->gogo_->add_statement(statement); this->gogo_->add_statement(statement);
} }
// CommClause = CommCase [ StatementList ] . // CommClause = CommCase ":" { Statement ";" } .
void void
Parse::comm_clause(Select_clauses* clauses, bool* saw_default) Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
...@@ -4173,6 +4186,11 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4173,6 +4186,11 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
bool got_case = this->comm_case(&is_send, &channel, &val, &varname, bool got_case = this->comm_case(&is_send, &channel, &val, &varname,
&is_default); &is_default);
if (this->peek_token()->is_op(OPERATOR_COLON))
this->advance_token();
else
error_at(this->location(), "expected colon");
Block* statements = NULL; Block* statements = NULL;
Named_object* var = NULL; Named_object* var = NULL;
if (this->peek_token()->is_op(OPERATOR_SEMICOLON)) if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
...@@ -4214,7 +4232,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default) ...@@ -4214,7 +4232,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
} }
} }
// CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" . // CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
bool bool
Parse::comm_case(bool* is_send, Expression** channel, Expression** val, Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
...@@ -4240,18 +4258,9 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val, ...@@ -4240,18 +4258,9 @@ Parse::comm_case(bool* is_send, Expression** channel, Expression** val,
return false; return false;
} }
if (!this->peek_token()->is_op(OPERATOR_COLON))
{
error_at(this->location(), "expected colon");
return false;
}
this->advance_token();
return true; return true;
} }
// SendExpr = Expression "<-" Expression .
// RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression . // RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression .
bool bool
...@@ -4291,7 +4300,7 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val, ...@@ -4291,7 +4300,7 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
} }
else else
{ {
Expression* left = this->expression(PRECEDENCE_CHANOP, true, true, NULL); Expression* left = this->expression(PRECEDENCE_NORMAL, true, true, NULL);
if (this->peek_token()->is_op(OPERATOR_EQ)) if (this->peek_token()->is_op(OPERATOR_EQ))
{ {
......
...@@ -44,7 +44,6 @@ class Parse ...@@ -44,7 +44,6 @@ class Parse
PRECEDENCE_NORMAL = 0, PRECEDENCE_NORMAL = 0,
PRECEDENCE_OROR, PRECEDENCE_OROR,
PRECEDENCE_ANDAND, PRECEDENCE_ANDAND,
PRECEDENCE_CHANOP,
PRECEDENCE_RELOP, PRECEDENCE_RELOP,
PRECEDENCE_ADDOP, PRECEDENCE_ADDOP,
PRECEDENCE_MULOP PRECEDENCE_MULOP
...@@ -229,6 +228,7 @@ class Parse ...@@ -229,6 +228,7 @@ class Parse
void statement_list(); void statement_list();
bool statement_list_may_start_here(); bool statement_list_may_start_here();
void expression_stat(Expression*); void expression_stat(Expression*);
void send_stmt(Expression*);
void inc_dec_stat(Expression*); void inc_dec_stat(Expression*);
void assignment(Expression*, Range_clause*); void assignment(Expression*, Range_clause*);
void tuple_assignment(Expression_list*, Range_clause*); void tuple_assignment(Expression_list*, Range_clause*);
......
...@@ -3987,6 +3987,90 @@ Statement::make_type_switch_statement(Named_object* var, Expression* expr, ...@@ -3987,6 +3987,90 @@ Statement::make_type_switch_statement(Named_object* var, Expression* expr,
return new Type_switch_statement(var, expr, location); return new Type_switch_statement(var, expr, location);
} }
// Class Send_statement.
// Traversal.
int
Send_statement::do_traverse(Traverse* traverse)
{
if (this->traverse_expression(traverse, &this->channel_) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return this->traverse_expression(traverse, &this->val_);
}
// Determine types.
void
Send_statement::do_determine_types()
{
this->channel_->determine_type_no_context();
Type* type = this->channel_->type();
Type_context context;
if (type->channel_type() != NULL)
context.type = type->channel_type()->element_type();
this->val_->determine_type(&context);
}
// Check types.
void
Send_statement::do_check_types(Gogo*)
{
Type* type = this->channel_->type();
if (type->is_error_type())
{
this->set_is_error();
return;
}
Channel_type* channel_type = type->channel_type();
if (channel_type == NULL)
{
error_at(this->location(), "left operand of %<<-%> must be channel");
this->set_is_error();
return;
}
Type* element_type = channel_type->element_type();
if (!Type::are_assignable(element_type, this->val_->type(), NULL))
{
this->report_error(_("incompatible types in send"));
return;
}
if (!channel_type->may_send())
{
this->report_error(_("invalid send on receive-only channel"));
return;
}
}
// Get a tree for a send statement.
tree
Send_statement::do_get_tree(Translate_context* context)
{
tree channel = this->channel_->get_tree(context);
tree val = this->val_->get_tree(context);
if (channel == error_mark_node || val == error_mark_node)
return error_mark_node;
Channel_type* channel_type = this->channel_->type()->channel_type();
val = Expression::convert_for_assignment(context,
channel_type->element_type(),
this->val_->type(),
val,
this->location());
return Gogo::send_on_channel(channel, val, true, this->for_select_,
this->location());
}
// Make a send statement.
Send_statement*
Statement::make_send_statement(Expression* channel, Expression* val,
source_location location)
{
return new Send_statement(channel, val, location);
}
// Class Select_clauses::Select_clause. // Class Select_clauses::Select_clause.
// Traversal. // Traversal.
...@@ -4043,7 +4127,7 @@ Select_clauses::Select_clause::lower(Block* b) ...@@ -4043,7 +4127,7 @@ Select_clauses::Select_clause::lower(Block* b)
// If this is a send clause, evaluate the value to send before the // If this is a send clause, evaluate the value to send before the
// select statement. // select statement.
Temporary_statement* val_temp = NULL; Temporary_statement* val_temp = NULL;
if (this->is_send_) if (this->is_send_ && !this->val_->is_constant())
{ {
val_temp = Statement::make_temporary(NULL, this->val_, loc); val_temp = Statement::make_temporary(NULL, this->val_, loc);
b->add_statement(val_temp); b->add_statement(val_temp);
...@@ -4054,11 +4138,14 @@ Select_clauses::Select_clause::lower(Block* b) ...@@ -4054,11 +4138,14 @@ Select_clauses::Select_clause::lower(Block* b)
Expression* ref = Expression::make_temporary_reference(channel_temp, loc); Expression* ref = Expression::make_temporary_reference(channel_temp, loc);
if (this->is_send_) if (this->is_send_)
{ {
Expression* ref2 = Expression::make_temporary_reference(val_temp, loc); Expression* ref2;
Send_expression* send = Expression::make_send(ref, ref2, loc); if (val_temp == NULL)
send->discarding_value(); ref2 = this->val_;
else
ref2 = Expression::make_temporary_reference(val_temp, loc);
Send_statement* send = Statement::make_send_statement(ref, ref2, loc);
send->set_for_select(); send->set_for_select();
init->add_statement(Statement::make_statement(send)); init->add_statement(send);
} }
else else
{ {
......
...@@ -23,6 +23,7 @@ class For_statement; ...@@ -23,6 +23,7 @@ class For_statement;
class For_range_statement; class For_range_statement;
class Switch_statement; class Switch_statement;
class Type_switch_statement; class Type_switch_statement;
class Send_statement;
class Select_statement; class Select_statement;
class Variable; class Variable;
class Named_object; class Named_object;
...@@ -99,6 +100,7 @@ class Statement ...@@ -99,6 +100,7 @@ class Statement
STATEMENT_UNNAMED_LABEL, STATEMENT_UNNAMED_LABEL,
STATEMENT_IF, STATEMENT_IF,
STATEMENT_CONSTANT_SWITCH, STATEMENT_CONSTANT_SWITCH,
STATEMENT_SEND,
STATEMENT_SELECT, STATEMENT_SELECT,
// These statements types are created by the parser, but they // These statements types are created by the parser, but they
...@@ -236,6 +238,10 @@ class Statement ...@@ -236,6 +238,10 @@ class Statement
static Type_switch_statement* static Type_switch_statement*
make_type_switch_statement(Named_object* var, Expression*, source_location); make_type_switch_statement(Named_object* var, Expression*, source_location);
// Make a send statement.
static Send_statement*
make_send_statement(Expression* channel, Expression* val, source_location);
// Make a select statement. // Make a select statement.
static Select_statement* static Select_statement*
make_select_statement(source_location); make_select_statement(source_location);
...@@ -592,6 +598,44 @@ class Return_statement : public Statement ...@@ -592,6 +598,44 @@ class Return_statement : public Statement
Expression_list* vals_; Expression_list* vals_;
}; };
// A send statement.
class Send_statement : public Statement
{
public:
Send_statement(Expression* channel, Expression* val,
source_location location)
: Statement(STATEMENT_SEND, location),
channel_(channel), val_(val), for_select_(false)
{ }
// Note that this is for a select statement.
void
set_for_select()
{ this->for_select_ = true; }
protected:
int
do_traverse(Traverse* traverse);
void
do_determine_types();
void
do_check_types(Gogo*);
tree
do_get_tree(Translate_context*);
private:
// The channel on which to send the value.
Expression* channel_;
// The value to send.
Expression* val_;
// Whether this is for a select statement.
bool for_select_;
};
// Select_clauses holds the clauses of a select statement. This is // Select_clauses holds the clauses of a select statement. This is
// built by the parser. // built by the parser.
......
...@@ -76,7 +76,6 @@ func main() { ...@@ -76,7 +76,6 @@ func main() {
var i64 int64 var i64 int64
var b bool var b bool
var s string var s string
var ok bool
var sync = make(chan bool) var sync = make(chan bool)
...@@ -86,35 +85,45 @@ func main() { ...@@ -86,35 +85,45 @@ func main() {
cb := make(chan bool, buffer) cb := make(chan bool, buffer)
cs := make(chan string, buffer) cs := make(chan string, buffer)
i32, ok = <-c32 select {
if ok { case i32 = <-c32:
panic("blocked i32sender") panic("blocked i32sender")
default:
} }
i64, ok = <-c64 select {
if ok { case i64 = <-c64:
panic("blocked i64sender") panic("blocked i64sender")
default:
} }
b, ok = <-cb select {
if ok { case b = <-cb:
panic("blocked bsender") panic("blocked bsender")
default:
} }
s, ok = <-cs select {
if ok { case s = <-cs:
panic("blocked ssender") panic("blocked ssender")
default:
} }
go i32receiver(c32, sync) go i32receiver(c32, sync)
try := 0 try := 0
for !(c32 <- 123) { Send32:
try++ for {
if try > maxTries { select {
println("i32receiver buffer=", buffer) case c32 <- 123:
panic("fail") break Send32
default:
try++
if try > maxTries {
println("i32receiver buffer=", buffer)
panic("fail")
}
sleep()
} }
sleep()
} }
<-sync <-sync
...@@ -123,13 +132,19 @@ func main() { ...@@ -123,13 +132,19 @@ func main() {
<-sync <-sync
} }
try = 0 try = 0
for i32, ok = <-c32; !ok; i32, ok = <-c32 { Recv32:
try++ for {
if try > maxTries { select {
println("i32sender buffer=", buffer) case i32 = <-c32:
panic("fail") break Recv32
default:
try++
if try > maxTries {
println("i32sender buffer=", buffer)
panic("fail")
}
sleep()
} }
sleep()
} }
if i32 != 234 { if i32 != 234 {
panic("i32sender value") panic("i32sender value")
...@@ -140,12 +155,18 @@ func main() { ...@@ -140,12 +155,18 @@ func main() {
go i64receiver(c64, sync) go i64receiver(c64, sync)
try = 0 try = 0
for !(c64 <- 123456) { Send64:
try++ for {
if try > maxTries { select {
panic("i64receiver") case c64 <- 123456:
break Send64
default:
try++
if try > maxTries {
panic("i64receiver")
}
sleep()
} }
sleep()
} }
<-sync <-sync
...@@ -154,12 +175,18 @@ func main() { ...@@ -154,12 +175,18 @@ func main() {
<-sync <-sync
} }
try = 0 try = 0
for i64, ok = <-c64; !ok; i64, ok = <-c64 { Recv64:
try++ for {
if try > maxTries { select {
panic("i64sender") case i64 = <-c64:
break Recv64
default:
try++
if try > maxTries {
panic("i64sender")
}
sleep()
} }
sleep()
} }
if i64 != 234567 { if i64 != 234567 {
panic("i64sender value") panic("i64sender value")
...@@ -170,12 +197,18 @@ func main() { ...@@ -170,12 +197,18 @@ func main() {
go breceiver(cb, sync) go breceiver(cb, sync)
try = 0 try = 0
for !(cb <- true) { SendBool:
try++ for {
if try > maxTries { select {
panic("breceiver") case cb <- true:
break SendBool
default:
try++
if try > maxTries {
panic("breceiver")
}
sleep()
} }
sleep()
} }
<-sync <-sync
...@@ -184,12 +217,18 @@ func main() { ...@@ -184,12 +217,18 @@ func main() {
<-sync <-sync
} }
try = 0 try = 0
for b, ok = <-cb; !ok; b, ok = <-cb { RecvBool:
try++ for {
if try > maxTries { select {
panic("bsender") case b = <-cb:
break RecvBool
default:
try++
if try > maxTries {
panic("bsender")
}
sleep()
} }
sleep()
} }
if !b { if !b {
panic("bsender value") panic("bsender value")
...@@ -200,12 +239,18 @@ func main() { ...@@ -200,12 +239,18 @@ func main() {
go sreceiver(cs, sync) go sreceiver(cs, sync)
try = 0 try = 0
for !(cs <- "hello") { SendString:
try++ for {
if try > maxTries { select {
panic("sreceiver") case cs <- "hello":
break SendString
default:
try++
if try > maxTries {
panic("sreceiver")
}
sleep()
} }
sleep()
} }
<-sync <-sync
...@@ -214,12 +259,18 @@ func main() { ...@@ -214,12 +259,18 @@ func main() {
<-sync <-sync
} }
try = 0 try = 0
for s, ok = <-cs; !ok; s, ok = <-cs { RecvString:
try++ for {
if try > maxTries { select {
panic("ssender") case s = <-cs:
break RecvString
default:
try++
if try > maxTries {
panic("ssender")
}
sleep()
} }
sleep()
} }
if s != "hello again" { if s != "hello again" {
panic("ssender value") panic("ssender value")
......
...@@ -9,49 +9,46 @@ package main ...@@ -9,49 +9,46 @@ package main
var ( var (
cr <-chan int cr <-chan int
cs chan<- int cs chan<- int
c chan int c chan int
) )
func main() { func main() {
cr = c // ok cr = c // ok
cs = c // ok cs = c // ok
c = cr // ERROR "illegal types|incompatible|cannot" c = cr // ERROR "illegal types|incompatible|cannot"
c = cs // ERROR "illegal types|incompatible|cannot" c = cs // ERROR "illegal types|incompatible|cannot"
cr = cs // ERROR "illegal types|incompatible|cannot" cr = cs // ERROR "illegal types|incompatible|cannot"
cs = cr // ERROR "illegal types|incompatible|cannot" cs = cr // ERROR "illegal types|incompatible|cannot"
c <- 0 // ok c <- 0 // ok
ok := c <- 0 // ok <-c // ok
_ = ok //TODO(rsc): uncomment when this syntax is valid for receive+check closed
<-c // ok // x, ok := <-c // ok
x, ok := <-c // ok // _, _ = x, ok
_, _ = x, ok
cr <- 0 // ERROR "send"
cr <- 0 // ERROR "send" <-cr // ok
ok = cr <- 0 // ERROR "send" //TODO(rsc): uncomment when this syntax is valid for receive+check closed
_ = ok // x, ok = <-cr // ok
<-cr // ok // _, _ = x, ok
x, ok = <-cr // ok
_, _ = x, ok cs <- 0 // ok
<-cs // ERROR "receive"
cs <- 0 // ok ////TODO(rsc): uncomment when this syntax is valid for receive+check closed
ok = cs <- 0 // ok //// x, ok = <-cs // ERROR "receive"
_ = ok //// _, _ = x, ok
<-cs // ERROR "receive"
x, ok = <-cs // ERROR "receive"
_, _ = x, ok
select { select {
case c <- 0: // ok case c <- 0: // ok
case x := <-c: // ok case x := <-c: // ok
_ = x _ = x
case cr <- 0: // ERROR "send" case cr <- 0: // ERROR "send"
case x := <-cr: // ok case x := <-cr: // ok
_ = x _ = x
case cs <- 0: // ok case cs <- 0: // ok
case x := <-cs: // ERROR "receive" case x := <-cs: // ERROR "receive"
_ = x _ = x
} }
} }
...@@ -21,14 +21,21 @@ type Chan interface { ...@@ -21,14 +21,21 @@ type Chan interface {
Impl() string Impl() string
} }
// direct channel operations // direct channel operations when possible
type XChan chan int type XChan chan int
func (c XChan) Send(x int) { func (c XChan) Send(x int) {
c <- x c <- x
} }
func (c XChan) Nbsend(x int) bool { func (c XChan) Nbsend(x int) bool {
return c <- x select {
case c <- x:
return true
default:
return false
}
panic("nbsend")
} }
func (c XChan) Recv() int { func (c XChan) Recv() int {
...@@ -36,8 +43,13 @@ func (c XChan) Recv() int { ...@@ -36,8 +43,13 @@ func (c XChan) Recv() int {
} }
func (c XChan) Nbrecv() (int, bool) { func (c XChan) Nbrecv() (int, bool) {
x, ok := <-c select {
return x, ok case x := <-c:
return x, true
default:
return 0, false
}
panic("nbrecv")
} }
func (c XChan) Close() { func (c XChan) Close() {
...@@ -54,6 +66,7 @@ func (c XChan) Impl() string { ...@@ -54,6 +66,7 @@ func (c XChan) Impl() string {
// indirect operations via select // indirect operations via select
type SChan chan int type SChan chan int
func (c SChan) Send(x int) { func (c SChan) Send(x int) {
select { select {
case c <- x: case c <- x:
...@@ -62,10 +75,10 @@ func (c SChan) Send(x int) { ...@@ -62,10 +75,10 @@ func (c SChan) Send(x int) {
func (c SChan) Nbsend(x int) bool { func (c SChan) Nbsend(x int) bool {
select { select {
case c <- x:
return true
default: default:
return false return false
case c <- x:
return true
} }
panic("nbsend") panic("nbsend")
} }
...@@ -80,10 +93,10 @@ func (c SChan) Recv() int { ...@@ -80,10 +93,10 @@ func (c SChan) Recv() int {
func (c SChan) Nbrecv() (int, bool) { func (c SChan) Nbrecv() (int, bool) {
select { select {
case x := <-c:
return x, true
default: default:
return 0, false return 0, false
case x := <-c:
return x, true
} }
panic("nbrecv") panic("nbrecv")
} }
...@@ -100,6 +113,62 @@ func (c SChan) Impl() string { ...@@ -100,6 +113,62 @@ func (c SChan) Impl() string {
return "(select)" return "(select)"
} }
// indirect operations via larger selects
var dummy = make(chan bool)
type SSChan chan int
func (c SSChan) Send(x int) {
select {
case c <- x:
case <-dummy:
}
}
func (c SSChan) Nbsend(x int) bool {
select {
default:
return false
case <-dummy:
case c <- x:
return true
}
panic("nbsend")
}
func (c SSChan) Recv() int {
select {
case <-dummy:
case x := <-c:
return x
}
panic("recv")
}
func (c SSChan) Nbrecv() (int, bool) {
select {
case <-dummy:
default:
return 0, false
case x := <-c:
return x, true
}
panic("nbrecv")
}
func (c SSChan) Close() {
close(c)
}
func (c SSChan) Closed() bool {
return closed(c)
}
func (c SSChan) Impl() string {
return "(select)"
}
func shouldPanic(f func()) { func shouldPanic(f func()) {
defer func() { defer func() {
if recover() == nil { if recover() == nil {
...@@ -137,7 +206,7 @@ func test1(c Chan) { ...@@ -137,7 +206,7 @@ func test1(c Chan) {
} }
// send should work with ,ok too: sent a value without blocking, so ok == true. // send should work with ,ok too: sent a value without blocking, so ok == true.
shouldPanic(func(){c.Nbsend(1)}) shouldPanic(func() { c.Nbsend(1) })
// the value should have been discarded. // the value should have been discarded.
if x := c.Recv(); x != 0 { if x := c.Recv(); x != 0 {
...@@ -145,7 +214,7 @@ func test1(c Chan) { ...@@ -145,7 +214,7 @@ func test1(c Chan) {
} }
// similarly Send. // similarly Send.
shouldPanic(func(){c.Send(2)}) shouldPanic(func() { c.Send(2) })
if x := c.Recv(); x != 0 { if x := c.Recv(); x != 0 {
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
} }
...@@ -195,9 +264,12 @@ func closedasync() chan int { ...@@ -195,9 +264,12 @@ func closedasync() chan int {
func main() { func main() {
test1(XChan(closedsync())) test1(XChan(closedsync()))
test1(SChan(closedsync())) test1(SChan(closedsync()))
test1(SSChan(closedsync()))
testasync1(XChan(closedasync())) testasync1(XChan(closedasync()))
testasync1(SChan(closedasync())) testasync1(SChan(closedasync()))
testasync1(SSChan(closedasync()))
testasync2(XChan(closedasync())) testasync2(XChan(closedasync()))
testasync2(SChan(closedasync())) testasync2(SChan(closedasync()))
testasync2(SSChan(closedasync()))
} }
...@@ -6,15 +6,16 @@ ...@@ -6,15 +6,16 @@
package main package main
func main(){ func main() {
c := make(chan int); //TODO(rsc): uncomment when this syntax is valid for receive+check closed
ok := false; // c := make(chan int);
var i int; // ok := false;
// var i int;
i, ok = <-c; // works //
_, _ = i, ok; // i, ok = <-c; // works
// _, _ = i, ok;
ca := new([2]chan int); //
i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2 // ca := new([2]chan int);
_, _ = i, ok; // i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2
// _, _ = i, ok;
} }
...@@ -13,11 +13,12 @@ var i int ...@@ -13,11 +13,12 @@ var i int
func multi() (int, int) { return 1, 2 } func multi() (int, int) { return 1, 2 }
func xxx() { func xxx() {
var c chan int //TODO(rsc): uncomment when this syntax is valid for receive+check closed
x, ok := <-c // var c chan int
// x, ok := <-c
var m map[int]int var m map[int]int
x, ok = m[1] x, ok := m[1]
var i interface{} var i interface{}
var xx int var xx int
......
...@@ -7,16 +7,17 @@ ...@@ -7,16 +7,17 @@
package main package main
func main() { func main() {
c := make(chan int, 1) //TODO(rsc): uncomment when this syntax is valid for receive+check closed
c <- 100 // c := make(chan int, 1)
x, ok := <-c // c <- 100
if x != 100 || !ok { // x, ok := <-c
println("x=", x, " ok=", ok, " want 100, true") // if x != 100 || !ok {
panic("fail") // println("x=", x, " ok=", ok, " want 100, true")
} // panic("fail")
x, ok = <-c // }
if x != 0 || ok { // x, ok = <-c
println("x=", x, " ok=", ok, " want 0, false") // if x != 0 || ok {
panic("fail") // println("x=", x, " ok=", ok, " want 0, false")
} // panic("fail")
// }
} }
...@@ -101,10 +101,13 @@ func main() { ...@@ -101,10 +101,13 @@ func main() {
c := make(chan byte, 1) c := make(chan byte, 1)
c <- 'C' c <- 'C'
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
// 15 16 // 15 16
*f(), p1 = <-e1(c, 16) // *f(), p1 = <-e1(c, 16)
*f(), p1 = <-e1(c, 16), true // delete uncommenting above
// 17 18 // 17 18
*f(), p2 = <-e1(c, 18) // *f(), p2 = <-e1(c, 18)
*f(), p2, _ = 0, false, e1(c, 18) // delete when uncommenting above
a[17] += '0' a[17] += '0'
if !p1 || p2 { if !p1 || p2 {
println("bad chan check", i, p1, p2) println("bad chan check", i, p1, p2)
......
...@@ -43,12 +43,9 @@ func main() { ...@@ -43,12 +43,9 @@ func main() {
_, b = m[2] // ERROR "cannot .* bool.*type Bool" _, b = m[2] // ERROR "cannot .* bool.*type Bool"
m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool" m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
b = c <- 1 // ERROR "cannot use.*type bool.*type Bool" ////TODO(rsc): uncomment when this syntax is valid for receive+check closed
_ = b //// _, b = <-c // ERROR "cannot .* bool.*type Bool"
asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool" //// _ = b
_, b = <-c // ERROR "cannot .* bool.*type Bool"
_ = b
var inter interface{} var inter interface{}
_, b = inter.(Map) // ERROR "cannot .* bool.*type Bool" _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment