summaryrefslogtreecommitdiff
path: root/src/cmd/gc/swt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/swt.c')
-rw-r--r--src/cmd/gc/swt.c63
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;
}