back to T{x}, stricter handling of T(x) vs x.(T)
R=ken
DELTA=131 (60 added, 41 deleted, 30 changed)
OCL=25617
CL=25633
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 0f8d265..8445a91 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -327,9 +327,9 @@
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
OLITERAL, OREGISTER, OINDREG,
OKEY, OPARAM,
+ OCOMPOS,
OCONV,
- OCONVDOT,
- OCONVPAREN,
+ ODOTTYPE,
OBAD,
OEXTEND, // 6g internal
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 320c9c6..20c981d 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -51,7 +51,7 @@
%type <node> stmt_list_r Astmt_list_r Bstmt_list_r
%type <node> Astmt Bstmt
%type <node> for_stmt for_body for_header
-%type <node> if_stmt if_body if_header select_stmt
+%type <node> if_stmt if_body if_header select_stmt condition
%type <node> simple_stmt osimple_stmt range_stmt semi_stmt
%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
%type <node> exprsym3_list_r exprsym3
@@ -89,6 +89,13 @@
%left '+' '-' '|' '^'
%left '*' '/' '%' '&' LLSH LRSH
+/*
+ * resolve { vs condition in favor of condition
+ */
+%left '{'
+%left Condition
+
+
%%
file:
package import_there imports oxdcl_list
@@ -562,7 +569,7 @@
$$->ntest = $3;
$$->nincr = $5;
}
-| osimple_stmt
+| condition
{
// normal test
$$ = nod(OFOR, N, N);
@@ -591,15 +598,30 @@
$$ = $2;
}
+/*
+ * using cond instead of osimple_stmt creates
+ * a shift/reduce conflict on an input like
+ *
+ * if x == []int { true } { true }
+ *
+ * at the first {, giving us an opportunity
+ * to resolve it by reduce, which implements
+ * the rule about { } inside if conditions
+ * needing parens.
+ */
+condition:
+ osimple_stmt %prec Condition
+
+
if_header:
- osimple_stmt
+ condition
{
// test
$$ = nod(OIF, N, N);
$$->ninit = N;
$$->ntest = $1;
}
-| osimple_stmt ';' osimple_stmt
+| osimple_stmt ';' condition
{
// init ; test
$$ = nod(OIF, N, N);
@@ -791,7 +813,7 @@
}
| pexpr '.' '(' type ')'
{
- $$ = nod(OCONVDOT, $1, N);
+ $$ = nod(ODOTTYPE, $1, N);
$$->type = $4;
}
| pexpr '[' expr ']'
@@ -841,24 +863,22 @@
$$ = nod(OMAKE, $5, N);
$$->type = $3;
}
-| convtype '(' braced_keyexpr_list ')'
+| convtype '(' expr ')'
{
- // typed literal
+ // conversion
$$ = rev($3);
if($$ == N)
$$ = nod(OEMPTY, N, N);
- $$ = nod(OCONVPAREN, $$, N);
+ $$ = nod(OCONV, $$, N);
$$->type = $1;
}
| convtype '{' braced_keyexpr_list '}'
{
- if(!debug['{'])
- warn("braces should now be parens");
- // composite literal
+ // composite expression
$$ = rev($3);
if($$ == N)
$$ = nod(OEMPTY, N, N);
- $$ = nod(OCONVPAREN, $$, N);
+ $$ = nod(OCOMPOS, $$, N);
$$->type = $1;
}
| fnliteral
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 2ddf6e8..7d5890c 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -634,9 +634,9 @@
[OXCASE] = "XCASE",
[OCMP] = "CMP",
[OFALL] = "FALL",
+ [OCOMPOS] = "COMPOS",
+ [ODOTTYPE] = "DOTTYPE",
[OCONV] = "CONV",
- [OCONVDOT] = "CONVDOT",
- [OCONVPAREN] = "CONVPAREN",
[OCOM] = "COM",
[OCONST] = "CONST",
[OCONTINUE] = "CONTINUE",
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 116fdec..c7deefc 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -510,7 +510,7 @@
}
break;
- case OCONVDOT:
+ case ODOTTYPE:
if(cl == 2 && cr == 1) {
// a,b = i.(T)
walktype(r->left, Erv);
@@ -593,13 +593,41 @@
goto ret;
case OCONV:
- case OCONVDOT:
- case OCONVPAREN:
+ case ODOTTYPE:
if(top != Erv)
goto nottop;
walkconv(n);
goto ret;
+ case OCOMPOS:
+ t = n->type;
+ if(t == T)
+ goto ret;
+ l = n->left;
+ if(l == N)
+ goto ret;
+ walktype(l, Erv);
+
+ // structure literal
+ if(t->etype == TSTRUCT) {
+ indir(n, structlit(n, N));
+ goto ret;
+ }
+
+ // array literal
+ if(t->etype == TARRAY) {
+ indir(n, arraylit(n, N));
+ goto ret;
+ }
+
+ // map literal
+ if(t->etype == TMAP) {
+ indir(n, maplit(n, N));
+ goto ret;
+ }
+ yyerror("invalid type for composite literal: %T", t);
+ goto ret;
+
case ORETURN:
if(top != Etop)
goto nottop;
@@ -887,11 +915,7 @@
case OADDR:
if(top != Erv)
goto nottop;
- if(n->left->op == OCONVPAREN && n->left->type != T)
- switch(n->left->type->etype) {
- case TSTRUCT:
- case TARRAY:
- case TMAP:
+ if(n->left->op == OCOMPOS && n->left->type != T) {
// turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
// initialize with
// nvar := new(*Point);
@@ -920,13 +944,14 @@
maplit(n->left, nstar);
break;
default:
- fatal("addr lit %T", n->left->type);
+ goto badlit;
}
indir(n, nvar);
goto ret;
}
+ badlit:
if(istype(n->left->type, TFUNC) && n->left->class == PFUNC) {
if(!n->diag) {
n->diag = 1;
@@ -1130,10 +1155,12 @@
yyerror("IF and FOR require a boolean type");
}
+
+
void
walkconv(Node *n)
{
- int et, op;
+ int et;
Type *t;
Node *l;
@@ -1145,17 +1172,20 @@
return;
walktype(l, Erv);
- switch(t->etype) {
- case TSTRUCT:
- case TMAP:
- case TARRAY:
- break;
- default:
- convlit1(l, t, 1);
+ convlit1(l, t, 1);
+
+ // if using .(T), interface assertion.
+ if(n->op == ODOTTYPE) {
+ // interface conversion
+ et = ifaceas(n->type, l->type, 1);
+ if(et != Inone) {
+ indir(n, ifaceop(n->type, l, et));
+ return;
+ }
+ goto bad;
}
- op = n->op;
- n->op = OCONV; // generic conversion
+ // otherwise, conversion.
// nil conversion
if(eqtype(t, l->type, 0)) {
@@ -1218,37 +1248,7 @@
return;
}
- // possible interface conversion if using .(T)
- if(op == OCONVDOT) {
- // interface conversion
- et = ifaceas(n->type, l->type, 1);
- if(et != Inone) {
- indir(n, ifaceop(n->type, l, et));
- return;
- }
- }
-
- // possible composite literal if using T()
- if(op == OCONVPAREN) {
- // structure literal
- if(t->etype == TSTRUCT) {
- indir(n, structlit(n, N));
- return;
- }
-
- // array literal
- if(t->etype == TARRAY) {
- indir(n, arraylit(n, N));
- return;
- }
-
- // map literal
- if(t->etype == TMAP) {
- indir(n, maplit(n, N));
- return;
- }
- }
-
+bad:
if(l->type != T)
yyerror("invalid conversion: %T to %T", l->type, t);
else if(n->left->op == OLIST)
@@ -1256,7 +1256,6 @@
}
-
/*
* return the first type
*/
@@ -3146,7 +3145,7 @@
n = list(n, a);
break;
- case OCONVDOT:
+ case ODOTTYPE:
// a,b := i.(T)
if(cl != 2)
goto badt;