Change c <- v from an expression to a statement.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 24 Mar 2011 00:01:44 +0000 (00:01 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 24 Mar 2011 00:01:44 +0000 (00:01 +0000)
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

15 files changed:
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/testsuite/go.test/test/chan/nonblock.go
gcc/testsuite/go.test/test/chan/perm.go
gcc/testsuite/go.test/test/closedchan.go
gcc/testsuite/go.test/test/fixedbugs/bug069.go
gcc/testsuite/go.test/test/fixedbugs/bug196.go
gcc/testsuite/go.test/test/fixedbugs/bug234.go
gcc/testsuite/go.test/test/fixedbugs/bug242.go
gcc/testsuite/go.test/test/named1.go

index 8660c755abbc580e1665260ac074ecb5ef0b4c87..125715bb2de8bb325f3c67a4ed18a3d9a7d3493c 100644 (file)
@@ -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.
 
index 1dc408d557f22e8ceb9179d86ea8d1fac0559563..fa240a69b8c139dc11979d4de3f7ee4511505884 100644 (file)
@@ -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_;
 };
index f8c143c9c298617ea72c5d4d4fa73286408ce214..f2476d549d11cf7af5c8a87f613520fd92a2c6bc 100644 (file)
@@ -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())
index 7c03870e82e3814336a719c34598e0b17945940c..2e591495684eb5e0744b113a18a787d5f254a776 100644 (file)
@@ -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 "&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 ( "++" | "--" ) .
 
 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))
        {
index 6f2ac64b1f71be8be3db29109d55bec1fc2366a6..04ae324f4d813c4bd4b05d8f2e39b88461c32d2d 100644 (file)
@@ -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*);
index c443519b77d0c90adc3e737b9d85e726ae61865a..5a4ad06132978e9426f4991afc1087afb615712a 100644 (file)
@@ -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
     {
index 80cdffe801ec2fe406304793b0c4a5fa329438cf..83d5436ac74beb2fc27852c618ce9f87128df61f 100644 (file)
@@ -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.
 
index 52f04bfb12f53c4d87c1c653616bfcd1f5a094f6..33afb3291652b11f93da64001ba36d85a84c5cb9 100644 (file)
@@ -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")
index d08c035193de0366005b370d695c7b5558be3cdc..c725829d13293aa8817b6ee2f239d8788728910e 100644 (file)
@@ -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"
-
-       c <- 0          // ok
-       ok := c <- 0    // ok
-       _ = ok
-       <-c             // ok
-       x, ok := <-c    // ok
-       _, _ = x, ok
-
-       cr <- 0 // ERROR "send"
-       ok = cr <- 0    // ERROR "send"
-       _ = ok
-       <-cr            // ok
-       x, ok = <-cr    // ok
-       _, _ = x, ok
-
-       cs <- 0 // ok
-       ok = cs <- 0    // ok
-       _ = ok
-       <-cs            // ERROR "receive"
-       x, ok = <-cs    // ERROR "receive"
-       _, _ = x, ok
+       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
+       <-c    // ok
+       //TODO(rsc): uncomment when this syntax is valid for receive+check closed
+       //      x, ok := <-c    // 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
+       <-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
        }
 }
index 8126d5a4e4c71ade746f8e836d7f25451cf19d73..46d9d0f5d211effcf6a34cd4e06dc034b6b93abc 100644 (file)
@@ -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()))
 }
index d6796cd72be19cdf4427c31208643f519d028633..bf73163134d709cb41b4fdb97f0add621cd54bb0 100644 (file)
@@ -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;
 }
index ea8ab0dc193c71e82686a814d0c8fbd11e36b2bb..8cb9c9990d9d3bf9d2cf5070a0b569278ea9fa77 100644 (file)
@@ -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
index b806ca64e98f2cad5ba97cb580afff2dd210fc91..9affad043027a3e6cde34f0a05fcc7c5d515d056 100644 (file)
@@ -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")
+       //      }
 }
index 5c21eaaf0084c36ce24b71f1b037457bcc961057..ad1cef8df4302b49baa0f30cb699990b74283241 100644 (file)
@@ -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)
index 600e502f9e8f31c8926a5665579483cd3f3c85a6..1776313f05cea2de56c2cba1e61b7de4d5635d4b 100644 (file)
@@ -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"