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
This commit is contained in:
parent
e110e232b6
commit
27a19c5847
@ -12357,103 +12357,6 @@ Expression::make_receive(Expression* channel, source_location 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
|
||||
// of a type.
|
||||
|
||||
|
@ -36,7 +36,6 @@ class Field_reference_expression;
|
||||
class Interface_field_reference_expression;
|
||||
class Type_guard_expression;
|
||||
class Receive_expression;
|
||||
class Send_expression;
|
||||
class Named_object;
|
||||
class Export;
|
||||
class Import;
|
||||
@ -89,7 +88,6 @@ class Expression
|
||||
EXPRESSION_COMPOSITE_LITERAL,
|
||||
EXPRESSION_HEAP_COMPOSITE,
|
||||
EXPRESSION_RECEIVE,
|
||||
EXPRESSION_SEND,
|
||||
EXPRESSION_TYPE_DESCRIPTOR,
|
||||
EXPRESSION_TYPE_INFO,
|
||||
EXPRESSION_STRUCT_FIELD_OFFSET,
|
||||
@ -271,10 +269,6 @@ class Expression
|
||||
static Receive_expression*
|
||||
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
|
||||
// type.
|
||||
static Expression*
|
||||
@ -356,8 +350,7 @@ class Expression
|
||||
|
||||
// This is called by the parser if the value of this expression is
|
||||
// being discarded. This issues warnings about computed values
|
||||
// being unused, and handles send expressions which act differently
|
||||
// depending upon whether the value is used.
|
||||
// being unused.
|
||||
void
|
||||
discarding_value()
|
||||
{ this->do_discarding_value(); }
|
||||
@ -1807,7 +1800,7 @@ class Receive_expression : public Expression
|
||||
public:
|
||||
Receive_expression(Expression* channel, source_location location)
|
||||
: Expression(EXPRESSION_RECEIVE, location),
|
||||
channel_(channel), is_value_discarded_(false), for_select_(false)
|
||||
channel_(channel), for_select_(false)
|
||||
{ }
|
||||
|
||||
// Return the channel.
|
||||
@ -1827,7 +1820,7 @@ class Receive_expression : public Expression
|
||||
|
||||
void
|
||||
do_discarding_value()
|
||||
{ this->is_value_discarded_ = true; }
|
||||
{ }
|
||||
|
||||
Type*
|
||||
do_type();
|
||||
@ -1855,67 +1848,6 @@ class Receive_expression : public Expression
|
||||
private:
|
||||
// The channel from which we are receiving.
|
||||
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.
|
||||
bool for_select_;
|
||||
};
|
||||
|
@ -1926,14 +1926,6 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
|
||||
{
|
||||
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
|
||||
// or defer, which we must not evaluate early.
|
||||
if (is_thunk && p + 1 == find_eval_ordering.end())
|
||||
|
@ -2944,9 +2944,6 @@ Parse::expression(Precedence precedence, bool may_be_sink,
|
||||
case OPERATOR_ANDAND:
|
||||
right_precedence = PRECEDENCE_ANDAND;
|
||||
break;
|
||||
case OPERATOR_CHANOP:
|
||||
right_precedence = PRECEDENCE_CHANOP;
|
||||
break;
|
||||
case OPERATOR_EQEQ:
|
||||
case OPERATOR_NOTEQ:
|
||||
case OPERATOR_LT:
|
||||
@ -2997,10 +2994,7 @@ Parse::expression(Precedence precedence, bool may_be_sink,
|
||||
Expression* right = this->expression(right_precedence, false,
|
||||
may_be_composite_lit,
|
||||
NULL);
|
||||
if (op == OPERATOR_CHANOP)
|
||||
left = Expression::make_send(left, right, binop_location);
|
||||
else
|
||||
left = Expression::make_binary(op, left, right, binop_location);
|
||||
left = Expression::make_binary(op, left, right, binop_location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3302,8 +3296,10 @@ Parse::labeled_stmt(const std::string& label_name, source_location location)
|
||||
this->statement(label);
|
||||
}
|
||||
|
||||
// SimpleStat =
|
||||
// ExpressionStat | IncDecStat | Assignment | SimpleVarDecl .
|
||||
// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt |
|
||||
// Assignment | ShortVarDecl .
|
||||
|
||||
// EmptyStmt was handled in Parse::statement.
|
||||
|
||||
// In order to make this work for if and switch statements, if
|
||||
// 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,
|
||||
return NULL;
|
||||
}
|
||||
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));
|
||||
else if (token->is_op(OPERATOR_COMMA)
|
||||
|| token->is_op(OPERATOR_EQ))
|
||||
@ -3430,6 +3429,20 @@ Parse::expression_stat(Expression* exp)
|
||||
this->gogo_->add_statement(Statement::make_statement(exp));
|
||||
}
|
||||
|
||||
// SendStmt = Channel "<-" 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 ( "++" | "--" ) .
|
||||
|
||||
void
|
||||
@ -4159,7 +4172,7 @@ Parse::select_stat(const Label* label)
|
||||
this->gogo_->add_statement(statement);
|
||||
}
|
||||
|
||||
// CommClause = CommCase [ StatementList ] .
|
||||
// CommClause = CommCase ":" { Statement ";" } .
|
||||
|
||||
void
|
||||
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,
|
||||
&is_default);
|
||||
|
||||
if (this->peek_token()->is_op(OPERATOR_COLON))
|
||||
this->advance_token();
|
||||
else
|
||||
error_at(this->location(), "expected colon");
|
||||
|
||||
Block* statements = NULL;
|
||||
Named_object* var = NULL;
|
||||
if (this->peek_token()->is_op(OPERATOR_SEMICOLON))
|
||||
@ -4214,7 +4232,7 @@ Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
|
||||
}
|
||||
}
|
||||
|
||||
// CommCase = ( "default" | ( "case" ( SendExpr | RecvExpr) ) ) ":" .
|
||||
// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
|
||||
|
||||
bool
|
||||
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;
|
||||
}
|
||||
|
||||
if (!this->peek_token()->is_op(OPERATOR_COLON))
|
||||
{
|
||||
error_at(this->location(), "expected colon");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->advance_token();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// SendExpr = Expression "<-" Expression .
|
||||
// RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression .
|
||||
|
||||
bool
|
||||
@ -4291,7 +4300,7 @@ Parse::send_or_recv_expr(bool* is_send, Expression** channel, Expression** val,
|
||||
}
|
||||
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))
|
||||
{
|
||||
|
@ -44,7 +44,6 @@ class Parse
|
||||
PRECEDENCE_NORMAL = 0,
|
||||
PRECEDENCE_OROR,
|
||||
PRECEDENCE_ANDAND,
|
||||
PRECEDENCE_CHANOP,
|
||||
PRECEDENCE_RELOP,
|
||||
PRECEDENCE_ADDOP,
|
||||
PRECEDENCE_MULOP
|
||||
@ -229,6 +228,7 @@ class Parse
|
||||
void statement_list();
|
||||
bool statement_list_may_start_here();
|
||||
void expression_stat(Expression*);
|
||||
void send_stmt(Expression*);
|
||||
void inc_dec_stat(Expression*);
|
||||
void assignment(Expression*, Range_clause*);
|
||||
void tuple_assignment(Expression_list*, Range_clause*);
|
||||
|
@ -3987,6 +3987,90 @@ Statement::make_type_switch_statement(Named_object* var, Expression* expr,
|
||||
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.
|
||||
|
||||
// Traversal.
|
||||
@ -4043,7 +4127,7 @@ Select_clauses::Select_clause::lower(Block* b)
|
||||
// If this is a send clause, evaluate the value to send before the
|
||||
// select statement.
|
||||
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);
|
||||
b->add_statement(val_temp);
|
||||
@ -4054,11 +4138,14 @@ Select_clauses::Select_clause::lower(Block* b)
|
||||
Expression* ref = Expression::make_temporary_reference(channel_temp, loc);
|
||||
if (this->is_send_)
|
||||
{
|
||||
Expression* ref2 = Expression::make_temporary_reference(val_temp, loc);
|
||||
Send_expression* send = Expression::make_send(ref, ref2, loc);
|
||||
send->discarding_value();
|
||||
Expression* ref2;
|
||||
if (val_temp == NULL)
|
||||
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();
|
||||
init->add_statement(Statement::make_statement(send));
|
||||
init->add_statement(send);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -23,6 +23,7 @@ class For_statement;
|
||||
class For_range_statement;
|
||||
class Switch_statement;
|
||||
class Type_switch_statement;
|
||||
class Send_statement;
|
||||
class Select_statement;
|
||||
class Variable;
|
||||
class Named_object;
|
||||
@ -99,6 +100,7 @@ class Statement
|
||||
STATEMENT_UNNAMED_LABEL,
|
||||
STATEMENT_IF,
|
||||
STATEMENT_CONSTANT_SWITCH,
|
||||
STATEMENT_SEND,
|
||||
STATEMENT_SELECT,
|
||||
|
||||
// These statements types are created by the parser, but they
|
||||
@ -236,6 +238,10 @@ class Statement
|
||||
static Type_switch_statement*
|
||||
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.
|
||||
static Select_statement*
|
||||
make_select_statement(source_location);
|
||||
@ -592,6 +598,44 @@ class Return_statement : public Statement
|
||||
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
|
||||
// built by the parser.
|
||||
|
||||
|
@ -76,7 +76,6 @@ func main() {
|
||||
var i64 int64
|
||||
var b bool
|
||||
var s string
|
||||
var ok bool
|
||||
|
||||
var sync = make(chan bool)
|
||||
|
||||
@ -86,35 +85,45 @@ func main() {
|
||||
cb := make(chan bool, buffer)
|
||||
cs := make(chan string, buffer)
|
||||
|
||||
i32, ok = <-c32
|
||||
if ok {
|
||||
select {
|
||||
case i32 = <-c32:
|
||||
panic("blocked i32sender")
|
||||
default:
|
||||
}
|
||||
|
||||
i64, ok = <-c64
|
||||
if ok {
|
||||
select {
|
||||
case i64 = <-c64:
|
||||
panic("blocked i64sender")
|
||||
default:
|
||||
}
|
||||
|
||||
b, ok = <-cb
|
||||
if ok {
|
||||
select {
|
||||
case b = <-cb:
|
||||
panic("blocked bsender")
|
||||
default:
|
||||
}
|
||||
|
||||
s, ok = <-cs
|
||||
if ok {
|
||||
select {
|
||||
case s = <-cs:
|
||||
panic("blocked ssender")
|
||||
default:
|
||||
}
|
||||
|
||||
go i32receiver(c32, sync)
|
||||
try := 0
|
||||
for !(c32 <- 123) {
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32receiver buffer=", buffer)
|
||||
panic("fail")
|
||||
Send32:
|
||||
for {
|
||||
select {
|
||||
case c32 <- 123:
|
||||
break Send32
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32receiver buffer=", buffer)
|
||||
panic("fail")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
<-sync
|
||||
|
||||
@ -123,13 +132,19 @@ func main() {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
for i32, ok = <-c32; !ok; i32, ok = <-c32 {
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32sender buffer=", buffer)
|
||||
panic("fail")
|
||||
Recv32:
|
||||
for {
|
||||
select {
|
||||
case i32 = <-c32:
|
||||
break Recv32
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
println("i32sender buffer=", buffer)
|
||||
panic("fail")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
if i32 != 234 {
|
||||
panic("i32sender value")
|
||||
@ -140,12 +155,18 @@ func main() {
|
||||
|
||||
go i64receiver(c64, sync)
|
||||
try = 0
|
||||
for !(c64 <- 123456) {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64receiver")
|
||||
Send64:
|
||||
for {
|
||||
select {
|
||||
case c64 <- 123456:
|
||||
break Send64
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64receiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
<-sync
|
||||
|
||||
@ -154,12 +175,18 @@ func main() {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
for i64, ok = <-c64; !ok; i64, ok = <-c64 {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64sender")
|
||||
Recv64:
|
||||
for {
|
||||
select {
|
||||
case i64 = <-c64:
|
||||
break Recv64
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("i64sender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
if i64 != 234567 {
|
||||
panic("i64sender value")
|
||||
@ -170,12 +197,18 @@ func main() {
|
||||
|
||||
go breceiver(cb, sync)
|
||||
try = 0
|
||||
for !(cb <- true) {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("breceiver")
|
||||
SendBool:
|
||||
for {
|
||||
select {
|
||||
case cb <- true:
|
||||
break SendBool
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("breceiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
<-sync
|
||||
|
||||
@ -184,12 +217,18 @@ func main() {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
for b, ok = <-cb; !ok; b, ok = <-cb {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("bsender")
|
||||
RecvBool:
|
||||
for {
|
||||
select {
|
||||
case b = <-cb:
|
||||
break RecvBool
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("bsender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
if !b {
|
||||
panic("bsender value")
|
||||
@ -200,12 +239,18 @@ func main() {
|
||||
|
||||
go sreceiver(cs, sync)
|
||||
try = 0
|
||||
for !(cs <- "hello") {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("sreceiver")
|
||||
SendString:
|
||||
for {
|
||||
select {
|
||||
case cs <- "hello":
|
||||
break SendString
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("sreceiver")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
<-sync
|
||||
|
||||
@ -214,12 +259,18 @@ func main() {
|
||||
<-sync
|
||||
}
|
||||
try = 0
|
||||
for s, ok = <-cs; !ok; s, ok = <-cs {
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("ssender")
|
||||
RecvString:
|
||||
for {
|
||||
select {
|
||||
case s = <-cs:
|
||||
break RecvString
|
||||
default:
|
||||
try++
|
||||
if try > maxTries {
|
||||
panic("ssender")
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
sleep()
|
||||
}
|
||||
if s != "hello again" {
|
||||
panic("ssender value")
|
||||
|
@ -9,49 +9,46 @@ package main
|
||||
var (
|
||||
cr <-chan int
|
||||
cs chan<- int
|
||||
c chan int
|
||||
c chan int
|
||||
)
|
||||
|
||||
func main() {
|
||||
cr = c // ok
|
||||
cs = c // ok
|
||||
c = cr // ERROR "illegal types|incompatible|cannot"
|
||||
c = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cr = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cs = cr // ERROR "illegal types|incompatible|cannot"
|
||||
cr = c // ok
|
||||
cs = c // ok
|
||||
c = cr // ERROR "illegal types|incompatible|cannot"
|
||||
c = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cr = cs // ERROR "illegal types|incompatible|cannot"
|
||||
cs = cr // ERROR "illegal types|incompatible|cannot"
|
||||
|
||||
c <- 0 // ok
|
||||
ok := c <- 0 // ok
|
||||
_ = ok
|
||||
<-c // ok
|
||||
x, ok := <-c // ok
|
||||
_, _ = x, ok
|
||||
c <- 0 // ok
|
||||
<-c // ok
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// x, ok := <-c // ok
|
||||
// _, _ = x, ok
|
||||
|
||||
cr <- 0 // ERROR "send"
|
||||
ok = cr <- 0 // ERROR "send"
|
||||
_ = ok
|
||||
<-cr // ok
|
||||
x, ok = <-cr // ok
|
||||
_, _ = x, ok
|
||||
cr <- 0 // ERROR "send"
|
||||
<-cr // ok
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// x, ok = <-cr // ok
|
||||
// _, _ = x, ok
|
||||
|
||||
cs <- 0 // ok
|
||||
ok = cs <- 0 // ok
|
||||
_ = ok
|
||||
<-cs // ERROR "receive"
|
||||
x, ok = <-cs // ERROR "receive"
|
||||
_, _ = x, ok
|
||||
cs <- 0 // ok
|
||||
<-cs // ERROR "receive"
|
||||
////TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
//// x, ok = <-cs // ERROR "receive"
|
||||
//// _, _ = x, ok
|
||||
|
||||
select {
|
||||
case c <- 0: // ok
|
||||
case x := <-c: // ok
|
||||
case c <- 0: // ok
|
||||
case x := <-c: // ok
|
||||
_ = x
|
||||
|
||||
case cr <- 0: // ERROR "send"
|
||||
case x := <-cr: // ok
|
||||
case cr <- 0: // ERROR "send"
|
||||
case x := <-cr: // ok
|
||||
_ = x
|
||||
|
||||
case cs <- 0: // ok
|
||||
case x := <-cs: // ERROR "receive"
|
||||
case cs <- 0: // ok
|
||||
case x := <-cs: // ERROR "receive"
|
||||
_ = x
|
||||
}
|
||||
}
|
||||
|
@ -21,14 +21,21 @@ type Chan interface {
|
||||
Impl() string
|
||||
}
|
||||
|
||||
// direct channel operations
|
||||
// direct channel operations when possible
|
||||
type XChan chan int
|
||||
|
||||
func (c XChan) Send(x int) {
|
||||
c <- x
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -36,8 +43,13 @@ func (c XChan) Recv() int {
|
||||
}
|
||||
|
||||
func (c XChan) Nbrecv() (int, bool) {
|
||||
x, ok := <-c
|
||||
return x, ok
|
||||
select {
|
||||
case x := <-c:
|
||||
return x, true
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
panic("nbrecv")
|
||||
}
|
||||
|
||||
func (c XChan) Close() {
|
||||
@ -54,6 +66,7 @@ func (c XChan) Impl() string {
|
||||
|
||||
// indirect operations via select
|
||||
type SChan chan int
|
||||
|
||||
func (c SChan) Send(x int) {
|
||||
select {
|
||||
case c <- x:
|
||||
@ -62,10 +75,10 @@ func (c SChan) Send(x int) {
|
||||
|
||||
func (c SChan) Nbsend(x int) bool {
|
||||
select {
|
||||
case c <- x:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
case c <- x:
|
||||
return true
|
||||
}
|
||||
panic("nbsend")
|
||||
}
|
||||
@ -80,10 +93,10 @@ func (c SChan) Recv() int {
|
||||
|
||||
func (c SChan) Nbrecv() (int, bool) {
|
||||
select {
|
||||
case x := <-c:
|
||||
return x, true
|
||||
default:
|
||||
return 0, false
|
||||
case x := <-c:
|
||||
return x, true
|
||||
}
|
||||
panic("nbrecv")
|
||||
}
|
||||
@ -100,6 +113,62 @@ func (c SChan) Impl() string {
|
||||
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()) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
@ -137,7 +206,7 @@ func test1(c Chan) {
|
||||
}
|
||||
|
||||
// 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.
|
||||
if x := c.Recv(); x != 0 {
|
||||
@ -145,7 +214,7 @@ func test1(c Chan) {
|
||||
}
|
||||
|
||||
// similarly Send.
|
||||
shouldPanic(func(){c.Send(2)})
|
||||
shouldPanic(func() { c.Send(2) })
|
||||
if x := c.Recv(); x != 0 {
|
||||
println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
|
||||
}
|
||||
@ -195,9 +264,12 @@ func closedasync() chan int {
|
||||
func main() {
|
||||
test1(XChan(closedsync()))
|
||||
test1(SChan(closedsync()))
|
||||
test1(SSChan(closedsync()))
|
||||
|
||||
testasync1(XChan(closedasync()))
|
||||
testasync1(SChan(closedasync()))
|
||||
testasync1(SSChan(closedasync()))
|
||||
testasync2(XChan(closedasync()))
|
||||
testasync2(SChan(closedasync()))
|
||||
testasync2(SSChan(closedasync()))
|
||||
}
|
||||
|
@ -6,15 +6,16 @@
|
||||
|
||||
package main
|
||||
|
||||
func main(){
|
||||
c := make(chan int);
|
||||
ok := false;
|
||||
var i int;
|
||||
|
||||
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
|
||||
_, _ = i, ok;
|
||||
func main() {
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// c := make(chan int);
|
||||
// ok := false;
|
||||
// var i int;
|
||||
//
|
||||
// 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
|
||||
// _, _ = i, ok;
|
||||
}
|
||||
|
@ -13,11 +13,12 @@ var i int
|
||||
func multi() (int, int) { return 1, 2 }
|
||||
|
||||
func xxx() {
|
||||
var c chan int
|
||||
x, ok := <-c
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// var c chan int
|
||||
// x, ok := <-c
|
||||
|
||||
var m map[int]int
|
||||
x, ok = m[1]
|
||||
x, ok := m[1]
|
||||
|
||||
var i interface{}
|
||||
var xx int
|
||||
|
@ -7,16 +7,17 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 1)
|
||||
c <- 100
|
||||
x, ok := <-c
|
||||
if x != 100 || !ok {
|
||||
println("x=", x, " ok=", ok, " want 100, true")
|
||||
panic("fail")
|
||||
}
|
||||
x, ok = <-c
|
||||
if x != 0 || ok {
|
||||
println("x=", x, " ok=", ok, " want 0, false")
|
||||
panic("fail")
|
||||
}
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// c := make(chan int, 1)
|
||||
// c <- 100
|
||||
// x, ok := <-c
|
||||
// if x != 100 || !ok {
|
||||
// println("x=", x, " ok=", ok, " want 100, true")
|
||||
// panic("fail")
|
||||
// }
|
||||
// x, ok = <-c
|
||||
// if x != 0 || ok {
|
||||
// println("x=", x, " ok=", ok, " want 0, false")
|
||||
// panic("fail")
|
||||
// }
|
||||
}
|
||||
|
@ -101,10 +101,13 @@ func main() {
|
||||
|
||||
c := make(chan byte, 1)
|
||||
c <- 'C'
|
||||
//TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
// 15 16
|
||||
*f(), p1 = <-e1(c, 16)
|
||||
// *f(), p1 = <-e1(c, 16)
|
||||
*f(), p1 = <-e1(c, 16), true // delete uncommenting above
|
||||
// 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'
|
||||
if !p1 || p2 {
|
||||
println("bad chan check", i, p1, p2)
|
||||
|
@ -43,12 +43,9 @@ func main() {
|
||||
_, b = m[2] // ERROR "cannot .* bool.*type Bool"
|
||||
m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
|
||||
|
||||
b = c <- 1 // ERROR "cannot use.*type bool.*type Bool"
|
||||
_ = b
|
||||
asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool"
|
||||
|
||||
_, b = <-c // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b
|
||||
////TODO(rsc): uncomment when this syntax is valid for receive+check closed
|
||||
//// _, b = <-c // ERROR "cannot .* bool.*type Bool"
|
||||
//// _ = b
|
||||
|
||||
var inter interface{}
|
||||
_, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
|
||||
|
Loading…
Reference in New Issue
Block a user