diff options
Diffstat (limited to 'src/cmd/gc/swt.c')
-rw-r--r-- | src/cmd/gc/swt.c | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index c2968c44b..f1a95587f 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" enum @@ -130,6 +132,7 @@ exprcmp(Case *c1, Case *c2) n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval); break; case CTINT: + case CTRUNE: n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval); break; case CTSTR: @@ -378,6 +381,7 @@ mkcaselist(Node *sw, int arg) switch(consttype(n->left)) { case CTFLT: case CTINT: + case CTRUNE: case CTSTR: c->type = Texprconst; } @@ -513,8 +517,7 @@ exprswitch(Node *sw) exprname = N; cas = nil; if(arg != Strue && arg != Sfalse) { - exprname = nod(OXXX, N, N); - tempname(exprname, sw->ntest->type); + exprname = temp(sw->ntest->type); cas = list1(nod(OAS, exprname, sw->ntest)); typechecklist(cas, Etop); } @@ -537,7 +540,7 @@ loop: } // deal with the variables one-at-a-time - if(c0->type != Texprconst) { + if(!okforcmp[t->etype] || c0->type != Texprconst) { a = exprbsw(c0, 1, arg); cas = list(cas, a); c0 = c0->link; @@ -671,20 +674,17 @@ typeswitch(Node *sw) * predeclare temporary variables * and the boolean var */ - facename = nod(OXXX, N, N); - tempname(facename, sw->ntest->right->type); + facename = temp(sw->ntest->right->type); a = nod(OAS, facename, sw->ntest->right); typecheck(&a, Etop); cas = list(cas, a); casebody(sw, facename); - boolname = nod(OXXX, N, N); - tempname(boolname, types[TBOOL]); + boolname = temp(types[TBOOL]); typecheck(&boolname, Erv); - hashname = nod(OXXX, N, N); - tempname(hashname, types[TUINT32]); + hashname = temp(types[TUINT32]); typecheck(&hashname, Erv); t = sw->ntest->right->type; @@ -792,7 +792,6 @@ walkswitch(Node *sw) * cases have OGOTO into statements. * both have inserted OBREAK statements */ - walkstmtlist(sw->ninit); if(sw->ntest == N) { sw->ntest = nodbool(1); typecheck(&sw->ntest, Erv); @@ -812,14 +811,16 @@ walkswitch(Node *sw) void typecheckswitch(Node *n) { - int top, lno; - Type *t; + int top, lno, ptr; + char *nilonly; + Type *t, *missing, *have; NodeList *l, *ll; Node *ncase, *nvar; Node *def; lno = lineno; typechecklist(n->ninit, Etop); + nilonly = nil; if(n->ntest != N && n->ntest->op == OTYPESW) { // type switch @@ -827,7 +828,7 @@ typecheckswitch(Node *n) typecheck(&n->ntest->right, Erv); t = n->ntest->right->type; if(t != T && t->etype != TINTER) - yyerror("cannot type switch on non-interface value %+N", n->ntest->right); + yyerror("cannot type switch on non-interface value %lN", n->ntest->right); } else { // value switch top = Erv; @@ -837,6 +838,16 @@ typecheckswitch(Node *n) t = n->ntest->type; } else t = types[TBOOL]; + if(t) { + if(!okforeq[t->etype] || isfixedarray(t)) + yyerror("cannot switch on %lN", n->ntest); + else if(t->etype == TARRAY) + nilonly = "slice"; + else if(t->etype == TFUNC) + nilonly = "func"; + else if(t->etype == TMAP) + nilonly = "map"; + } } n->type = t; @@ -856,21 +867,37 @@ typecheckswitch(Node *n) typecheck(&ll->n, Erv | Etype); if(ll->n->type == T || t == T) continue; + setlineno(ncase); switch(top) { case Erv: // expression switch defaultlit(&ll->n, t); if(ll->n->op == OTYPE) yyerror("type %T is not an expression", ll->n->type); - else if(ll->n->type != T && !eqtype(ll->n->type, t)) - yyerror("case %+N in %T switch", ll->n, t); + else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) { + if(n->ntest) + yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t); + else + yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type); + } else if(nilonly && !isconst(ll->n, CTNIL)) { + yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest); + } break; case Etype: // type switch - if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) + if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) { ; - else if(ll->n->op != OTYPE && ll->n->type != T) { - yyerror("%#N is not a type", ll->n); + } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||? + yyerror("%lN is not a type", ll->n); // reset to original type ll->n = n->ntest->right; + } else if(ll->n->type->etype != TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) { + if(have && !missing->broke && !have->broke) + yyerror("impossible type switch case: %lN cannot have dynamic type %T" + " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", + n->ntest->right, ll->n->type, missing->sym, have->sym, have->type, + missing->sym, missing->type); + else if(!missing->broke) + yyerror("impossible type switch case: %lN cannot have dynamic type %T" + " (missing %S method)", n->ntest->right, ll->n->type, missing->sym); } break; } |