compiler: Fix parse of (<- chan <- chan <- int)(x).

From-SVN: r192011
This commit is contained in:
Ian Lance Taylor 2012-10-02 22:22:28 +00:00
parent d8ea0885d7
commit e395eacb4e
2 changed files with 83 additions and 8 deletions

View File

@ -3315,6 +3315,61 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
bool* is_type_switch)
{
const Token* token = this->peek_token();
// There is a complex parse for <- chan. The choices are
// Convert x to type <- chan int:
// (<- chan int)(x)
// Receive from (x converted to type chan <- chan int):
// (<- chan <- chan int (x))
// Convert x to type <- chan (<- chan int).
// (<- chan <- chan int)(x)
if (token->is_op(OPERATOR_CHANOP))
{
Location location = token->location();
if (this->advance_token()->is_keyword(KEYWORD_CHAN))
{
Expression* expr = this->primary_expr(false, may_be_composite_lit,
NULL);
if (expr->is_error_expression())
return expr;
else if (!expr->is_type_expression())
return Expression::make_receive(expr, location);
else
{
if (expr->type()->is_error_type())
return expr;
// We picked up "chan TYPE", but it is not a type
// conversion.
Channel_type* ct = expr->type()->channel_type();
if (ct == NULL)
{
// This is probably impossible.
error_at(location, "expected channel type");
return Expression::make_error(location);
}
else if (ct->may_receive())
{
// <- chan TYPE.
Type* t = Type::make_channel_type(false, true,
ct->element_type());
return Expression::make_type(t, location);
}
else
{
// <- chan <- TYPE. Because we skipped the leading
// <-, we parsed this as chan <- TYPE. With the
// leading <-, we parse it as <- chan (<- TYPE).
Type *t = this->reassociate_chan_direction(ct, location);
return Expression::make_type(t, location);
}
}
}
this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
token = this->peek_token();
}
if (token->is_op(OPERATOR_PLUS)
|| token->is_op(OPERATOR_MINUS)
|| token->is_op(OPERATOR_NOT)
@ -3327,14 +3382,6 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
Operator op = token->op();
this->advance_token();
if (op == OPERATOR_CHANOP
&& this->peek_token()->is_keyword(KEYWORD_CHAN))
{
// This is "<- chan" which must be the start of a type.
this->unget_token(Token::make_operator_token(op, location));
return Expression::make_type(this->type(), location);
}
Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
if (expr->is_error_expression())
;
@ -3354,6 +3401,32 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
is_type_switch);
}
// This is called for the obscure case of
// (<- chan <- chan int)(x)
// In unary_expr we remove the leading <- and parse the remainder,
// which gives us
// chan <- (chan int)
// When we add the leading <- back in, we really want
// <- chan (<- chan int)
// This means that we need to reassociate.
Type*
Parse::reassociate_chan_direction(Channel_type *ct, Location location)
{
Channel_type* ele = ct->element_type()->channel_type();
if (ele == NULL)
{
error_at(location, "parse error");
return Type::make_error_type();
}
Type* sub = ele;
if (ele->may_send())
sub = Type::make_channel_type(false, true, ele->element_type());
else
sub = this->reassociate_chan_direction(ele, location);
return Type::make_channel_type(false, true, sub);
}
// Statement =
// Declaration | LabeledStmt | SimpleStmt |
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |

View File

@ -14,6 +14,7 @@ class Named_object;
class Type;
class Typed_identifier;
class Typed_identifier_list;
class Channel_type;
class Function_type;
class Block;
class Expression;
@ -229,6 +230,7 @@ class Parse
bool expression_may_start_here();
Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
bool* is_type_switch);
Type* reassociate_chan_direction(Channel_type*, Location);
Expression* qualified_expr(Expression*, Location);
Expression* id_to_expression(const std::string&, Location);
void statement(Label*);