]> Cypherpunks repositories - gostls13.git/commitdiff
new switch implementation
authorKen Thompson <ken@golang.org>
Thu, 5 Mar 2009 23:49:34 +0000 (15:49 -0800)
committerKen Thompson <ken@golang.org>
Thu, 5 Mar 2009 23:49:34 +0000 (15:49 -0800)
in preparation of type switch.
no functional change (yet).

R=r
OCL=25784
CL=25788

src/cmd/6g/gen.c
src/cmd/6g/gg.h
src/cmd/gc/Makefile
src/cmd/gc/go.h
src/cmd/gc/subr.c
src/cmd/gc/swt.c [new file with mode: 0644]
src/cmd/gc/walk.c

index d14ad30bb9dc951f586cfc98a6c86ea4d9c0bef8..9bc6126ab70f404dd86f99b3220cebb130890750 100644 (file)
@@ -260,8 +260,8 @@ loop:
                break;
 
        case OFOR:
-               p1 = gbranch(AJMP, T);                  //              goto test
                sbreak = breakpc;
+               p1 = gbranch(AJMP, T);                  //              goto test
                breakpc = gbranch(AJMP, T);             // break:       goto done
                scontin = continpc;
                continpc = pc;
@@ -299,15 +299,15 @@ loop:
                break;
 
        case OSWITCH:
-               p1 = gbranch(AJMP, T);                  //              goto test
                sbreak = breakpc;
+               p1 = gbranch(AJMP, T);                  //              goto test
                breakpc = gbranch(AJMP, T);             // break:       goto done
                patch(p1, pc);                          // test:
                if(labloop != L) {
                        labloop->op = OFOR;
                        labloop->breakpc = breakpc;
                }
-               swgen(n);                               //              switch(test) body
+               gen(n->nbody, L);                       //              switch(test) body
                patch(breakpc, pc);                     // done:
                breakpc = sbreak;
                break;
@@ -367,279 +367,6 @@ ret:
        lineno = lno;
 }
 
-Case*
-csort(Case *l, int(*f)(Case*, Case*))
-{
-       Case *l1, *l2, *le;
-
-       if(l == 0 || l->slink == 0)
-               return l;
-
-       l1 = l;
-       l2 = l;
-       for(;;) {
-               l2 = l2->slink;
-               if(l2 == 0)
-                       break;
-               l2 = l2->slink;
-               if(l2 == 0)
-                       break;
-               l1 = l1->slink;
-       }
-
-       l2 = l1->slink;
-       l1->slink = 0;
-       l1 = csort(l, f);
-       l2 = csort(l2, f);
-
-       /* set up lead element */
-       if((*f)(l1, l2) < 0) {
-               l = l1;
-               l1 = l1->slink;
-       } else {
-               l = l2;
-               l2 = l2->slink;
-       }
-       le = l;
-
-       for(;;) {
-               if(l1 == 0) {
-                       while(l2) {
-                               le->slink = l2;
-                               le = l2;
-                               l2 = l2->slink;
-                       }
-                       le->slink = 0;
-                       break;
-               }
-               if(l2 == 0) {
-                       while(l1) {
-                               le->slink = l1;
-                               le = l1;
-                               l1 = l1->slink;
-                       }
-                       break;
-               }
-               if((*f)(l1, l2) < 0) {
-                       le->slink = l1;
-                       le = l1;
-                       l1 = l1->slink;
-               } else {
-                       le->slink = l2;
-                       le = l2;
-                       l2 = l2->slink;
-               }
-       }
-       le->slink = 0;
-       return l;
-}
-
-int
-casecmp(Case *c1, Case *c2)
-{
-       int w;
-
-       w = whatis(c1->scase);
-       if(w != whatis(c2->scase))
-               fatal("casecmp1");
-
-       switch(w) {
-       case Wlitfloat:
-               return mpcmpfltflt(c1->scase->val.u.fval, c2->scase->val.u.fval);
-       case Wlitint:
-               return mpcmpfixfix(c1->scase->val.u.xval, c2->scase->val.u.xval);
-       case Wlitstr:
-               return cmpslit(c1->scase, c2->scase);
-//     case Wlitbool:
-//     case Wlitnil:
-       }
-
-       fatal("casecmp2");
-       return 0;
-}
-
-void
-swconst(Case *sa, int nc, Node *n1, Node *tmp)
-{
-       Case *s, *sb;
-       Prog *p1, *p2, *p3;
-       int n;
-
-       // small number of cases --
-       // test them sequentially
-       if(nc < 4) {
-               for(s=sa; s!=C; s=s->slink) {
-                       setlineno(s->scase);
-                       memset(n1, 0, sizeof(*n1));
-                       n1->op = OEQ;
-                       n1->left = tmp;
-                       n1->right = s->scase;
-                       walktype(n1, Erv);
-                       bgen(n1, 1, s->sprog);
-               }
-               return;
-       }
-
-       // large number of cases --
-       // find the middle and recur on each half
-
-       n = nc/2;
-       for(s=sa; s!=C; s=s->slink) {
-               n--;
-               if(n == 0)
-                       break;
-       }
-       n = nc/2;
-       sb = s->slink;
-       s->slink = C;
-
-       p1 = gbranch(AJMP, T);                  // goto midcmp
-       p2 = pc;                                // low half of switch
-       swconst(sa, n, n1, tmp);
-
-       p3 = gbranch(AJMP, T);                  // goto end
-       patch(p1, pc);
-
-       setlineno(s->scase);
-       memset(n1, 0, sizeof(*n1));
-       n1->op = OLE;
-       n1->left = tmp;
-       n1->right = s->scase;
-       walktype(n1, Erv);
-       bgen(n1, 1, p2);
-
-       swconst(sb, nc-n, n1, tmp);             // high half of switch
-       patch(p3, pc);
-}
-
-void
-swgen(Node *n)
-{
-       Node *c1, *c2;
-       Node n1, tmp;
-       Case *s0, *se, *s, *sa;
-       Prog *p1, *dflt;
-       int32 lno;
-       int any, nc;
-       Iter save1, save2;
-
-// botch - put most of this code in
-// walk. gen binary search for
-// sequence of constant cases
-
-       lno = setlineno(n);
-
-       p1 = gbranch(AJMP, T);
-       s0 = C;
-       se = C;
-
-       // walk thru the body placing breaks
-       // and labels into the case statements
-
-       any = 0;
-       dflt = P;
-       c1 = listfirst(&save1, &n->nbody);
-       while(c1 != N) {
-               setlineno(c1);
-               if(c1->op == OEMPTY)
-                       break;
-               if(c1->op != OCASE) {
-                       if(s0 == C && dflt == P)
-                               yyerror("unreachable statements in a switch");
-                       gen(c1, L);
-
-                       any = 1;
-                       if(c1->op == OFALL)
-                               any = 0;
-                       c1 = listnext(&save1);
-                       continue;
-               }
-
-               // put in the break between cases
-               if(any)
-                       patch(gbranch(AJMP, T), breakpc);
-               any = 1;
-
-               // loop over case expressions
-               c2 = listfirst(&save2, &c1->left);
-               if(c2 == N)
-                       dflt = pc;
-
-               while(c2 != N) {
-                       s = mal(sizeof(*s));
-                       if(s0 == C)
-                               s0 = s;
-                       else
-                               se->slink = s;
-                       se = s;
-
-                       s->scase = c2;          // case expression
-                       s->sprog = pc;          // where to go
-
-                       c2 = listnext(&save2);
-               }
-
-               c1 = listnext(&save1);
-       }
-
-       lineno = lno;
-
-       if(any)
-               patch(gbranch(AJMP, T), breakpc);
-
-       patch(p1, pc);
-
-       if(n->ntest != N)
-               if(n->ntest->ninit != N)
-                       gen(n->ntest->ninit, L);
-       tempname(&tmp, n->ntest->type);
-       cgen(n->ntest, &tmp);
-
-       sa = C;         // base of constant cases
-       nc = 0;
-       for(s=s0; s!=C; s=s->slink) {
-               switch(whatis(s->scase)) {
-               case Wlitfloat:
-               case Wlitint:
-               case Wlitstr:
-//             case Wlitbool:
-//             case Wlitnil:
-                       nc++;
-                       if(sa == C)
-                               sa = s;
-                       se = s;
-                       continue;
-               }
-               if(sa != C) {
-                       se->slink = C;
-                       sa = csort(sa, casecmp);
-                       swconst(sa, nc, &n1, &tmp);
-                       nc = 0;
-                       sa = C;
-               }
-               setlineno(s->scase);
-               memset(&n1, 0, sizeof(n1));
-               n1.op = OEQ;
-               n1.left = &tmp;
-               n1.right = s->scase;
-               walktype(&n1, Erv);
-               bgen(&n1, 1, s->sprog);
-       }
-       if(sa != C) {
-               se->slink = C;
-               sa = csort(sa, casecmp);
-               swconst(sa, nc, &n1, &tmp);
-       }
-       if(dflt != P) {
-               patch(gbranch(AJMP, T), dflt);
-               goto ret;
-       }
-       patch(gbranch(AJMP, T), breakpc);
-
-ret:
-       lineno = lno;
-}
-
 void
 inarggen(void)
 {
index a44f104b8b066c883247c063b0f81ae355c0597f..741527c432f1d99fe83d8f89f689f550037bc415 100644 (file)
@@ -64,15 +64,6 @@ struct Sig
        Sig*    link;
 };
 
-typedef        struct  Case Case;
-struct Case
-{
-       Prog*   sprog;
-       Node*   scase;
-       Case*   slink;
-};
-#define        C       ((Case*)0)
-
 typedef        struct  Pool Pool;
 struct Pool
 {
@@ -143,8 +134,6 @@ EXTERN      int     sizeof_Array;   // runtime sizeof(Array)
 void   compile(Node*);
 void   proglist(void);
 void   gen(Node*, Label*);
-void   swgen(Node*);
-void   selgen(Node*);
 Node*  lookdot(Node*, Node*, int);
 void   inarggen(void);
 void   cgen_as(Node*, Node*);
index 1ab4497689f1de1af608d610a886f5b5cc128316..4237e972a9f909455287d0401a51c01d2701920b 100644 (file)
@@ -21,6 +21,7 @@ OFILES=\
        dcl.$O\
        export.$O\
        walk.$O\
+       swt.$O\
        const.$O\
        mparith1.$O\
        mparith2.$O\
index 76e440db4ba4347de526f350d0a48d934aef2477..dfd975fba4e44fd6dd62bbba06c33cf6a7c61b3c 100644 (file)
@@ -812,8 +812,7 @@ void        walktype(Node*, int);
 void   walkconv(Node*);
 void   walkas(Node*);
 void   walkbool(Node*);
-Type*  walkswitch(Node*, Type*(*)(Node*, Type*));
-int    casebody(Node*);
+void   walkswitch(Node*);
 void   walkselect(Node*);
 int    whatis(Node*);
 void   walkdot(Node*);
index bb2c31ebdb4c2a64bc61adeee19cf839ecf10b26..aa8b01a53b5a0c6f5d9ab029a423e7ec904a10f1 100644 (file)
@@ -547,8 +547,11 @@ loop:
                return;
 
        case OCASE:
-               // the right side points to the next case
-               print("%O%J\n", n->op, n);
+               // the right side points to label of the body
+               if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
+                       print("%O%J GOTO %N\n", n->op, n, n->right->left);
+               else
+                       print("%O%J\n", n->op, n);
                dodump(n->left, dep+1);
                return;
        }
@@ -654,8 +657,8 @@ opnames[] =
        [OCMP]          = "CMP",
        [OFALL]         = "FALL",
        [OCOMPOS]       = "COMPOS",
-       [ODOTTYPE]              = "DOTTYPE",
-       [OCONV] = "CONV",
+       [ODOTTYPE]      = "DOTTYPE",
+       [OCONV]         = "CONV",
        [OCOM]          = "COM",
        [OCONST]        = "CONST",
        [OCONTINUE]     = "CONTINUE",
@@ -724,7 +727,7 @@ opnames[] =
        [OPRINT]        = "PRINT",
        [OPRINTN]       = "PRINTN",
        [OPARAM]        = "PARAM",
-       [ODCL]  = "DCL",
+       [ODCL]          = "DCL",
        [OXXX]          = "XXX",
 };
 
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
new file mode 100644 (file)
index 0000000..dc32665
--- /dev/null
@@ -0,0 +1,333 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include       "go.h"
+
+/*
+ * walktype
+ */
+Type*
+sw0(Node *c, Type *place)
+{
+       Node *r;
+
+       if(c == N)
+               return T;
+       if(c->op != OAS) {
+               walktype(c, Erv);
+               return T;
+       }
+       walktype(c->left, Elv);
+
+       r = c->right;
+       if(c == N)
+               return T;
+
+       switch(r->op) {
+       default:
+               goto bad;
+       case ORECV:
+               // <-chan
+               walktype(r->left, Erv);
+               if(!istype(r->left->type, TCHAN))
+                       goto bad;
+               break;
+       case OINDEX:
+               // map[e]
+               walktype(r->left, Erv);
+               if(!istype(r->left->type, TMAP))
+                       goto bad;
+               break;
+       case ODOTTYPE:
+               // interface.(type)
+               walktype(r->left, Erv);
+               if(!istype(r->left->type, TINTER))
+                       goto bad;
+               break;
+       }
+       c->type = types[TBOOL];
+       return T;
+
+bad:
+       yyerror("inappropriate assignment in a case statement");
+       return T;
+}
+
+/*
+ * return the first type
+ */
+Type*
+sw1(Node *c, Type *place)
+{
+       if(place == T)
+               return c->type;
+       return place;
+}
+
+/*
+ * return a suitable type
+ */
+Type*
+sw2(Node *c, Type *place)
+{
+       return types[TINT];     // botch
+}
+
+/*
+ * check that switch type
+ * is compat with all the cases
+ */
+Type*
+sw3(Node *c, Type *place)
+{
+       if(place == T)
+               return c->type;
+       if(c->type == T)
+               c->type = place;
+       convlit(c, place);
+       if(!ascompat(place, c->type))
+               badtype(OSWITCH, place, c->type);
+       return place;
+}
+
+/*
+ * over all cases, call paramenter function.
+ * four passes of these are used to allocate
+ * types to cases and switch
+ */
+Type*
+walkcases(Node *sw, Type*(*call)(Node*, Type*))
+{
+       Iter save;
+       Node *n;
+       Type *place;
+       int32 lno;
+
+       lno = setlineno(sw);
+       place = call(sw->ntest, T);
+
+       n = listfirst(&save, &sw->nbody->left);
+       if(n->op == OEMPTY)
+               return T;
+
+loop:
+       if(n == N) {
+               lineno = lno;
+               return place;
+       }
+
+       if(n->op != OCASE)
+               fatal("walkcases: not case %O\n", n->op);
+
+       if(n->left != N) {
+               setlineno(n->left);
+               place = call(n->left, place);
+       }
+       n = listnext(&save);
+       goto loop;
+}
+
+Node*
+newlabel()
+{
+       static int label;
+
+       label++;
+       snprint(namebuf, sizeof(namebuf), "%.6d", label);
+       return newname(lookup(namebuf));
+}
+
+/*
+ * build separate list of statements and cases
+ * make labels between cases and statements
+ * deal with fallthrough, break, unreachable statements
+ */
+void
+casebody(Node *sw)
+{
+       Iter save;
+       Node *os, *oc, *t, *c;
+       Node *cas, *stat, *def;
+       Node *go, *br;
+       int32 lno;
+
+       lno = setlineno(sw);
+       t = listfirst(&save, &sw->nbody);
+       if(t == N || t->op == OEMPTY) {
+               sw->nbody = nod(OLIST, N, N);
+               return;
+       }
+
+       cas = N;        // cases
+       stat = N;       // statements
+       def = N;        // defaults
+       os = N;         // last statement
+       oc = N;         // last case
+       br = nod(OBREAK, N, N);
+
+loop:
+
+       if(t == N) {
+               if(oc == N && os != N)
+                       yyerror("first switch statement must be a case");
+
+               stat = list(stat, br);
+               cas = list(cas, def);
+
+               sw->nbody = nod(OLIST, rev(cas), rev(stat));
+//dump("case", sw->nbody->left);
+//dump("stat", sw->nbody->right);
+               lineno = lno;
+               return;
+       }
+
+       lno = setlineno(t);
+
+       switch(t->op) {
+       case OXCASE:
+               t->op = OCASE;
+               if(oc == N && os != N)
+                       yyerror("first switch statement must be a case");
+
+               if(os != N && os->op == OXFALL)
+                       os->op = OFALL;
+               else
+                       stat = list(stat, br);
+
+               go = nod(OGOTO, newlabel(), N);
+
+               c = t->left;
+               if(c == N) {
+                       if(def != N)
+                               yyerror("more than one default case");
+
+                       // reuse original default case
+                       t->right = go;
+                       def = t;
+               }
+
+               // expand multi-valued cases
+               for(; c!=N; c=c->right) {
+                       if(c->op != OLIST) {
+                               // reuse original case
+                               t->left = c;
+                               t->right = go;
+                               cas = list(cas, t);
+                               break;
+                       }
+                       cas = list(cas, nod(OCASE, c->left, go));
+               }
+               stat = list(stat, nod(OLABEL, go->left, N));
+               oc = t;
+               os = N;
+               break;
+
+       default:
+               stat = list(stat, t);
+               os = t;
+               break;
+       }
+       t = listnext(&save);
+       goto loop;
+}
+
+/*
+ * rebulid case statements into if .. goto
+ */
+void
+prepsw(Node *sw)
+{
+       Iter save;
+       Node *name, *cas;
+       Node *t, *a;
+       int bool;
+
+       bool = 0;
+       if(whatis(sw->ntest) == Wlitbool) {
+               bool = 1;               // true
+               if(sw->ntest->val.u.xval == 0)
+                       bool = 2;       // false
+       }
+
+       cas = N;
+       name = N;
+       if(bool == 0) {
+               name = nod(OXXX, N, N);
+               tempname(name, sw->ntest->type);
+               cas = nod(OAS, name, sw->ntest);
+       }
+
+       t = listfirst(&save, &sw->nbody->left);
+
+loop:
+       if(t == N) {
+               sw->nbody->left = rev(cas);
+               walkstate(sw->nbody->left);
+//dump("case", sw->nbody->left);
+               return;
+       }
+
+       if(t->left == N) {
+               cas = list(cas, t->right);              // goto default
+               t = listnext(&save);
+               goto loop;
+       }
+
+       a = nod(OIF, N, N);
+       a->nbody = t->right;                            // then goto l
+
+       switch(bool) {
+       default:
+               // not bool const
+               a->ntest = nod(OEQ, name, t->left);     // if name == val
+               break;
+
+       case 1:
+               // bool true
+               a->ntest = t->left;                     // if val
+               break;
+
+       case 2:
+               // bool false
+               a->ntest = nod(ONOT, t->left, N);       // if !val
+               break;
+       }
+       cas = list(cas, a);
+
+       t = listnext(&save);
+       goto loop;
+}
+
+void
+walkswitch(Node *n)
+{
+       Type *t;
+
+       casebody(n);
+       if(n->ntest == N)
+               n->ntest = booltrue;
+
+       walkstate(n->ninit);
+       walktype(n->ntest, Erv);
+       walkstate(n->nbody);
+
+       // walktype
+       walkcases(n, sw0);
+
+       // find common type
+       t = n->ntest->type;
+       if(t == T)
+               t = walkcases(n, sw1);
+
+       // if that fails pick a type
+       if(t == T)
+               t = walkcases(n, sw2);
+
+       // set the type on all literals
+       if(t != T) {
+               walkcases(n, sw3);
+               convlit(n->ntest, t);
+               prepsw(n);
+       }
+}
index 3ae0f52f7c5a3da86f6dd3734ff469f83e6f70ef..d82dfd4ebf09065ac1ecebb91a776de277ad7fcc 100644 (file)
@@ -4,9 +4,6 @@
 
 #include       "go.h"
 
-static Type*   sw1(Node*, Type*);
-static Type*   sw2(Node*, Type*);
-static Type*   sw3(Node*, Type*);
 static Node*   curfn;
 
 enum
@@ -318,26 +315,7 @@ loop:
                if(top != Etop)
                        goto nottop;
 
-               casebody(n->nbody);
-               if(n->ntest == N)
-                       n->ntest = booltrue;
-               walkstate(n->ninit);
-               walktype(n->ntest, Erv);
-               walkstate(n->nbody);
-
-               // find common type
-               if(n->ntest->type == T)
-                       n->ntest->type = walkswitch(n, sw1);
-
-               // if that fails pick a type
-               if(n->ntest->type == T)
-                       n->ntest->type = walkswitch(n, sw2);
-
-               // set the type on all literals
-               if(n->ntest->type != T)
-                       walkswitch(n, sw3);
-               walktype(n->ntest, Erv);        // BOTCH is this right
-               walktype(n->nincr, Erv);
+               walkswitch(n);
                goto ret;
 
        case OSELECT:
@@ -577,7 +555,6 @@ loop:
        case OCASE:
                if(top != Etop)
                        goto nottop;
-               walktype(n->left, Erv);
                walkstate(n->right);
                goto ret;
 
@@ -1251,124 +1228,11 @@ walkconv(Node *n)
 bad:
        if(l->type != T)
                yyerror("invalid conversion: %T to %T", l->type, t);
-       else if(n->left->op == OLIST)
+       else
+       if(n->left->op == OLIST)
                yyerror("invalid type for composite literal: %T", t);
 }
 
-
-/*
- * return the first type
- */
-Type*
-sw1(Node *c, Type *place)
-{
-       if(place == T)
-               return c->type;
-       return place;
-}
-
-/*
- * return a suitable type
- */
-Type*
-sw2(Node *c, Type *place)
-{
-       return types[TINT];     // botch
-}
-
-/*
- * check that switch type
- * is compat with all the cases
- */
-Type*
-sw3(Node *c, Type *place)
-{
-       if(place == T)
-               return c->type;
-       if(c->type == T)
-               c->type = place;
-       convlit(c, place);
-       if(!ascompat(place, c->type))
-               badtype(OSWITCH, place, c->type);
-       return place;
-}
-
-Type*
-walkswitch(Node *sw, Type*(*call)(Node*, Type*))
-{
-       Node *n, *c;
-       Type *place;
-       place = call(sw->ntest, T);
-
-       setlineno(sw);
-
-       n = sw->nbody;
-       if(n->op == OLIST)
-               n = n->left;
-       if(n->op == OEMPTY)
-               return T;
-
-       for(; n!=N; n=n->right) {
-               if(n->op != OCASE)
-                       fatal("walkswitch: not case %O\n", n->op);
-               for(c=n->left; c!=N; c=c->right) {
-                       if(c->op != OLIST) {
-                               setlineno(c);
-                               place = call(c, place);
-                               break;
-                       }
-                       setlineno(c);
-                       place = call(c->left, place);
-               }
-       }
-       return place;
-}
-
-int
-casebody(Node *n)
-{
-       Node *oc, *ot, *t;
-       Iter save;
-
-       /*
-        * look to see if statements at top level have
-        * case labels attached to them. convert the illegal
-        * ops XFALL and XCASE into legal ops FALL and CASE.
-        * all unconverted ops will thus be caught as illegal
-        */
-
-       oc = N;         // last case statement
-       ot = N;         // last statement (look for XFALL)
-       t = listfirst(&save, &n);
-
-loop:
-       if(t == N) {
-               /* empty switch */
-               if(oc == N)
-                       return 0;
-               return 1;
-       }
-       if(t->op == OXCASE) {
-               /* rewrite and link top level cases */
-               t->op = OCASE;
-               if(oc != N)
-                       oc->right = t;
-               oc = t;
-
-               /* rewrite top fall that preceed case */
-               if(ot != N && ot->op == OXFALL)
-                       ot->op = OFALL;
-       }
-
-       /* if first statement is not case */
-       if(oc == N)
-               return 0;
-
-       ot = t;
-       t = listnext(&save);
-       goto loop;
-}
-
 Node*
 selcase(Node *n, Node *var)
 {
@@ -1477,21 +1341,58 @@ out:
        return r;
 }
 
+/*
+ * enumerate the special cases
+ * of the case statement:
+ *     case v := <-chan                // select and switch
+ *     case v := map[]                 // switch
+ *     case v := interface.(TYPE)      // switch
+ */
 Node*
 selectas(Node *name, Node *expr)
 {
        Node *a;
        Type *t;
 
-       if(expr == N || expr->op != ORECV)
-               goto bad;
-       walktype(expr->left, Erv);
-       t = expr->left->type;
-       if(t == T)
+       if(expr == N)
                goto bad;
-       if(t->etype != TCHAN)
+       switch(expr->op) {
+       default:
+//dump("case", expr);
                goto bad;
-       a = old2new(name, t->type);
+
+       case ORECV:
+               walktype(expr->left, Erv);
+               t = expr->left->type;
+               if(t == T)
+                       goto bad;
+               if(t->etype != TCHAN)
+                       goto bad;
+               t = t->type;
+               break;
+
+       case OINDEX:
+               walktype(expr->left, Erv);
+               walktype(expr->right, Erv);
+               t = expr->left->type;
+               if(t == T)
+                       goto bad;
+               if(t->etype != TMAP)
+                       goto bad;
+               t = t->type;
+               break;
+
+       case ODOTTYPE:
+               walktype(expr->left, Erv);
+               t = expr->left->type;
+               if(t == T)
+                       goto bad;
+               if(t->etype != TINTER)
+                       goto bad;
+               t = expr->type;
+               break;
+       }
+       a = old2new(name, t);
        return a;
 
 bad:
@@ -1523,7 +1424,7 @@ walkselect(Node *sel)
        oc = N;         // last case
        def = N;        // default case
 
-       for(count=0; n!=N; n=listnext(&iter)) {
+       for(; n!=N; n=listnext(&iter)) {
                setlineno(n);
 
                switch(n->op) {