]> Cypherpunks repositories - gostls13.git/commitdiff
more 6g reorg; checkpoint.
authorRuss Cox <rsc@golang.org>
Mon, 3 Aug 2009 18:58:52 +0000 (11:58 -0700)
committerRuss Cox <rsc@golang.org>
Mon, 3 Aug 2009 18:58:52 +0000 (11:58 -0700)
typecheck.c is now responsible for all type checking
except for assignment and function argument "..."

R=ken
OCL=32661
CL=32667

25 files changed:
src/cmd/8g/gsubr.c
src/cmd/gc/const.c
src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/print.c
src/cmd/gc/sinit.c
src/cmd/gc/subr.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/chan/perm.go
test/const1.go
test/convert3.go
test/convlit.go
test/convlit1.go
test/fixedbugs/bug022.go
test/fixedbugs/bug062.go
test/fixedbugs/bug090.go
test/fixedbugs/bug121.go
test/fixedbugs/bug131.go
test/fixedbugs/bug146.go
test/fixedbugs/bug170.go
test/func4.go
test/golden.out
test/interface/pointer.go

index 77a4532f03088530c112bed1a67b06be1de49aca..6a48dfabd1997b3ec785dd069c5a28fd1b5c4581 100755 (executable)
@@ -907,6 +907,8 @@ nodarg(Type *t, int fp)
                n->class = PPARAM;
                break;
        }
+
+       n->typecheck = 1;
        return n;
 }
 
index 8b4046bf53ea4d7f9e61d25b4ad54bcb5b531a26..bbbc8d7399d12da438a696d81e55a6dead7a9b95 100644 (file)
@@ -200,8 +200,6 @@ bad:
                defaultlit(&n, T);
                *np = n;
        }
-       yyerror("cannot convert %T constant to %T", n->type, t);
-       n->diag = 1;
        return;
 }
 
@@ -336,6 +334,9 @@ evconst(Node *n)
 
        switch(n->op) {
        case OMAKE:
+       case OMAKEMAP:
+       case OMAKESLICE:
+       case OMAKECHAN:
                return;
        }
 
@@ -557,7 +558,7 @@ evconst(Node *n)
                if(cmpslit(nl, nr) > 0)
                        goto settrue;
                goto setfalse;
-       case TUP(OADD, CTSTR):
+       case TUP(OADDSTR, CTSTR):
                len = v.u.sval->len + nr->val.u.sval->len;
                str = mal(sizeof(*str) + len);
                str->len = len;
@@ -605,6 +606,7 @@ unary:
        case TUP(OCONV, CTFLT):
        case TUP(OCONV, CTSTR):
        case TUP(OCONV, CTNIL):
+       case TUP(OARRAYBYTESTR, CTNIL):
                convlit1(&nl, n->type, 1);
                break;
 
index 978d05026733d4fcb804409d70c6fcf60d5daa45..d1802c83d3e317199f1aba81b503b459c547ceb3 100644 (file)
@@ -672,9 +672,9 @@ funclit1(Node *ntype, NodeList *body)
        for(l=func->cvars; l; l=l->next) {
                a = l->n;
                d = oldname(a->sym);
-               addrescapes(d);
                args = list(args, nod(OADDR, d, N));
        }
+       typechecklist(args, Erv);
 
        n = nod(OCALL, clos, N);
        n->list = args;
@@ -1642,7 +1642,7 @@ embedded(Sym *s)
 NodeList*
 variter(NodeList *vl, Node *nt, NodeList *el)
 {
-       int doexpr;
+       int doexpr, lno;
        Node *v, *e, *a;
        Type *tv;
        NodeList *r;
@@ -1663,23 +1663,37 @@ variter(NodeList *vl, Node *nt, NodeList *el)
                                break;
                        }
                        e = el->n;
-                       el = el->next;
                } else
                        e = N;
 
                v = vl->n;
                tv = t;
-               if(t == T) {
+               if(e) {
+                       lno = lineno;
+                       lineno = v->lineno;
                        typecheck(&e, Erv);
-                       defaultlit(&e, T);
-                       tv = e->type;
+                       defaultlit(&e, t);
+                       if(t)
+                               e = typecheckconv(nil, e, t, 0);
+                       if(tv == nil)
+                               tv = e->type;
+                       if(tv && tv->etype == TNIL) {
+                               yyerror("cannot initialize %#N to untyped nil", v);
+                               tv = nil;
+                       }
+                       lineno = lno;
                }
+
                a = N;
-               if(e != N || funcdepth > 0)
+               if((e != N && tv != T) || funcdepth > 0)
                        a = nod(OAS, v, e);
                dodclvar(v, tv, &r);
                if(a != N)
                        r = list(r, a);
+               if(el) {
+                       el->n = e;
+                       el = el->next;
+               }
        }
        if(el != nil)
                yyerror("extra expr in var dcl");
index 33969ec8a2c7d2e90d82135d710aad23e54e0050..7b2776dd76887a7d9b9869139b9325e4b58f9797 100644 (file)
@@ -328,36 +328,41 @@ enum
        OLITERAL,
 
        // exprs
-       OADD, OSUB, OOR, OXOR,
+       OADD, OSUB, OOR, OXOR, OADDSTR,
        OADDR,
        OANDAND,
+       OAPPENDSTR,
        OARRAY,
+       OARRAYBYTESTR, OARRAYRUNESTR,
        OAS, OAS2, OASOP,
        OBAD,
        OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
        OCAP,
        OCLOSE,
        OCLOSED,
-       OCOMPOS, OCOMPSLICE, OCOMPMAP,
-       OCONV, OCONVNOP, OCONVRUNE, OCONVSTRB, OCONVSTRI, OCONVA2S,
+       OCMPIFACE, OCMPSTR,
+       OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
+       OCOMPSLICE, OCOMPMAP,
+       OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE,
        ODCL, ODCLFUNC, ODCLFIELD, ODCLARG,
        ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
        ODOTTYPE,
        OEQ, ONE, OLT, OLE, OGE, OGT,
        OFUNC,
        OIND,
-       OINDEX, OINDEXSTR, OINDEXMAP, OINDEXARR,
+       OINDEX, OINDEXSTR, OINDEXMAP,
        OKEY, OPARAM,
        OLEN,
-       OMAKE,
+       OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
        OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
        ONEW,
        ONOT, OCOM, OPLUS, OMINUS,
        OOROR,
        OPANIC, OPANICN, OPRINT, OPRINTN,
-       OSEND,
-       OSLICE, OSLICESTR, OSLICEARR,
+       OSEND, OSENDNB,
+       OSLICE, OSLICEARR, OSLICESTR,
        ORECV,
+       ORUNESTR,
 
        // stmts
        OBLOCK,
@@ -470,10 +475,9 @@ enum
 enum
 {
        Etop = 1<<1,    // evaluated at statement level
-       Elv = 1<<2,     // evaluated in lvalue context
-       Erv = 1<<3,     // evaluated in rvalue context
-       Etype = 1<<4,
-       Ecall = 1<<5,
+       Erv = 1<<2,     // evaluated in value context
+       Etype = 1<<3,
+       Ecall = 1<<4,
 };
 
 #define        BITS    5
@@ -658,6 +662,8 @@ EXTERN      ushort  blockgen;               // max block number
 EXTERN ushort  block;                  // current block number
 EXTERN int     hasdefer;               // flag that curfn has defer statetment
 
+EXTERN Node*   curfn;
+
 EXTERN int     maxround;
 EXTERN int     widthptr;
 
@@ -986,14 +992,12 @@ NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
 NodeList*      ascompatte(int, Type**, NodeList*, int, NodeList**);
 int    ascompat(Type*, Type*);
 Node*  newcompat(Node*);
-Node*  makecompat(Node*);
 Node*  stringop(Node*, NodeList**);
 Type*  fixmap(Type*);
 Node*  mapop(Node*, NodeList**);
 Type*  fixchan(Type*);
 Node*  chanop(Node*, NodeList**);
-Node*  arrayop(Node*);
-Node*  ifacecvt(Type*, Node*, int);
+Node*  ifacecvt(Type*, Node*, int, NodeList**);
 Node*  ifaceop(Node*);
 int    ifaceas(Type*, Type*, int);
 int    ifaceas1(Type*, Type*, int);
@@ -1011,11 +1015,11 @@ Node*   arraylit(Node*, Node*, NodeList**);
 Node*  maplit(Node*, Node*, NodeList**);
 Node*  selectas(Node*, Node*, NodeList**);
 Node*  old2new(Node*, Type*, NodeList**);
-void   addrescapes(Node*);
 void   heapmoves(void);
 void   walkdeflist(NodeList*);
 void   walkdef(Node*);
 void   typechecklist(NodeList*, int);
+Node*  typecheckconv(Node*, Node*, Type*, int);
 Node*  typecheck(Node**, int);
 
 /*
index 97800d34dccf75ae2c4e77cb03f1bbe5d1db062b..4e280c17780783cfb68941c90f2db69b7f139e53 100644 (file)
@@ -123,7 +123,8 @@ file:
        {
                if(debug['f'])
                        frame(1);
-               fninit($4);
+               if(nerrors == 0)
+                       fninit($4);
                if(nsyntaxerrors == 0)
                        testdclstack();
        }
@@ -882,7 +883,7 @@ pexpr:
 |      convtype lbrace braced_keyval_list '}'
        {
                // composite expression
-               $$ = nod(OCOMPOS, N, $1);
+               $$ = nod(OCOMPLIT, N, $1);
                $$->list = $3;
 
                // If the opening brace was an LBODY,
@@ -894,7 +895,7 @@ pexpr:
 |      pexpr '{' braced_keyval_list '}'
        {
                // composite expression
-               $$ = nod(OCOMPOS, N, $1);
+               $$ = nod(OCOMPLIT, N, $1);
                $$->list = $3;
        }
 |      fnliteral
index 18d1ba38f495d28e50947b0ceed007886b00a3f5..5792422b4b614e3fe60a0643ef786d3cc75715dc 100644 (file)
@@ -208,11 +208,12 @@ exprfmt(Fmt *f, Node *n, int prec)
                exprfmt(f, n->left, 0);
                break;
 
-       case OCOMPOS:
+       case OCOMPLIT:
                fmtprint(f, "<compos>");
                break;
 
        case ODOT:
+       case ODOTPTR:
        case ODOTINTER:
        case ODOTMETH:
                exprfmt(f, n->left, 7);
index 10cbc36494f023b609d8a2c55f18cb515189b849..485b7f6849918a5b62c5264da8ea80a20c4cbd57 100644 (file)
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+/*
+ * static initialization
+ */
+
 #include       "go.h"
 
 static struct
index d05830bce41e01b7acd5299d5deea1254d223a01..52cd3a09da6ca3bfdbcf9c88cfa231c4d8e31a18 100644 (file)
@@ -1209,6 +1209,14 @@ Nconv(Fmt *fp)
                goto out;
        }
 
+       if(fp->flags & FmtSign) {
+               if(n->type == T || n->type->etype == TNIL)
+                       fmtprint(fp, "nil");
+               else
+                       fmtprint(fp, "%#N (type %T)", n, n->type);
+               goto out;
+       }
+
        if(fp->flags & FmtSharp) {
                exprfmt(fp, n, 0);
                goto out;
@@ -1593,22 +1601,7 @@ eqtype(Type *t1, Type *t2)
 int
 cvttype(Type *dst, Type *src)
 {
-       Sym *ds, *ss;
-       int ret;
-
-       if(eqtype1(dst, src, 0, 0))
-               return 1;
-
-       // Can convert if assignment compatible when
-       // top-level names are ignored.
-       ds = dst->sym;
-       dst->sym = nil;
-       ss = src->sym;
-       src->sym = nil;
-       ret = ascompat(dst, src);
-       dst->sym = ds;
-       src->sym = ss;
-       return ret == 1;
+       return eqtype1(dst, src, 0, 0);
 }
 
 int
@@ -1746,6 +1739,7 @@ noconv(Type *t1, Type *t2)
 void
 argtype(Node *on, Type *t)
 {
+       dowidth(t);
        if(!subtype(&on->type, t, 0))
                fatal("argtype: failed %N %T\n", on, t);
 }
@@ -2274,7 +2268,7 @@ saferef(Node *n, NodeList **init)
                r = nod(OXXX, N, N);
                *r = *n;
                r->left = l;
-               typecheck(&r, Elv);
+               typecheck(&r, Erv);
                walkexpr(&r, init);
                return r;
 
@@ -2288,7 +2282,7 @@ saferef(Node *n, NodeList **init)
                walkexpr(&a, init);
                *init = list(*init, a);
                r = nod(OIND, l, N);
-               typecheck(&r, Elv);
+               typecheck(&r, Erv);
                walkexpr(&r, init);
                return r;
        }
index ac83ca85521a9b7be9467bbbea9993290cbbdeba..5f82b08eee9fe148e030f0ab444f95325867f62a 100644 (file)
@@ -2,12 +2,35 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+/*
+ * 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.
+ * sets n->walk to walking function.
+ *
+ * TODO:
+ *     trailing ... section of function calls
+ *     statements
+ */
+
 #include "go.h"
 
 static void    implicitstar(Node**);
 static int     onearg(Node*);
 static int     lookdot(Node*, Type*);
-static int     convert(Node**, Type*, int);
+static void    typecheckaste(int, Type*, NodeList*);
+static int     exportassignok(Type*);
+static Type*   lookdot1(Sym *s, Type *t, Type *f);
+static int     nokeys(NodeList*);
+static void    typecheckcomplit(Node**);
+static void    addrescapes(Node*);
+
+static void    checklvalue(Node*, char*);
+static void checkassign(Node*);
+static void checkassignlist(NodeList*);
+static int     islvalue(Node*);
 
 void
 typechecklist(NodeList *l, int top)
@@ -17,26 +40,23 @@ typechecklist(NodeList *l, int 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.
+ * type check node *np.
  * 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, op, nerr, len;
-       NodeList *ll;
+       int et, op;
        Node *n, *l, *r;
        NodeList *args;
-       int i, lno, ok;
+       int lno, ok;
        Type *t;
 
        n = *np;
-       if(n == N || n->typecheck == 1)
+       if(n == N)
+               return N;
+       if(n->typecheck == 1 && n->op != ONAME) // XXX for test/func4.go
                return n;
        if(n->typecheck == 2)
                fatal("typecheck loop");
@@ -63,7 +83,7 @@ reswitch:
                goto ret;
 
        case ONONAME:
-               ok |= Elv | Erv;
+               ok |= Erv;
                goto ret;
 
        case ONAME:
@@ -72,8 +92,6 @@ reswitch:
                        goto error;
                }
                ok |= Erv;
-               if(n->class != PFUNC)
-                       ok |= Elv;
                goto ret;
 
        /*
@@ -187,7 +205,7 @@ reswitch:
         * type or expr
         */
        case OIND:
-               l = typecheck(&n->left, top | Etype);
+               l = typecheck(&n->left, Erv | Etype);
                if((t = l->type) == T)
                        goto error;
                if(l->op == OTYPE) {
@@ -198,9 +216,10 @@ reswitch:
                        goto ret;
                }
                if(!isptr[t->etype]) {
-                       yyerror("invalid indirect %#N (non-pointer type %T)", n, t);
+                       yyerror("invalid indirect of %+N", n);
                        goto error;
                }
+               ok |= Erv;
                n->type = t->type;
                goto ret;
 
@@ -209,7 +228,8 @@ reswitch:
         */
        case OASOP:
                ok |= Etop;
-               l = typecheck(&n->left, Elv);
+               l = typecheck(&n->left, Erv);
+               checkassign(n->left);
                r = typecheck(&n->right, Erv);
                if(l->type == T || r->type == T)
                        goto error;
@@ -280,6 +300,19 @@ reswitch:
                                n->right = r;
                        }
                }
+               if(et == TSTRING) {
+                       if(iscmp[n->op]) {
+                               n->etype = n->op;
+                               n->op = OCMPSTR;
+                       } else if(n->op == OASOP)
+                               n->op = OAPPENDSTR;
+                       else if(n->op == OADD)
+                               n->op = OADDSTR;
+               }
+               if(et == TINTER) {
+                       n->etype = n->op;
+                       n->op = OCMPIFACE;
+               }
                n->type = t;
                goto ret;
 
@@ -315,73 +348,29 @@ reswitch:
         * exprs
         */
        case OADDR:
-               typecheck(&n->left, Elv);
+               typecheck(&n->left, Erv);
+               if(n->left->type == T)
+                       goto error;
+               switch(n->left->op) {
+               case OMAPLIT:
+               case OSTRUCTLIT:
+               case OARRAYLIT:
+                       break;
+               default:
+                       checklvalue(n->left, "take the address of");
+               }
                defaultlit(&n->left, T);
                l = n->left;
                if((t = l->type) == T)
                        goto error;
+               addrescapes(n->left);
                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)
+       case OCOMPLIT:
+               typecheckcomplit(&n);
+               if(n->type == T)
                        goto error;
-               n->type = t;
                goto ret;
 
        case ODOT:
@@ -399,7 +388,7 @@ reswitch:
                        n->op = ODOTPTR;
                }
                if(!lookdot(n, t)) {
-                       yyerror("%#N undefined (%S in type %T)", n, n->right->sym, t);
+                       yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
                        goto error;
                }
                switch(n->op) {
@@ -409,7 +398,6 @@ reswitch:
                        break;
                default:
                        ok |= Erv;
-                       // TODO ok |= Elv sometimes
                        break;
                }
                goto ret;
@@ -448,24 +436,24 @@ reswitch:
                        goto error;
 
                case TARRAY:
-                       ok |= Erv | Elv;
+                       ok |= Erv;
                        defaultlit(&n->right, types[TUINT]);
                        n->type = t->type;
                        break;
 
                case TMAP:
                        n->etype = 0;
-                       if(top & Elv)
-                               n->etype = 1;   // clumsy hack
-                       ok |= Erv | Elv;
+                       ok |= Erv;
                        defaultlit(&n->right, t->down);
                        n->type = t->type;
+                       n->op = OINDEXMAP;
                        break;
 
                case TSTRING:
                        ok |= Erv;
                        defaultlit(&n->right, types[TUINT]);
                        n->type = types[TUINT8];
+                       n->op = OINDEXSTR;
                        break;
                }
                goto ret;
@@ -477,11 +465,11 @@ reswitch:
                if((t = l->type) == T)
                        goto error;
                if(t->etype != TCHAN) {
-                       yyerror("invalid operation: %#N (recv from non-chan type %T)", n, t);
+                       yyerror("invalid operation: %#N (receive 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);
+                       yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
                        goto error;
                }
                n->type = t->type;
@@ -496,7 +484,7 @@ reswitch:
                if((t = l->type) == T)
                        goto error;
                if(!(t->chan & Csend)) {
-                       yyerror("invalid operation: %#N (send to recv-only type %T)", n, t);
+                       yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
                        goto error;
                }
                defaultlit(&n->right, t->type);
@@ -506,7 +494,7 @@ reswitch:
                // TODO: more aggressive
                n->etype = 0;
                if(top & Erv)
-                       n->etype = 1;   // clumsy hack
+                       n->op = OSENDNB;
                ok |= Etop | Erv;
                n->type = types[TBOOL];
                goto ret;
@@ -527,13 +515,13 @@ reswitch:
                if((t = n->right->left->type) == T)
                        goto error;
                if(!isint[t->etype]) {
-                       yyerror("invalid array index %#N (type %T)", n->right->left, t);
+                       yyerror("invalid slice 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);
+                       yyerror("invalid slice index %#N (type %T)", n->right->right, t);
                        goto error;
                }
                l = n->left;
@@ -541,24 +529,25 @@ reswitch:
                        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:
+               if(istype(t, TSTRING)) {
+                       n->type = t;
+                       n->op = OSLICESTR;
+                       goto ret;
+               }
+               if(isfixedarray(t)) {
                        n->type = typ(TARRAY);
-                       n->type->type = t;
+                       n->type->type = t->type;
                        n->type->bound = -1;
-                       n = arrayop(n);
-                       break;
-
-               case TSTRING:
+                       dowidth(n->type);
+                       n->op = OSLICEARR;
+                       goto ret;
+               }
+               if(isslice(t)) {
                        n->type = t;
-                       n = stringop(n, nil);
-                       break;
+                       goto ret;
                }
-               goto ret;
+               yyerror("cannot slice %#N (type %T)", l, t);
+               goto error;
 
        /*
         * call and call like
@@ -572,14 +561,16 @@ reswitch:
                        n->right = N;
                        goto reswitch;
                }
-               l = typecheck(&n->left, Erv | Etype | Ecall);
+               typecheck(&n->left, Erv | Etype | Ecall);
+               defaultlit(&n->left, T);
+               l = n->left;
                typechecklist(n->list, Erv);
                if((t = l->type) == T)
-{
-yyerror("skip %#N", n);
                        goto error;
-}
-               if(l->op == OTYPE) {
+               dowidth(t);
+
+               switch(l->op) {
+               case OTYPE:
                        ok |= Erv;
                        // turn CALL(type, arg) into CONV(arg) w/ type
                        n->left = N;
@@ -588,8 +579,25 @@ yyerror("skip %#N", n);
                        n->op = OCONV;
                        n->type = l->type;
                        goto doconv;
+
+               case ODOTINTER:
+                       n->op = OCALLINTER;
+                       break;
+
+               case ODOTMETH:
+                       n->op = OCALLMETH;
+                       typecheckaste(OCALL, getthisx(t), list1(l->left));
+                       break;
+
+               default:
+                       n->op = OCALLFUNC;
+                       if(t->etype != TFUNC) {
+                               yyerror("cannot call non-function %#N (type %T)", l, t);
+                               goto error;
+                       }
+                       break;
                }
-               // TODO: check args
+               typecheckaste(OCALL, getinargx(t), n->list);
                if(t->outtuple == 0) {
                        ok |= Etop;
                        goto ret;
@@ -642,9 +650,7 @@ yyerror("skip %#N", n);
                goto ret;
 
        case OCLOSED:
-               ok |= Erv;
        case OCLOSE:
-               ok |= Etop;
                if(onearg(n) < 0)
                        goto error;
                typecheck(&n->left, Erv);
@@ -656,25 +662,22 @@ yyerror("skip %#N", n);
                        yyerror("invalid operation: %#N (non-chan type %T)", n, t);
                        goto error;
                }
-               if(n->op == OCLOSED)
+               if(n->op == OCLOSED) {
                        n->type = types[TBOOL];
+                       ok |= Erv;
+               } else
+                       ok |= Etop;
                goto ret;
 
        case OCONV:
        doconv:
                typecheck(&n->left, Erv);
                defaultlit(&n->left, n->type);
-               if((t = n->left->type) == T)
+               if((t = n->left->type) == T || n->type == T)
                        goto error;
-               switch(convert(&n->left, n->type, 1)) {
-               case -1:
+               n = typecheckconv(n, n->left, n->type, 1);
+               if(n->type == T)
                        goto error;
-               case 0:
-                       n = n->left;
-                       break;
-               case OCONV:
-                       break;
-               }
                goto ret;
 
        case OMAKE:
@@ -723,8 +726,11 @@ yyerror("skip %#N", n);
                                yyerror("non-integer cap argument to make(%T)", t);
                                goto error;
                        }
+                       if(r == N)
+                               r = nodintconst(0);
                        n->left = l;
                        n->right = r;
+                       n->op = OMAKESLICE;
                        break;
 
                case TMAP:
@@ -740,7 +746,9 @@ yyerror("skip %#N", n);
                                        goto error;
                                }
                                n->left = l;
-                       }
+                       } else
+                               n->left = nodintconst(0);
+                       n->op = OMAKEMAP;
                        break;
 
                case TCHAN:
@@ -757,11 +765,14 @@ yyerror("skip %#N", n);
                                        goto error;
                                }
                                n->left = l;
-                       }
+                       } else
+                               n->left = nodintconst(0);
+                       n->op = OMAKECHAN;
                        break;
                }
                if(args != nil) {
                        yyerror("too many arguments to make(%T)", t);
+                       n->op = OMAKE;
                        goto error;
                }
                n->type = t;
@@ -796,12 +807,16 @@ yyerror("skip %#N", n);
         * statements
         */
        case OAS:
-               typecheck(&n->left, Elv);
+               typecheck(&n->left, Erv);
+               checkassign(n->left);
                typecheck(&n->right, Erv);
+               if(n->left->type != T && n->right && n->right->type != T)
+                       n->right = typecheckconv(nil, n->right, n->left->type, 0);
                goto ret;
 
        case OAS2:
-               typechecklist(n->list, Elv);
+               typechecklist(n->list, Erv);
+               checkassignlist(n->list);
                typechecklist(n->rlist, Erv);
                goto ret;
 
@@ -835,7 +850,9 @@ yyerror("skip %#N", n);
 
        case ORETURN:
                typechecklist(n->list, Erv);
-               // TODO convert
+               if(curfn->type->outnamed && n->list == nil)
+                       goto ret;
+               typecheckaste(ORETURN, getoutargx(curfn->type), n->list);
                goto ret;
 
        case OSELECT:
@@ -851,7 +868,7 @@ yyerror("skip %#N", n);
                goto ret;
 
        case OTYPECASE:
-               typecheck(&n->left, Elv);
+               typecheck(&n->left, Erv);
                goto ret;
 
        case OTYPESW:
@@ -870,7 +887,7 @@ ret:
                yyerror("type %T is not an expression", n->type);
                goto error;
        }
-       if((top & (Elv|Erv|Etype)) == Etype && n->op != OTYPE) {
+       if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
                yyerror("%O is not a type", n->op);
                goto error;
        }
@@ -982,7 +999,7 @@ lookdot(Node *n, Type *t)
                if(t->etype == TINTER) {
                        if(isptr[n->left->type->etype]) {
                                n->left = nod(OIND, n->left, N);        // implicitstar
-                               typecheck(&n->left, Elv);
+                               typecheck(&n->left, Erv);
                        }
                        n->op = ODOTINTER;
                }
@@ -994,7 +1011,8 @@ lookdot(Node *n, Type *t)
                rcvr = getthisx(f2->type)->type->type;
                if(!eqtype(rcvr, tt)) {
                        if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
-                               typecheck(&n->left, Elv);
+                               typecheck(&n->left, Erv);
+                               checklvalue(n->left, "call pointer method on");
                                addrescapes(n->left);
                                n->left = nod(OADDR, n->left, N);
                                typecheck(&n->left, Erv);
@@ -1016,104 +1034,624 @@ lookdot(Node *n, Type *t)
        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)
+nokeys(NodeList *l)
 {
-       int et;
-       Node *n, *n1;
-       Type *tt;
+       for(; l; l=l->next)
+               if(l->n->op == OKEY)
+                       return 0;
+       return 1;
+}
 
-       n = *np;
+Node*
+typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
+{
+       int et, op;
+       Node *n1;
 
-       if(n->type == t)
-               return 0;
+       op = OCONV;
+       et = 0;
 
-       if(eqtype(n->type, t))
-               return OCONV;
+       // preexisting error
+       if(t == T || t->etype == TFORW)
+               return n;
+
+       /*
+        * implicit conversions
+        */
 
-       // XXX wtf?
        convlit1(&n, t, explicit);
        if(n->type == T)
-               return -1;
+               return n;
+
+       if(eqtype(t, n->type)) {
+               exportassignok(t);
+               op = OCONVNOP;
+               if(!explicit || t == n->type)
+                       return n;
+               goto conv;
+       }
+
+       // interfaces are not subject to the name restrictions below.
+       // accept anything involving interfaces and let walkiface
+       // generate a good message.  some messages have to be
+       // delayed anyway.
+       if(isnilinter(t) || isnilinter(n->type) || isinter(t) || isinter(n->type)) {
+               et = ifaceas1(t, n->type, 0);
+               op = OCONVIFACE;
+               goto conv;
+       }
+
+       // otherwise, if concrete types have names, they must match.
+       if(!explicit && t->sym && n->type->sym && t != n->type)
+               goto badimplicit;
+
+       // channel must not lose directionality
+       if(t->etype == TCHAN && n->type->etype == TCHAN) {
+               if(t->chan & ~n->type->chan) {
+                       if(!explicit)
+                               goto badimplicit;
+                       goto badexplicit;
+               }
+               if(eqtype(t->type, n->type->type)) {
+                       op = OCONVNOP;
+                       goto conv;
+               }
+       }
 
-       // no-op conversion
-       if(cvttype(t, n->type) == 1) {
+       // array to slice
+       if(isslice(t) && isptr[n->type->etype] && isfixedarray(n->type->type)
+       && eqtype(t->type, n->type->type->type)) {
+               op = OCONVSLICE;
+               goto conv;
+       }
+
+       if(!explicit) {
+       badimplicit:
+               yyerror("cannot use %+N as type %T", n, t);
+               n = nod(OCONV, n, N);   // leave type == T
+               n->typecheck = 1;
+               return n;
+       }
+
+       /*
+        * explicit conversions
+        */
+
+       // same representation
+       if(cvttype(t, n->type)) {
                if(n->op == OLITERAL) {
                        // can convert literal in place
                        n1 = nod(OXXX, N, N);
                        *n1 = *n;
                        n1->type = t;
-                       *np = n1;
-                       return 0;
+                       return n1;
                }
-               return OCONV;
-       }
-
-       if(!explicit) {
-               yyerror("cannot use %#N (type %T) as type %T", n, n->type, t);
-               return -1;
+               op = OCONVNOP;
+               goto conv;
        }
 
        // simple fix-float
-       if(isint[n->type->etype] || isfloat[n->type->etype])
-       if(isint[t->etype] || isfloat[t->etype]) {
+       if(isint[t->etype] || isfloat[t->etype])
+       if(isint[n->type->etype] || isfloat[n->type->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;
+               goto conv;
        }
 
        // to string
        if(istype(t, TSTRING)) {
                // integer rune
-               et = n->type->etype;
-               if(isint[et]) {
-               //      xxx;
-                       return OCONVRUNE;
+               if(isint[n->type->etype]) {
+                       op = ORUNESTR;
+                       goto conv;
+               }
+
+               // *[10]byte -> string?  convert *[10]byte -> []byte
+               // in preparation for next step
+               if(isptr[n->type->etype] && isfixedarray(n->type->type)) {
+                       switch(n->type->type->type->etype) {
+                       case TUINT8:
+                       case TINT:
+                               n1 = nod(OCONV, n, N);
+                               n1->type = typ(TARRAY);
+                               n1->type->bound = -1;
+                               n1->type->type = n->type->type->type;
+                               dowidth(n1->type);
+                               typecheck(&n1, Erv);
+                               walkexpr(&n1, nil);
+                               n = n1;
+                               break;
+                       }
                }
 
-               // []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;
+               // []byte -> string
+               if(isslice(n->type)) {
+                       switch(n->type->type->etype) {
+                       case TUINT8:
+                               op = OARRAYBYTESTR;
+                               goto conv;
+                       case TINT:
+                               op = OARRAYRUNESTR;
+                               goto conv;
+                       }
                }
        }
 
-       // 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;
+               goto conv;
 
        // convert from unsafe pointer
        if(isptrto(n->type, TANY)
        && (isptr[t->etype] || t->etype == TUINTPTR))
-               return OCONV;
+               goto conv;
+
+badexplicit:
+       yyerror("cannot convert %+N to type %T", n, t);
+       nconv->type = T;
+       return nconv;
+
+conv:
+       if(nconv == nil) {
+               nconv = nod(OXXX, n, N);
+               nconv->type = t;
+               nconv->typecheck = 1;
+       }
+       nconv->etype = et;
+       nconv->op = op;
+       return nconv;
+}
+
+/*
+ * typecheck assignment: type list = type list
+ */
+static void
+typecheckastt(int op, Type *t1, Type *t2)
+{
+       for(t1=t1->type, t2=t2->type; t1; t1=t1->down, t2=t2->down) {
+               if(t2 == nil) {
+                       yyerror("too few");
+                       return;
+               }
+               if(!eqtype(t1->type, t2->type)) {
+                       yyerror("wrong");
+               }
+       }
+       if(t2 != nil)
+               yyerror("too many");
+}
+
+/*
+ * typecheck assignment: type list = expression list
+ */
+static void
+typecheckaste(int op, Type *tstruct, NodeList *nl)
+{
+       Type *t, *tl;
+       Node *n;
+
+       if(nl != nil && nl->next == nil && nl->n->type != T && nl->n->type->etype == TSTRUCT && nl->n->type->funarg) {
+               typecheckastt(op, tstruct, nl->n->type);
+               return;
+       }
+
+       for(tl=tstruct->type; tl; tl=tl->down) {
+               t = tl->type;
+               if(isddd(t)) {
+                       for(; nl; nl=nl->next)
+                               defaultlit(&nl->n, T);
+                       return;
+               }
+               if(nl == nil) {
+                       yyerror("not enough arguments to %#O", op);
+                       return;
+               }
+               n = nl->n;
+               if(n->type != T)
+                       nl->n = typecheckconv(nil, n, t, 0);
+               nl = nl->next;
+       }
+       if(nl != nil) {
+               yyerror("too many arguments to %#O", op);
+               return;
+       }
+}
+
+/*
+ * do the export rules allow writing to this type?
+ * cannot be implicitly assigning to any type with
+ * an unavailable field.
+ */
+static int
+exportassignok(Type *t)
+{
+       Type *f;
+       Sym *s;
+
+       if(t == T)
+               return 1;
+       switch(t->etype) {
+       default:
+               // most types can't contain others; they're all fine.
+               break;
+       case TSTRUCT:
+               for(f=t->type; f; f=f->down) {
+                       if(f->etype != TFIELD)
+                               fatal("structas: not field");
+                       s = f->sym;
+                       // s == nil doesn't happen for embedded fields (they get the type symbol).
+                       // it only happens for fields in a ... struct.
+                       if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
+                               yyerror("implicit assignment of %T field '%s'", t, s->name);
+                               return 0;
+                       }
+                       if(!exportassignok(f->type))
+                               return 0;
+               }
+               break;
+
+       case TARRAY:
+               if(t->bound < 0)        // slices are pointers; that's fine
+                       break;
+               if(!exportassignok(t->type))
+                       return 0;
+               break;
+       }
+       return 1;
+}
+
+
+/*
+ * type check composite
+ */
+
+static void
+fielddup(Node *n, Node *hash[], ulong nhash)
+{
+       uint h;
+       char *s;
+       Node *a;
+
+       if(n->op != ONAME)
+               fatal("fielddup: not ONAME");
+       s = n->sym->name;
+       h = stringhash(s)%nhash;
+       for(a=hash[h]; a!=N; a=a->ntest) {
+               if(strcmp(a->sym->name, s) == 0) {
+                       yyerror("duplicate field name in struct literal: %s", s);
+                       return;
+               }
+       }
+       n->ntest = hash[h];
+       hash[h] = n;
+}
+
+static void
+keydup(Node *n, Node *hash[], ulong nhash)
+{
+       uint h;
+       ulong b;
+       double d;
+       int i;
+       Node *a;
+       Node cmp;
+       char *s;
+
+       evconst(n);
+       if(n->op != OLITERAL)
+               return; // we dont check variables
+
+       switch(n->val.ctype) {
+       default:        // unknown, bool, nil
+               b = 23;
+               break;
+       case CTINT:
+               b = mpgetfix(n->val.u.xval);
+               break;
+       case CTFLT:
+               d = mpgetflt(n->val.u.fval);
+               s = (char*)&d;
+               b = 0;
+               for(i=sizeof(d); i>0; i--)
+                       b = b*PRIME1 + *s++;
+               break;
+       case CTSTR:
+               b = 0;
+               s = n->val.u.sval->s;
+               for(i=n->val.u.sval->len; i>0; i--)
+                       b = b*PRIME1 + *s++;
+               break;
+       }
+
+       h = b%nhash;
+       memset(&cmp, 0, sizeof(cmp));
+       for(a=hash[h]; a!=N; a=a->ntest) {
+               cmp.op = OEQ;
+               cmp.left = n;
+               cmp.right = a;
+               evconst(&cmp);
+               b = cmp.val.u.bval;
+               if(b) {
+                       // too lazy to print the literal
+                       yyerror("duplicate key in map literal");
+                       return;
+               }
+       }
+       n->ntest = hash[h];
+       hash[h] = n;
+}
 
-       yyerror("cannot convert %#N (type %T) to type %T", n, n->type, t);
-       return -1;
+static void
+indexdup(Node *n, Node *hash[], ulong nhash)
+{
+       uint h;
+       Node *a;
+       ulong b, c;
+
+       if(n->op != OLITERAL)
+               fatal("indexdup: not OLITERAL");
+
+       b = mpgetfix(n->val.u.xval);
+       h = b%nhash;
+       for(a=hash[h]; a!=N; a=a->ntest) {
+               c = mpgetfix(a->val.u.xval);
+               if(b == c) {
+                       yyerror("duplicate index in array literal: %ld", b);
+                       return;
+               }
+       }
+       n->ntest = hash[h];
+       hash[h] = n;
+}
+
+static void
+typecheckcomplit(Node **np)
+{
+       int bad, i, len, nerr;
+       Node *l, *n, *hash[101];
+       NodeList *ll;
+       Type *t, *f;
+
+       n = *np;
+
+       memset(hash, 0, sizeof hash);
+
+       // TODO: dup detection
+       l = typecheck(&n->right /* sic */, Etype /* TODO | Edotarray */);
+       if((t = l->type) == T)
+               goto error;
+       nerr = nerrors;
+       switch(t->etype) {
+       default:
+               yyerror("invalid type for composite literal: %T", t);
+               n->type = T;
+               break;
+
+       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);
+                               if(i < 0) {
+                                       yyerror("array index must be non-negative integer constant");
+                                       i = -(1<<30);   // stay negative for a while
+                               }
+                               typecheck(&l->right, Erv);
+                               defaultlit(&l->right, t->type);
+                               l->right = typecheckconv(nil, l->right, t->type, 0);
+                       } else {
+                               typecheck(&ll->n, Erv);
+                               defaultlit(&ll->n, t->type);
+                               ll->n = typecheckconv(nil, ll->n, t->type, 0);
+                               ll->n = nod(OKEY, nodintconst(i), ll->n);
+                               ll->n->left->type = types[TINT];
+                               ll->n->left->typecheck = 1;
+                       }
+                       if(i >= 0)
+                               indexdup(ll->n->left, hash, nelem(hash));
+                       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;
+               if(t->bound < 0)
+                       n->right = nodintconst(len);
+               n->op = OARRAYLIT;
+               break;
+
+       case TMAP:
+               for(ll=n->list; ll; ll=ll->next) {
+                       l = ll->n;
+                       if(l->op != OKEY) {
+                               typecheck(&ll->n, Erv);
+                               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);
+                       l->left = typecheckconv(nil, l->left, t->down, 0);
+                       l->right = typecheckconv(nil, l->right, t->type, 0);
+                       keydup(l->left, hash, nelem(hash));
+               }
+               n->op = OMAPLIT;
+               break;
+
+       case TSTRUCT:
+               bad = 0;
+               if(n->list != nil && nokeys(n->list)) {
+                       // simple list of variables
+                       f = t->type;
+                       for(ll=n->list; ll; ll=ll->next) {
+                               typecheck(&ll->n, Erv);
+                               if(f == nil) {
+                                       if(!bad++)
+                                               yyerror("too many values in struct initializer");
+                                       continue;
+                               }
+                               ll->n = typecheckconv(nil, ll->n, f->type, 0);
+                               ll->n = nod(OKEY, newname(f->sym), ll->n);
+                               ll->n->left->typecheck = 1;
+                               f = f->down;
+                       }
+               } else {
+                       // keyed list
+                       for(ll=n->list; ll; ll=ll->next) {
+                               l = ll->n;
+                               if(l->op != OKEY) {
+                                       if(!bad++)
+                                               yyerror("mixture of field:value and value initializers");
+                                       typecheck(&ll->n, Erv);
+                                       continue;
+                               }
+                               if(l->left->sym == S) {
+                                       yyerror("invalid field name %#N in struct initializer", l->left);
+                                       typecheck(&l->right, Erv);
+                                       continue;
+                               }
+                               l->left->typecheck = 1;
+                               f = lookdot1(l->left->sym, t, t->type);
+                               typecheck(&l->right, Erv);
+                               if(f == nil)
+                                       continue;
+                               fielddup(newname(f->sym), hash, nelem(hash));
+                               l->right = typecheckconv(nil, l->right, f->type, 0);
+                       }
+               }
+               n->op = OSTRUCTLIT;
+               break;
+       }
+       if(nerr != nerrors)
+               goto error;
+       n->type = t;
+
+       *np = n;
+       return;
+
+error:
+       n->type = T;
+       *np = n;
+}
+
+/*
+ * the address of n has been taken and might be used after
+ * the current function returns.  mark any local vars
+ * as needing to move to the heap.
+ */
+static void
+addrescapes(Node *n)
+{
+       char buf[100];
+       switch(n->op) {
+       default:
+               // probably a type error already.
+               // dump("addrescapes", n);
+               break;
+
+       case ONAME:
+               if(n->noescape)
+                       break;
+               switch(n->class) {
+               case PPARAMOUT:
+                       yyerror("cannot take address of out parameter %s", n->sym->name);
+                       break;
+               case PAUTO:
+               case PPARAM:
+                       // if func param, need separate temporary
+                       // to hold heap pointer.
+                       if(n->class == PPARAM) {
+                               // expression to refer to stack copy
+                               n->stackparam = nod(OPARAM, n, N);
+                               n->stackparam->type = n->type;
+                               n->stackparam->addable = 1;
+                               n->stackparam->xoffset = n->xoffset;
+                       }
+
+                       n->class |= PHEAP;
+                       n->addable = 0;
+                       n->ullman = 2;
+                       n->alloc = callnew(n->type);
+                       n->xoffset = 0;
+
+                       // create stack variable to hold pointer to heap
+                       n->heapaddr = nod(0, N, N);
+                       tempname(n->heapaddr, ptrto(n->type));
+                       snprint(buf, sizeof buf, "&%S", n->sym);
+                       n->heapaddr->sym = lookup(buf);
+                       break;
+               }
+               break;
+
+       case OIND:
+       case ODOTPTR:
+               break;
+
+       case ODOT:
+       case OINDEX:
+               // ODOTPTR has already been introduced,
+               // so these are the non-pointer ODOT and OINDEX.
+               // In &x[0], if x is a slice, then x does not
+               // escape--the pointer inside x does, but that
+               // is always a heap pointer anyway.
+               if(!isslice(n->left->type))
+                       addrescapes(n->left);
+               break;
+       }
+}
+
+static int
+islvalue(Node *n)
+{
+       switch(n->op) {
+       case OINDEX:
+       case OIND:
+       case ODOTPTR:
+               return 1;
+       case ODOT:
+               return islvalue(n->left);
+       case ONAME:
+               if(n->class == PFUNC)
+                       return 0;
+               return 1;
+       }
+       return 0;
+}
+
+static void
+checklvalue(Node *n, char *verb)
+{
+       if(!islvalue(n))
+               yyerror("cannot %s %#N", verb, n);
+}
+
+static void
+checkassign(Node *n)
+{
+       if(islvalue(n))
+               return;
+       if(n->op == OINDEXMAP) {
+               n->etype = 1;
+               return;
+       }
+       yyerror("cannot assign to %#N", n);
+}
+
+static void
+checkassignlist(NodeList *l)
+{
+       for(; l; l=l->next)
+               checkassign(l->n);
 }
index 91f1ea875ae75eb4d05451825667a11c38ff9bbd..d9f2a9092c937b5d02c976b7263a9628a23a7173 100644 (file)
@@ -4,15 +4,13 @@
 
 #include       "go.h"
 
-static Node*   curfn;
-
-static Node*   prcompat(Node*);
+static Node*   walkprint(Node*, NodeList**);
 static Node*   mkcall(char*, Type*, NodeList**, ...);
 static Node*   mkcall1(Node*, Type*, NodeList**, ...);
 static Node*   conv(Node*, Type*);
 static Node*   chanfn(char*, int, Type*);
 static Node*   mapfn(char*, Type*);
-
+static Node*   makenewvar(Type*, NodeList**, Node**);
 enum
 {
        Inone,
@@ -79,7 +77,6 @@ void
 walk(Node *fn)
 {
        char s[50];
-       // int nerr;
 
        curfn = fn;
        if(debug['W']) {
@@ -89,12 +86,9 @@ walk(Node *fn)
        if(curfn->type->outtuple)
                if(walkret(curfn->nbody))
                        yyerror("function ends without a return statement");
-       // nerr = nerrors;
        typechecklist(curfn->nbody, Etop);
-       /* TODO(rsc)
-       if(nerrors != nerr)
+       if(nerrors != 0)
                return;
-       */
        walkstmtlist(curfn->nbody);
        if(debug['W']) {
                snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
@@ -223,6 +217,7 @@ walkstmt(Node **np)
                dump("nottop", n);
                break;
 
+       case OAPPENDSTR:
        case OASOP:
        case OAS:
        case OAS2:
@@ -336,16 +331,22 @@ walkexpr(Node **np, NodeList **init)
        Node *r, *l;
        NodeList *ll, *lr;
        Type *t;
-       Sym *s;
        int et, cl, cr;
        int32 lno;
-       Node *n;
+       Node *n, *fn;
 
        n = *np;
 
        if(n == N)
                return;
 
+       // annoying case - not typechecked
+       if(n->op == OKEY) {
+               walkexpr(&n->left, init);
+               walkexpr(&n->right, init);
+               return;
+       }
+
        lno = setlineno(n);
 
        if(debug['w'] > 1)
@@ -356,7 +357,6 @@ walkexpr(Node **np, NodeList **init)
                fatal("missed typecheck");
        }
 
-reswitch:
        t = T;
        et = Txxx;
 
@@ -367,15 +367,9 @@ reswitch:
                goto ret;
 
        case OTYPE:
-       case OCALLMETH:
-       case OCALLINTER:
-       case OCALLFUNC:
        case ONONAME:
        case OINDREG:
        case OEMPTY:
-       case OCONVNOP:
-       case OCOMPMAP:
-       case OCOMPSLICE:
                goto ret;
 
        case ONOT:
@@ -401,6 +395,13 @@ reswitch:
        case OOROR:
        case OSUB:
        case OMUL:
+       case OEQ:
+       case ONE:
+       case OLT:
+       case OLE:
+       case OGE:
+       case OGT:
+       case OADD:
                walkexpr(&n->left, init);
                walkexpr(&n->right, init);
                goto ret;
@@ -410,7 +411,7 @@ reswitch:
        case OPANIC:
        case OPANICN:
                walkexprlist(n->list, init);
-               n = prcompat(n);
+               n = walkprint(n, init);
                goto ret;
 
        case OLITERAL:
@@ -420,104 +421,50 @@ reswitch:
        case ONAME:
                if(!(n->class & PHEAP) && n->class != PPARAMREF)
                        n->addable = 1;
-               if(n->type == T) {
-                       s = n->sym;
-                       if(s->undef == 0) {
-                               if(n->etype != 0)
-                                       yyerror("walkexpr: %S must be called", s, init);
-                               else
-                                       yyerror("walkexpr: %S undeclared", s, init);
-                               s->undef = 1;
-                       }
-               }
                goto ret;
 
-       case OCALL:
-               if(n->left == N)
+       case OCALLINTER:
+               t = n->left->type;
+               if(n->list && n->list->n->op == OAS)
                        goto ret;
-
-               if(n->left->op == ONAME && n->left->etype != 0) {
-                       // builtin OLEN, OCAP, etc.
-                       n->op = n->left->etype;
-                       n->left = N;
-                       goto reswitch;
-               }
-
                walkexpr(&n->left, init);
-               defaultlit(&n->left, T);
+               walkexprlist(n->list, init);
+               ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+               n->list = reorder1(ll);
+               goto ret;
 
+       case OCALLFUNC:
                t = n->left->type;
-               if(t == T)
+               if(n->list && n->list->n->op == OAS)
                        goto ret;
-
-               switch(n->left->op) {
-               case ODOTMETH:
-                       n->op = OCALLMETH;
-                       break;
-               case ODOTINTER:
-                       n->op = OCALLINTER;
-                       break;
-               case OTYPE:
-                       n->op = OCONV;
-                       // turn CALL(type, arg) into CONV(arg) w/ type.
-                       n->type = n->left->type;
-                       if(n->list == nil) {
-                               yyerror("missing argument in type conversion");
-                               goto ret;
-                       }
-                       if(n->list->next != nil) {
-                               yyerror("too many arguments in type conversion");
-                               goto ret;
-                       }
-                       n->left = n->list->n;
-                       n->list = nil;
-                       goto reswitch;
-               default:
-                       n->op = OCALLFUNC;
-                       break;
+               walkexpr(&n->left, init);
+               walkexprlist(n->list, init);
+               ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+               n->list = reorder1(ll);
+               if(isselect(n)) {
+                       // special prob with selectsend and selectrecv:
+                       // if chan is nil, they don't know big the channel
+                       // element is and therefore don't know how to find
+                       // the output bool, so we clear it before the call.
+                       Node *b;
+                       b = nodbool(0);
+                       lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
+                       n->list = concat(n->list, lr);
                }
+               goto ret;
 
-               if(t->etype != TFUNC) {
-                       yyerror("call of a non-function: %T", t);
+       case OCALLMETH:
+               t = n->left->type;
+               if(n->list && n->list->n->op == OAS)
                        goto ret;
-               }
-
-               dowidth(t);
+               walkexpr(&n->left, init);
                walkexprlist(n->list, init);
-
-               switch(n->op) {
-               default:
-                       fatal("walk: op: %O", n->op);
-
-               case OCALLINTER:
-                       ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
-                       n->list = reorder1(ll);
-                       break;
-
-               case OCALLFUNC:
-                       ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
-                       n->list = reorder1(ll);
-                       if(isselect(n)) {
-                               // special prob with selectsend and selectrecv:
-                               // if chan is nil, they don't know big the channel
-                               // element is and therefore don't know how to find
-                               // the output bool, so we clear it before the call.
-                               Node *b;
-                               b = nodbool(0);
-                               lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
-                               n->list = concat(n->list, lr);
-                       }
-                       break;
-
-               case OCALLMETH:
-                       ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
-                       lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
-                       ll = concat(ll, lr);
-                       n->left->left = N;
-                       ullmancalc(n->left);
-                       n->list = reorder1(ll);
-                       break;
-               }
+               ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+               lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
+               ll = concat(ll, lr);
+               n->left->left = N;
+               ullmancalc(n->left);
+               n->list = reorder1(ll);
                goto ret;
 
        case OAS:
@@ -571,12 +518,10 @@ reswitch:
                        }
                        break;
 
-               case OINDEX:
+               case OINDEXMAP:
                        if(cl == 2 && cr == 1) {
                                // a,b = map[] - mapaccess2
                                walkexpr(&r->left, init);
-                               if(!istype(r->left->type, TMAP))
-                                       break;
                                l = mapop(n, init);
                                if(l == N)
                                        break;
@@ -634,7 +579,7 @@ reswitch:
                                }
                                if(et == Inone)
                                        break;
-                               r = ifacecvt(r->type, r->left, et);
+                               r = ifacecvt(r->type, r->left, et, init);
                                ll = ascompatet(n->op, n->list, &r->type, 0, init);
                                n = liststmt(concat(list1(r), ll));
                                goto ret;
@@ -643,11 +588,9 @@ reswitch:
                }
 
                switch(l->op) {
-               case OINDEX:
+               case OINDEXMAP:
                        if(cl == 1 && cr == 2) {
                                // map[] = a,b - mapassign2
-                               if(!istype(l->left->type, TMAP))
-                                       break;
                                l = mapop(n, init);
                                if(l == N)
                                        break;
@@ -664,42 +607,18 @@ reswitch:
 
        case ODOTTYPE:
                walkdottype(n, init);
-               // fall through
-       case OCONV:
                walkconv(&n, init);
                goto ret;
 
-       case OCOMPOS:
-               walkexpr(&n->right, init);
-               t = n->right->type;
-               n->type = t;
-               if(t == T)
-                       goto ret;
-
-               switch(t->etype) {
-               default:
-                       yyerror("invalid type for composite literal: %T", t);
-                       goto ret;
-
-               case TSTRUCT:
-                       r = structlit(n, N, init);
-                       break;
-
-               case TARRAY:
-                       r = arraylit(n, N, init);
-                       break;
-
-               case TMAP:
-                       r = maplit(n, N, init);
-                       break;
-               }
-               n = r;
+       case OCONV:
+       case OCONVNOP:
+               walkexpr(&n->left, init);
                goto ret;
 
        case OASOP:
                walkexpr(&n->left, init);
                l = n->left;
-               if(l->op == OINDEX && istype(l->left->type, TMAP))
+               if(l->op == OINDEXMAP)
                        n = mapop(n, init);
                walkexpr(&n->right, init);
                if(n->etype == OANDNOT) {
@@ -708,11 +627,7 @@ reswitch:
                        n->right->type = n->right->left->type;
                        goto ret;
                }
-               if(istype(n->left->type, TSTRING)) {
-                       n = stringop(n, init);
-                       goto ret;
-               }
-               
+
                /*
                 * on 32-bit arch, rewrite 64-bit ops into l = l op r
                 */
@@ -734,25 +649,6 @@ reswitch:
                n->right->type = n->right->left->type;
                goto ret;
 
-       case OEQ:
-       case ONE:
-       case OLT:
-       case OLE:
-       case OGE:
-       case OGT:
-       case OADD:
-               walkexpr(&n->left, init);
-               walkexpr(&n->right, init);
-               if(istype(n->left->type, TSTRING)) {
-                       n = stringop(n, nil);
-                       goto ret;
-               }
-               if(isinter(n->left->type)) {
-                       n = ifaceop(n);
-                       goto ret;
-               }
-               goto ret;
-
        case ODIV:
        case OMOD:
                /*
@@ -779,131 +675,246 @@ reswitch:
        case OINDEX:
                walkexpr(&n->left, init);
                walkexpr(&n->right, init);
-               if(n->left == N || n->right == N)
+               goto ret;
+
+       case OINDEXMAP:
+               if(n->etype == 1)
                        goto ret;
                t = n->left->type;
-               if(t == T)
-                       goto ret;
-
-               switch(t->etype) {
-               case TSTRING:
-                       n = stringop(n, nil);
-                       break;
-
-               case TMAP:
-                       if(n->etype != 1)       // clumsy hack
-                               n = mapop(n, nil);
-                       break;
-               }
+               n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
                goto ret;
 
-       case OCLOSE:
-       case OCLOSED:
-       case OSEND:
        case ORECV:
                walkexpr(&n->left, init);
                walkexpr(&n->right, init);
-               n = chanop(n, init);
+               n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, n->left);
                goto ret;
 
        case OSLICE:
                walkexpr(&n->left, init);
                walkexpr(&n->right->left, init);
                walkexpr(&n->right->right, init);
-               if(n->left == N || n->right == N)
-                       goto ret;
-               t = n->left->type;
-               if(t == T)
+               // dynamic slice
+               // arraysliced(old []any, lb int, hb int, width int) (ary []any)
+               t = n->type;
+               fn = syslook("arraysliced", 1);
+               argtype(fn, t->type);                   // any-1
+               argtype(fn, t->type);                   // any-2
+               n = mkcall1(fn, t, init,
+                       n->left,
+                       conv(n->right->left, types[TINT]),
+                       conv(n->right->right, types[TINT]),
+                       nodintconst(t->type->width));
+               goto ret;
+
+       case OSLICEARR:
+               walkexpr(&n->left, init);
+               walkexpr(&n->right->left, init);
+               walkexpr(&n->right->right, init);
+               // static slice
+               // arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any)
+               t = n->type;
+               fn = syslook("arrayslices", 1);
+               argtype(fn, n->left->type);     // any-1
+               argtype(fn, t->type);                   // any-2
+               n = mkcall1(fn, t, init,
+                       nod(OADDR, n->left, N), nodintconst(t->bound),
+                       conv(n->right->left, types[TINT]),
+                       conv(n->right->right, types[TINT]),
+                       nodintconst(t->type->width));
+               goto ret;
+
+       case OADDR:;
+               Node *nvar, *nstar;
+
+               // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
+               // initialize with
+               //      nvar := new(*Point);
+               //      *nvar = Point(1, 2);
+               // and replace expression with nvar
+               switch(n->left->op) {
+               case OARRAYLIT:
+                       nvar = makenewvar(n->type, init, &nstar);
+                       arraylit(n->left, nstar, init);
+                       n = nvar;
                        goto ret;
-               if(t->etype == TSTRING) {
-                       n = stringop(n, nil);
+
+               case OMAPLIT:
+                       nvar = makenewvar(n->type, init, &nstar);
+                       maplit(n->left, nstar, init);
+                       n = nvar;
                        goto ret;
-               }
-               if(t->etype == TARRAY) {
-                       n = arrayop(n);
+
+
+               case OSTRUCTLIT:
+                       nvar = makenewvar(n->type, init, &nstar);
+                       structlit(n->left, nstar, init);
+                       n = nvar;
                        goto ret;
                }
+
+               walkexpr(&n->left, init);
                goto ret;
 
-       case OADDR:
-               if(n->left->op == OCOMPOS) {
-                       walkexpr(&n->left->right, init);
-                       n->left->type = n->left->right->type;
-                       if(n->left->type == T)
-                               goto ret;
+       case ONEW:
+               n = callnew(n->type->type);
+               goto ret;
 
-                       Node *nvar, *nas, *nstar;
+       case OCMPSTR:
+               // sys_cmpstring(s1, s2) :: 0
+               r = mkcall("cmpstring", types[TINT], init,
+                       conv(n->left, types[TSTRING]),
+                       conv(n->right, types[TSTRING]));
+               r = nod(n->etype, r, nodintconst(0));
+               typecheck(&r, Erv);
+               n = r;
+               goto ret;
 
-                       // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
-                       // initialize with
-                       //      nvar := new(*Point);
-                       //      *nvar = Point(1, 2);
-                       // and replace expression with nvar
+       case OADDSTR:
+               // sys_catstring(s1, s2)
+               n = mkcall("catstring", n->type, init,
+                       conv(n->left, types[TSTRING]),
+                       conv(n->right, types[TSTRING]));
+               goto ret;
 
-                       nvar = nod(OXXX, N, N);
-                       tempname(nvar, ptrto(n->left->type));
+       case OAPPENDSTR:
+               // s1 = sys_catstring(s1, s2)
+               if(n->etype != OADD)
+                       fatal("walkasopstring: not add");
+               r = mkcall("catstring", n->left->type, init,
+                       conv(n->left, types[TSTRING]),
+                       conv(n->right, types[TSTRING]));
+               r = nod(OAS, n->left, r);
+               n = r;
+               goto ret;
 
-                       nas = nod(OAS, nvar, callnew(n->left->type));
-                       typecheck(&nas, Etop);
-                       walkexpr(&nas, init);
-                       *init = list(*init, nas);
+       case OSLICESTR:
+               // sys_slicestring(s, lb, hb)
+               n = mkcall("slicestring", n->type, init,
+                       conv(n->left, types[TSTRING]),
+                       conv(n->right->left, types[TINT]),
+                       conv(n->right->right, types[TINT]));
+               goto ret;
 
-                       nstar = nod(OIND, nvar, N);
-                       nstar->type = n->left->type;
+       case OINDEXSTR:
+               // TODO(rsc): should be done in back end
+               // sys_indexstring(s, i)
+               n = mkcall("indexstring", n->type, init,
+                       conv(n->left, types[TSTRING]),
+                       conv(n->right, types[TINT]));
+               goto ret;
 
-                       switch(n->left->type->etype) {
-                       case TSTRUCT:
-                               structlit(n->left, nstar, init);
-                               break;
-                       case TARRAY:
-                               arraylit(n->left, nstar, init);
-                               break;
-                       case TMAP:
-                               maplit(n->left, nstar, init);
-                               break;
-                       default:
-                               goto badlit;
-                       }
+       case OCLOSE:
+               // cannot use chanfn - closechan takes any, not chan any
+               fn = syslook("closechan", 1);
+               argtype(fn, n->left->type);
+               n = mkcall1(fn, T, init, n->left);
+               goto ret;
 
-//                     walkexpr(&n->left->left, init);
-                       n = nvar;
-                       goto ret;
-               }
+       case OCLOSED:
+               // cannot use chanfn - closechan takes any, not chan any
+               fn = syslook("closedchan", 1);
+               argtype(fn, n->left->type);
+               n = mkcall1(fn, n->type, init, n->left);
+               goto ret;
 
-       badlit:
-               if(istype(n->left->type, TFUNC) && n->left->class == PFUNC) {
-                       if(!n->diag) {
-                               n->diag = 1;
-                               yyerror("cannot take address of function");
-                       }
-               }
-               if(n->left == N)
-                       goto ret;
-               walkexpr(&n->left, init);
-               t = n->left->type;
-               if(t == T)
-                       goto ret;
-               addrescapes(n->left);
-               n->type = ptrto(t);
+       case OMAKECHAN:
+               n = mkcall1(chanfn("newchan", 1, n->type), n->type, init,
+                       nodintconst(n->type->type->width),
+                       nodintconst(algtype(n->type->type)),
+                       conv(n->left, types[TINT]));
                goto ret;
 
-       case OMAKE:
-               n = makecompat(n);
+       case OMAKEMAP:
+               t = n->type;
+
+               fn = syslook("newmap", 1);
+               argtype(fn, t->down);   // any-1
+               argtype(fn, t->type);   // any-2
+
+               n = mkcall1(fn, n->type, init,
+                       nodintconst(t->down->width),    // key width
+                       nodintconst(t->type->width),            // val width
+                       nodintconst(algtype(t->down)),  // key algorithm
+                       nodintconst(algtype(t->type)),          // val algorithm
+                       conv(n->left, types[TINT]));
                goto ret;
 
-       case ONEW:
-               if(n->list == nil) {
-                       yyerror("missing argument to new");
-                       goto ret;
-               }
-               if(n->list->next)
-                       yyerror("too many arguments to new");
-               walkexpr(&n->list->n, init);
-               l = n->list->n;
-               if((t = l->type) == T)
-                       ;
+       case OMAKESLICE:
+               // newarray(nel int, max int, width int) (ary []any)
+               t = n->type;
+               fn = syslook("newarray", 1);
+               argtype(fn, t->type);                   // any-1
+               n = mkcall1(fn, n->type, nil,
+                       conv(n->left, types[TINT]),
+                       conv(n->right, types[TINT]),
+                       nodintconst(t->type->width));
+               goto ret;
+
+       case ORUNESTR:
+               // sys_intstring(v)
+               n = mkcall("intstring", n->type, init, conv(n->left, types[TINT64]));   // TODO(rsc): int64?!
+               goto ret;
+
+       case OARRAYBYTESTR:
+               // arraystring([]byte) string;
+               n = mkcall("arraystring", n->type, init, n->left);
+               goto ret;
+
+       case OARRAYRUNESTR:
+               // arraystring([]byte) string;
+               n = mkcall("arraystringi", n->type, init, n->left);
+               goto ret;
+
+       case OCMPIFACE:
+               // ifaceeq(i1 any-1, i2 any-2) (ret bool);
+               if(!eqtype(n->left->type, n->right->type))
+                       fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
+               if(isnilinter(n->left->type))
+                       fn = syslook("efaceeq", 1);
                else
-                       n = callnew(t);
+                       fn = syslook("ifaceeq", 1);
+               argtype(fn, n->right->type);
+               argtype(fn, n->left->type);
+               r = mkcall1(fn, n->type, init, n->left, n->right);
+               if(n->etype == ONE) {
+                       r = nod(ONOT, r, N);
+                       typecheck(&r, Erv);
+               }
+               n = r;
+               goto ret;
+
+       case OARRAYLIT:
+               n = arraylit(n, N, init);
+               goto ret;
+
+       case OMAPLIT:
+               n = maplit(n, N, init);
+               goto ret;
+
+       case OSTRUCTLIT:
+               n = structlit(n, N, init);
+               goto ret;
+
+       case OSEND:
+               n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
+               goto ret;
+
+       case OSENDNB:
+               n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
+               goto ret;
+
+       case OCONVIFACE:
+               walkexpr(&n->left, init);
+               n = ifacecvt(n->type, n->left, n->etype, init);
+               goto ret;
+
+       case OCONVSLICE:
+               // arrays2d(old *any, nel int) (ary []any)
+               fn = syslook("arrays2d", 1);
+               argtype(fn, n->left->type->type);               // any-1
+               argtype(fn, n->type->type);                     // any-2
+               n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
                goto ret;
        }
        fatal("missing switch %O", n->op);
@@ -917,6 +928,23 @@ ret:
        *np = n;
 }
 
+Node*
+makenewvar(Type *t, NodeList **init, Node **nstar)
+{
+       Node *nvar, *nas;
+
+       nvar = nod(OXXX, N, N);
+       tempname(nvar, t);
+       nas = nod(OAS, nvar, callnew(t->type));
+       typecheck(&nas, Etop);
+       walkexpr(&nas, init);
+       *init = list(*init, nas);
+
+       *nstar = nod(OIND, nvar, N);
+       typecheck(nstar, Erv);
+       return nvar;
+}
+
 void
 walkbool(Node **np)
 {
@@ -958,7 +986,6 @@ walkconv(Node **np, NodeList **init)
        t = n->type;
        if(t == T)
                return;
-       typecheck(&n->left, Erv);
        walkexpr(&n->left, init);
        l = n->left;
        if(l == N)
@@ -969,110 +996,19 @@ walkconv(Node **np, NodeList **init)
        // if using .(T), interface assertion.
        if(n->op == ODOTTYPE) {
                et = ifaceas1(t, l->type, 1);
-               if(et == I2Isame || et == E2Esame)
-                       goto nop;
-               if(et != Inone) {
-                       n = ifacecvt(t, l, et);
-                       *np = n;
+               if(et == I2Isame || et == E2Esame) {
+                       n->op = OCONVNOP;
                        return;
                }
-               goto bad;
-       }
-
-       // otherwise, conversion.
-       convlit1(&n->left, t, 1);
-       l = n->left;
-       if(l->type == T)
-               return;
-
-       // no-op conversion
-       if(cvttype(t, l->type) == 1) {
-       nop:
-               if(l->op == OLITERAL) {
-                       *n = *l;
-                       n->type = t;
-                       return;
-               }
-               // leave OCONV node in place
-               // in case tree gets walked again.
-               // back end will ignore.
-               n->op = OCONVNOP;
-               return;
-       }
-
-       // to/from interface.
-       // ifaceas1 will generate a good error
-       // if the conversion is invalid.
-       if(t->etype == TINTER || l->type->etype == TINTER) {
-               n = ifacecvt(t, l, ifaceas1(t, l->type, 0));
-               *np = n;
-               return;
-       }
-
-       // simple fix-float
-       if(isint[l->type->etype] || isfloat[l->type->etype])
-       if(isint[t->etype] || isfloat[t->etype]) {
-               evconst(n);
-               return;
-       }
-
-       // to string
-       if(l->type != T)
-       if(istype(t, TSTRING)) {
-               et = l->type->etype;
-               if(isint[et]) {
-                       n = stringop(n, nil);
-                       *np = n;
-                       return;
-               }
-
-               // can convert []byte and *[10]byte
-               if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TUINT8))
-               || (isslice(l->type) && istype(l->type->type, TUINT8))) {
-                       n->op = OARRAY;
-                       n = stringop(n, nil);
-                       *np = n;
-                       return;
-               }
-
-               // can convert []int and *[10]int
-               if((isptr[et] && isfixedarray(l->type->type) && istype(l->type->type->type, TINT))
-               || (isslice(l->type) && istype(l->type->type, TINT))) {
-                       n->op = OARRAY;
-                       n = stringop(n, nil);
-                       *np = n;
-                       return;
-               }
-       }
-
-       // convert dynamic to static generated by ONEW/OMAKE
-       if(isfixedarray(t) && isslice(l->type))
-               return;
-
-       // convert static array to dynamic array
-       if(isslice(t) && isptr[l->type->etype] && isfixedarray(l->type->type)) {
-               if(eqtype(t->type->type, l->type->type->type->type)) {
-                       n = arrayop(n);
+               if(et != Inone) {
+                       n = ifacecvt(t, l, et, init);
                        *np = n;
                        return;
                }
+               goto bad;
        }
 
-       // convert to unsafe.pointer
-       if(isptrto(n->type, TANY)) {
-               if(isptr[l->type->etype])
-                       return;
-               if(l->type->etype == TUINTPTR)
-                       return;
-       }
-
-       // convert from unsafe.pointer
-       if(isptrto(l->type, TANY)) {
-               if(isptr[t->etype])
-                       return;
-               if(t->etype == TUINTPTR)
-                       return;
-       }
+       fatal("walkconv");
 
 bad:
        if(n->diag)
@@ -1279,6 +1215,7 @@ walkselect(Node *sel)
                        break;
 
                case OSEND:
+               case OSENDNB:
                case ORECV:
                        break;
                }
@@ -1325,14 +1262,15 @@ ascompatee1(int op, Node *l, Node *r, NodeList **init)
         * a expression. called in
         *      expr = expr
         */
+       if(l->type != T && l->type->etype == TFORW)
+               return N;
+       if(r->type != T && r->type->etype ==TFORW)
+               return N;
        convlit(&r, l->type);
        if(!ascompat(l->type, r->type)) {
                badtype(op, l->type, r->type);
                return N;
        }
-       if(l->op == ONAME && l->class == PFUNC)
-               yyerror("cannot assign to function");
-
        a = nod(OAS, l, r);
        a = convas(a, init);
        return a;
@@ -1653,7 +1591,7 @@ loop:
                }
                goto ret;
        }
-       convlit(&r, l->type);
+
        if(!ascompat(l->type, r->type)) {
                badtype(op, l->type, r->type);
                return nil;
@@ -1676,49 +1614,6 @@ ret:
        return nn;
 }
 
-/*
- * do the export rules allow writing to this type?
- * cannot be implicitly assigning to any type with
- * an unavailable field.
- */
-int
-exportasok(Type *t)
-{
-       Type *f;
-       Sym *s;
-
-       if(t == T)
-               return 1;
-       switch(t->etype) {
-       default:
-               // most types can't contain others; they're all fine.
-               break;
-       case TSTRUCT:
-               for(f=t->type; f; f=f->down) {
-                       if(f->etype != TFIELD)
-                               fatal("structas: not field");
-                       s = f->sym;
-                       // s == nil doesn't happen for embedded fields (they get the type symbol).
-                       // it only happens for fields in a ... struct.
-                       if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
-                               yyerror("implicit assignment of %T field '%s'", t, s->name);
-                               return 0;
-                       }
-                       if(!exportasok(f->type))
-                               return 0;
-               }
-               break;
-
-       case TARRAY:
-               if(t->bound < 0)        // slices are pointers; that's fine
-                       break;
-               if(!exportasok(t->type))
-                       return 0;
-               break;
-       }
-       return 1;
-}
-
 /*
  * can we assign var of type src to var of type dst?
  * return 0 if not, 1 if conversion is trivial, 2 if conversion is non-trivial.
@@ -1726,10 +1621,8 @@ exportasok(Type *t)
 int
 ascompat(Type *dst, Type *src)
 {
-       if(eqtype(dst, src)) {
-               exportasok(src);
+       if(eqtype(dst, src))
                return 1;
-       }
 
        if(dst == T || src == T)
                return 0;
@@ -1775,7 +1668,7 @@ ascompat(Type *dst, Type *src)
 
 // generate code for print
 static Node*
-prcompat(Node *nn)
+walkprint(Node *nn, NodeList **init)
 {
        Node *r;
        Node *n;
@@ -1792,10 +1685,9 @@ prcompat(Node *nn)
 
        for(l=all; l; l=l->next) {
                if(notfirst)
-                       calls = list(calls, mkcall("printsp", T, nil));
+                       calls = list(calls, mkcall("printsp", T, init));
                notfirst = op == OPRINTN || op == OPANICN;
 
-               typecheck(&l->n, Erv);
                n = l->n;
                if(n->op == OLITERAL) {
                        switch(n->val.ctype) {
@@ -1811,7 +1703,7 @@ prcompat(Node *nn)
                        defaultlit(&n, types[TINT64]);
                defaultlit(&n, nil);
                l->n = n;
-               if(n->type == T)
+               if(n->type == T || n->type->etype == TFORW)
                        continue;
 
                et = n->type->etype;
@@ -1861,64 +1753,18 @@ prcompat(Node *nn)
        if(op == OPRINTN)
                calls = list(calls, mkcall("printnl", T, nil));
        typechecklist(calls, Etop);
-       walkexprlist(calls, nil);
+       walkexprlist(calls, init);
 
        if(op == OPANIC || op == OPANICN)
                r = mkcall("panicl", T, nil);
        else
                r = nod(OEMPTY, N, N);
        typecheck(&r, Etop);
-       walkexpr(&r, nil);
+       walkexpr(&r, init);
        r->ninit = calls;
        return r;
 }
 
-Node*
-makecompat(Node *n)
-{
-       Type *t;
-       Node *l, *r;
-       NodeList *args, *init;
-
-//dump("makecompat", n);
-       args = n->list;
-       if(args == nil) {
-               yyerror("make requires type argument");
-               return n;
-       }
-       r = N;
-       l = args->n;
-       args = args->next;
-       init = nil;
-       walkexpr(&l, &init);
-       if(l->op != OTYPE) {
-               yyerror("cannot make(expr)");
-               return n;
-       }
-       t = l->type;
-       n->type = t;
-       n->list = args;
-
-       if(t != T)
-       switch(t->etype) {
-       case TARRAY:
-               if(!isslice(t))
-                       goto bad;
-               return arrayop(n);
-       case TMAP:
-               return mapop(n, nil);
-       case TCHAN:
-               return chanop(n, nil);
-       }
-
-bad:
-       if(!n->diag) {
-               n->diag = 1;
-               yyerror("cannot make(%T)", t);
-       }
-       return n;
-}
-
 Node*
 callnew(Type *t)
 {
@@ -1930,93 +1776,6 @@ callnew(Type *t)
        return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
 }
 
-Node*
-stringop(Node *n, NodeList **init)
-{
-       Node *r, *fn;
-
-       switch(n->op) {
-       default:
-               fatal("stringop: unknown op %O", n->op);
-
-       case OEQ:
-       case ONE:
-       case OGE:
-       case OGT:
-       case OLE:
-       case OLT:
-               // sys_cmpstring(s1, s2) :: 0
-               r = mkcall("cmpstring", types[TINT], init,
-                       conv(n->left, types[TSTRING]),
-                       conv(n->right, types[TSTRING]));
-               r = nod(n->op, r, nodintconst(0));
-               typecheck(&r, Erv);
-               break;
-
-       case OADD:
-               // sys_catstring(s1, s2)
-               r = mkcall("catstring", n->type, init,
-                       conv(n->left, types[TSTRING]),
-                       conv(n->right, types[TSTRING]));
-               break;
-
-       case OASOP:
-               // sys_catstring(s1, s2)
-               switch(n->etype) {
-               default:
-                       fatal("stringop: unknown op %O-%O", n->op, n->etype);
-
-               case OADD:
-                       // s1 = sys_catstring(s1, s2)
-                       if(n->etype != OADD)
-                               fatal("stringop: not cat");
-                       r = mkcall("catstring", n->left->type, init,
-                               conv(n->left, types[TSTRING]),
-                               conv(n->right, types[TSTRING]));
-                       r = nod(OAS, n->left, r);
-                       break;
-               }
-               break;
-
-
-       case OSLICE:
-               // sys_slicestring(s, lb, hb)
-               r = mkcall("slicestring", n->type, init,
-                       conv(n->left, types[TSTRING]),
-                       conv(n->right->left, types[TINT]),
-                       conv(n->right->right, types[TINT]));
-               break;
-
-       case OINDEX:
-               // TODO(rsc): should be done in back end
-               // sys_indexstring(s, i)
-               r = mkcall("indexstring", n->type, init,
-                       conv(n->left, types[TSTRING]),
-                       conv(n->right, types[TINT]));
-               break;
-
-       case OCONV:
-               // sys_intstring(v)
-               r = mkcall("intstring", n->type, init,
-                       conv(n->left, types[TINT64]));  // TODO(rsc): int64?!
-               break;
-
-       case OARRAY:
-               // arraystring([]byte) string;
-               r = n->left;
-               fn = syslook("arraystring", 0);
-               if(r->type != T && r->type->type != T) {
-                       if(istype(r->type->type, TINT) || istype(r->type->type->type, TINT)) {
-                               // arraystring([]byte) string;
-                               fn = syslook("arraystringi", 0);
-                       }
-               }
-               r = mkcall1(fn, n->type, init, r);
-               break;
-       }
-       return r;
-}
-
 Type*
 fixmap(Type *t)
 {
@@ -2061,7 +1820,7 @@ mapop(Node *n, NodeList **init)
 {
        Node *r, *a, *l;
        Type *t;
-       Node *fn, *hint;
+       Node *fn;
        int cl, cr;
        NodeList *args;
 
@@ -2070,49 +1829,9 @@ mapop(Node *n, NodeList **init)
        default:
                fatal("mapop: unknown op %O", n->op);
 
-       case OMAKE:
-               cl = count(n->list);
-               if(cl > 1)
-                       yyerror("too many arguments to make map");
-
-               // newmap(keysize int, valsize int,
-               //      keyalg int, valalg int,
-               //      hint int) (hmap map[any-1]any-2);
-
-               t = fixmap(n->type);
-               if(t == T)
-                       break;
-
-               fn = syslook("newmap", 1);
-               argtype(fn, t->down);   // any-1
-               argtype(fn, t->type);   // any-2
-               
-               if(cl == 1)
-                       hint = n->list->n;
-               else
-                       hint = nodintconst(0);
-
-               r = mkcall1(fn, n->type, init,
-                       nodintconst(t->down->width),    // key width
-                       nodintconst(t->type->width),            // val width
-                       nodintconst(algtype(t->down)),  // key algorithm
-                       nodintconst(algtype(t->type)),          // val algorithm
-                       hint);
-               break;
-
-       case OINDEX:
-               // mapaccess1(hmap map[any]any, key any) (val any);
-
-               t = fixmap(n->left->type);
-               if(t == T)
-                       break;
-
-               r = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
-               break;
-
        case OAS:
                // mapassign1(hmap map[any-1]any-2, key any-3, val any-4);
-               if(n->left->op != OINDEX)
+               if(n->left->op != OINDEXMAP)
                        goto shape;
 
                t = fixmap(n->left->left->type);
@@ -2135,7 +1854,7 @@ mapop(Node *n, NodeList **init)
        assign2:
                // mapassign2(hmap map[any]any, key any, val any, pres bool);
                l = n->list->n;
-               if(l->op != OINDEX)
+               if(l->op != OINDEXMAP)
                        goto shape;
 
                t = fixmap(l->left->type);
@@ -2150,7 +1869,7 @@ mapop(Node *n, NodeList **init)
 
 //dump("access2", n);
                r = n->rlist->n;
-               if(r->op != OINDEX)
+               if(r->op != OINDEXMAP)
                        goto shape;
 
                t = fixmap(r->left->type);
@@ -2184,8 +1903,7 @@ mapop(Node *n, NodeList **init)
 
                a = nod(OXXX, N, N);
                *a = *n->left;          // copy of map[tmpi]
-               a->typecheck = 0;
-               a->type = T;
+               a->etype = 0;
                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);
@@ -2200,59 +1918,17 @@ shape:
        return N;
 }
 
-Node*
-chanop(Node *n, NodeList **init)
-{
-       Node *r, *a, *fn;
-       Type *t;
-       int cl, cr;
-
-       r = n;
-       switch(n->op) {
-       default:
-               fatal("chanop: unknown op %O", n->op);
-
-       case OCLOSE:
-               // closechan(hchan *chan any);
-               t = fixchan(n->left->type);
-               if(t == T)
-                       break;
-               fn = syslook("closechan", 1);
-               argtype(fn, t);
-               r = mkcall1(fn, T, init, n->left);
-               break;
-
-       case OCLOSED:
-               // closedchan(hchan *chan any) bool;
-               t = fixchan(n->left->type);
-               if(t == T)
-                       break;
-               fn = syslook("closedchan", 1);
-               argtype(fn, t);
-               r = mkcall1(fn, n->type, init, n->left);
-               break;
-
-       case OMAKE:
-               cl = count(n->list);
-               if(cl > 1)
-                       yyerror("too many arguments to make chan");
-
-               // newchan(elemsize int, elemalg int,
-               //      hint int) (hmap *chan[any-1]);
-
-               t = fixchan(n->type);
-               if(t == T)
-                       break;
+Node*
+chanop(Node *n, NodeList **init)
+{
+       Node *r, *fn;
+       Type *t;
+       int cl, cr;
 
-               if(cl == 1)
-                       a = conv(n->list->n, types[TINT]);
-               else
-                       a = nodintconst(0);
-               r = mkcall1(chanfn("newchan", 1, t), n->type, init,
-                       nodintconst(t->type->width),
-                       nodintconst(algtype(t->type)),
-                       a);
-               break;
+       r = n;
+       switch(n->op) {
+       default:
+               fatal("chanop: unknown op %O", n->op);
 
        case OAS2:
                cl = count(n->list);
@@ -2278,45 +1954,6 @@ chanop(Node *n, NodeList **init)
                r = n;
                walkexpr(&r, init);
                break;
-
-       case ORECV:
-               // should not happen - nonblocking is OAS w/ ORECV now.
-               if(n->right != N) {
-                       dump("recv2", n);
-                       fatal("chanop recv2");
-               }
-
-               // chanrecv1(hchan *chan any) (elem any);
-               t = fixchan(n->left->type);
-               if(t == T)
-                       break;
-               if(!(t->chan & Crecv)) {
-                       yyerror("cannot receive from %T", t);
-                       break;
-               }
-
-               r = mkcall1(chanfn("chanrecv1", 2, t), n->type, init, n->left);
-               break;
-
-       case OSEND:
-               t = fixchan(n->left->type);
-               if(t == T)
-                       break;
-               if(!(t->chan & Csend)) {
-                       yyerror("cannot send to %T", t);
-                       break;
-               }
-               if(n->etype == 1)       // clumsy hack
-                       goto send2;
-
-               // chansend1(hchan *chan any, elem any);
-               r = mkcall1(chanfn("chansend1", 2, t), T, init, n->left, n->right);
-               break;
-
-       send2:
-               // chansend2(hchan *chan any, val any) (pres bool);
-               r = mkcall1(chanfn("chansend2", 2, t), n->type, init, n->left, n->right);
-               break;
        }
        return r;
 
@@ -2325,6 +1962,7 @@ shape:
        return N;
 }
 
+
 Type*
 fixarray(Type *t)
 {
@@ -2344,104 +1982,6 @@ bad:
 
 }
 
-Node*
-arrayop(Node *n)
-{
-       Node *r, *nel, *max;
-       NodeList *args;
-       Type *t, *tl;
-       Node *fn;
-       int cl;
-
-       r = n;
-       switch(n->op) {
-       default:
-               fatal("darrayop: unknown op %O", n->op);
-
-       case OCONVNOP:
-               return n;
-
-       case OCONV:
-               // arrays2d(old *any, nel int) (ary []any)
-               if(n->left->type == T || !isptr[n->left->type->etype])
-                       break;
-               t = fixarray(n->left->type->type);
-               tl = fixarray(n->type);
-               if(t == T || tl == T)
-                       break;
-
-               fn = syslook("arrays2d", 1);
-               argtype(fn, t);                         // any-1
-               argtype(fn, tl->type);                  // any-2
-
-               n->left = mkcall1(fn, n->type, nil, n->left, nodintconst(t->bound));
-               typecheck(&n, Erv);
-               walkexpr(&n, nil);
-               return n;
-
-       case OAS:
-               n->right = arrayop(conv(n->right, n->left->type));
-               return n;
-
-       case OMAKE:
-               cl = count(n->list);
-               if(cl > 2)
-                       yyerror("too many arguments to make array");
-
-               // newarray(nel int, max int, width int) (ary []any)
-               t = fixarray(n->type);
-               if(t == T)
-                       break;
-               fn = syslook("newarray", 1);
-               argtype(fn, t->type);                   // any-1
-
-               nel = conv(n->list->n, types[TINT]);
-               if(cl < 2)
-                       max = nodintconst(0);
-               else
-                       max = conv(n->list->next->n, types[TINT]);
-               r = mkcall1(fn, n->type, nil,
-                       nel, max, nodintconst(t->type->width));
-               break;
-
-       case OSLICE:
-               // arrayslices(old any, nel int, lb int, hb int, width int) (ary []any)
-               // arraysliced(old []any, lb int, hb int, width int) (ary []any)
-
-               t = fixarray(n->left->type);
-               if(t == T)
-                       break;
-
-               if(t->bound >= 0) {
-                       // static slice
-                       args = list1(nod(OADDR, n->left, N));           // old
-                       args = list(args, nodintconst(t->bound));               // nel
-
-                       fn = syslook("arrayslices", 1);
-                       argtype(fn, t);                         // any-1
-                       argtype(fn, t->type);                   // any-2
-               } else {
-                       // dynamic slice
-                       args = list1(n->left);                          // old
-
-                       fn = syslook("arraysliced", 1);
-                       argtype(fn, t->type);                   // any-1
-                       argtype(fn, t->type);                   // any-2
-               }
-
-               args = list(args, conv(n->right->left, types[TINT]));   // lb
-               args = list(args, conv(n->right->right, types[TINT]));  // hb
-               args = list(args, nodintconst(t->type->width)); // width
-
-               r = nod(OCALL, fn, N);
-               r->list = args;
-               typecheck(&r, Erv);
-               walkexpr(&r, nil);
-               break;
-       }
-       return r;
-}
-
 /*
  * assigning src to dst involving interfaces?
  * return op to use.
@@ -2520,7 +2060,7 @@ ifacename[] =
 };
 
 Node*
-ifacecvt(Type *tl, Node *n, int et)
+ifacecvt(Type *tl, Node *n, int et, NodeList **init)
 {
        Type *tr;
        Node *r, *on;
@@ -2532,6 +2072,10 @@ ifacecvt(Type *tl, Node *n, int et)
        default:
                fatal("ifacecvt: unknown op %d\n", et);
 
+       case I2Isame:
+       case E2Esame:
+               return n;
+
        case T2I:
                // ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
                args = list1(typename(tl));     // sigi
@@ -2541,6 +2085,7 @@ ifacecvt(Type *tl, Node *n, int et)
                on = syslook("ifaceT2I", 1);
                argtype(on, tr);
                argtype(on, tl);
+               dowidth(on->type);
                break;
 
        case I2T:
@@ -2586,45 +2131,10 @@ ifacecvt(Type *tl, Node *n, int et)
        r = nod(OCALL, on, N);
        r->list = args;
        typecheck(&r, Erv);
-       walkexpr(&r, nil);
+       walkexpr(&r, init);
        return r;
 }
 
-Node*
-ifaceop(Node *n)
-{
-       Node *r, *on;
-       NodeList *args;
-
-       switch(n->op) {
-       default:
-               fatal("ifaceop %O", n->op);
-
-       case OEQ:
-       case ONE:
-               // ifaceeq(i1 any-1, i2 any-2) (ret bool);
-               args = list1(n->left);          // i1
-               args = list(args, n->right);    // i2
-
-               if(!eqtype(n->left->type, n->right->type))
-                       fatal("ifaceop %O %T %T", n->op, n->left->type, n->right->type);
-               if(isnilinter(n->left->type))
-                       on = syslook("efaceeq", 1);
-               else
-                       on = syslook("ifaceeq", 1);
-               argtype(on, n->right->type);
-               argtype(on, n->left->type);
-
-               r = nod(OCALL, on, N);
-               r->list = args;
-               if(n->op == ONE)
-                       r = nod(ONOT, r, N);
-               typecheck(&r, Erv);
-               walkexpr(&r, nil);
-               return r;
-       }
-}
-
 Node*
 convas(Node *n, NodeList **init)
 {
@@ -2634,6 +2144,7 @@ convas(Node *n, NodeList **init)
 
        if(n->op != OAS)
                fatal("convas: not OAS %O", n->op);
+       n->typecheck = 1;
 
        lt = T;
        rt = T;
@@ -2648,38 +2159,23 @@ convas(Node *n, NodeList **init)
        if(lt == T || rt == T)
                goto out;
 
-       if(n->left->op == OINDEX)
-       if(istype(n->left->left->type, TMAP)) {
+       if(n->left->op == OINDEXMAP) {
                n = mapop(n, init);
                goto out;
        }
 
-       if(n->left->op == OSEND)
-       if(n->left->type != T) {
-               n = chanop(n, init);
-               goto out;
-       }
-
        if(eqtype(lt, rt))
                goto out;
 
        et = ifaceas(lt, rt, 0);
        if(et != Inone) {
-               n->right = ifacecvt(lt, r, et);
-               goto out;
-       }
-
-       if(isslice(lt) && isptr[rt->etype] && isfixedarray(rt->type)) {
-               if(!eqtype(lt->type->type, rt->type->type->type))
-                       goto bad;
-               n = arrayop(n);
+               n->right = ifacecvt(lt, r, et, init);
                goto out;
        }
 
        if(ascompat(lt, rt))
                goto out;
 
-bad:
        badtype(n->op, lt, rt);
 
 out:
@@ -2897,15 +2393,13 @@ multi:
        default:
                goto badt;
 
-       case OINDEX:
+       case OINDEXMAP:
                // check if rhs is a map index.
                // if so, types are valuetype,bool
                if(cl != 2)
                        goto badt;
                walkexpr(&nr->left, &init);
                t = nr->left->type;
-               if(!istype(t, TMAP))
-                       goto badt;
                a = mixedoldnew(ll->n, t->type);
                n = list1(a);
                a = mixedoldnew(ll->next->n, types[TBOOL]);
@@ -3387,38 +2881,13 @@ reorder4(NodeList *ll)
        return ll;
 }
 
-static void
-fielddup(Node *n, Node *hash[], ulong nhash)
-{
-       uint h;
-       char *s;
-       Node *a;
-
-       if(n->op != ONAME)
-               fatal("fielddup: not ONAME");
-       s = n->sym->name;
-       h = stringhash(s)%nhash;
-       for(a=hash[h]; a!=N; a=a->ntest) {
-               if(strcmp(a->sym->name, s) == 0) {
-                       yyerror("duplicate field name in struct literal: %s", s);
-                       return;
-               }
-       }
-       n->ntest = hash[h];
-       hash[h] = n;
-}
-
 Node*
 structlit(Node *n, Node *var, NodeList **init)
 {
-       Iter savel;
-       Type *l, *t;
+       Type *t;
        Node *r, *a;
-       Node* hash[101];
        NodeList *nl;
-       int nerr;
 
-       nerr = nerrors;
        t = n->type;
        if(t->etype != TSTRUCT)
                fatal("structlit: not struct");
@@ -3429,141 +2898,45 @@ structlit(Node *n, Node *var, NodeList **init)
        }
 
        nl = n->list;
-       if(nl == nil || nl->n->op == OKEY)
-               goto keyval;
-
-       l = structfirst(&savel, &n->type);
-       for(; nl; nl=nl->next) {
-               r = nl->n;
-               // assignment to every field
-               if(l == T)
-                       break;
-               if(r->op == OKEY) {
-                       yyerror("mixture of value and field:value initializers");
-                       return var;
-               }
 
-               // build list of var.field = expr
-               a = nod(ODOT, var, newname(l->sym));
-               a = nod(OAS, a, r);
+       if(count(n->list) < structcount(t)) {
+               a = nod(OAS, var, N);
                typecheck(&a, Etop);
                walkexpr(&a, init);
-               if(nerr != nerrors)
-                       return var;
                *init = list(*init, a);
-
-               l = structnext(&savel);
        }
-       if(l != T)
-               yyerror("struct literal expect expr of type %T", l);
-       if(nl != nil)
-               yyerror("struct literal too many expressions");
-       return var;
-
-keyval:
-       memset(hash, 0, sizeof(hash));
-       a = nod(OAS, var, N);
-       typecheck(&a, Etop);
-       walkexpr(&a, init);
-       *init = list(*init, a);
 
        for(; nl; nl=nl->next) {
                r = nl->n;
 
-               // assignment to field:value elements
-               if(r->op != OKEY) {
-                       yyerror("mixture of field:value and value initializers");
-                       break;
-               }
-
                // build list of var.field = expr
                a = nod(ODOT, var, newname(r->left->sym));
-               fielddup(a->right, hash, nelem(hash));
-               if(nerr != nerrors)
-                       break;
-
                a = nod(OAS, a, r->right);
                typecheck(&a, Etop);
                walkexpr(&a, init);
-               if(nerr != nerrors)
-                       break;
-
                *init = list(*init, a);
        }
        return var;
 }
 
-static void
-indexdup(Node *n, Node *hash[], ulong nhash)
-{
-       uint h;
-       Node *a;
-       ulong b, c;
-
-       if(n->op != OLITERAL)
-               fatal("indexdup: not OLITERAL");
-
-       b = mpgetfix(n->val.u.xval);
-       h = b%nhash;
-       for(a=hash[h]; a!=N; a=a->ntest) {
-               c = mpgetfix(a->val.u.xval);
-               if(b == c) {
-                       yyerror("duplicate index in array literal: %ld", b);
-                       return;
-               }
-       }
-       n->ntest = hash[h];
-       hash[h] = n;
-}
-
 Node*
 arraylit(Node *n, Node *var, NodeList **init)
 {
        Type *t;
        Node *r, *a;
        NodeList *l;
-       long ninit, b;
-       Node* hash[101];
-       int nerr;
 
-       nerr = nerrors;
        t = n->type;
-       if(t->etype != TARRAY)
-               fatal("arraylit: not array");
-
-       // find max index
-       ninit = 0;
-       b = 0;
-
-       for(l=n->list; l; l=l->next) {
-               r = l->n;
-               if(r->op == OKEY) {
-                       evconst(r->left);
-                       b = nonnegconst(r->left);
-               }
-               b++;
-               if(b > ninit)
-                       ninit = b;
-       }
-
-       b = t->bound;
-       if(b == -100) {
-               // flag for [...]
-               b = ninit;
-               if(var == N)
-                       t = shallow(t);
-               t->bound = b;
-       }
 
        if(var == N) {
                var = nod(OXXX, N, N);
                tempname(var, t);
        }
 
-       if(b < 0) {
+       if(t->bound < 0) {
                // slice
                a = nod(OMAKE, N, N);
-               a->list = list(list1(typenod(t)), nodintconst(ninit));
+               a->list = list(list1(typenod(t)), n->right);
                a = nod(OAS, var, a);
                typecheck(&a, Etop);
                walkexpr(&a, init);
@@ -3571,7 +2944,7 @@ arraylit(Node *n, Node *var, NodeList **init)
        } else {
                // if entire array isnt initialized,
                // then clear the array
-               if(ninit < b) {
+               if(count(n->list) < t->bound) {
                        a = nod(OAS, var, N);
                        typecheck(&a, Etop);
                        walkexpr(&a, init);
@@ -3579,96 +2952,17 @@ arraylit(Node *n, Node *var, NodeList **init)
                }
        }
 
-       b = 0;
-       memset(hash, 0, sizeof(hash));
        for(l=n->list; l; l=l->next) {
                r = l->n;
                // build list of var[c] = expr
-               if(r->op == OKEY) {
-                       b = nonnegconst(r->left);
-                       if(b < 0) {
-                               yyerror("array index must be non-negative constant");
-                               break;
-                       }
-                       r = r->right;
-               }
-
-               if(t->bound >= 0 && b > t->bound) {
-                       yyerror("array index out of bounds");
-                       break;
-               }
-
-               a = nodintconst(b);
-               indexdup(a, hash, nelem(hash));
-               if(nerr != nerrors)
-                       break;
-
-               a = nod(OINDEX, var, a);
-               a = nod(OAS, a, r);
+               a = nod(OINDEX, var, r->left);
+               a = nod(OAS, a, r->right);
                typecheck(&a, Etop);
                walkexpr(&a, init);     // add any assignments in r to top
-               if(nerr != nerrors)
-                       break;
-
                *init = list(*init, a);
-               b++;
-       }
-       return var;
-}
-
-static void
-keydup(Node *n, Node *hash[], ulong nhash)
-{
-       uint h;
-       ulong b;
-       double d;
-       int i;
-       Node *a;
-       Node cmp;
-       char *s;
-
-       evconst(n);
-       if(n->op != OLITERAL)
-               return; // we dont check variables
-
-       switch(n->val.ctype) {
-       default:        // unknown, bool, nil
-               b = 23;
-               break;
-       case CTINT:
-               b = mpgetfix(n->val.u.xval);
-               break;
-       case CTFLT:
-               d = mpgetflt(n->val.u.fval);
-               s = (char*)&d;
-               b = 0;
-               for(i=sizeof(d); i>0; i--)
-                       b = b*PRIME1 + *s++;
-               break;
-       case CTSTR:
-               b = 0;
-               s = n->val.u.sval->s;
-               for(i=n->val.u.sval->len; i>0; i--)
-                       b = b*PRIME1 + *s++;
-               break;
        }
 
-       h = b%nhash;
-       memset(&cmp, 0, sizeof(cmp));
-       for(a=hash[h]; a!=N; a=a->ntest) {
-               cmp.op = OEQ;
-               cmp.left = n;
-               cmp.right = a;
-               evconst(&cmp);
-               b = cmp.val.u.bval;
-               if(b) {
-                       // too lazy to print the literal
-                       yyerror("duplicate key in map literal");
-                       return;
-               }
-       }
-       n->ntest = hash[h];
-       hash[h] = n;
+       return var;
 }
 
 Node*
@@ -3700,16 +2994,7 @@ maplit(Node *n, Node *var, NodeList **init)
        memset(hash, 0, sizeof(hash));
        for(l=n->list; l; l=l->next) {
                r = l->n;
-               if(r->op != OKEY) {
-                       yyerror("map literal must have key:value pairs");
-                       break;
-               }
-
                // build list of var[c] = expr
-               keydup(r->left, hash, nelem(hash));
-               if(nerr != nerrors)
-                       break;
-
                a = nod(OINDEX, var, r->left);
                a = nod(OAS, a, r->right);
                typecheck(&a, Etop);
@@ -3722,72 +3007,6 @@ maplit(Node *n, Node *var, NodeList **init)
        return var;
 }
 
-/*
- * the address of n has been taken and might be used after
- * the current function returns.  mark any local vars
- * as needing to move to the heap.
- */
-void
-addrescapes(Node *n)
-{
-       char buf[100];
-       switch(n->op) {
-       default:
-               // probably a type error already.
-               // dump("addrescapes", n);
-               break;
-
-       case ONAME:
-               if(n->noescape)
-                       break;
-               switch(n->class) {
-               case PPARAMOUT:
-                       yyerror("cannot take address of out parameter %s", n->sym->name);
-                       break;
-               case PAUTO:
-               case PPARAM:
-                       // if func param, need separate temporary
-                       // to hold heap pointer.
-                       if(n->class == PPARAM) {
-                               // expression to refer to stack copy
-                               n->stackparam = nod(OPARAM, n, N);
-                               n->stackparam->type = n->type;
-                               n->stackparam->addable = 1;
-                               n->stackparam->xoffset = n->xoffset;
-                       }
-
-                       n->class |= PHEAP;
-                       n->addable = 0;
-                       n->ullman = 2;
-                       n->alloc = callnew(n->type);
-                       n->xoffset = 0;
-
-                       // create stack variable to hold pointer to heap
-                       n->heapaddr = nod(0, N, N);
-                       tempname(n->heapaddr, ptrto(n->type));
-                       snprint(buf, sizeof buf, "&%S", n->sym);
-                       n->heapaddr->sym = lookup(buf);
-                       break;
-               }
-               break;
-
-       case OIND:
-       case ODOTPTR:
-               break;
-
-       case ODOT:
-       case OINDEX:
-               // ODOTPTR has already been introduced,
-               // so these are the non-pointer ODOT and OINDEX.
-               // In &x[0], if x is a slice, then x does not
-               // escape--the pointer inside x does, but that
-               // is always a heap pointer anyway.
-               if(!isslice(n->left->type))
-                       addrescapes(n->left);
-               break;
-       }
-}
-
 /*
  * walk through argin parameters.
  * generate and return code to allocate
@@ -3843,7 +3062,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
        n = fn->type->intuple;
        for(i=0; i<n; i++)
                args = list(args, va_arg(va, Node*));
-       
+
        r = nod(OCALL, fn, N);
        r->list = args;
        if(fn->type->outtuple > 0)
@@ -3860,7 +3079,7 @@ mkcall(char *name, Type *t, NodeList **init, ...)
 {
        Node *r;
        va_list va;
-       
+
        va_start(va, init);
        r = vmkcall(syslook(name, 0), t, init, va);
        va_end(va);
@@ -3872,7 +3091,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...)
 {
        Node *r;
        va_list va;
-       
+
        va_start(va, init);
        r = vmkcall(fn, t, init, va);
        va_end(va);
@@ -3887,7 +3106,6 @@ conv(Node *n, Type *t)
        n = nod(OCONV, n, N);
        n->type = t;
        typecheck(&n, Erv);
-       walkexpr(&n, nil);
        return n;
 }
 
index cdbef6246c92637d80f21ebe2a7378eb2c48d80e..b19cbf3261e784ad33846d07cddf0b5344917f38 100644 (file)
@@ -15,10 +15,10 @@ var (
 func main() {
        cr = c;         // ok
        cs = c;         // ok
-       c = cr;         // ERROR "illegal types|incompatible"
-       c = cs;         // ERROR "illegal types|incompatible"
-       cr = cs;        // ERROR "illegal types|incompatible"
-       cs = cr;        // ERROR "illegal types|incompatible"
+       c = cr;         // ERROR "illegal types|incompatible|cannot"
+       c = cs;         // ERROR "illegal types|incompatible|cannot"
+       cr = cs;        // ERROR "illegal types|incompatible|cannot"
+       cs = cr;        // ERROR "illegal types|incompatible|cannot"
 
        c <- 0;         // ok
        ok := c <- 0;   // ok
index 0d48ada5e2dce69003e87558aef434e13ca3b9ec..622b837a54b21fffe81f9aa37a14c7c80ef09bb8 100644 (file)
@@ -65,15 +65,15 @@ var (
 func f(int);
 
 func main() {
-       f(Int8);        // ERROR "convert|wrong type"
-       f(Minus1);      // ERROR "convert|wrong type"
-       f(Uint8);       // ERROR "convert|wrong type"
+       f(Int8);        // ERROR "convert|wrong type|cannot"
+       f(Minus1);      // ERROR "convert|wrong type|cannot"
+       f(Uint8);       // ERROR "convert|wrong type|cannot"
        f(Const);       // OK
-       f(Float32);     // ERROR "convert|wrong type"
-       f(Float);       // ERROR "convert|wrong type"
+       f(Float32);     // ERROR "convert|wrong type|cannot"
+       f(Float);       // ERROR "convert|wrong type|cannot"
        f(ConstFloat);  // ERROR "truncate"
        f(ConstFloat - 0.5);    // OK
-       f(Big); // ERROR "convert|wrong type"
-       f(String);      // ERROR "convert|wrong type"
-       f(Bool);        // ERROR "convert|wrong type"
+       f(Big); // ERROR "convert|wrong type|cannot"
+       f(String);      // ERROR "convert|wrong type|cannot"
+       f(Bool);        // ERROR "convert|wrong type|cannot"
 }
index d733ce2c30a7f54462d8e165f04d7cb57d0efb6e..cb05000128f365ee878d5ebeacb4e5a34cca36c8 100644 (file)
@@ -21,5 +21,5 @@ var g = []int(nil)
 type H *[4]int
 type J []int
 var h H
-var j1 J = h   // ERROR "compat|illegal"
+var j1 J = h   // ERROR "compat|illegal|cannot|cannot"
 var j2 = J(h)
index be12e63835455f6eb4296d19c4e9744246cc5ec6..e65dad3df69c1c8f6ff13394ba4f8c2db52bcec6 100644 (file)
@@ -19,11 +19,11 @@ var x7 = float(1e1000);     // ERROR "overflow"
 
 // implicit conversions merit scrutiny
 var s string;
-var bad1 string = 1;   // ERROR "conver|incompatible"
-var bad2 = s + 1;              // ERROR "conver|incompatible"
-var bad3 = s + 'a';    // ERROR "conver|incompatible"
-var bad4 = "a" + 1;    // ERROR "literals|incompatible|convert"
-var bad5 = "a" + 'a';  // ERROR "literals|incompatible|convert"
+var bad1 string = 1;   // ERROR "conver|incompatible|invalid|cannot"
+var bad2 = s + 1;              // ERROR "conver|incompatible|invalid"
+var bad3 = s + 'a';    // ERROR "conver|incompatible|invalid"
+var bad4 = "a" + 1;    // ERROR "literals|incompatible|convert|invalid"
+var bad5 = "a" + 'a';  // ERROR "literals|incompatible|convert|invalid"
 
 var bad6 int = 1.5;    // ERROR "convert|truncate"
 var bad7 int = 1e100;  // ERROR "overflow"
index 94d28969b793c0b0f51bddc244faf99671971305..1e6673cb641b9742a5f46f1a3f4bf559f3f7e606 100644 (file)
@@ -6,12 +6,12 @@
 
 package main
 
-var a = []int { "a" }; // ERROR "conver|incompatible"
+var a = []int { "a" }; // ERROR "conver|incompatible|cannot"
 var b = int { 1 };     // ERROR "compos"
 
 
 func f() int
 
 func main() {
-       if f < 1 { }    // ERROR "conver|incompatible"
+       if f < 1 { }    // ERROR "conver|incompatible|invalid"
 }
index 79641487079965421e17187b7bab348c5dc4d2f3..0250135a52808cc7b20acc97ab00aadb3bbef0b1 100644 (file)
@@ -9,7 +9,7 @@ package main
 func putint(digits *string) {
        var i byte;
        i = (*digits)[7];  // compiles
-       i = digits[7];  // ERROR "illegal|is not"
+       i = digits[7];  // ERROR "illegal|is not|invalid"
 }
 
 func main() {
index 8a9ba959ec906d1d9961e2b01285eadd9847568f..4346c5a5f9ef61c77201a1063d731eb6a519be38 100644 (file)
@@ -7,5 +7,5 @@
 package main
 
 func main() {
-  var s string = nil;  // ERROR "illegal|invalid"
+  var s string = nil;  // ERROR "illegal|invalid|cannot"
 }
index 50e08b7f583488a7c7a590cb666083dfcf3a4989..8318ab9c0c0ac1f78e924bc98dc9924b2940fa35 100644 (file)
@@ -38,9 +38,9 @@ func main() {
        assert(i != f3div2, "i != f3div2");     // ERROR "truncate"
 
        const g float64 = 1.0;
-       i = g;  // ERROR "convert|incompatible"
+       i = g;  // ERROR "convert|incompatible|cannot"
 
        const h float64 = 3.14;
-       i = h;  // ERROR "convert|incompatible"
+       i = h;  // ERROR "convert|incompatible|cannot"
        i = int(h);     // ERROR "truncate"
 }
index 5840095b9cd43c80696834678480649651ee4797..6473fa995a804a1b7b73a769ad95c3586b9a9744 100644 (file)
@@ -10,16 +10,6 @@ type T func()
 
 type I interface {
        f, g ();
-       h T;  // should only allow FunctionType here
+       h T;  // ERROR "syntax"
 }
 
-type S struct {
-}
-
-func (s *S) f() {}
-func (s *S) g() {}
-func (s *S) h() {}  // here we can't write (s *S) T either
-
-func main() {
-       var i I = new(S);
-}
index 376f528f657d0d7f659317c5df87c58973508db1..c2644c4a3f8d554bd6f7b3dceaa471b4ecdfc412 100644 (file)
@@ -8,5 +8,5 @@ package main
 
 func main() {
   const a uint64 = 10;
-  var b int64 = a;     // ERROR "convert"
+  var b int64 = a;     // ERROR "convert|cannot"
 }
index aef8476453161cae75a20d23922d8612fff21f96..41a6d3afd916d0a4be2d5a8bba526fe2ddf54bfb 100644 (file)
@@ -10,5 +10,5 @@ func main() {
        type Slice []byte;
        a := [...]byte{ 0 };
        b := Slice(&a);         // This should be OK.
-       c := Slice(a);          // ERROR "invalid|illegal"
+       c := Slice(a);          // ERROR "invalid|illegal|cannot"
 }
index b04e7718717daecc046f8601f501116a20f343b1..e7f1c5120dc61a5eb226742dd896c7fccee848f4 100644 (file)
@@ -5,9 +5,10 @@
 // license that can be found in the LICENSE file.
 
 package main
-var v1 = ([10]int)(nil)                // ERROR "illegal|nil|invalid"
-var v2 [10]int = nil           // ERROR "illegal|nil|incompatible"
-var v3 [10]int
+var v1 = ([10]int)(nil);       // ERROR "illegal|nil|invalid"
+var v2 [10]int = nil;          // ERROR "illegal|nil|incompatible"
+var v3 [10]int;
+var v4 = nil;  // ERROR "nil"
 func main() {
        v3 = nil;               // ERROR "illegal|nil|incompatible"
 }
index f9e394fdf7dd962abb7f89c323543b40e201f94f..bcf5b93fa40e15f3b0e26285bb2faa215ce0697d 100644 (file)
@@ -9,6 +9,6 @@ package main
 var notmain func()
 
 func main() {
-       var x = &main;          // ERROR "address of function|invalid"
-       main = notmain; // ERROR "assign to function|invalid"
+       var x = &main;          // ERROR "address of|invalid"
+       main = notmain; // ERROR "assign to|invalid"
 }
index ca01bd2a660e658daf20d57caa09f60841d5a874..d1403736b9e87702d0adfdd10cfc33fdc66f67d6 100644 (file)
@@ -132,13 +132,6 @@ throw: interface conversion
 
 panic PC=xxx
 
-=========== fixedbugs/bug121.go
-fixedbugs/bug121.go:9: syntax error near T
-fixedbugs/bug121.go:20: incomplete type I
-fixedbugs/bug121.go:20: illegal types for operand: AS
-       I
-       *S
-
 =========== fixedbugs/bug148.go
 2 3
 interface is main.T, not main.T·bug148·1
index 202c37d86054b0ac8605dedb9a506675ced83172..d94ec7cadad6d222d00e82d4091427dc0dd46645 100644 (file)
@@ -32,6 +32,6 @@ func AddInst(Inst) *Inst {
 func main() {
        re := new(Regexp);
        print("call addinst\n");
-       var x Inst = AddInst(new(Start));       // ERROR "illegal|incompatible"
+       var x Inst = AddInst(new(Start));       // ERROR "illegal|incompatible|is not"
        print("return from  addinst\n");
 }