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
cgen_callret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
cgen_aret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
case OCALLMETH:
case OCALLINTER:
- case OCALL:
+ case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;
cgen_callret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
cgen_aret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
case OCALLMETH:
case OCALLINTER:
- case OCALL:
+ case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;
cgen_callret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_callret(n, res);
break;
cgen_aret(n, res);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
cgen_aret(n, res);
break;
case OCALLMETH:
case OCALLINTER:
- case OCALL:
+ case OCALLFUNC:
t = n->left->type;
if(isptr[t->etype])
t = t->type;
gen.$O\
obj.$O\
print.$O\
+ typecheck.$O\
$(LIB): $(OFILES)
ar rsc $(LIB) $(OFILES)
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");
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;
}
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);
Val v;
Mpint b;
+ switch(n->op) {
+ case OMAKE:
+ return;
+ }
+
nl = n->left;
if(nl == N || nl->type == T)
return;
case TUP(OCONV, CTINT):
case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR):
+ case TUP(OCONV, CTNIL):
convlit1(&nl, n->type, 1);
break;
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;
* get the same type going out.
*/
void
-defaultlit2(Node **lp, Node **rp)
+defaultlit2(Node **lp, Node **rp, int force)
{
Node *l, *r;
convlit(lp, r->type);
return;
}
+ if(!force)
+ return;
if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
convlit(lp, types[TFLOAT]);
convlit(rp, types[TFLOAT]);
autodcl = dcl();
autodcl->back = autodcl;
- walkexpr(&t, Etype, &t->ninit);
+ typecheck(&t, Etype);
funcargs(t->type);
return 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) {
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);
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);
}
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
t = T;
if(nt) {
- walkexpr(&nt, Etype, &nt->ninit);
+ typecheck(&nt, Etype);
t = nt->type;
}
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];
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];
cgen_callinter(n, N, 0);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n, 0);
break;
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;
cgen_callinter(n->left, N, proc);
break;
- case OCALL:
+ case OCALLFUNC:
cgen_call(n->left, proc);
break;
}
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,
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
EXTERN uchar okforlen[NTYPE];
EXTERN uchar okforarith[NTYPE];
EXTERN uchar* okfor[OEND];
+EXTERN uchar iscmp[OEND];
EXTERN Mpint* minintval[NTYPE];
EXTERN Mpint* maxintval[NTYPE];
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*);
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*);
typedcl:
typedclname ntype
{
- walkexpr(&$2, Etype, &$2->ninit);
+ typecheck(&$2, Etype);
updatetype($1, $2->type);
resumecheckwidth();
}
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;
// done in casebody()
poptodcl();
$$ = nod(OXCASE, N, N);
+ typecheck(&$4, Erv);
$$->list = list1(nod(OAS, selectas($2, $4, &$$->ninit), $4));
}
| LDEFAULT ':'
n = nod(OTFUNC, N, N);
n->list = $3;
n->rlist = $5;
- walkexpr(&n, Etype, &n->ninit);
+ typecheck(&n, Etype);
$$->type = n->type;
funchdr($$);
}
exprfmt(Fmt *f, Node *n, int prec)
{
int nprec;
-
+
nprec = 0;
if(n == nil) {
fmtprint(f, "<nil>");
case OLITERAL:
nprec = 7;
break;
-
+
case OMUL:
case ODIV:
case OMOD:
case OANDNOT:
nprec = 6;
break;
-
+
case OADD:
case OSUB:
case OOR:
case OXOR:
nprec = 5;
break;
-
+
case OEQ:
case OLT:
case OLE:
case ONE:
nprec = 4;
break;
-
+
case OSEND:
nprec = 3;
break;
-
+
case OANDAND:
nprec = 2;
break;
-
+
case OOROR:
nprec = 1;
break;
case ONONAME:
fmtprint(f, "%S", n->sym);
break;
-
+
case OTYPE:
fmtprint(f, "%T", n->type);
break;
fmtprint(f, "[]");
exprfmt(f, n->left, PFIXME);
break;
-
+
case OTMAP:
fmtprint(f, "map[");
exprfmt(f, n->left, 0);
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:
fmtprint(f, " %#O ", n->op);
exprfmt(f, n->right, nprec+1);
break;
-
+
case OADDR:
case OCOM:
case OIND:
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, "[");
exprfmt(f, n->right->right, 0);
fmtprint(f, "]");
break;
-
+
case OCALL:
+ case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
exprfmt(f, n->left, 7);
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:
bound = -1; // open bound
init = nil;
- walkexpr(&b, Erv, &init);
+ typecheck(&b, Erv);
if(b != nil) {
switch(consttype(b)) {
default:
[OBAD] = "BAD",
[OBLOCK] = "BLOCK",
[OBREAK] = "BREAK",
+ [OCALLFUNC] = "CALLFUNC",
[OCALLINTER] = "CALLINTER",
[OCALLMETH] = "CALLMETH",
[OCALL] = "CALL",
ul++;
goto out;
case OCALL:
+ case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
ul = UINF;
r = nod(OXXX, N, N);
*r = *n;
r->left = l;
+ typecheck(&r, Elv);
walkexpr(&r, Elv, init);
return r;
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;
}
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;
n->left->right = newname(dotlist[c].field->sym);
}
ret:
- n->ninit = concat(init, n->ninit);
return n;
}
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");
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;
}
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;
exprname = nod(OXXX, N, N);
tempname(exprname, sw->ntest->type);
cas = list1(nod(OAS, exprname, sw->ntest));
+ typechecklist(cas, Etop);
}
c0 = mkcaselist(sw, arg);
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);
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;
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;
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;
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))
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);
* 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) {
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go.h"
+
+static void implicitstar(Node**);
+static int onearg(Node*);
+static int lookdot(Node*, Type*);
+static int convert(Node**, Type*, int);
+
+void
+typechecklist(NodeList *l, int top)
+{
+ for(; l; l=l->next)
+ typecheck(&l->n, top);
+}
+
+/*
+ * type check the whole tree of an expression.
+ * calculates expression types.
+ * evaluates compile time constants.
+ * marks variables that escape the local frame.
+ * rewrites n->op to be more specific in some cases.
+ * replaces *np with a new pointer in some cases.
+ * returns the final value of *np as a convenience.
+ */
+Node*
+typecheck(Node **np, int top)
+{
+ int et, et1, et2, op, nerr, len;
+ NodeList *ll;
+ Node *n, *l, *r;
+ NodeList *args;
+ int i, lno, ok;
+ Type *t;
+
+ n = *np;
+ if(n == N || n->typecheck == 1)
+ return n;
+ if(n->typecheck == 2)
+ fatal("typecheck loop");
+ n->typecheck = 2;
+
+ if(n->sym && n->walkdef != 1)
+ walkdef(n);
+
+ lno = setlineno(n);
+
+reswitch:
+ ok = 0;
+ switch(n->op) {
+ default:
+ // until typecheck is complete, do nothing.
+ dump("typecheck", n);
+ fatal("typecheck %O", n->op);
+
+ /*
+ * names
+ */
+ case OLITERAL:
+ ok |= Erv;
+ goto ret;
+
+ case ONONAME:
+ ok |= Elv | Erv;
+ goto ret;
+
+ case ONAME:
+ if(n->etype != 0) {
+ yyerror("must call builtin %S", n->sym);
+ goto error;
+ }
+ ok |= Erv;
+ if(n->class != PFUNC)
+ ok |= Elv;
+ goto ret;
+
+ /*
+ * types (OIND is with exprs)
+ */
+ case OTYPE:
+ ok |= Etype;
+ if(n->type == T)
+ goto error;
+ break;
+
+ case OTARRAY:
+ ok |= Etype;
+ t = typ(TARRAY);
+ l = n->left;
+ r = n->right;
+ if(l == nil) {
+ t->bound = -1;
+ } else {
+ typecheck(&l, Erv | Etype);
+ switch(l->op) {
+ default:
+ yyerror("invalid array bound %#N", l);
+ goto error;
+
+ case OLITERAL:
+ if(consttype(l) == CTINT) {
+ t->bound = mpgetfix(l->val.u.xval);
+ if(t->bound < 0) {
+ yyerror("array bound must be non-negative");
+ goto error;
+ }
+ }
+ break;
+
+ case OTYPE:
+ if(l->type == T)
+ goto error;
+ if(l->type->etype != TDDD) {
+ yyerror("invalid array bound %T", l->type);
+ goto error;
+ }
+ t->bound = -100;
+ break;
+ }
+ }
+ typecheck(&r, Etype);
+ if(r->type == T)
+ goto error;
+ t->type = r->type;
+ n->op = OTYPE;
+ n->type = t;
+ n->left = N;
+ n->right = N;
+ checkwidth(t);
+ break;
+
+ case OTMAP:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ r = typecheck(&n->right, Etype);
+ if(l->type == T || r->type == T)
+ goto error;
+ n->op = OTYPE;
+ n->type = maptype(l->type, r->type);
+ n->left = N;
+ n->right = N;
+ break;
+
+ case OTCHAN:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ if(l->type == T)
+ goto error;
+ t = typ(TCHAN);
+ t->type = l->type;
+ t->chan = n->etype;
+ n->op = OTYPE;
+ n->type = t;
+ n->left = N;
+ n->etype = 0;
+ break;
+
+ case OTSTRUCT:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = dostruct(n->list, TSTRUCT);
+ if(n->type == T)
+ goto error;
+ n->list = nil;
+ break;
+
+ case OTINTER:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = dostruct(n->list, TINTER);
+ if(n->type == T)
+ goto error;
+ n->type = sortinter(n->type);
+ break;
+
+ case OTFUNC:
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = functype(n->left, n->list, n->rlist);
+ if(n->type == T)
+ goto error;
+ break;
+
+ /*
+ * type or expr
+ */
+ case OIND:
+ l = typecheck(&n->left, top | Etype);
+ if((t = l->type) == T)
+ goto error;
+ if(l->op == OTYPE) {
+ ok |= Etype;
+ n->op = OTYPE;
+ n->type = ptrto(l->type);
+ n->left = N;
+ goto ret;
+ }
+ if(!isptr[t->etype]) {
+ yyerror("invalid indirect %#N (non-pointer type %T)", n, t);
+ goto error;
+ }
+ n->type = t->type;
+ goto ret;
+
+ /*
+ * arithmetic exprs
+ */
+ case OASOP:
+ ok |= Etop;
+ l = typecheck(&n->left, Elv);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ op = n->etype;
+ goto arith;
+
+ case OADD:
+ case OAND:
+ case OANDAND:
+ case OANDNOT:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLT:
+ case OLSH:
+ case ORSH:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case OOR:
+ case OOROR:
+ case OSUB:
+ case OXOR:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ op = n->op;
+ arith:
+ if(op == OLSH || op == ORSH)
+ goto shift;
+ // ideal mixed with non-ideal
+ defaultlit2(&l, &r, 0);
+ n->left = l;
+ n->right = r;
+ t = l->type;
+ if(t->etype == TIDEAL)
+ t = r->type;
+ et = t->etype;
+ if(et == TIDEAL)
+ et = TINT;
+ if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+ badbinary:
+ yyerror("invalid operation: %#N (type %T %#O %T)", n, l->type, op, r->type);
+ goto error;
+ }
+ if(!okfor[op][et])
+ goto badbinary;
+ // okfor allows any array == array;
+ // restrict to slice == nil and nil == slice.
+ if(l->type->etype == TARRAY && !isslice(l->type))
+ goto badbinary;
+ if(r->type->etype == TARRAY && !isslice(r->type))
+ goto badbinary;
+ if(isslice(l->type) && !isnil(l) && !isnil(r))
+ goto badbinary;
+ t = l->type;
+ if(iscmp[n->op])
+ t = types[TBOOL];
+ n->type = t;
+ goto ret;
+
+ shift:
+ defaultlit(&r, types[TUINT]);
+ n->right = r;
+ t = r->type;
+ if(!isint[t->etype] || issigned[t->etype]) {
+ yyerror("invalid operation: %#N (shift count type %T)", n, r->type);
+ goto error;
+ }
+ // no defaultlit for left
+ // the outer context gives the type
+ n->type = l->type;
+ goto ret;
+
+ case OCOM:
+ case OMINUS:
+ case ONOT:
+ case OPLUS:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv);
+ if((t = l->type) == T)
+ goto error;
+ if(!okfor[n->op][t->etype]) {
+ yyerror("invalid operation: %#O %T", n->op, t);
+ goto error;
+ }
+ n->type = t;
+ goto ret;
+
+ /*
+ * exprs
+ */
+ case OADDR:
+ l = typecheck(&n->left, Elv);
+ if((t = l->type) == T)
+ goto error;
+ n->type = ptrto(t);
+ goto ret;
+
+ case OCOMPOS:
+ l = typecheck(&n->right /* sic */, Etype /* TODO | Edotarray */);
+ if((t = l->type) == T)
+ goto error;
+ nerr = nerrors;
+ switch(t->etype) {
+ case TARRAY:
+ len = 0;
+ i = 0;
+ for(ll=n->list; ll; ll=ll->next) {
+ l = ll->n;
+ if(l->op == OKEY) {
+ typecheck(&l->left, Erv);
+ evconst(l->left);
+ i = nonnegconst(l->left);
+ typecheck(&l->right, Erv);
+ defaultlit(&l->right, t->type);
+ // TODO more forceful conversion of l->right
+ } else {
+ typecheck(&ll->n, Erv);
+ defaultlit(&ll->n, t->type);
+ // TODO more forceful conversion
+ }
+ i++;
+ if(i > len) {
+ len = i;
+ if(t->bound >= 0 && len > t->bound) {
+ setlineno(l);
+ yyerror("array index out of bounds");
+ t->bound = -1; // no more errors
+ }
+ }
+ }
+ if(t->bound == -100)
+ t->bound = len;
+ break;
+
+ case TMAP:
+ for(ll=n->list; ll; ll=ll->next) {
+ l = ll->n;
+ if(l->op != OKEY) {
+ yyerror("missing key in map literal");
+ continue;
+ }
+ typecheck(&l->left, Erv);
+ typecheck(&l->right, Erv);
+ defaultlit(&l->left, t->down);
+ defaultlit(&l->right, t->type);
+ // TODO more forceful
+ }
+ break;
+
+ case TSTRUCT:
+ // fatal("compos %T", t);
+ ;
+ }
+ if(nerr != nerrors)
+ goto error;
+ n->type = t;
+ goto ret;
+
+ case ODOT:
+ l = typecheck(&n->left, Erv);
+ if((t = l->type) == T)
+ goto error;
+ if(n->right->op != ONAME) {
+ yyerror("rhs of . must be a name"); // impossible
+ goto error;
+ }
+ if(isptr[t->etype]) {
+ t = t->type;
+ if(t == T)
+ goto error;
+ n->op = ODOTPTR;
+ }
+ if(!lookdot(n, t)) {
+ yyerror("%#N undefined (%S in type %T)", n, n->right->sym, t);
+ goto error;
+ }
+ switch(n->op) {
+ case ODOTINTER:
+ case ODOTMETH:
+ ok |= Ecall;
+ break;
+ default:
+ ok |= Erv;
+ // TODO ok |= Elv sometimes
+ break;
+ }
+ goto ret;
+
+ case ODOTTYPE:
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(!isinter(t)) {
+ yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
+ goto error;
+ }
+ if(n->right != N) {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ n->right = N;
+ if(n->type == T)
+ goto error;
+ }
+ goto ret;
+
+ case OINDEX:
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ implicitstar(&n->left);
+ l = n->left;
+ typecheck(&n->right, Erv);
+ r = n->right;
+ if((t = l->type) == T || r->type == T)
+ goto error;
+ switch(t->etype) {
+ default:
+ yyerror("invalid operation: %#N (index of type %T)", n, t);
+ goto error;
+
+ case TARRAY:
+ ok |= Erv | Elv;
+ defaultlit(&n->right, types[TUINT]);
+ n->type = t->type;
+ break;
+
+ case TMAP:
+ ok |= Erv | Elv;
+ defaultlit(&n->right, t->down);
+ n->type = t->type;
+ break;
+
+ case TSTRING:
+ ok |= Erv;
+ defaultlit(&n->right, types[TUINT]);
+ n->type = types[TUINT8];
+ break;
+ }
+ goto ret;
+
+ case ORECV:
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(t->etype != TCHAN) {
+ yyerror("invalid operation: %#N (recv from non-chan type %T)", n, t);
+ goto error;
+ }
+ if(!(t->chan & Crecv)) {
+ yyerror("invalid operation: %#N (recv from send-only type %T)", n, t);
+ goto error;
+ }
+ n->type = t->type;
+ ok |= Erv;
+ goto ret;
+
+ case OSEND:
+ l = typecheck(&n->left, Erv);
+ typecheck(&n->right, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(!(t->chan & Csend)) {
+ yyerror("invalid operation: %#N (send to recv-only type %T)", n, t);
+ goto error;
+ }
+ defaultlit(&n->right, t->type);
+ r = n->right;
+ if((t = r->type) == T)
+ goto error;
+ // TODO: more aggressive
+ ok |= Etop | Erv;
+ n->type = types[TBOOL];
+ goto ret;
+
+ case OSLICE:
+ ok |= Erv;
+ typecheck(&n->left, top);
+ typecheck(&n->right->left, Erv);
+ typecheck(&n->right->right, Erv);
+ defaultlit(&n->left, T);
+ defaultlit(&n->right->left, types[TUINT]);
+ defaultlit(&n->right->right, types[TUINT]);
+ implicitstar(&n->left);
+ if(n->right->left == N || n->right->right == N) {
+ yyerror("missing slice bounds?");
+ goto error;
+ }
+ if((t = n->right->left->type) == T)
+ goto error;
+ if(!isint[t->etype]) {
+ yyerror("invalid array index %#N (type %T)", n->right->left, t);
+ goto error;
+ }
+ if((t = n->right->right->type) == T)
+ goto error;
+ if(!isint[t->etype]) {
+ yyerror("invalid array index %#N (type %T)", n->right->right, t);
+ goto error;
+ }
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ // TODO(rsc): 64-bit slice index needs to be checked
+ // for overflow in generated code
+ switch(t->etype) {
+ default:
+ yyerror("invalid operation: %#N (slice of type %T)", n, t);
+ goto error;
+
+ case TARRAY:
+ ok |= Elv;
+ n = arrayop(n, Erv);
+ break;
+
+ case TSTRING:
+ n = stringop(n, Erv, nil);
+ break;
+ }
+ goto ret;
+
+ /*
+ * call and call like
+ */
+ case OCALL:
+ l = n->left;
+ if(l->op == ONAME && l->etype != 0) {
+ // builtin: OLEN, OCAP, etc.
+ n->op = l->etype;
+ n->left = n->right;
+ n->right = N;
+ goto reswitch;
+ }
+ l = typecheck(&n->left, Erv | Etype | Ecall);
+ typechecklist(n->list, Erv);
+ if((t = l->type) == T)
+{
+yyerror("skip %#N", n);
+ goto error;
+}
+ if(l->op == OTYPE) {
+ ok |= Erv;
+ // turn CALL(type, arg) into CONV(arg) w/ type
+ n->left = N;
+ if(onearg(n) < 0)
+ goto error;
+ n->op = OCONV;
+ n->type = l->type;
+ goto doconv;
+ }
+ // TODO: check args
+ if(t->outtuple == 0) {
+ ok |= Etop;
+ goto ret;
+ }
+ if(t->outtuple == 1) {
+ ok |= Erv;
+ t = getoutargx(l->type)->type;
+ if(t->etype == TFIELD)
+ t = t->type;
+ n->type = t;
+ goto ret;
+ }
+ // multiple return
+ // ok |= Emulti;
+ n->type = getoutargx(l->type);
+ goto ret;
+
+ case OCAP:
+ case OLEN:
+ if(onearg(n) < 0)
+ goto error;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ implicitstar(&n->left);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ switch(n->op) {
+ case OCAP:
+ if(!okforcap[t->etype])
+ goto badcall1;
+ break;
+ case OLEN:
+ if(!okforlen[t->etype])
+ goto badcall1;
+ break;
+ }
+ // might be constant
+ switch(t->etype) {
+ case TSTRING:
+ if(isconst(l, CTSTR))
+ nodconst(n, types[TINT], l->val.u.sval->len);
+ break;
+ case TARRAY:
+ if(t->bound >= 0)
+ nodconst(n, types[TINT], t->bound);
+ break;
+ }
+ n->type = types[TINT];
+ goto ret;
+
+ case OCLOSED:
+ ok |= Erv;
+ case OCLOSE:
+ ok |= Etop;
+ if(onearg(n) < 0)
+ goto error;
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, T);
+ l = n->left;
+ if((t = l->type) == T)
+ goto error;
+ if(t->etype != TCHAN) {
+ yyerror("invalid operation: %#N (non-chan type %T)", n, t);
+ goto error;
+ }
+ goto ret;
+
+ case OCONV:
+ doconv:
+ typecheck(&n->left, Erv);
+ defaultlit(&n->left, n->type);
+ if((t = n->left->type) == T)
+ goto error;
+ switch(convert(&n->left, n->type, 1)) {
+ case -1:
+ goto error;
+ case 0:
+ n = n->left;
+ break;
+ case OCONV:
+ break;
+ }
+ goto ret;
+
+ case OMAKE:
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing argument to make");
+ goto error;
+ }
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Etype);
+ if((t = l->type) == T)
+ goto error;
+
+ switch(t->etype) {
+ default:
+ badmake:
+ yyerror("cannot make type %T", t);
+ goto error;
+
+ case TARRAY:
+ if(!isslice(t))
+ goto badmake;
+ if(args == nil) {
+ yyerror("missing len argument to make(%T)", t);
+ goto error;
+ }
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TUINT]);
+ r = N;
+ if(args != nil) {
+ r = args->n;
+ args = args->next;
+ typecheck(&r, Erv);
+ defaultlit(&r, types[TUINT]);
+ }
+ if(l->type == T || (r && r->type == T))
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer len argument to make(%T)", t);
+ goto error;
+ }
+ if(r && !isint[r->type->etype]) {
+ yyerror("non-integer cap argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ n->right = r;
+ break;
+
+ case TMAP:
+ if(args != nil) {
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TUINT]);
+ if(l->type == T)
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer size argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ }
+ break;
+
+ case TCHAN:
+ l = N;
+ if(args != nil) {
+ l = args->n;
+ args = args->next;
+ typecheck(&l, Erv);
+ defaultlit(&l, types[TUINT]);
+ if(l->type == T)
+ goto error;
+ if(!isint[l->type->etype]) {
+ yyerror("non-integer buffer argument to make(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ }
+ break;
+ }
+ if(args != nil) {
+ yyerror("too many arguments to make(%T)", t);
+ goto error;
+ }
+ n->type = t;
+ goto ret;
+
+ case ONEW:
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing argument to new");
+ goto error;
+ }
+ l = args->n;
+ typecheck(&l, Etype);
+ if((t = l->type) == T)
+ goto error;
+ if(args->next != nil) {
+ yyerror("too many arguments to new(%T)", t);
+ goto error;
+ }
+ n->left = l;
+ n->type = ptrto(t);
+ goto ret;
+
+ case OPANIC:
+ case OPANICN:
+ case OPRINT:
+ case OPRINTN:
+ typechecklist(n->list, Erv);
+ goto ret;
+
+ /*
+ * statements
+ */
+ case OAS:
+ typecheck(&n->left, Elv);
+ typecheck(&n->right, Erv);
+ goto ret;
+
+ case OAS2:
+ typechecklist(n->list, Elv);
+ typechecklist(n->rlist, Erv);
+ goto ret;
+
+ case OBREAK:
+ case OCONTINUE:
+ case ODCL:
+ case OEMPTY:
+ case OGOTO:
+ case OLABEL:
+ case OXFALL:
+ goto ret;
+
+ case ODEFER:
+ case OPROC:
+ typecheck(&n->left, Etop);
+ goto ret;
+
+ case OFOR:
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv); // TODO Ebool
+ typecheck(&n->nincr, Etop);
+ typechecklist(n->nbody, Etop);
+ goto ret;
+
+ case OIF:
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv); // TODO Ebool
+ typechecklist(n->nbody, Etop);
+ typechecklist(n->nelse, Etop);
+ goto ret;
+
+ case ORETURN:
+ typechecklist(n->list, Erv);
+ // TODO convert
+ goto ret;
+
+ case OSELECT:
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv);
+ typechecklist(n->list, Etop);
+ goto ret;
+
+ case OSWITCH:
+ typechecklist(n->ninit, Etop);
+ typecheck(&n->ntest, Erv);
+ typechecklist(n->list, Etop);
+ goto ret;
+
+ case OTYPECASE:
+ typecheck(&n->left, Elv);
+ goto ret;
+
+ case OTYPESW:
+ typecheck(&n->right, Erv);
+ goto ret;
+
+ case OXCASE:
+ typechecklist(n->list, Erv);
+ typechecklist(n->nbody, Etop);
+ goto ret;
+ }
+
+ret:
+ evconst(n);
+ if(n->op == OTYPE && !(top & Etype)) {
+ yyerror("type %T is not an expression", n->type);
+ goto error;
+ }
+ if((top & (Elv|Erv|Etype)) == Etype && n->op != OTYPE) {
+ yyerror("%O is not a type", n->op);
+ goto error;
+ }
+ if((ok & Ecall) && !(top & Ecall)) {
+ yyerror("must call method %#N", n);
+ goto error;
+ }
+
+ /* TODO
+ if(n->type == T)
+ fatal("typecheck nil type");
+ */
+ goto out;
+
+badcall1:
+ yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
+ goto error;
+
+error:
+ n->type = T;
+
+out:
+ lineno = lno;
+ n->typecheck = 1;
+ *np = n;
+ return n;
+}
+
+static void
+implicitstar(Node **nn)
+{
+ Type *t;
+ Node *n;
+
+ // insert implicit * if needed
+ n = *nn;
+ t = n->type;
+ if(t == T || !isptr[t->etype])
+ return;
+ t = t->type;
+ if(t == T)
+ return;
+ if(!isfixedarray(t))
+ return;
+ n = nod(OIND, n, N);
+ typecheck(&n, Erv);
+ *nn = n;
+}
+
+static int
+onearg(Node *n)
+{
+ if(n->left != N)
+ return 0;
+ if(n->list == nil) {
+ yyerror("missing argument to %#O - %#N", n->op, n);
+ return -1;
+ }
+ n->left = n->list->n;
+ if(n->list->next != nil) {
+ yyerror("too many arguments to %#O", n->op);
+ n->list = nil;
+ return -1;
+ }
+ n->list = nil;
+ return 0;
+}
+
+static Type*
+lookdot1(Sym *s, Type *t, Type *f)
+{
+ Type *r;
+
+ r = T;
+ for(; f!=T; f=f->down) {
+ if(f->sym != s)
+ continue;
+ if(r != T) {
+ yyerror("ambiguous DOT reference %T.%S", t, s);
+ break;
+ }
+ r = f;
+ }
+ return r;
+}
+
+static int
+lookdot(Node *n, Type *t)
+{
+ Type *f1, *f2, *tt, *rcvr;
+ Sym *s;
+
+ s = n->right->sym;
+
+ f1 = T;
+ if(t->etype == TSTRUCT || t->etype == TINTER)
+ f1 = lookdot1(s, t, t->type);
+
+ f2 = methtype(n->left->type);
+ if(f2 != T)
+ f2 = lookdot1(s, f2, f2->method);
+
+ if(f1 != T) {
+ if(f2 != T)
+ yyerror("ambiguous DOT reference %S as both field and method",
+ n->right->sym);
+ n->xoffset = f1->width;
+ n->type = f1->type;
+ if(t->etype == TINTER) {
+ if(isptr[n->left->type->etype]) {
+ n->left = nod(OIND, n->left, N); // implicitstar
+ typecheck(&n->left, Elv);
+ }
+ n->op = ODOTINTER;
+ }
+ return 1;
+ }
+
+ if(f2 != T) {
+ tt = n->left->type;
+ rcvr = getthisx(f2->type)->type->type;
+ if(!eqtype(rcvr, tt)) {
+ if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
+ typecheck(&n->left, Elv);
+ addrescapes(n->left);
+ n->left = nod(OADDR, n->left, N);
+ typecheck(&n->left, Erv);
+ } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
+ n->left = nod(OIND, n->left, N);
+ typecheck(&n->left, Erv);
+ } else {
+ // method is attached to wrong type?
+ fatal("method mismatch: %T for %T", rcvr, tt);
+ }
+ }
+ n->right = methodname(n->right, n->left->type);
+ n->xoffset = f2->width;
+ n->type = f2->type;
+ n->op = ODOTMETH;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * try to convert *np to t.
+ * explicit means conversion like int64(n).
+ * not explicit means assignment, return, or function call parameter.
+ * return -1 for failure, 0 if OCONV node not needed, 1 if OCONV is needed.
+ */
+static int
+convert(Node **np, Type *t, int explicit)
+{
+ int et;
+ Node *n, *n1;
+ Type *tt;
+
+ n = *np;
+
+ if(n->type == t)
+ return 0;
+
+ if(eqtype(n->type, t))
+ return OCONV;
+
+ // XXX wtf?
+ convlit1(&n, t, explicit);
+ if(n->type == T)
+ return -1;
+
+ // no-op conversion
+ if(cvttype(t, n->type) == 1) {
+ nop:
+ if(n->op == OLITERAL) {
+ // can convert literal in place
+ n1 = nod(OXXX, N, N);
+ *n1 = *n;
+ n1->type = t;
+ *np = n1;
+ return 0;
+ }
+ return OCONV;
+ }
+
+ if(!explicit) {
+ yyerror("cannot use %#N (type %T) as type %T", n, n->type, t);
+ return -1;
+ }
+
+ // simple fix-float
+ if(isint[n->type->etype] || isfloat[n->type->etype])
+ if(isint[t->etype] || isfloat[t->etype]) {
+ // evconst(n); // XXX is this needed?
+ return OCONV;
+ }
+
+ // to/from interface.
+ // ifaceas1 will generate a good error if the conversion fails.
+ if(t->etype == TINTER || n->type->etype == TINTER) {
+ n = ifacecvt(t, n, ifaceas1(t, n->type, 0));
+ n->type = t;
+ *np = n;
+ return 0;
+ }
+
+ // to string
+ if(istype(t, TSTRING)) {
+ // integer rune
+ et = n->type->etype;
+ if(isint[et]) {
+ // xxx;
+ return OCONVRUNE;
+ }
+
+ // []byte and *[10]byte -> string
+ tt = T;
+ if(isptr[et] && isfixedarray(n->type->type))
+ tt = n->type->type->type;
+ else if(isslice(n->type))
+ tt = n->type->type;
+ if(tt) {
+ if(tt->etype == TUINT8)
+ return OCONVSTRB;
+ if(tt->etype == TINT)
+ return OCONVSTRI;
+ }
+ }
+
+ // convert static array to slice
+ if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type)
+ && eqtype(t->type, n->type->type->type))
+ return OCONVA2S;
+
+ // convert to unsafe pointer
+ if(isptrto(t, TANY)
+ && (isptr[n->type->etype] || n->type->etype == TUINTPTR))
+ return OCONV;
+
+ // convert from unsafe pointer
+ if(isptrto(n->type, TANY)
+ && (isptr[t->etype] || t->etype == TUINTPTR))
+ return OCONV;
+
+ yyerror("cannot convert %#N (type %T) to type %T", n, n->type, t);
+ return -1;
+}
if(curfn->type->outtuple)
if(walkret(curfn->nbody))
yyerror("function ends without a return statement");
+ typechecklist(curfn->nbody, Etop);
walkstmtlist(curfn->nbody);
if(debug['W']) {
snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
{
if(debug['W'])
dump("\nbefore gettype", *np);
- walkexpr(np, Erv, init);
+ typecheck(np, Erv);
if(debug['W'])
dump("after gettype", *np);
}
switch(n->op) {
case OLITERAL:
if(n->ntype != N) {
- walkexpr(&n->ntype, Etype, &init);
+ typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
n->ntype = N;
if(n->type == T) {
dump("walkdef nil defn", n);
yyerror("xxx");
}
- walkexpr(&e, Erv, &init);
+ typecheck(&e, Erv);
if(e->op != OLITERAL) {
yyerror("const initializer must be constant");
goto ret;
case OCALLMETH:
case OCALLINTER:
case OCALL:
+ case OCALLFUNC:
case OSEND:
case ORECV:
case OPRINT:
*np = n;
}
-void
-implicitstar(Node **nn)
-{
- Type *t;
- Node *n;
-
- // insert implicit * if needed
- n = *nn;
- t = n->type;
- if(t == T || !isptr[t->etype])
- return;
- t = t->type;
- if(t == T)
- return;
- if(!isfixedarray(t))
- return;
- n = nod(OIND, n, N);
- walkexpr(&n, Elv, nil);
- *nn = n;
-}
-
-void
-typechecklist(NodeList *l, int top)
-{
- for(; l; l=l->next)
- typecheck(&l->n, top);
-}
-
-/*
- * type check the whole tree of an expression.
- * calculates expression types.
- * evaluates compile time constants.
- * marks variables that escape the local frame.
- * rewrites n->op to be more specific in some cases.
- * replaces *np with a new pointer in some cases.
- * returns the final value of *np as a convenience.
- */
-Node*
-typecheck(Node **np, int top)
-{
- int et, et1, et2;
- Node *n, *l, *r;
- int lno, ok;
- Type *t;
-
- n = *np;
- if(n == N || n->typecheck == 1)
- return n;
- if(n->typecheck == 2)
- fatal("typecheck loop");
- n->typecheck = 2;
-
- if(n->sym && n->walkdef != 1)
- walkdef(n);
-
- lno = setlineno(n);
-
- ok = 0;
- switch(n->op) {
- default:
- // until typecheck is complete, do nothing.
- goto ret;
- dump("typecheck", n);
- fatal("typecheck %O", n->op);
-
- /*
- * names
- */
- case OLITERAL:
- ok |= Erv;
- goto ret;
-
- case ONONAME:
- ok |= Elv | Erv;
- goto ret;
-
- case ONAME:
- if(n->etype != 0) {
- yyerror("must call builtin %S", n->sym);
- goto error;
- }
- ok |= Erv;
- if(n->class != PFUNC)
- ok |= Elv;
- goto ret;
-
- /*
- * types (OIND is with exprs)
- */
- case OTYPE:
- ok |= Etype;
- if(n->type == T)
- goto error;
- break;
-
- case OTARRAY:
- ok |= Etype;
- t = typ(TARRAY);
- l = n->left;
- r = n->right;
- if(l == nil) {
- t->bound = -1;
- } else {
- typecheck(&l, Erv | Etype);
- walkexpr(&l, Erv | Etype, &n->ninit); // TODO: remove
- switch(l->op) {
- default:
- yyerror("invalid array bound %O", l->op);
- goto error;
-
- case OLITERAL:
- if(consttype(l) == CTINT) {
- t->bound = mpgetfix(l->val.u.xval);
- if(t->bound < 0) {
- yyerror("array bound must be non-negative");
- goto error;
- }
- }
- break;
-
- case OTYPE:
- if(l->type == T)
- goto error;
- if(l->type->etype != TDDD) {
- yyerror("invalid array bound %T", l->type);
- goto error;
- }
- t->bound = -100;
- break;
- }
- }
- typecheck(&r, Etype);
- if(r->type == T)
- goto error;
- t->type = r->type;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->right = N;
- checkwidth(t);
- break;
-
- case OTMAP:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- r = typecheck(&n->right, Etype);
- if(l->type == T || r->type == T)
- goto error;
- n->op = OTYPE;
- n->type = maptype(l->type, r->type);
- n->left = N;
- n->right = N;
- break;
-
- case OTCHAN:
- ok |= Etype;
- l = typecheck(&n->left, Etype);
- if(l->type == T)
- goto error;
- t = typ(TCHAN);
- t->type = l->type;
- t->chan = n->etype;
- n->op = OTYPE;
- n->type = t;
- n->left = N;
- n->etype = 0;
- break;
-
- case OTSTRUCT:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TSTRUCT);
- if(n->type == T)
- goto error;
- n->list = nil;
- break;
-
- case OTINTER:
- ok |= Etype;
- n->op = OTYPE;
- n->type = dostruct(n->list, TINTER);
- if(n->type == T)
- goto error;
- n->type = sortinter(n->type);
- break;
-
- case OTFUNC:
- ok |= Etype;
- n->op = OTYPE;
- n->type = functype(n->left, n->list, n->rlist);
- if(n->type == T)
- goto error;
- break;
-
- /*
- * exprs
- */
- case OADD:
- case OAND:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case OSUB:
- case OXOR:
- ok |= Erv;
- l = typecheck(&n->left, Erv | Eideal);
- r = typecheck(&n->right, Erv | Eideal);
- if(l->type == T || r->type == T)
- goto error;
- et1 = l->type->etype;
- et2 = r->type->etype;
- if(et1 == TIDEAL || et1 == TNIL || et2 == TIDEAL || et2 == TNIL)
- if(et1 != TIDEAL && et1 != TNIL || et2 != TIDEAL && et2 != TNIL) {
- // ideal mixed with non-ideal
- defaultlit2(&l, &r);
- n->left = l;
- n->right = r;
- }
- t = l->type;
- if(t->etype == TIDEAL)
- t = r->type;
- et = t->etype;
- if(et == TIDEAL)
- et = TINT;
- if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- badbinary:
- yyerror("invalid operation: %#N", n);
- goto error;
- }
- if(!okfor[n->op][et])
- goto badbinary;
- // okfor allows any array == array;
- // restrict to slice == nil and nil == slice.
- if(l->type->etype == TARRAY && !isslice(l->type))
- goto badbinary;
- if(r->type->etype == TARRAY && !isslice(r->type))
- goto badbinary;
- if(isslice(l->type) && !isnil(l) && !isnil(r))
- goto badbinary;
- evconst(n);
- goto ret;
-
- case OCOM:
- case OMINUS:
- case ONOT:
- case OPLUS:
- ok |= Erv;
- l = typecheck(&n->left, Erv | Eideal);
- walkexpr(&n->left, Erv | Eideal, &n->ninit); // TODO: remove
- if((t = l->type) == T)
- goto error;
- if(!okfor[n->op][t->etype]) {
- yyerror("invalid operation: %#O %T", n->op, t);
- goto error;
- }
- n->type = t;
- goto ret;
-
- /*
- * type or expr
- */
- case OIND:
- typecheck(&n->left, top | Etype);
- if(n->left->op == OTYPE) {
- ok |= Etype;
- n->op = OTYPE;
- n->type = ptrto(n->left->type);
- n->left = N;
- goto ret;
- }
-
- // TODO: OIND expression type checking
- goto ret;
-
- }
-
-ret:
- evconst(n);
- if(n->op == OTYPE && !(top & Etype)) {
- yyerror("type %T is not an expression", n->type);
- goto error;
- }
- if((top & (Elv|Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%O is not a type", n->op);
- goto error;
- }
-
- /* TODO
- if(n->type == T)
- fatal("typecheck nil type");
- */
- goto out;
-
-error:
- n->type = T;
-
-out:
- lineno = lno;
- n->typecheck = 1;
- *np = n;
- return n;
-}
-
/*
* walk the whole tree of the body of an
if(debug['w'] > 1 && top == Etop)
dump("walk-before", n);
- if(n->typecheck != 1)
- typecheck(&n, top | typeok);
+ if(n->typecheck != 1) {
+ dump("missed typecheck", n);
+ fatal("missed typecheck");
+ }
reswitch:
t = T;
case OCALLMETH:
case OCALLINTER:
+ case OCALLFUNC:
+ goto ret;
+
case OCALL:
if(top == Elv)
goto nottop;
- if(n->type != T)
- goto ret;
-
if(n->left == N)
goto ret;
// builtin OLEN, OCAP, etc.
n->op = n->left->etype;
n->left = N;
-//dump("do", n);
goto reswitch;
}
- walkexpr(&n->left, Erv | Etype, init);
+ walkexpr(&n->left, Erv | Etype | Ecall, init);
defaultlit(&n->left, T);
t = n->left->type;
if(t == T)
goto ret;
- if(n->left->op == ODOTMETH)
+ switch(n->left->op) {
+ case ODOTMETH:
n->op = OCALLMETH;
- if(n->left->op == ODOTINTER)
+ break;
+ case ODOTINTER:
n->op = OCALLINTER;
- if(n->left->op == OTYPE) {
+ break;
+ case OTYPE:
n->op = OCONV;
if(!(top & Erv))
goto nottop;
n->left = n->list->n;
n->list = nil;
goto reswitch;
+ default:
+ n->op = OCALLFUNC;
+ break;
}
if(t->etype != TFUNC) {
n->list = reorder1(ll);
break;
- case OCALL:
+ case OCALLFUNC:
ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
if(isselect(n)) {
switch(r->op) {
case OCALLMETH:
case OCALLINTER:
+ case OCALLFUNC:
case OCALL:
if(cr == 1) {
// a,b,... = fn()
if(cl == 2 && cr == 1) {
// a,b = map[] - mapaccess2
walkexpr(&r->left, Erv, init);
- implicitstar(&r->left);
if(!istype(r->left->type, TMAP))
break;
l = mapop(n, top, init);
case I2Isame:
case E2Esame:
n->rlist = list(list1(r->left), nodbool(1));
+ typechecklist(n->rlist, Erv);
goto multias;
case I2E:
n->list = list(list1(n->right), nodbool(1));
+ typechecklist(n->rlist, Erv);
goto multias;
case I2T:
et = I2T2;
evconst(n);
if(n->op == OLITERAL)
goto ret;
- defaultlit2(&n->left, &n->right);
+ defaultlit2(&n->left, &n->right, iscmp[n->op]);
if(n->left->type == T || n->right->type == T)
goto ret;
if(!eqtype(n->left->type, n->right->type))
}
walkexpr(&n->left, Erv, init);
defaultlit(&n->left, T);
- implicitstar(&n->left);
t = n->left->type;
if(t == T)
goto ret;
}
walkexpr(&n->left, Erv, init);
defaultlit(&n->left, T);
- implicitstar(&n->left);
t = n->left->type;
if(t == T)
goto ret;
goto ret;
defaultlit(&n->left, T);
- implicitstar(&n->left);
t = n->left->type;
if(t == T)
defaultlit(&n->left, T);
defaultlit(&n->right->left, types[TUINT]);
defaultlit(&n->right->right, types[TUINT]);
- implicitstar(&n->left);
t = n->left->type;
if(t == T)
goto ret;
case ODOTPTR:
case ODOTMETH:
case ODOTINTER:
- if(top == Etop)
- goto nottop;
- defaultlit(&n->left, T);
- walkdot(n, init);
+ walkexpr(&n->left, Erv, init);
goto ret;
case OADDR:
tempname(nvar, ptrto(n->left->type));
nas = nod(OAS, nvar, callnew(n->left->type));
+ typecheck(&nas, Etop);
walkexpr(&nas, Etop, init);
*init = list(*init, nas);
// TODO(rsc): Can do this more efficiently,
// but OSUB is wrong. Should be in back end anyway.
n = nod(OMUL, n->left, nodintconst(-1));
+ typecheck(&n, Erv);
walkexpr(&n, Erv, init);
goto ret;
}
r->list = list(list1(n->left), n->right);
r = nod(OCONV, r, N);
r->type = n->left->left->type;
+ typecheck(&r, Erv);
walkexpr(&r, Erv, init);
n = r;
goto ret;
break;
l = saferef(n->left, init);
r = nod(OAS, l, nod(n->etype, l, n->right));
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
n = r;
goto ret;
if(n->diag)
goto ret;
n->diag = 1;
- switch((top | typeok) & ~Eideal) {
+ switch(top | typeok) {
default:
yyerror("didn't expect %O here [top=%d]", n->op, top);
break;
t = n->type;
if(t == T)
return;
+ typecheck(&n->left, Erv);
walkexpr(&n->left, Erv, init);
l = n->left;
if(l == N)
tempname(on, l->left->type);
on->sym = lookup("!tmpselect!");
r->left = on;
- nbod = list(n->ninit, nod(OAS, l->left, on));
+ on = nod(OAS, l->left, on);
+ typecheck(&on, Etop);
+ nbod = list(n->ninit, on);
n->ninit = nil;
}
break;
r = nod(OCALL, on, N);
r->list = args;
r = nod(OAS, var, r);
+ typecheck(&r, Etop);
+ typechecklist(res, Etop);
sel->ninit = list1(r);
sel->nbody = res;
lineno = lno;
}
-Type*
-lookdot1(Sym *s, Type *t, Type *f)
-{
- Type *r;
-
- r = T;
- for(; f!=T; f=f->down) {
- if(f->sym != s)
- continue;
- if(r != T) {
- yyerror("ambiguous DOT reference %T.%S", t, s);
- break;
- }
- r = f;
- }
- return r;
-}
-
-int
-lookdot(Node *n, Type *t)
-{
- Type *f1, *f2, *tt, *rcvr;
- Sym *s;
-
- s = n->right->sym;
-
- f1 = T;
- if(t->etype == TSTRUCT || t->etype == TINTER)
- f1 = lookdot1(s, t, t->type);
-
- f2 = methtype(n->left->type);
- if(f2 != T)
- f2 = lookdot1(s, f2, f2->method);
-
- if(f1 != T) {
- if(f2 != T)
- yyerror("ambiguous DOT reference %S as both field and method",
- n->right->sym);
- n->xoffset = f1->width;
- n->type = f1->type;
- if(t->etype == TINTER) {
- if(isptr[n->left->type->etype]) {
- n->left = nod(OIND, n->left, N); // implicitstar
- walkexpr(&n->left, Elv, nil);
- }
- n->op = ODOTINTER;
- }
- return 1;
- }
-
- if(f2 != T) {
- tt = n->left->type;
- rcvr = getthisx(f2->type)->type->type;
- if(!eqtype(rcvr, tt)) {
- if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
- walkexpr(&n->left, Elv, nil);
- addrescapes(n->left);
- n->left = nod(OADDR, n->left, N);
- n->left->type = ptrto(tt);
- } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
- n->left = nod(OIND, n->left, N);
- n->left->type = tt->type;
- } else {
- // method is attached to wrong type?
- fatal("method mismatch: %T for %T", rcvr, tt);
- }
- }
- n->right = methodname(n->right, n->left->type);
- n->xoffset = f2->width;
- n->type = f2->type;
- n->op = ODOTMETH;
- return 1;
- }
-
- return 0;
-}
-
-void
-walkdot(Node *n, NodeList **init)
-{
- Type *t;
-
- walkexprlist(n->ninit, Etop, init);
- if(n->ninit != nil) {
- *init = concat(*init, n->ninit);
- n->ninit = nil;
- }
-
- if(n->left == N || n->right == N)
- return;
- switch(n->op) {
- case ODOTINTER:
- case ODOTMETH:
- return; // already done
- }
-
- walkexpr(&n->left, Erv, init);
- if(n->right->op != ONAME) {
- yyerror("rhs of . must be a name");
- return;
- }
-
- t = n->left->type;
- if(t == T)
- return;
-
- // as a structure field or pointer to structure field
- if(isptr[t->etype]) {
- t = t->type;
- if(t == T)
- return;
- n->op = ODOTPTR;
- }
-
- if(!lookdot(n, t)) {
- if(!n->diag) {
- n->diag = 1;
- yyerror("undefined: %T field %S", n->left->type, n->right->sym);
- }
- }
-}
-
Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
*r->left = *var;
r->left->type = r->right->type;
r->left->xoffset += t->width;
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
lr->n = r;
t = t->down;
fatal("misaligned multiple return\n\t%T\n\t%T", r->type, *nl);
a = nodarg(*nl, fp);
a->type = r->type;
- return list1(convas(nod(OAS, a, r), init));
+ nn = list1(convas(nod(OAS, a, r), init));
+ goto ret;
}
loop:
a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
- return nn;
+ goto ret;
}
// normal case -- make a structure of all
// remaining arguments and pass a pointer to
// it to the ddd parameter (empty interface)
- return mkdotargs(lr, nn, l, fp, init);
+ nn = mkdotargs(lr, nn, l, fp, init);
+ goto ret;
}
if(l == T || r == N) {
dumptypes(nl, "expected");
dumpnodetypes(lr0, "given");
}
- return nn;
+ goto ret;
}
convlit(&r, l->type);
if(!ascompat(l->type, r->type)) {
if(lr != nil)
r = lr->n;
goto loop;
+
+ret:
+ for(lr=nn; lr; lr=lr->next)
+ lr->n->typecheck = 1;
+ return nn;
}
/*
}
notfirst = fmt;
- walkexpr(&l->n, Erv, nil);
+ typecheck(&l->n, Erv);
n = l->n;
if(n->op == OLITERAL) {
switch(n->val.ctype) {
break;
}
}
+ if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
+ defaultlit(&n, types[TINT64]);
defaultlit(&n, nil);
l->n = n;
if(n->type == T)
on = syslook("printnl", 0);
calls = list(calls, nod(OCALL, on, N));
}
+ typechecklist(calls, Etop);
walkexprlist(calls, Etop, nil);
if(dopanic)
r = nodpanic(0);
else
r = nod(OEMPTY, N, N);
+ typecheck(&r, Etop);
walkexpr(&r, Etop, nil);
r->ninit = calls;
return r;
args = list1(n);
n = nod(OCALL, on, N);
n->list = args;
+ typecheck(&n, Etop);
walkexpr(&n, Etop, nil);
return n;
}
args = list1(r);
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, Erv, nil);
return r;
}
break;
}
+ typecheck(&r, top);
walkexpr(&r, top, init);
return r;
}
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, top, nil);
r->type = n->type;
break;
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, Erv, nil);
r->type = t->type;
break;
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
break;
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
break;
a = nod(OCALL, on, N);
a->list = args;
+ typecheck(&a, Erv);
n->rlist = list1(a);
+ typecheck(&n, Etop);
walkexpr(&n, Etop, init);
r = n;
break;
tempname(a, t->down); // tmpi
r = nod(OAS, a, n->left->right); // tmpi := index
n->left->right = a; // m[tmpi]
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
*init = list(*init, r);
*a = *n->left; // copy of map[tmpi]
a = nod(n->etype, a, n->right); // m[tmpi] op right
r = nod(OAS, n->left, a); // map[tmpi] = map[tmpi] op right
+ typecheck(&r, Etop);
walkexpr(&r, Etop, init);
break;
}
fatal("chanop: unknown op %O", n->op);
case OCLOSE:
- cl = count(n->list);
- if(cl > 1)
- yyerror("too many arguments to close");
- else if(cl < 1)
- yyerror("missing argument to close");
- n->left = n->list->n;
-
// closechan(hchan *chan any);
t = fixchan(n->left->type);
if(t == T)
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
walkexpr(&r, top, nil);
r->type = n->type;
break;
case OCLOSED:
- cl = count(n->list);
- if(cl > 1)
- yyerror("too many arguments to closed");
- else if(cl < 1)
- yyerror("missing argument to closed");
- n->left = n->list->n;
-
// closedchan(hchan *chan any) bool;
t = fixchan(n->left->type);
if(t == T)
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, top, nil);
n->type = r->type;
break;
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, top, nil);
r->type = n->type;
break;
argtype(on, t->type); // any-2
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
n->rlist->n = r;
r = n;
walkexpr(&r, Etop, init);
argtype(on, t->type); // any-2
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, Erv, nil);
break;
argtype(on, t->type); // any-2
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
walkexpr(&r, Etop, nil);
break;
argtype(on, t->type); // any-2
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Etop);
walkexpr(&r, Etop, nil);
break;
}
r = nod(OCALL, on, N);
r->list = args;
n->left = r;
+ typecheck(&n, Erv);
walkexpr(&n, top, nil);
return n;
argtype(on, t->type); // any-1
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, top, nil);
r->type = t; // if t had a name, going through newarray lost it
break;
r = nod(OCALL, on, N);
r->list = args;
- walkexpr(&r, top, nil);
+ typecheck(&r, Erv);
break;
}
return r;
r = nod(OCALL, on, N);
r->list = args;
+ typecheck(&r, Erv);
walkexpr(&r, Erv, nil);
return r;
}
r->list = args;
if(n->op == ONE)
r = nod(ONOT, r, N);
+ typecheck(&r, Erv);
walkexpr(&r, Erv, nil);
return r;
}
nr = lr->n;
switch(nr->op) {
case OCALL:
+ case OCALLFUNC:
if(nr->left->op == ONAME && nr->left->etype != 0)
break;
- walkexpr(&nr->left, Erv | Etype, &init);
+ typecheck(&nr->left, Erv | Etype | Ecall);
+ walkexpr(&nr->left, Erv | Etype | Ecall, &init);
if(nr->left->op == OTYPE)
break;
goto call;
case OCALLMETH:
case OCALLINTER:
+ typecheck(&nr->left, Erv);
walkexpr(&nr->left, Erv, &init);
call:
convlit(&nr->left, types[TFUNC]);
l = savel->n;
r = saver->n;
- walkexpr(&r, Erv, &init);
+ typecheck(&r, Erv);
defaultlit(&r, T);
saver->n = r;
a = mixedoldnew(l, r->type);
goto out;
multi:
+ typecheck(&nr, Erv);
+ lr->n = nr;
+
/*
* there is a list on the left
* and a mono on the right.
if(cl != 2)
goto badt;
walkexpr(&nr->left, Erv, &init);
- implicitstar(&nr->left);
t = nr->left->type;
if(!istype(t, TMAP))
goto badt;
nl = ll->n;
if(nl->diag == 0) {
nl->diag = 1;
- yyerror("assignment count mismatch: %d = %d", cl, cr);
+ yyerror("assignment count mismatch: %d = %d %#N", cl, cr, lr->n);
}
outl:
n = ll;
n = nod(OFOR, N, N);
init = nil;
- walkexpr(&nn->right, Erv, &init);
- implicitstar(&nn->right);
+ typecheck(&nn->right, Erv);
m = nn->right;
local = nn->etype;
// build list of var.field = expr
a = nod(ODOT, var, newname(l->sym));
a = nod(OAS, a, r);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
if(nerr != nerrors)
return var;
keyval:
memset(hash, 0, sizeof(hash));
a = nod(OAS, var, N);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
*init = list(*init, a);
break;
a = nod(OAS, a, r->right);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
if(nerr != nerrors)
break;
a = nod(OMAKE, N, N);
a->list = list(list1(typenod(t)), nodintconst(ninit));
a = nod(OAS, var, a);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
*init = list(*init, a);
} else {
// then clear the array
if(ninit < b) {
a = nod(OAS, var, N);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
*init = list(*init, a);
}
a = nod(OINDEX, var, a);
a = nod(OAS, a, r);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init); // add any assignments in r to top
if(nerr != nerrors)
break;
a = nod(OMAKE, N, N);
a->list = list1(typenod(t));
a = nod(OAS, var, a);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
*init = list(*init, a);
a = nod(OINDEX, var, r->left);
a = nod(OAS, a, r->right);
+ typecheck(&a, Etop);
walkexpr(&a, Etop, init);
if(nerr != nerrors)
break;