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);