diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 7ec215b0e47..0f8d26506d4 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -326,7 +326,10 @@ enum OINDEX, OSLICE, ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV, OLITERAL, OREGISTER, OINDREG, - OCONV, OCOMP, OKEY, OPARAM, + OKEY, OPARAM, + OCONV, + OCONVDOT, + OCONVPAREN, OBAD, OEXTEND, // 6g internal @@ -805,6 +808,7 @@ void gettype(Node*, Node*); void walk(Node*); void walkstate(Node*); void walktype(Node*, int); +void walkconv(Node*); void walkas(Node*); void walkbool(Node*); Type* walkswitch(Node*, Type*(*)(Node*, Type*)); @@ -840,8 +844,8 @@ Node* reorder2(Node*); Node* reorder3(Node*); Node* reorder4(Node*); Node* structlit(Node*, Node*); -Node* arraylit(Node*); -Node* maplit(Node*); +Node* arraylit(Node*, Node*); +Node* maplit(Node*, Node*); Node* selectas(Node*, Node*); Node* old2new(Node*, Type*); void addrescapes(Node*); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 29a08912d4a..072db35b682 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -791,7 +791,7 @@ pexpr: } | pexpr '.' '(' type ')' { - $$ = nod(OCONV, $1, N); + $$ = nod(OCONVDOT, $1, N); $$->type = $4; } | pexpr '[' expr ']' @@ -841,20 +841,24 @@ pexpr: $$ = nod(OMAKE, $5, N); $$->type = $3; } -| latype '(' expr ')' +| convtype '(' braced_keyexpr_list ')' { - $$ = nod(OCONV, $3, N); - $$->type = oldtype($1); + // typed literal + $$ = rev($3); + if($$ == N) + $$ = nod(OEMPTY, N, N); + $$ = nod(OCONVPAREN, $$, N); + $$->type = $1; } | convtype '{' braced_keyexpr_list '}' { + if(!debug['{']) + warn("braces should now be parens"); // composite literal $$ = rev($3); if($$ == N) $$ = nod(OEMPTY, N, N); - if(!iscomposite($1)) - yyerror("illegal composite literal type %T", $1); - $$ = nod(OCOMP, $$, N); + $$ = nod(OCONVPAREN, $$, N); $$->type = $1; } | fnliteral diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 841f5c36141..2ddf6e8cadc 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -634,9 +634,10 @@ opnames[] = [OXCASE] = "XCASE", [OCMP] = "CMP", [OFALL] = "FALL", - [OCONV] = "CONV", + [OCONV] = "CONV", + [OCONVDOT] = "CONVDOT", + [OCONVPAREN] = "CONVPAREN", [OCOM] = "COM", - [OCOMP] = "COMP", [OCONST] = "CONST", [OCONTINUE] = "CONTINUE", [ODCLARG] = "DCLARG", diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 440c897795d..1d206334876 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -507,7 +507,7 @@ loop: } break; - case OCONV: + case OCONVDOT: if(cl == 2 && cr == 1) { // a,b = i.(T) walktype(r->left, Erv); @@ -590,128 +590,11 @@ loop: goto ret; case OCONV: - if(top == Etop) + case OCONVDOT: + case OCONVPAREN: + if(top != Erv) goto nottop; - - l = n->left; - if(l == N) - goto ret; - - walktype(l, Erv); - - t = n->type; - if(t == T) - goto ret; - - convlit1(l, t, 1); - - // nil conversion - if(eqtype(t, l->type, 0)) { - if(l->op != ONAME) { - indir(n, l); - n->type = t; - } - goto ret; - } - - // simple fix-float - if(l->type != T) - if(isint[l->type->etype] || isfloat[l->type->etype]) - if(isint[t->etype] || isfloat[t->etype]) { - evconst(n); - goto ret; - } - - // to string - if(l->type != T) - if(istype(t, TSTRING)) { - et = l->type->etype; - if(isint[et]) { - indir(n, stringop(n, top)); - goto ret; - } - if(et == TARRAY) - if(istype(l->type->type, TUINT8)) { - n->op = OARRAY; - indir(n, stringop(n, top)); - goto ret; - } - } - - // convert dynamic to static generated by ONEW/OMAKE - if(isfixedarray(t) && isslice(l->type)) - goto ret; - - // convert static array to dynamic array - if(isslice(t) && isfixedarray(l->type)) { - if(eqtype(t->type->type, l->type->type->type, 0)) { - indir(n, arrayop(n, Erv)); - goto ret; - } - } - - // interface assignment - et = ifaceas(n->type, l->type, 1); - if(et != Inone) { - indir(n, ifaceop(n->type, l, et)); - goto ret; - } - - // convert to unsafe.pointer - if(isptrto(n->type, TANY)) { - if(isptr[l->type->etype]) - goto ret; - if(l->type->etype == TUINTPTR) - goto ret; - } - - // convert from unsafe.pointer - if(isptrto(l->type, TANY)) { - if(isptr[n->type->etype]) - goto ret; - if(n->type->etype == TUINTPTR) - goto ret; - } - - if(l->type != T) - yyerror("cannot convert %T to %T", l->type, t); - goto ret; - - case OCOMP: - if(top == Etop) - goto nottop; - - l = n->left; - if(l == N) - goto ret; - - walktype(l, Erv); - - t = n->type; - if(t == T) - goto ret; - - // structure literal - if(t->etype == TSTRUCT) { - indir(n, structlit(n, nil)); - goto ret; - } - - // array literal - if(t->etype == TARRAY) { - r = arraylit(n); - indir(n, r); - goto ret; - } - - // map literal - if(t->etype == TMAP) { - r = maplit(n); - indir(n, r); - goto ret; - } - - yyerror("bad composite literal %T", t); + walkconv(n); goto ret; case ORETURN: @@ -1001,14 +884,18 @@ loop: case OADDR: if(top != Erv) goto nottop; - if(n->left->op == OCOMP && n->left->type != T) - if(n->left->type->etype == TSTRUCT) { - // turn &Point{1, 2} into allocation. + if(n->left->op == OCONVPAREN && n->left->type != T) + switch(n->left->type->etype) { + case TSTRUCT: + case TARRAY: + case TMAP: + // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation. // initialize with // nvar := new(*Point); - // *nvar = Point{1, 2}; + // *nvar = Point(1, 2); // and replace expression with nvar - Node *nvar, *nas; + ; // stupid c syntax - case label must be on stmt, not decl + Node *nvar, *nas, *nstar; nvar = nod(OXXX, N, N); tempname(nvar, ptrto(n->left->type)); @@ -1016,10 +903,27 @@ loop: nas = nod(OAS, nvar, callnew(n->left->type)); addtop = list(addtop, nas); - structlit(n->left, nvar); + nstar = nod(OIND, nvar, N); + nstar->type = n->left->type; + + switch(n->left->type->etype) { + case TSTRUCT: + structlit(n->left, nstar); + break; + case TARRAY: + arraylit(n->left, nstar); + break; + case TMAP: + maplit(n->left, nstar); + break; + default: + fatal("addr lit %T", n->left->type); + } + indir(n, nvar); goto ret; } + if(istype(n->left->type, TFUNC) && n->left->class == PFUNC) { if(!n->diag) { n->diag = 1; @@ -1223,6 +1127,133 @@ walkbool(Node *n) yyerror("IF and FOR require a boolean type"); } +void +walkconv(Node *n) +{ + int et, op; + Type *t; + Node *l; + + t = n->type; + if(t == T) + return; + l = n->left; + if(l == N) + return; + walktype(l, Erv); + + switch(t->etype) { + case TSTRUCT: + case TMAP: + case TARRAY: + break; + default: + convlit1(l, t, 1); + } + + op = n->op; + n->op = OCONV; // generic conversion + + // nil conversion + if(eqtype(t, l->type, 0)) { + if(l->op != ONAME) { + indir(n, l); + n->type = t; + } + return; + } + + // simple fix-float + if(l->type != T) + if(isint[l->type->etype] || isfloat[l->type->etype]) + if(isint[t->etype] || isfloat[t->etype]) { + evconst(n); + return; + } + + // to string + if(l->type != T) + if(istype(t, TSTRING)) { + et = l->type->etype; + if(isint[et]) { + indir(n, stringop(n, Erv)); + return; + } + if(et == TARRAY) + if(istype(l->type->type, TUINT8)) { + n->op = OARRAY; + indir(n, stringop(n, Erv)); + return; + } + } + + // convert dynamic to static generated by ONEW/OMAKE + if(isfixedarray(t) && isslice(l->type)) + return; + + // convert static array to dynamic array + if(isslice(t) && isfixedarray(l->type)) { + if(eqtype(t->type->type, l->type->type->type, 0)) { + indir(n, arrayop(n, Erv)); + return; + } + } + + // convert to unsafe.pointer + if(isptrto(n->type, TANY)) { + if(isptr[l->type->etype]) + return; + if(l->type->etype == TUINTPTR) + return; + } + + // convert from unsafe.pointer + if(isptrto(l->type, TANY)) { + if(isptr[n->type->etype]) + return; + if(n->type->etype == TUINTPTR) + 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; + } + } + + if(l->type != T) + yyerror("invalid conversion: %T to %T", l->type, t); + else if(n->left->op == OLIST) + yyerror("invalid type for composite literal: %T", t); +} + + + /* * return the first type */ @@ -3110,7 +3141,7 @@ multi: n = list(n, a); break; - case OCONV: + case OCONVDOT: // a,b := i.(T) if(cl != 2) goto badt; @@ -3538,11 +3569,11 @@ loop: } Node* -arraylit(Node *n) +arraylit(Node *n, Node *var) { Iter saver; Type *t; - Node *var, *r, *a, *nnew; + Node *r, *a, *nnew; int idx, ninit, b; t = n->type; @@ -3567,8 +3598,10 @@ arraylit(Node *n) t->bound = b; } - var = nod(OXXX, N, N); - tempname(var, t); + if(var == N) { + var = nod(OXXX, N, N); + tempname(var, t); + } nnew = nil; if(b < 0) { @@ -3606,18 +3639,20 @@ arraylit(Node *n) } Node* -maplit(Node *n) +maplit(Node *n, Node *var) { Iter saver; Type *t; - Node *var, *r, *a; + Node *r, *a; t = n->type; if(t->etype != TMAP) fatal("maplit: not map"); - var = nod(OXXX, N, N); - tempname(var, t); + if(var == N) { + var = nod(OXXX, N, N); + tempname(var, t); + } a = nod(OMAKE, N, N); a->type = t;