update type switch to match spec.

R=ken
OCL=34471
CL=34471
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index ea348c0..c933357 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -375,7 +375,7 @@
 	OSELECT,
 	OSWITCH,
 	OTYPECASE,
-	OTYPESW,
+	OTYPESW,	// l = r.(type)
 
 	// types
 	OTCHAN,
@@ -676,7 +676,8 @@
 EXTERN	int	maxround;
 EXTERN	int	widthptr;
 
-EXTERN	Node*	typeswvar;
+EXTERN	Node*	typesw;
+EXTERN	Node*	nblank;
 
 EXTERN	char*	structpkg;
 extern	int	thechar;
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 920799e..bb8a588 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -191,7 +191,7 @@
 		my->lastlineno = $1;
 		import->block = 1;	// at top level
 	}
-	
+
 
 import_stmt_list:
 	import_stmt
@@ -230,10 +230,10 @@
 		pkgimportname = $2;
 		if(strcmp($2->name, "main") == 0)
 			yyerror("cannot import package main");
-			
+
 		// TODO(rsc): This is not quite precise enough a check
 		// (it excludes google/util/hash from importing hash)
-		// but it is enough to reduce confusion during the 
+		// but it is enough to reduce confusion during the
 		// 2009/09/01 release when all the "import myself"
 		// statements have to go away in programs building
 		// against the release.  Once the programs have converted
@@ -424,7 +424,7 @@
 				yyerror("expr.(type) must be alone in list");
 			else if($1->next != nil)
 				yyerror("argument count mismatch: %d = %d", count($1), 1);
-			$$ = nod(OTYPESW, $1->n, $3->n->left);
+			$$ = nod(OTYPESW, $1->n, $3->n->right);
 			break;
 		}
 		$$ = colas($1, $3);
@@ -443,30 +443,19 @@
 case:
 	LCASE expr_or_type_list ':'
 	{
-		Node *n, *ntype;
+		Node *n;
 
 		// will be converted to OCASE
 		// right will point to next case
 		// done in casebody()
 		poptodcl();
 		$$ = nod(OXCASE, N, N);
-		if(typeswvar != N && typeswvar->right != N) {
-			// type switch
-			ntype = $2->n;
-			if($2->next != nil)
-				yyerror("type switch case cannot be list");
-			if(ntype->op == OLITERAL && ntype->val.ctype == CTNIL) {
-				// case nil
-				$$->list = list1(nod(OTYPECASE, N, N));
-				break;
-			}
-			n = newname(typeswvar->right->sym);
+		$$->list = $2;
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			n = newname(n->sym);
 			declare(n, dclcontext);
-			n->ntype = ntype;
-			$$->list = list1(nod(OTYPECASE, n, N));
-		} else {
-			// expr switch
-			$$->list = $2;
+			$$->nname = n;
 		}
 		break;
 	}
@@ -490,8 +479,16 @@
 	}
 |	LDEFAULT ':'
 	{
+		Node *n;
+
 		poptodcl();
 		$$ = nod(OXCASE, N, N);
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			n = newname(n->sym);
+			declare(n, dclcontext);
+			$$->nname = n;
+		}
 	}
 
 compound_stmt:
@@ -637,18 +634,16 @@
 	{
 		Node *n;
 		n = $3->ntest;
-		if(n != N && n->op == OTYPESW)
-			n = n->left;
-		else
+		if(n != N && n->op != OTYPESW)
 			n = N;
-		typeswvar = nod(OXXX, typeswvar, n);
+		typesw = nod(OXXX, typesw, n);
 	}
 	switch_body
 	{
 		$$ = $3;
 		$$->op = OSWITCH;
 		$$->list = $5;
-		typeswvar = typeswvar->left;
+		typesw = typesw->left;
 		popdcl();
 	}
 
@@ -823,7 +818,7 @@
 	}
 |	pexpr '.' '(' LTYPE ')'
 	{
-		$$ = nod(OTYPESW, $1, N);
+		$$ = nod(OTYPESW, N, $1);
 	}
 |	pexpr '[' expr ']'
 	{
@@ -1289,20 +1284,14 @@
 	name_or_type
 |	sym name_or_type
 	{
-		$$ = $1->def;
-		if($$ == N) {
-			$$ = nod(ONONAME, N, N);
-			$$->sym = $1;
-		}
+		$$ = nod(ONONAME, N, N);
+		$$->sym = $1;
 		$$ = nod(OKEY, $$, $2);
 	}
 |	sym dotdotdot
 	{
-		$$ = $1->def;
-		if($$ == N) {
-			$$ = nod(ONONAME, N, N);
-			$$->sym = $1;
-		}
+		$$ = nod(ONONAME, N, N);
+		$$->sym = $1;
 		$$ = nod(OKEY, $$, $2);
 	}
 |	dotdotdot
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 73223c8..42bbe04 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1359,6 +1359,7 @@
 	s->def->sym = s;
 	types[TBLANK] = typ(TBLANK);
 	s->def->type = types[TBLANK];
+	nblank = s->def;
 }
 
 struct
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index 002bd4e..60696e6 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -249,13 +249,13 @@
  * deal with fallthrough, break, unreachable statements
  */
 void
-casebody(Node *sw)
+casebody(Node *sw, Node *typeswvar)
 {
 	Node *os, *oc, *n, *c, *last;
 	Node *def;
 	NodeList *cas, *stat, *l, *lc;
 	Node *go, *br;
-	int32 lno;
+	int32 lno, needvar;
 
 	lno = setlineno(sw);
 	if(sw->list == nil)
@@ -274,6 +274,7 @@
 		if(n->op != OXCASE)
 			fatal("casebody %O", n->op);
 		n->op = OCASE;
+		needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
 
 		go = nod(OGOTO, newlabel(), N);
 		if(n->list == nil) {
@@ -300,6 +301,14 @@
 		}
 
 		stat = list(stat, nod(OLABEL, go->left, N));
+		if(typeswvar && needvar && n->nname != N) {
+			NodeList *l;
+
+			l = list1(nod(ODCL, n->nname, N));
+			l = list(l, nod(OAS, n->nname, typeswvar));
+			typechecklist(l, Etop);
+			stat = concat(stat, l);
+		}
 		stat = concat(stat, n->nbody);
 
 		// botch - shouldnt fall thru declaration
@@ -348,16 +357,16 @@
 		switch(arg) {
 		case Stype:
 			c->hash = 0;
-			if(n->left->left == N) {
+			if(n->left->op == OLITERAL) {
 				c->type = Ttypenil;
 				continue;
 			}
-			if(istype(n->left->left->type, TINTER)) {
+			if(istype(n->left->type, TINTER)) {
 				c->type = Ttypevar;
 				continue;
 			}
 
-			c->hash = typehash(n->left->left->type);
+			c->hash = typehash(n->left->type);
 			c->type = Ttypeconst;
 			continue;
 
@@ -483,6 +492,7 @@
 	Type *t;
 	int arg, ncase;
 
+	casebody(sw, N);
 
 	arg = Snorm;
 	if(isconst(sw->ntest, CTBOOL)) {
@@ -564,13 +574,18 @@
 	NodeList *init;
 	Node *a, *b, *var;
 
-	var = t->left->left;
-	init = list1(nod(ODCL, var, N));
+	var = t->nname;
+	init = nil;
+	if(var == N) {
+		typecheck(&nblank, Erv | Easgn);
+		var = nblank;
+	} else
+		init = list1(nod(ODCL, var, N));
 
 	a = nod(OAS2, N, N);
 	a->list = list(list1(var), boolname);	// var,bool =
 	b = nod(ODOTTYPE, facename, N);
-	b->type = t->left->left->type;		// interface.(type)
+	b->type = t->left->type;		// interface.(type)
 	a->rlist = list1(b);
 	typecheck(&a, Etop);
 	init = list(init, a);
@@ -678,6 +693,8 @@
 	typecheck(&a, Etop);
 	cas = list(cas, a);
 
+	casebody(sw, facename);
+
 	boolname = nod(OXXX, N, N);
 	tempname(boolname, types[TBOOL]);
 	typecheck(&boolname, Erv);
@@ -758,10 +775,10 @@
 		sw->ntest = nodbool(1);
 		typecheck(&sw->ntest, Erv);
 	}
-	casebody(sw);
-
+	
 	if(sw->ntest->op == OTYPESW) {
 		typeswitch(sw);
+//dump("sw", sw);
 		return;
 	}
 	exprswitch(sw);
@@ -776,7 +793,7 @@
 	int top, lno;
 	Type *t;
 	NodeList *l, *ll;
-	Node *ncase;
+	Node *ncase, *nvar;
 	Node *def;
 
 	lno = lineno;
@@ -784,11 +801,11 @@
 
 	if(n->ntest != N && n->ntest->op == OTYPESW) {
 		// type switch
-		typecheck(&n->ntest, Etop);
 		top = Etype;
-		t = n->ntest->type;
+		typecheck(&n->ntest->right, Erv);
+		t = n->ntest->right->type;
 		if(t != T && t->etype != TINTER)
-			yyerror("cannot type switch on non-interface value %+N", n->ntest);
+			yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
 	} else {
 		// value switch
 		top = Erv;
@@ -814,12 +831,37 @@
 		} else {
 			for(ll=ncase->list; ll; ll=ll->next) {
 				setlineno(ll->n);
-				typecheck(&ll->n, Erv);	// TODO(rsc): top
-				if(ll->n->type == T || t == T || top != Erv)
+				typecheck(&ll->n, Erv | Etype);
+				if(ll->n->type == T || t == T)
 					continue;
-				defaultlit(&ll->n, t);
-				if(ll->n->type != T && !eqtype(ll->n->type, t))
-					yyerror("case %+N in switch of %+N %#O", ll->n, n->ntest, ll->n->op);
+				switch(top) {
+				case Erv:	// expression switch
+					defaultlit(&ll->n, t);
+					if(ll->n->op == OTYPE)
+						yyerror("type %T is not an expression", ll->n->type);
+					else if(ll->n->type != T && !eqtype(ll->n->type, t))
+						yyerror("case %+N in switch of %+N %#O", ll->n, n->ntest, ll->n->op);
+					break;
+				case Etype:	// type switch
+					if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
+						;
+					else if(ll->n->op != OTYPE && ll->n->type != T)
+						yyerror("%#N is not a type", ll->n);
+					break;
+				}
+			}
+		}
+		if(top == Etype && n->type != T) {
+			ll = ncase->list;
+			nvar = ncase->nname;
+			if(nvar != N) {
+				if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
+					// single entry type switch
+					nvar->ntype = typenod(ll->n->type);
+				} else {
+					// multiple entry type switch or default
+					nvar->ntype = typenod(n->type);
+				}
 			}
 		}
 		typechecklist(ncase->nbody, Etop);