more 6g reorg; checkpoint.
typecheck.c is now responsible for all type checking
except for assignment and function argument "..."

R=ken
OCL=32661
CL=32667
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 77a4532..6a48dfa 100755
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -907,6 +907,8 @@
 		n->class = PPARAM;
 		break;
 	}
+
+	n->typecheck = 1;
 	return n;
 }
 
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 8b4046b..bbbc8d7 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -200,8 +200,6 @@
 		defaultlit(&n, T);
 		*np = n;
 	}
-	yyerror("cannot convert %T constant to %T", n->type, t);
-	n->diag = 1;
 	return;
 }
 
@@ -336,6 +334,9 @@
 
 	switch(n->op) {
 	case OMAKE:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case OMAKECHAN:
 		return;
 	}
 
@@ -557,7 +558,7 @@
 		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 @@
 	case TUP(OCONV, CTFLT):
 	case TUP(OCONV, CTSTR):
 	case TUP(OCONV, CTNIL):
+	case TUP(OARRAYBYTESTR, CTNIL):
 		convlit1(&nl, n->type, 1);
 		break;
 
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 978d050..d1802c8 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -672,9 +672,9 @@
 	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 @@
 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 @@
 				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");
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 33969ec..7b2776d 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -328,36 +328,41 @@
 	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
 {
 	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	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*	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*	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);
 
 /*
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 97800d3..4e280c1 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -123,7 +123,8 @@
 	{
 		if(debug['f'])
 			frame(1);
-		fninit($4);
+		if(nerrors == 0)
+			fninit($4);
 		if(nsyntaxerrors == 0)
 			testdclstack();
 	}
@@ -882,7 +883,7 @@
 |	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 '{' braced_keyval_list '}'
 	{
 		// composite expression
-		$$ = nod(OCOMPOS, N, $1);
+		$$ = nod(OCOMPLIT, N, $1);
 		$$->list = $3;
 	}
 |	fnliteral
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index 18d1ba3..5792422 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -208,11 +208,12 @@
 		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);
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 10cbc36..485b7f6 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -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
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index d05830b..52cd3a0 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -1209,6 +1209,14 @@
 		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 @@
 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 @@
 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 @@
 		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 @@
 		walkexpr(&a, init);
 		*init = list(*init, a);
 		r = nod(OIND, l, N);
-		typecheck(&r, Elv);
+		typecheck(&r, Erv);
 		walkexpr(&r, init);
 		return r;
 	}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index ac83ca8..5f82b08 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -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 @@
 }
 
 /*
- * 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 @@
 		goto ret;
 
 	case ONONAME:
-		ok |= Elv | Erv;
+		ok |= Erv;
 		goto ret;
 
 	case ONAME:
@@ -72,8 +92,6 @@
 			goto error;
 		}
 		ok |= Erv;
-		if(n->class != PFUNC)
-			ok |= Elv;
 		goto ret;
 
 	/*
@@ -187,7 +205,7 @@
 	 * 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 @@
 			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 @@
 	 */
 	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 @@
 				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 @@
 	 * 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)
+	case OCOMPLIT:
+		typecheckcomplit(&n);
+		if(n->type == T)
 			goto error;
-		nerr = nerrors;
-		switch(t->etype) {
-		case TARRAY:
-			len = 0;
-			i = 0;
-			for(ll=n->list; ll; ll=ll->next) {
-				l = ll->n;
-				if(l->op == OKEY) {
-					typecheck(&l->left, Erv);
-					evconst(l->left);
-					i = nonnegconst(l->left);
-					typecheck(&l->right, Erv);
-					defaultlit(&l->right, t->type);
-					// TODO more forceful conversion of l->right
-				} else {
-					typecheck(&ll->n, Erv);
-					defaultlit(&ll->n, t->type);
-					// TODO more forceful conversion
-				}
-				i++;
-				if(i > len) {
-					len = i;
-					if(t->bound >= 0 && len > t->bound) {
-						setlineno(l);
-						yyerror("array index out of bounds");
-						t->bound = -1;	// no more errors
-					}
-				}
-			}
-			if(t->bound == -100)
-				t->bound = len;
-			break;
-
-		case TMAP:
-			for(ll=n->list; ll; ll=ll->next) {
-				l = ll->n;
-				if(l->op != OKEY) {
-					yyerror("missing key in map literal");
-					continue;
-				}
-				typecheck(&l->left, Erv);
-				typecheck(&l->right, Erv);
-				defaultlit(&l->left, t->down);
-				defaultlit(&l->right, t->type);
-				// TODO more forceful
-			}
-			break;
-
-		case TSTRUCT:
-		//	fatal("compos %T", t);
-			;
-		}
-		if(nerr != nerrors)
-			goto error;
-		n->type = t;
 		goto ret;
 
 	case ODOT:
@@ -399,7 +388,7 @@
 			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 @@
 			break;
 		default:
 			ok |= Erv;
-			// TODO ok |= Elv sometimes
 			break;
 		}
 		goto ret;
@@ -448,24 +436,24 @@
 			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 @@
 		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 @@
 		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 @@
 		// 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 @@
 		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 @@
 			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:
-			n->type = typ(TARRAY);
-			n->type->type = t;
-			n->type->bound = -1;
-			n = arrayop(n);
-			break;
-
-		case TSTRING:
+		if(istype(t, TSTRING)) {
 			n->type = t;
-			n = stringop(n, nil);
-			break;
+			n->op = OSLICESTR;
+			goto ret;
 		}
-		goto ret;
+		if(isfixedarray(t)) {
+			n->type = typ(TARRAY);
+			n->type->type = t->type;
+			n->type->bound = -1;
+			dowidth(n->type);
+			n->op = OSLICEARR;
+			goto ret;
+		}
+		if(isslice(t)) {
+			n->type = t;
+			goto ret;
+		}
+		yyerror("cannot slice %#N (type %T)", l, t);
+		goto error;
 
 	/*
 	 * call and call like
@@ -572,14 +561,16 @@
 			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 @@
 			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 @@
 		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("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("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 @@
 					goto error;
 				}
 				n->left = l;
-			}
+			} else
+				n->left = nodintconst(0);
+			n->op = OMAKEMAP;
 			break;
 
 		case TCHAN:
@@ -757,11 +765,14 @@
 					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 @@
 	 * 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 @@
 
 	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 @@
 		goto ret;
 
 	case OTYPECASE:
-		typecheck(&n->left, Elv);
+		typecheck(&n->left, Erv);
 		goto ret;
 
 	case OTYPESW:
@@ -870,7 +887,7 @@
 		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 @@
 		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 @@
 		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 @@
 	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;
 
-	// XXX wtf?
+	/*
+	 * implicit conversions
+	 */
+
 	convlit1(&n, t, explicit);
 	if(n->type == T)
-		return -1;
+		return n;
 
-	// no-op conversion
-	if(cvttype(t, n->type) == 1) {
+	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;
+		}
+	}
+
+	// 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;
 		}
 
-		// []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;
+		// *[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 -> 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;
 
-	yyerror("cannot convert %#N (type %T) to type %T", n, n->type, t);
-	return -1;
+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;
+}
+
+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);
 }
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 91f1ea8..d9f2a90 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -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 @@
 walk(Node *fn)
 {
 	char s[50];
-	// int nerr;
 
 	curfn = fn;
 	if(debug['W']) {
@@ -89,12 +86,9 @@
 	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 @@
 		dump("nottop", n);
 		break;
 
+	case OAPPENDSTR:
 	case OASOP:
 	case OAS:
 	case OAS2:
@@ -336,16 +331,22 @@
 	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 @@
 		fatal("missed typecheck");
 	}
 
-reswitch:
 	t = T;
 	et = Txxx;
 
@@ -367,15 +367,9 @@
 		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 @@
 	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 @@
 	case OPANIC:
 	case OPANICN:
 		walkexprlist(n->list, init);
-		n = prcompat(n);
+		n = walkprint(n, init);
 		goto ret;
 
 	case OLITERAL:
@@ -420,104 +421,50 @@
 	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 OCALLINTER:
+		t = n->left->type;
+		if(n->list && n->list->n->op == OAS)
+			goto ret;
+		walkexpr(&n->left, init);
+		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(n->list && n->list->n->op == OAS)
+			goto ret;
+		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;
 
-	case OCALL:
-		if(n->left == N)
-			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);
-
+	case OCALLMETH:
 		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;
-		}
-
-		if(t->etype != TFUNC) {
-			yyerror("call of a non-function: %T", t);
-			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 @@
 			}
 			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 @@
 				}
 				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 @@
 		}
 
 		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 @@
 
 	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 @@
 			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 @@
 		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 @@
 	case OINDEX:
 		walkexpr(&n->left, init);
 		walkexpr(&n->right, init);
-		if(n->left == N || n->right == N)
-			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;
-		}
 		goto ret;
 
-	case OCLOSE:
-	case OCLOSED:
-	case OSEND:
+	case OINDEXMAP:
+		if(n->etype == 1)
+			goto ret;
+		t = n->left->type;
+		n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
+		goto ret;
+
 	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)
-			goto ret;
-		if(t->etype == TSTRING) {
-			n = stringop(n, nil);
-			goto ret;
-		}
-		if(t->etype == TARRAY) {
-			n = arrayop(n);
-			goto ret;
-		}
+		// 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 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 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;
 
-			Node *nvar, *nas, *nstar;
+	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
+		// 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;
 
-			nvar = nod(OXXX, N, N);
-			tempname(nvar, ptrto(n->left->type));
+		case OMAPLIT:
+			nvar = makenewvar(n->type, init, &nstar);
+			maplit(n->left, nstar, init);
+			n = nvar;
+			goto ret;
 
-			nas = nod(OAS, nvar, callnew(n->left->type));
-			typecheck(&nas, Etop);
-			walkexpr(&nas, init);
-			*init = list(*init, nas);
 
-			nstar = nod(OIND, nvar, N);
-			nstar->type = n->left->type;
-
-			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;
-			}
-
-//			walkexpr(&n->left->left, init);
+		case OSTRUCTLIT:
+			nvar = makenewvar(n->type, init, &nstar);
+			structlit(n->left, nstar, init);
 			n = nvar;
 			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);
-		goto ret;
-
-	case OMAKE:
-		n = makecompat(n);
 		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)
-			;
+		n = callnew(n->type->type);
+		goto ret;
+
+	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;
+
+	case OADDSTR:
+		// sys_catstring(s1, s2)
+		n = mkcall("catstring", n->type, init,
+			conv(n->left, types[TSTRING]),
+			conv(n->right, types[TSTRING]));
+		goto ret;
+
+	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;
+
+	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;
+
+	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;
+
+	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;
+
+	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;
+
+	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 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 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 @@
 	*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 @@
 	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 @@
 	// if using .(T), interface assertion.
 	if(n->op == ODOTTYPE) {
 		et = ifaceas1(t, l->type, 1);
-		if(et == I2Isame || et == E2Esame)
-			goto nop;
+		if(et == I2Isame || et == E2Esame) {
+			n->op = OCONVNOP;
+			return;
+		}
 		if(et != Inone) {
-			n = ifacecvt(t, l, et);
+			n = ifacecvt(t, l, et, init);
 			*np = n;
 			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);
-			*np = n;
-			return;
-		}
-	}
-
-	// 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 @@
 			break;
 
 		case OSEND:
+		case OSENDNB:
 		case ORECV:
 			break;
 		}
@@ -1325,14 +1262,15 @@
 	 * 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 @@
 		}
 		goto ret;
 	}
-	convlit(&r, l->type);
+
 	if(!ascompat(l->type, r->type)) {
 		badtype(op, l->type, r->type);
 		return nil;
@@ -1677,59 +1615,14 @@
 }
 
 /*
- * 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.
  */
 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 @@
 
 // generate code for print
 static Node*
-prcompat(Node *nn)
+walkprint(Node *nn, NodeList **init)
 {
 	Node *r;
 	Node *n;
@@ -1792,10 +1685,9 @@
 
 	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 @@
 			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,65 +1753,19 @@
 	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)
 {
 	Node *fn;
@@ -1930,93 +1776,6 @@
 	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 @@
 {
 	Node *r, *a, *l;
 	Type *t;
-	Node *fn, *hint;
+	Node *fn;
 	int cl, cr;
 	NodeList *args;
 
@@ -2070,49 +1829,9 @@
 	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 @@
 	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 @@
 
 //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 @@
 
 		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);
@@ -2203,7 +1921,7 @@
 Node*
 chanop(Node *n, NodeList **init)
 {
-	Node *r, *a, *fn;
+	Node *r, *fn;
 	Type *t;
 	int cl, cr;
 
@@ -2212,48 +1930,6 @@
 	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;
-
-		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;
-
 	case OAS2:
 		cl = count(n->list);
 		cr = count(n->rlist);
@@ -2278,45 +1954,6 @@
 		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 @@
 	return N;
 }
 
+
 Type*
 fixarray(Type *t)
 {
@@ -2344,104 +1982,6 @@
 
 }
 
-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 @@
 };
 
 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 @@
 	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 @@
 		on = syslook("ifaceT2I", 1);
 		argtype(on, tr);
 		argtype(on, tl);
+		dowidth(on->type);
 		break;
 
 	case I2T:
@@ -2586,46 +2131,11 @@
 	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)
 {
 	Node *l, *r;
@@ -2634,6 +2144,7 @@
 
 	if(n->op != OAS)
 		fatal("convas: not OAS %O", n->op);
+	n->typecheck = 1;
 
 	lt = T;
 	rt = T;
@@ -2648,38 +2159,23 @@
 	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 @@
 	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 @@
 	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 @@
 	}
 
 	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 @@
 	} 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,98 +2952,19 @@
 		}
 	}
 
-	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;
-}
-
 Node*
 maplit(Node *n, Node *var, NodeList **init)
 {
@@ -3700,16 +2994,7 @@
 	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);
@@ -3723,72 +3008,6 @@
 }
 
 /*
- * 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
  * copies of escaped parameters to the heap.
@@ -3843,7 +3062,7 @@
 	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 @@
 {
 	Node *r;
 	va_list va;
-	
+
 	va_start(va, init);
 	r = vmkcall(syslook(name, 0), t, init, va);
 	va_end(va);
@@ -3872,7 +3091,7 @@
 {
 	Node *r;
 	va_list va;
-	
+
 	va_start(va, init);
 	r = vmkcall(fn, t, init, va);
 	va_end(va);
@@ -3887,7 +3106,6 @@
 	n = nod(OCONV, n, N);
 	n->type = t;
 	typecheck(&n, Erv);
-	walkexpr(&n, nil);
 	return n;
 }