typechecking checkpoint.

started to move typechecking to another file.
can build entire tree still, but lots of work
is duplicated.  much to clean up.

R=ken
OCL=32536
CL=32543
This commit is contained in:
Russ Cox 2009-07-30 16:53:08 -07:00
parent 34b277f046
commit ff3a73b407
15 changed files with 1327 additions and 555 deletions

View File

@ -281,7 +281,7 @@ cgen(Node *n, Node *res)
cgen_callret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
@ -404,7 +404,7 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
@ -811,7 +811,7 @@ stkof(Node *n)
case OCALLMETH:
case OCALLINTER:
case OCALL:
case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;

View File

@ -300,7 +300,7 @@ cgen(Node *n, Node *res)
cgen_callret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
@ -420,7 +420,7 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
@ -827,7 +827,7 @@ stkof(Node *n)
case OCALLMETH:
case OCALLINTER:
case OCALL:
case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;

View File

@ -306,7 +306,7 @@ cgen(Node *n, Node *res)
cgen_callret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
@ -447,7 +447,7 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
@ -922,7 +922,7 @@ stkof(Node *n)
case OCALLMETH:
case OCALLINTER:
case OCALL:
case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;

View File

@ -35,6 +35,7 @@ OFILES=\
gen.$O\
obj.$O\
print.$O\
typecheck.$O\
$(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES)

View File

@ -339,6 +339,14 @@ typeinit(void)
okfor[OCAP] = okforcap;
okfor[OLEN] = okforlen;
// comparison
iscmp[OLT] = 1;
iscmp[OGT] = 1;
iscmp[OGE] = 1;
iscmp[OLE] = 1;
iscmp[OEQ] = 1;
iscmp[ONE] = 1;
mpatofix(maxintval[TINT8], "0x7f");
mpatofix(minintval[TINT8], "-0x80");
mpatofix(maxintval[TINT16], "0x7fff");

View File

@ -89,12 +89,17 @@ convlit1(Node **np, Type *t, int explicit)
switch(n->op) {
default:
if(n->type->etype == TIDEAL) {
convlit(&n->left, t);
convlit(&n->right, t);
n->type = t;
}
return;
case OLITERAL:
break;
case OLSH:
case ORSH:
convlit1(&n->left, t, explicit);
convlit(&n->left, t);
n->type = n->left->type;
return;
}
@ -259,11 +264,15 @@ overflow(Val v, Type *t)
return;
switch(v.ctype) {
case CTINT:
if(!isint[t->etype])
fatal("overflow: %T integer constant", t);
if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0
|| mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
yyerror("constant %B overflows %T", v.u.xval, t);
break;
case CTFLT:
if(!isfloat[t->etype])
fatal("overflow: %T floating-point constant", t);
if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) < 0
|| mpcmpfltflt(v.u.fval, maxfltval[t->etype]) > 0)
yyerror("constant %#F overflows %T", v.u.fval, t);
@ -325,6 +334,11 @@ evconst(Node *n)
Val v;
Mpint b;
switch(n->op) {
case OMAKE:
return;
}
nl = n->left;
if(nl == N || nl->type == T)
return;
@ -590,6 +604,7 @@ unary:
case TUP(OCONV, CTINT):
case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR):
case TUP(OCONV, CTNIL):
convlit1(&nl, n->type, 1);
break;
@ -711,6 +726,11 @@ defaultlit(Node **np, Type *t)
defaultlit(&n->left, t);
n->type = n->left->type;
return;
default:
defaultlit(&n->left, t);
defaultlit(&n->right, t);
n->type = n->left->type;
return;
}
lno = lineno;
@ -753,7 +773,7 @@ defaultlit(Node **np, Type *t)
* get the same type going out.
*/
void
defaultlit2(Node **lp, Node **rp)
defaultlit2(Node **lp, Node **rp, int force)
{
Node *l, *r;
@ -769,6 +789,8 @@ defaultlit2(Node **lp, Node **rp)
convlit(lp, r->type);
return;
}
if(!force)
return;
if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
convlit(lp, types[TFLOAT]);
convlit(rp, types[TFLOAT]);

View File

@ -528,7 +528,7 @@ funclit0(Node *t)
autodcl = dcl();
autodcl->back = autodcl;
walkexpr(&t, Etype, &t->ninit);
typecheck(&t, Etype);
funcargs(t->type);
return t;
}
@ -703,7 +703,7 @@ stotype(NodeList *l, int et, Type **t)
if(n->op != ODCLFIELD)
fatal("stotype: oops %N\n", n);
if(n->right != N) {
walkexpr(&n->right, Etype, &init);
typecheck(&n->right, Etype);
n->type = n->right->type;
n->right = N;
if(n->embedded && n->type != T) {
@ -1298,7 +1298,7 @@ xanondcl(Node *nt)
Node *n;
Type *t;
walkexpr(&nt, Etype, &nt->ninit);
typecheck(&nt, Etype);
t = nt->type;
if(nt->op != OTYPE) {
yyerror("%S is not a type", nt->sym);
@ -1318,7 +1318,7 @@ namedcl(Node *nn, Node *nt)
if(nn->op == OKEY)
nn = nn->left;
if(nn->sym == S) {
walkexpr(&nn, Etype, &nn->ninit);
typecheck(&nn, Etype);
yyerror("cannot mix anonymous %T with named arguments", nn->type);
return xanondcl(nn);
}
@ -1326,7 +1326,7 @@ namedcl(Node *nn, Node *nt)
if(nt == N)
yyerror("missing type for argument %S", nn->sym);
else {
walkexpr(&nt, Etype, &nt->ninit);
typecheck(&nt, Etype);
if(nt->op != OTYPE)
yyerror("%S is not a type", nt->sym);
else
@ -1650,7 +1650,7 @@ variter(NodeList *vl, Node *nt, NodeList *el)
t = T;
if(nt) {
walkexpr(&nt, Etype, &nt->ninit);
typecheck(&nt, Etype);
t = nt->type;
}
@ -1763,7 +1763,7 @@ unsafenmagic(Node *fn, NodeList *args)
n = nod(OLITERAL, N, N);
if(strcmp(s->name, "Sizeof") == 0) {
walkexpr(&r, Erv, &n->ninit);
typecheck(&r, Erv);
tr = r->type;
if(r->op == OLITERAL && r->val.ctype == CTSTR)
tr = types[TSTRING];
@ -1775,12 +1775,12 @@ unsafenmagic(Node *fn, NodeList *args)
if(strcmp(s->name, "Offsetof") == 0) {
if(r->op != ODOT && r->op != ODOTPTR)
goto no;
walkexpr(&r, Erv, &n->ninit);
typecheck(&r, Erv);
v = r->xoffset;
goto yes;
}
if(strcmp(s->name, "Alignof") == 0) {
walkexpr(&r, Erv, &n->ninit);
typecheck(&r, Erv);
tr = r->type;
if(r->op == OLITERAL && r->val.ctype == CTSTR)
tr = types[TSTRING];

View File

@ -321,7 +321,7 @@ gen(Node *n)
cgen_callinter(n, N, 0);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n, 0);
break;
@ -360,7 +360,7 @@ cgen_callmeth(Node *n, int proc)
if(l->op != ODOTMETH)
fatal("cgen_callmeth: not dotmethod: %N");
n->op = OCALL;
n->op = OCALLFUNC;
n->left = n->left->right;
n->left->type = l->type;
@ -387,7 +387,7 @@ cgen_proc(Node *n, int proc)
cgen_callinter(n->left, N, proc);
break;
case OCALL:
case OCALLFUNC:
cgen_call(n->left, proc);
break;
}

View File

@ -343,14 +343,15 @@ enum
OCONTINUE,
OADDR,
OIND,
OCALL, OCALLMETH, OCALLINTER,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OINDEX, OSLICE,
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
OREGISTER, OINDREG,
OKEY, OPARAM,
OCOMPOS, OCOMPSLICE, OCOMPMAP,
OCONV, OCONVNOP,
ODOTTYPE, OTYPESW,
OCONV, OCONVNOP, OCONVRUNE, OCONVSTRB, OCONVSTRI,
OCONVA2S,
ODOTTYPE, OTYPESW, OTYPECASE,
OBAD,
OTCHAN, OTMAP, OTSTRUCT, OTINTER, OTFUNC, OTARRAY,
@ -440,7 +441,7 @@ enum
Elv = 1<<2, // evaluated in lvalue context
Erv = 1<<3, // evaluated in rvalue context
Etype = 1<<4,
Eideal = 1<<5,
Ecall = 1<<5,
};
#define BITS 5
@ -593,6 +594,7 @@ EXTERN uchar okforcap[NTYPE];
EXTERN uchar okforlen[NTYPE];
EXTERN uchar okforarith[NTYPE];
EXTERN uchar* okfor[OEND];
EXTERN uchar iscmp[OEND];
EXTERN Mpint* minintval[NTYPE];
EXTERN Mpint* maxintval[NTYPE];
@ -830,7 +832,6 @@ int Wconv(Fmt*);
int Zconv(Fmt*);
int lookdot0(Sym*, Type*, Type**);
Type* lookdot1(Sym*, Type*, Type*);
int adddot1(Sym*, Type*, int, Type**);
Node* adddot(Node*);
void expandmeth(Sym*, Type*);
@ -846,7 +847,7 @@ Type* dodcltype(Type*);
void updatetype(Type*, Type*);
void dodclconst(Node*, Node*);
void defaultlit(Node**, Type*);
void defaultlit2(Node**, Node**);
void defaultlit2(Node**, Node**, int);
int structcount(Type*);
void addmethod(Node*, Type*, int);
Node* methodname(Node*, Type*);

View File

@ -400,7 +400,7 @@ typedclname:
typedcl:
typedclname ntype
{
walkexpr(&$2, Etype, &$2->ninit);
typecheck(&$2, Etype);
updatetype($1, $2->type);
resumecheckwidth();
}
@ -478,21 +478,21 @@ case:
yyerror("type switch case cannot be list");
if(n->op == OLITERAL && n->val.ctype == CTNIL) {
// case nil
$$->list = list1(nod(OTYPESW, N, N));
$$->list = list1(nod(OTYPECASE, N, N));
break;
}
// TODO: move
e = nerrors;
walkexpr(&n, Etype | Erv, &$$->ninit);
typecheck(&n, Etype | Erv);
if(n->op == OTYPE) {
n = old2new(typeswvar->right, n->type, &$$->ninit);
$$->list = list1(nod(OTYPESW, n, N));
$$->list = list1(nod(OTYPECASE, n, N));
break;
}
// maybe walkexpr found problems that keep
// maybe typecheck found problems that keep
// e from being valid even outside a type switch.
// only complain if walkexpr didn't print new errors.
// only complain if typecheck didn't print new errors.
if(nerrors == e)
yyerror("non-type case in type switch");
$$->diag = 1;
@ -518,6 +518,7 @@ case:
// done in casebody()
poptodcl();
$$ = nod(OXCASE, N, N);
typecheck(&$4, Erv);
$$->list = list1(nod(OAS, selectas($2, $4, &$$->ninit), $4));
}
| LDEFAULT ':'
@ -1143,7 +1144,7 @@ fndcl:
n = nod(OTFUNC, N, N);
n->list = $3;
n->rlist = $5;
walkexpr(&n, Etype, &n->ninit);
typecheck(&n, Etype);
$$->type = n->type;
funchdr($$);
}

View File

@ -24,7 +24,7 @@ void
exprfmt(Fmt *f, Node *n, int prec)
{
int nprec;
nprec = 0;
if(n == nil) {
fmtprint(f, "<nil>");
@ -38,7 +38,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case OLITERAL:
nprec = 7;
break;
case OMUL:
case ODIV:
case OMOD:
@ -48,14 +48,14 @@ exprfmt(Fmt *f, Node *n, int prec)
case OANDNOT:
nprec = 6;
break;
case OADD:
case OSUB:
case OOR:
case OXOR:
nprec = 5;
break;
case OEQ:
case OLT:
case OLE:
@ -64,15 +64,15 @@ exprfmt(Fmt *f, Node *n, int prec)
case ONE:
nprec = 4;
break;
case OSEND:
nprec = 3;
break;
case OANDAND:
nprec = 2;
break;
case OOROR:
nprec = 1;
break;
@ -117,7 +117,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case ONONAME:
fmtprint(f, "%S", n->sym);
break;
case OTYPE:
fmtprint(f, "%T", n->type);
break;
@ -126,7 +126,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "[]");
exprfmt(f, n->left, PFIXME);
break;
case OTMAP:
fmtprint(f, "map[");
exprfmt(f, n->left, 0);
@ -146,19 +146,31 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, PCHAN);
}
break;
case OTSTRUCT:
fmtprint(f, "<struct>");
break;
case OTINTER:
fmtprint(f, "<inter>");
break;
case OTFUNC:
fmtprint(f, "<func>");
break;
case OAS:
exprfmt(f, n->left, 0);
fmtprint(f, " = ");
exprfmt(f, n->right, 0);
break;
case OASOP:
exprfmt(f, n->left, 0);
fmtprint(f, " %#O= ", n->etype);
exprfmt(f, n->right, 0);
break;
case OADD:
case OANDAND:
case OANDNOT:
@ -182,7 +194,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, " %#O ", n->op);
exprfmt(f, n->right, nprec+1);
break;
case OADDR:
case OCOM:
case OIND:
@ -195,35 +207,35 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, " ");
exprfmt(f, n->left, 0);
break;
case OCOMPOS:
fmtprint(f, "<compos>");
break;
case ODOT:
case ODOTINTER:
case ODOTMETH:
exprfmt(f, n->left, 7);
if(n->sym == S)
if(n->right == N || n->right->sym == S)
fmtprint(f, ".<nil>");
else
fmtprint(f, ".%s", n->sym->name);
fmtprint(f, ".%s", n->right->sym->name);
break;
case ODOTTYPE:
exprfmt(f, n->left, 7);
fmtprint(f, ".(");
exprfmt(f, n->right, 0);
fmtprint(f, ")");
break;
case OINDEX:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
exprfmt(f, n->right, 0);
fmtprint(f, "]");
break;
case OSLICE:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
@ -232,8 +244,9 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->right->right, 0);
fmtprint(f, "]");
break;
case OCALL:
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
exprfmt(f, n->left, 7);
@ -241,13 +254,13 @@ exprfmt(Fmt *f, Node *n, int prec)
exprlistfmt(f, n->list);
fmtprint(f, ")");
break;
case OCONV:
fmtprint(f, "%T(", n->type);
exprfmt(f, n->left, 0);
fmtprint(f, ")");
break;
case OCAP:
case OCLOSE:
case OCLOSED:

View File

@ -461,7 +461,7 @@ aindex(Node *b, Type *t)
bound = -1; // open bound
init = nil;
walkexpr(&b, Erv, &init);
typecheck(&b, Erv);
if(b != nil) {
switch(consttype(b)) {
default:
@ -638,6 +638,7 @@ opnames[] =
[OBAD] = "BAD",
[OBLOCK] = "BLOCK",
[OBREAK] = "BREAK",
[OCALLFUNC] = "CALLFUNC",
[OCALLINTER] = "CALLINTER",
[OCALLMETH] = "CALLMETH",
[OCALL] = "CALL",
@ -2100,6 +2101,7 @@ ullmancalc(Node *n)
ul++;
goto out;
case OCALL:
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
ul = UINF;
@ -2389,6 +2391,7 @@ saferef(Node *n, NodeList **init)
r = nod(OXXX, N, N);
*r = *n;
r->left = l;
typecheck(&r, Elv);
walkexpr(&r, Elv, init);
return r;
@ -2398,9 +2401,11 @@ saferef(Node *n, NodeList **init)
l = nod(OXXX, N, N);
tempname(l, ptrto(n->type));
a = nod(OAS, l, nod(OADDR, n, N));
typecheck(&a, Etop);
walkexpr(&a, Etop, init);
*init = list(*init, a);
r = nod(OIND, l, N);
typecheck(&r, Elv);
walkexpr(&r, Elv, init);
return r;
}
@ -2555,13 +2560,11 @@ out:
Node*
adddot(Node *n)
{
NodeList *init;
Type *t;
Sym *s;
int c, d;
init = nil;
walkexpr(&n->left, Erv, &init);
typecheck(&n->left, Erv);
t = n->left->type;
if(t == T)
goto ret;
@ -2589,7 +2592,6 @@ out:
n->left->right = newname(dotlist[c].field->sym);
}
ret:
n->ninit = concat(init, n->ninit);
return n;
}

View File

@ -247,14 +247,15 @@ sw0(Node **cp, Type *place, int arg)
switch(c->op) {
default:
if(arg == Stype) {
yyerror("inappropriate case for a type switch");
yyerror("expression case in a type switch");
return T;
}
walkexpr(cp, Erv, nil);
break;
case OTYPESW:
case OTYPECASE:
if(arg != Stype)
yyerror("inappropriate type case");
yyerror("type case in an expression switch");
break;
case OAS:
yyerror("inappropriate assignment in a case statement");
@ -542,12 +543,14 @@ exprbsw(Case *c0, int ncase, int arg)
case Sfalse:
a = nod(OIF, N, N);
a->ntest = nod(ONOT, n->left, N); // if !val
typecheck(&a->ntest, Erv);
a->nbody = list1(n->right); // then goto l
break;
default:
a = nod(OIF, N, N);
a->ntest = nod(OEQ, exprname, n->left); // if name == val
typecheck(&a->ntest, Erv);
a->nbody = list1(n->right); // then goto l
break;
}
@ -566,6 +569,7 @@ exprbsw(Case *c0, int ncase, int arg)
c = c->link;
a = nod(OIF, N, N);
a->ntest = nod(OLE, exprname, c->node->left);
typecheck(&a->ntest, Erv);
a->nbody = list1(exprbsw(c0, half, arg));
a->nelse = list1(exprbsw(c->link, ncase-half, arg));
return a;
@ -619,6 +623,7 @@ exprswitch(Node *sw)
exprname = nod(OXXX, N, N);
tempname(exprname, sw->ntest->type);
cas = list1(nod(OAS, exprname, sw->ntest));
typechecklist(cas, Etop);
}
c0 = mkcaselist(sw, arg);
@ -686,6 +691,7 @@ typeone(Node *t)
b = nod(ODOTTYPE, facename, N);
b->type = t->left->left->type; // interface.(type)
a->rlist = list1(b);
typecheck(&a, Etop);
init = list(init, a);
b = nod(OIF, N, N);
@ -716,6 +722,7 @@ typebsw(Case *c0, int ncase)
v.ctype = CTNIL;
a = nod(OIF, N, N);
a->ntest = nod(OEQ, facename, nodlit(v));
typecheck(&a->ntest, Erv);
a->nbody = list1(n->right); // if i==nil { goto l }
cas = list(cas, a);
break;
@ -728,6 +735,7 @@ typebsw(Case *c0, int ncase)
case Ttypeconst:
a = nod(OIF, N, N);
a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
typecheck(&a->ntest, Erv);
a->nbody = list1(typeone(n));
cas = list(cas, a);
break;
@ -744,6 +752,7 @@ typebsw(Case *c0, int ncase)
c = c->link;
a = nod(OIF, N, N);
a->ntest = nod(OLE, hashname, nodintconst(c->hash));
typecheck(&a->ntest, Erv);
a->nbody = list1(typebsw(c0, half));
a->nelse = list1(typebsw(c->link, ncase-half));
return a;
@ -786,13 +795,16 @@ typeswitch(Node *sw)
facename = nod(OXXX, N, N);
tempname(facename, sw->ntest->right->type);
a = nod(OAS, facename, sw->ntest->right);
typecheck(&a, Etop);
cas = list(cas, a);
boolname = nod(OXXX, N, N);
tempname(boolname, types[TBOOL]);
typecheck(&boolname, Erv);
hashname = nod(OXXX, N, N);
tempname(hashname, types[TUINT32]);
typecheck(&hashname, Erv);
t = sw->ntest->right->type;
if(isnilinter(t))
@ -803,6 +815,7 @@ typeswitch(Node *sw)
a = nod(OCALL, a, N);
a->list = list1(facename);
a = nod(OAS, hashname, a);
typecheck(&a, Etop);
cas = list(cas, a);
c0 = mkcaselist(sw, Stype);
@ -861,8 +874,10 @@ walkswitch(Node *sw)
* both have inserted OBREAK statements
*/
walkstmtlist(sw->ninit);
if(sw->ntest == N)
if(sw->ntest == N) {
sw->ntest = nodbool(1);
typecheck(&sw->ntest, Erv);
}
casebody(sw);
if(sw->ntest->op == OTYPESW) {

1099
src/cmd/gc/typecheck.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff