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) ...@@ -704,6 +704,7 @@ nodlit(Val v)
return n; return n;
} }
// TODO(rsc): combine with convlit
void void
defaultlit(Node **np, Type *t) defaultlit(Node **np, Type *t)
{ {
...@@ -713,7 +714,7 @@ defaultlit(Node **np, Type *t) ...@@ -713,7 +714,7 @@ defaultlit(Node **np, Type *t)
n = *np; n = *np;
if(n == N) if(n == N)
return; return;
if(n->type == T || n->type->etype != TIDEAL) if(n->type == T || (n->type->etype != TIDEAL && n->type->etype != TNIL))
return; return;
switch(n->op) { switch(n->op) {
...@@ -739,6 +740,16 @@ defaultlit(Node **np, Type *t) ...@@ -739,6 +740,16 @@ defaultlit(Node **np, Type *t)
lineno = n->lineno; lineno = n->lineno;
switch(n->val.ctype) { switch(n->val.ctype) {
default: 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); yyerror("defaultlit: unknown literal: %#N", n);
break; break;
case CTINT: case CTINT:
......
...@@ -334,7 +334,7 @@ enum ...@@ -334,7 +334,7 @@ enum
OAPPENDSTR, OAPPENDSTR,
OARRAY, OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR, OARRAYBYTESTR, OARRAYRUNESTR,
OAS, OAS2, OASOP, OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD, OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP, OCAP,
...@@ -952,18 +952,6 @@ void dumpexport(void); ...@@ -952,18 +952,6 @@ void dumpexport(void);
void dumpexporttype(Sym*); void dumpexporttype(Sym*);
void dumpexportvar(Sym*); void dumpexportvar(Sym*);
void dumpexportconst(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 importconst(Sym *s, Type *t, Node *v);
void importmethod(Sym *s, Type *t); void importmethod(Sym *s, Type *t);
void importtype(Sym *s, Type *t); void importtype(Sym *s, Type *t);
...@@ -981,7 +969,6 @@ void walkexprlist(NodeList*, NodeList**); ...@@ -981,7 +969,6 @@ void walkexprlist(NodeList*, NodeList**);
void walkconv(Node**, NodeList**); void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**); void walkdottype(Node*, NodeList**);
void walkas(Node*); void walkas(Node*);
void walkbool(Node**);
void walkswitch(Node*); void walkswitch(Node*);
void walkselect(Node*); void walkselect(Node*);
void walkdot(Node*, NodeList**); void walkdot(Node*, NodeList**);
...@@ -990,21 +977,14 @@ Node* ascompatee1(int, Node*, Node*, NodeList**); ...@@ -990,21 +977,14 @@ Node* ascompatee1(int, Node*, Node*, NodeList**);
NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
NodeList* ascompatte(int, Type**, NodeList*, 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**); Node* mapop(Node*, NodeList**);
Type* fixchan(Type*); Type* fixchan(Type*);
Node* chanop(Node*, NodeList**);
Node* ifacecvt(Type*, Node*, int, NodeList**); Node* ifacecvt(Type*, Node*, int, NodeList**);
Node* ifaceop(Node*);
int ifaceas(Type*, Type*, int); int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int); int ifaceas1(Type*, Type*, int);
void ifacecheck(Type*, Type*, int, int); void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void); void runifacechecks(void);
Node* convas(Node*, NodeList**); Node* convas(Node*, NodeList**);
void arrayconv(Type*, Node*);
Node* colas(NodeList*, NodeList*); Node* colas(NodeList*, NodeList*);
Node* dorange(Node*); Node* dorange(Node*);
NodeList* reorder1(NodeList*); NodeList* reorder1(NodeList*);
...@@ -1019,6 +999,7 @@ void heapmoves(void); ...@@ -1019,6 +999,7 @@ void heapmoves(void);
void walkdeflist(NodeList*); void walkdeflist(NodeList*);
void walkdef(Node*); void walkdef(Node*);
void typechecklist(NodeList*, int); void typechecklist(NodeList*, int);
void typecheckswitch(Node*);
Node* typecheckconv(Node*, Node*, Type*, int); Node* typecheckconv(Node*, Node*, Type*, int);
Node* typecheck(Node**, int); Node* typecheck(Node**, int);
......
...@@ -231,6 +231,7 @@ exprfmt(Fmt *f, Node *n, int prec) ...@@ -231,6 +231,7 @@ exprfmt(Fmt *f, Node *n, int prec)
break; break;
case OINDEX: case OINDEX:
case OINDEXMAP:
exprfmt(f, n->left, 7); exprfmt(f, n->left, 7);
fmtprint(f, "["); fmtprint(f, "[");
exprfmt(f, n->right, 0); exprfmt(f, n->right, 0);
......
...@@ -233,112 +233,6 @@ csort(Case *l, int(*f)(Case*, Case*)) ...@@ -233,112 +233,6 @@ csort(Case *l, int(*f)(Case*, Case*))
return l; 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* Node*
newlabel(void) newlabel(void)
{ {
...@@ -597,22 +491,9 @@ exprswitch(Node *sw) ...@@ -597,22 +491,9 @@ exprswitch(Node *sw)
arg = Sfalse; arg = Sfalse;
} }
walkexpr(&sw->ntest, &sw->ninit); walkexpr(&sw->ntest, &sw->ninit);
t = sw->type;
/*
* 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);
if(t == T) if(t == T)
return; return;
walkcases(sw, sw3, arg);
convlit(&sw->ntest, t);
/* /*
* convert the switch into OIF statements * convert the switch into OIF statements
...@@ -785,7 +666,6 @@ typeswitch(Node *sw) ...@@ -785,7 +666,6 @@ typeswitch(Node *sw)
yyerror("type switch must be on an interface"); yyerror("type switch must be on an interface");
return; return;
} }
walkcases(sw, sw0, Stype);
cas = nil; cas = nil;
/* /*
...@@ -886,3 +766,64 @@ walkswitch(Node *sw) ...@@ -886,3 +766,64 @@ walkswitch(Node *sw)
} }
exprswitch(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