diff options
author | Russ Cox <rsc@golang.org> | 2009-08-04 10:26:29 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-08-04 10:26:29 -0700 |
commit | 1e2833c42ac62b80c2f2798aa3cf0b606f6b6e03 (patch) | |
tree | 4f7cbb90612106ece0f86914aee1f18b156c25a7 /src/cmd/gc/swt.c | |
parent | 57cb3773ef6976e41a674e9ea4105f4337d58965 (diff) | |
download | golang-1e2833c42ac62b80c2f2798aa3cf0b606f6b6e03.tar.gz |
type checking of assignments, switch, if, for
R=ken
OCL=32716
CL=32720
Diffstat (limited to 'src/cmd/gc/swt.c')
-rw-r--r-- | src/cmd/gc/swt.c | 183 |
1 files changed, 62 insertions, 121 deletions
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index a885bb371..17a443348 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -233,112 +233,6 @@ csort(Case *l, int(*f)(Case*, Case*)) return l; } -/* - * walktype - */ -Type* -sw0(Node **cp, Type *place, int arg) -{ - Node *c; - - c = *cp; - if(c == N) - return T; - switch(c->op) { - default: - if(arg == Stype) { - yyerror("expression case in a type switch"); - return T; - } - walkexpr(cp, nil); - break; - case OTYPESW: - case OTYPECASE: - if(arg != Stype) - yyerror("type case in an expression switch"); - break; - case OAS: - yyerror("inappropriate assignment in a case statement"); - break; - } - return T; -} - -/* - * return the first type - */ -Type* -sw1(Node **cp, Type *place, int arg) -{ - Node *c; - - c = *cp; - if(place != T) - return notideal(c->type); - return place; -} - -/* - * return a suitable type - */ -Type* -sw2(Node **cp, Type *place, int arg) -{ - return types[TINT]; // botch -} - -/* - * check that switch type - * is compat with all the cases - */ -Type* -sw3(Node **cp, Type *place, int arg) -{ - Node *c; - - c = *cp; - if(place == T) - return c->type; - if(c->type == T) - c->type = place; - convlit(cp, place); - c = *cp; - if(!ascompat(place, c->type)) - badtype(OSWITCH, place, c->type); - return place; -} - -/* - * over all cases, call parameter function. - * four passes of these are used to allocate - * types to cases and switch - */ -Type* -walkcases(Node *sw, Type*(*call)(Node**, Type*, int arg), int arg) -{ - Node *n; - NodeList *l; - Type *place; - int32 lno; - - lno = setlineno(sw); - place = call(&sw->ntest, T, arg); - - for(l=sw->list; l; l=l->next) { - n = l->n; - - if(n->op != OCASE) - fatal("walkcases: not case %O\n", n->op); - - if(n->left != N && !n->diag) { - setlineno(n); - place = call(&n->left, place, arg); - } - } - lineno = lno; - return place; -} - Node* newlabel(void) { @@ -597,22 +491,9 @@ exprswitch(Node *sw) arg = Sfalse; } walkexpr(&sw->ntest, &sw->ninit); - - /* - * pass 0,1,2,3 - * walk the cases as appropriate for switch type - */ - walkcases(sw, sw0, arg); - t = notideal(sw->ntest->type); - if(t == T) - t = walkcases(sw, sw1, arg); - if(t == T) - t = walkcases(sw, sw2, arg); + t = sw->type; if(t == T) return; - walkcases(sw, sw3, arg); - convlit(&sw->ntest, t); - /* * convert the switch into OIF statements @@ -785,7 +666,6 @@ typeswitch(Node *sw) yyerror("type switch must be on an interface"); return; } - walkcases(sw, sw0, Stype); cas = nil; /* @@ -886,3 +766,64 @@ walkswitch(Node *sw) } exprswitch(sw); } + +/* + * type check switch statement + */ +void +typecheckswitch(Node *n) +{ + int top, lno; + Type *t; + NodeList *l, *ll; + Node *ncase; + Node *def; + + lno = lineno; + typechecklist(n->ninit, Etop); + + if(n->ntest != N && n->ntest->op == OTYPESW) { + // type switch + typecheck(&n->ntest, Etop); + top = Etype; + t = n->ntest->type; + if(t != T && t->etype != TINTER) + yyerror("cannot type switch on non-interface value %+N", n->ntest); + } else { + // value switch + top = Erv; + if(n->ntest) { + typecheck(&n->ntest, Erv); + defaultlit(&n->ntest, T); + t = n->ntest->type; + } else + t = types[TBOOL]; + } + n->type = t; + + def = N; + for(l=n->list; l; l=l->next) { + ncase = l->n; + setlineno(n); + if(ncase->list == nil) { + // default + if(def != N) + yyerror("multiple defaults in switch (first at %L)", def->lineno); + else + def = ncase; + } else { + for(ll=ncase->list; ll; ll=ll->next) { + setlineno(ll->n); + typecheck(&ll->n, Erv); // TODO(rsc): top + if(ll->n->type == T || t == T || top != Erv) + continue; + defaultlit(&ll->n, t); + if(ll->n->type != T && !eqtype(ll->n->type, t)) + yyerror("case %+N in switch of %+N %#O", ll->n, n->ntest, ll->n->op); + } + } + typechecklist(ncase->nbody, Etop); + } + + lineno = lno; +} |