]> Cypherpunks repositories - gostls13.git/commitdiff
typechecking checkpoint.
authorRuss Cox <rsc@golang.org>
Thu, 30 Jul 2009 23:53:08 +0000 (16:53 -0700)
committerRuss Cox <rsc@golang.org>
Thu, 30 Jul 2009 23:53:08 +0000 (16:53 -0700)
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

15 files changed:
src/cmd/5g/cgen.c
src/cmd/6g/cgen.c
src/cmd/8g/cgen.c
src/cmd/gc/Makefile
src/cmd/gc/align.c
src/cmd/gc/const.c
src/cmd/gc/dcl.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/print.c
src/cmd/gc/subr.c
src/cmd/gc/swt.c
src/cmd/gc/typecheck.c [new file with mode: 0644]
src/cmd/gc/walk.c

index 6e9d9aa8b6abceee17fa9b5da83c8cc0ca5de302..e431dc03cf0d9fd06a8edbdcede846a2824a6178 100644 (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;
index 27ad4fdbe6aa6ccae8fe65b8ba4dae94e9a0d4b0..de7bf6313faffb73103919b94153dcb97e5fc89d 100644 (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;
index 2306387493b9ff655465d137870abe4e84ab393b..5664ac53d8c5d562ffeb8c4c65e5aeec861b639d 100644 (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;
index 697cca9409f00dfbd272baedc00ca1523f26435a..2338163ac986a92826a28d3ffffe5832fd56b2d2 100644 (file)
@@ -35,6 +35,7 @@ OFILES=\
        gen.$O\
        obj.$O\
        print.$O\
+       typecheck.$O\
 
 $(LIB): $(OFILES)
        ar rsc $(LIB) $(OFILES)
index 5735cbd5c59b53e8c1dc7f026524d9531b8f3fc4..b3abd57ba0328ef89d54f974a0e891a4b390ce2e 100644 (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");
index 02f17b7d5ac2fc99a8f50fba9676b74b35e38211..8b4046bf53ea4d7f9e61d25b4ad54bcb5b531a26 100644 (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]);
index d050b8bca8a6bcf5fbff96ec8d50522ccb54f079..3440de692b4b93c4597b7b42eb1583865d436595 100644 (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];
index 46373f8b82b1c2cc63c8cd6d81aed8ab87e6c6ae..f87b70e95cbb131dfc7109bdbda3356aed67d104 100644 (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;
        }
index d4412baa120190904f0b7ab6b77c724812209c65..778162d9c1da4e5ac9d25658da921b8ff93c0da8 100644 (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*);
index 4cf6fd771c4a3920a287c6a6cae408b98cc13a5c..97800d34dccf75ae2c4e77cb03f1bbe5d1db062b 100644 (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($$);
        }
index fc96b3a2bfc7f471a623eee7d870d13131d4a7e4..18d1ba38f495d28e50947b0ceed007886b00a3f5 100644 (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:
index 4ea0683d029df5ff24b31b114a63978bc2cbde0d..1512dab28b97e30204013f2ad7a19d0b1cabf9ff 100644 (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;
 }
 
index 785a401b5b8f3ae0c298765f4717902fb95a0292..aa8fa81a142cb20e51bc4b4b66a6bd94808e1967 100644 (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) {
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
new file mode 100644 (file)
index 0000000..cf250f2
--- /dev/null
@@ -0,0 +1,1099 @@
+// 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;
+}
index 807edb84ab89af0da33b221ae6d222092f91e1ed..95350c97da706a351d11b1fbc14b1c1d5618c5c0 100644 (file)
@@ -81,6 +81,7 @@ walk(Node *fn)
        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);
@@ -98,7 +99,7 @@ gettype(Node **np, NodeList **init)
 {
        if(debug['W'])
                dump("\nbefore gettype", *np);
-       walkexpr(np, Erv, init);
+       typecheck(np, Erv);
        if(debug['W'])
                dump("after gettype", *np);
 }
@@ -145,7 +146,7 @@ walkdef(Node *n)
        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) {
@@ -160,7 +161,7 @@ walkdef(Node *n)
                        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;
@@ -217,6 +218,7 @@ walkstmt(Node **np)
        case OCALLMETH:
        case OCALLINTER:
        case OCALL:
+       case OCALLFUNC:
        case OSEND:
        case ORECV:
        case OPRINT:
@@ -299,319 +301,6 @@ walkstmt(Node **np)
        *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
@@ -651,8 +340,10 @@ walkexpr(Node **np, int top, NodeList **init)
        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;
@@ -738,13 +429,13 @@ reswitch:
 
        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;
 
@@ -752,22 +443,24 @@ reswitch:
                        // 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;
@@ -784,6 +477,9 @@ reswitch:
                        n->left = n->list->n;
                        n->list = nil;
                        goto reswitch;
+               default:
+                       n->op = OCALLFUNC;
+                       break;
                }
 
                if(t->etype != TFUNC) {
@@ -818,7 +514,7 @@ reswitch:
                        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)) {
@@ -886,6 +582,7 @@ reswitch:
                switch(r->op) {
                case OCALLMETH:
                case OCALLINTER:
+               case OCALLFUNC:
                case OCALL:
                        if(cr == 1) {
                                // a,b,... = fn()
@@ -902,7 +599,6 @@ reswitch:
                        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);
@@ -938,9 +634,11 @@ reswitch:
                                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;
@@ -1109,7 +807,7 @@ reswitch:
                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))
@@ -1176,7 +874,6 @@ reswitch:
                }
                walkexpr(&n->left, Erv, init);
                defaultlit(&n->left, T);
-               implicitstar(&n->left);
                t = n->left->type;
                if(t == T)
                        goto ret;
@@ -1211,7 +908,6 @@ reswitch:
                }
                walkexpr(&n->left, Erv, init);
                defaultlit(&n->left, T);
-               implicitstar(&n->left);
                t = n->left->type;
                if(t == T)
                        goto ret;
@@ -1237,7 +933,6 @@ reswitch:
                        goto ret;
 
                defaultlit(&n->left, T);
-               implicitstar(&n->left);
 
                t = n->left->type;
                if(t == T)
@@ -1331,7 +1026,6 @@ reswitch:
                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;
@@ -1350,10 +1044,7 @@ reswitch:
        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:
@@ -1378,6 +1069,7 @@ reswitch:
                        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);
 
@@ -1540,6 +1232,7 @@ reswitch:
                        // 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;
                }
@@ -1588,6 +1281,7 @@ reswitch:
                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;
@@ -1598,6 +1292,7 @@ reswitch:
                        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;
@@ -1612,7 +1307,7 @@ nottop:
        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;
@@ -1718,6 +1413,7 @@ walkconv(Node **np, NodeList **init)
        t = n->type;
        if(t == T)
                return;
+       typecheck(&n->left, Erv);
        walkexpr(&n->left, Erv, init);
        l = n->left;
        if(l == N)
@@ -2075,7 +1771,9 @@ walkselect(Node *sel)
                                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;
@@ -2112,6 +1810,8 @@ walkselect(Node *sel)
        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;
@@ -2125,128 +1825,6 @@ walkselect(Node *sel)
        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)
 {
@@ -2451,6 +2029,7 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, 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;
@@ -2544,7 +2123,8 @@ ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
                        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:
@@ -2562,13 +2142,14 @@ 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) {
@@ -2580,7 +2161,7 @@ loop:
                        dumptypes(nl, "expected");
                        dumpnodetypes(lr0, "given");
                }
-               return nn;
+               goto ret;
        }
        convlit(&r, l->type);
        if(!ascompat(l->type, r->type)) {
@@ -2598,6 +2179,11 @@ loop:
        if(lr != nil)
                r = lr->n;
        goto loop;
+
+ret:
+       for(lr=nn; lr; lr=lr->next)
+               lr->n->typecheck = 1;
+       return nn;
 }
 
 /*
@@ -2721,7 +2307,7 @@ prcompat(NodeList *all, int fmt, int dopanic)
                }
                notfirst = fmt;
 
-               walkexpr(&l->n, Erv, nil);
+               typecheck(&l->n, Erv);
                n = l->n;
                if(n->op == OLITERAL) {
                        switch(n->val.ctype) {
@@ -2733,6 +2319,8 @@ prcompat(NodeList *all, int fmt, int dopanic)
                                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)
@@ -2786,12 +2374,14 @@ prcompat(NodeList *all, int fmt, int dopanic)
                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;
@@ -2808,6 +2398,7 @@ nodpanic(int32 lineno)
        args = list1(n);
        n = nod(OCALL, on, N);
        n->list = args;
+       typecheck(&n, Etop);
        walkexpr(&n, Etop, nil);
        return n;
 }
@@ -2871,6 +2462,7 @@ callnew(Type *t)
        args = list1(r);
        r = nod(OCALL, on, N);
        r->list = args;
+       typecheck(&r, Erv);
        walkexpr(&r, Erv, nil);
        return r;
 }
@@ -3002,6 +2594,7 @@ stringop(Node *n, int top, NodeList **init)
                break;
        }
 
+       typecheck(&r, top);
        walkexpr(&r, top, init);
        return r;
 }
@@ -3097,6 +2690,7 @@ mapop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Erv);
                walkexpr(&r, top, nil);
                r->type = n->type;
                break;
@@ -3131,6 +2725,7 @@ mapop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Erv);
                walkexpr(&r, Erv, nil);
                r->type = t->type;
                break;
@@ -3160,6 +2755,7 @@ mapop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Etop);
                walkexpr(&r, Etop, init);
                break;
 
@@ -3197,6 +2793,7 @@ mapop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Etop);
                walkexpr(&r, Etop, init);
                break;
 
@@ -3224,7 +2821,9 @@ mapop(Node *n, int top, NodeList **init)
 
                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;
@@ -3239,6 +2838,7 @@ mapop(Node *n, int top, NodeList **init)
                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);
 
@@ -3246,6 +2846,7 @@ mapop(Node *n, int top, NodeList **init)
                *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;
        }
@@ -3275,13 +2876,6 @@ chanop(Node *n, int top, NodeList **init)
                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)
@@ -3295,18 +2889,12 @@ chanop(Node *n, int top, NodeList **init)
 
                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)
@@ -3320,6 +2908,7 @@ chanop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Erv);
                walkexpr(&r, top, nil);
                n->type = r->type;
                break;
@@ -3353,6 +2942,7 @@ chanop(Node *n, int top, NodeList **init)
 
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Erv);
                walkexpr(&r, top, nil);
                r->type = n->type;
                break;
@@ -3385,6 +2975,7 @@ chanop(Node *n, int top, NodeList **init)
                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);
@@ -3417,6 +3008,7 @@ chanop(Node *n, int top, NodeList **init)
                argtype(on, t->type);   // any-2
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Erv);
                walkexpr(&r, Erv, nil);
                break;
 
@@ -3443,6 +3035,7 @@ chanop(Node *n, int top, NodeList **init)
                argtype(on, t->type);   // any-2
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Etop);
                walkexpr(&r, Etop, nil);
                break;
 
@@ -3458,6 +3051,7 @@ chanop(Node *n, int top, NodeList **init)
                argtype(on, t->type);   // any-2
                r = nod(OCALL, on, N);
                r->list = args;
+               typecheck(&r, Etop);
                walkexpr(&r, Etop, nil);
                break;
        }
@@ -3523,6 +3117,7 @@ arrayop(Node *n, int top)
                r = nod(OCALL, on, N);
                r->list = args;
                n->left = r;
+               typecheck(&n, Erv);
                walkexpr(&n, top, nil);
                return n;
 
@@ -3571,6 +3166,7 @@ arrayop(Node *n, int top)
                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;
@@ -3621,7 +3217,7 @@ arrayop(Node *n, int top)
 
                r = nod(OCALL, on, N);
                r->list = args;
-               walkexpr(&r, top, nil);
+               typecheck(&r, Erv);
                break;
        }
        return r;
@@ -3770,6 +3366,7 @@ ifacecvt(Type *tl, Node *n, int et)
 
        r = nod(OCALL, on, N);
        r->list = args;
+       typecheck(&r, Erv);
        walkexpr(&r, Erv, nil);
        return r;
 }
@@ -3803,6 +3400,7 @@ ifaceop(Node *n)
                r->list = args;
                if(n->op == ONE)
                        r = nod(ONOT, r, N);
+               typecheck(&r, Erv);
                walkexpr(&r, Erv, nil);
                return r;
        }
@@ -4004,14 +3602,17 @@ colas(NodeList *ll, NodeList *lr)
                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]);
@@ -4054,7 +3655,7 @@ colas(NodeList *ll, NodeList *lr)
                l = savel->n;
                r = saver->n;
 
-               walkexpr(&r, Erv, &init);
+               typecheck(&r, Erv);
                defaultlit(&r, T);
                saver->n = r;
                a = mixedoldnew(l, r->type);
@@ -4064,6 +3665,9 @@ colas(NodeList *ll, NodeList *lr)
        goto out;
 
 multi:
+       typecheck(&nr, Erv);
+       lr->n = nr;
+
        /*
         * there is a list on the left
         * and a mono on the right.
@@ -4080,7 +3684,6 @@ multi:
                if(cl != 2)
                        goto badt;
                walkexpr(&nr->left, Erv, &init);
-               implicitstar(&nr->left);
                t = nr->left->type;
                if(!istype(t, TMAP))
                        goto badt;
@@ -4124,7 +3727,7 @@ 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;
@@ -4172,8 +3775,7 @@ dorange(Node *nn)
        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;
 
@@ -4625,6 +4227,7 @@ structlit(Node *n, Node *var, NodeList **init)
                // 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;
@@ -4641,6 +4244,7 @@ structlit(Node *n, Node *var, NodeList **init)
 keyval:
        memset(hash, 0, sizeof(hash));
        a = nod(OAS, var, N);
+       typecheck(&a, Etop);
        walkexpr(&a, Etop, init);
        *init = list(*init, a);
 
@@ -4660,6 +4264,7 @@ keyval:
                        break;
 
                a = nod(OAS, a, r->right);
+               typecheck(&a, Etop);
                walkexpr(&a, Etop, init);
                if(nerr != nerrors)
                        break;
@@ -4741,6 +4346,7 @@ arraylit(Node *n, Node *var, NodeList **init)
                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 {
@@ -4748,6 +4354,7 @@ arraylit(Node *n, Node *var, NodeList **init)
                // then clear the array
                if(ninit < b) {
                        a = nod(OAS, var, N);
+                       typecheck(&a, Etop);
                        walkexpr(&a, Etop, init);
                        *init = list(*init, a);
                }
@@ -4779,6 +4386,7 @@ arraylit(Node *n, Node *var, NodeList **init)
 
                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;
@@ -4866,6 +4474,7 @@ maplit(Node *n, Node *var, NodeList **init)
        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);
 
@@ -4884,6 +4493,7 @@ maplit(Node *n, Node *var, NodeList **init)
 
                a = nod(OINDEX, var, r->left);
                a = nod(OAS, a, r->right);
+               typecheck(&a, Etop);
                walkexpr(&a, Etop, init);
                if(nerr != nerrors)
                        break;