diff options
Diffstat (limited to 'src/cmd/gc/swt.c')
-rw-r--r-- | src/cmd/gc/swt.c | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index f1a95587f..a497b8622 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -117,12 +117,15 @@ exprcmp(Case *c1, Case *c2) n1 = c1->node->left; n2 = c2->node->left; + // sort by type (for switches on interface) ct = n1->val.ctype; - if(ct != n2->val.ctype) { - // invalid program, but return a sort - // order so that we can give a better - // error later. + if(ct != n2->val.ctype) return ct - n2->val.ctype; + if(!eqtype(n1->type, n2->type)) { + if(n1->type->vargen > n2->type->vargen) + return +1; + else + return -1; } // sort by constant value @@ -259,10 +262,11 @@ casebody(Node *sw, Node *typeswvar) Node *go, *br; int32 lno, needvar; - lno = setlineno(sw); if(sw->list == nil) return; + lno = setlineno(sw); + cas = nil; // cases stat = nil; // statements def = N; // defaults @@ -270,7 +274,7 @@ casebody(Node *sw, Node *typeswvar) for(l=sw->list; l; l=l->next) { n = l->n; - lno = setlineno(n); + setlineno(n); if(n->op != OXCASE) fatal("casebody %O", n->op); n->op = OCASE; @@ -378,6 +382,7 @@ mkcaselist(Node *sw, int arg) case Strue: case Sfalse: c->type = Texprvar; + c->hash = typehash(n->left->type); switch(consttype(n->left)) { case CTFLT: case CTINT: @@ -442,6 +447,10 @@ exprbsw(Case *c0, int ncase, int arg) n = c0->node; lno = setlineno(n); + if(assignop(n->left->type, exprname->type, nil) == OCONVIFACE || + assignop(exprname->type, n->left->type, nil) == OCONVIFACE) + goto snorm; + switch(arg) { case Strue: a = nod(OIF, N, N); @@ -457,6 +466,7 @@ exprbsw(Case *c0, int ncase, int arg) break; default: + snorm: a = nod(OIF, N, N); a->ntest = nod(OEQ, exprname, n->left); // if name == val typecheck(&a->ntest, Erv); @@ -520,6 +530,8 @@ exprswitch(Node *sw) exprname = temp(sw->ntest->type); cas = list1(nod(OAS, exprname, sw->ntest)); typechecklist(cas, Etop); + } else { + exprname = nodbool(arg == Strue); } c0 = mkcaselist(sw, arg); @@ -786,7 +798,6 @@ typeswitch(Node *sw) void walkswitch(Node *sw) { - /* * reorder the body into (OLIST, cases, statements) * cases have OGOTO into statements. @@ -813,7 +824,7 @@ typecheckswitch(Node *n) { int top, lno, ptr; char *nilonly; - Type *t, *missing, *have; + Type *t, *badtype, *missing, *have; NodeList *l, *ll; Node *ncase, *nvar; Node *def; @@ -839,10 +850,14 @@ typecheckswitch(Node *n) } else t = types[TBOOL]; if(t) { - if(!okforeq[t->etype] || isfixedarray(t)) + if(!okforeq[t->etype]) yyerror("cannot switch on %lN", n->ntest); - else if(t->etype == TARRAY) + else if(t->etype == TARRAY && !isfixedarray(t)) nilonly = "slice"; + else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ) + yyerror("cannot switch on %lN", n->ntest); + else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ) + yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype); else if(t->etype == TFUNC) nilonly = "func"; else if(t->etype == TMAP) @@ -889,7 +904,7 @@ typecheckswitch(Node *n) 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)) { + } else if(ll->n->type->etype != TINTER && t->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", |