Commit d8c19c80 authored by Russ Cox's avatar Russ Cox

type checking of assignments, switch, if, for

R=ken
OCL=32716
CL=32720
parent 417683c3
......@@ -704,6 +704,7 @@ nodlit(Val v)
return n;
}
// TODO(rsc): combine with convlit
void
defaultlit(Node **np, Type *t)
{
......@@ -713,7 +714,7 @@ defaultlit(Node **np, Type *t)
n = *np;
if(n == N)
return;
if(n->type == T || n->type->etype != TIDEAL)
if(n->type == T || (n->type->etype != TIDEAL && n->type->etype != TNIL))
return;
switch(n->op) {
......@@ -739,6 +740,16 @@ defaultlit(Node **np, Type *t)
lineno = n->lineno;
switch(n->val.ctype) {
default:
if(t != T) {
convlit(np, t);
break;
}
if(n->val.ctype == CTNIL) {
lineno = lno;
yyerror("use of untyped nil");
n->type = T;
break;
}
yyerror("defaultlit: unknown literal: %#N", n);
break;
case CTINT:
......
......@@ -334,7 +334,7 @@ enum
OAPPENDSTR,
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OAS, OAS2, OASOP,
OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,
......@@ -952,18 +952,6 @@ void dumpexport(void);
void dumpexporttype(Sym*);
void dumpexportvar(Sym*);
void dumpexportconst(Sym*);
void doimportv1(Node*, Node*);
void doimportc1(Node*, Val*);
void doimportc2(Node*, Node*, Val*);
void doimport1(Node*, Node*, Node*);
void doimport2(Node*, Val*, Node*);
void doimport3(Node*, Node*);
void doimport4(Node*, Node*);
void doimport5(Node*, Val*);
void doimport6(Node*, Node*);
void doimport7(Node*, Node*);
void doimport8(Node*, Val*, Node*);
void doimport9(Sym*, Node*);
void importconst(Sym *s, Type *t, Node *v);
void importmethod(Sym *s, Type *t);
void importtype(Sym *s, Type *t);
......@@ -981,7 +969,6 @@ void walkexprlist(NodeList*, NodeList**);
void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**);
void walkas(Node*);
void walkbool(Node**);
void walkswitch(Node*);
void walkselect(Node*);
void walkdot(Node*, NodeList**);
......@@ -990,21 +977,14 @@ Node* ascompatee1(int, Node*, Node*, NodeList**);
NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**);
int ascompat(Type*, Type*);
Node* newcompat(Node*);
Node* stringop(Node*, NodeList**);
Type* fixmap(Type*);
Node* mapop(Node*, NodeList**);
Type* fixchan(Type*);
Node* chanop(Node*, NodeList**);
Node* ifacecvt(Type*, Node*, int, NodeList**);
Node* ifaceop(Node*);
int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int);
void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void);
Node* convas(Node*, NodeList**);
void arrayconv(Type*, Node*);
Node* colas(NodeList*, NodeList*);
Node* dorange(Node*);
NodeList* reorder1(NodeList*);
......@@ -1019,6 +999,7 @@ void heapmoves(void);
void walkdeflist(NodeList*);
void walkdef(Node*);
void typechecklist(NodeList*, int);
void typecheckswitch(Node*);
Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int);
......
......@@ -231,6 +231,7 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OINDEX:
case OINDEXMAP:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
exprfmt(f, n->right, 0);
......
......@@ -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;
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment