]> Cypherpunks repositories - gostls13.git/commitdiff
1. type switches
authorKen Thompson <ken@golang.org>
Sat, 7 Mar 2009 01:50:43 +0000 (17:50 -0800)
committerKen Thompson <ken@golang.org>
Sat, 7 Mar 2009 01:50:43 +0000 (17:50 -0800)
2. fixed fault on bug128
3. got rid of typeof
4. fixed bug in t,ok = I2T

R=r
OCL=25873
CL=25873

src/cmd/gc/go.h
src/cmd/gc/go.y
src/cmd/gc/lex.c
src/cmd/gc/subr.c
src/cmd/gc/swt.c
src/runtime/iface.c

index dfd975fba4e44fd6dd62bbba06c33cf6a7c61b3c..e96a85cc5a3da817ffc60637dacb0abc6091009b 100644 (file)
@@ -329,7 +329,7 @@ enum
        OKEY, OPARAM,
        OCOMPOS,
        OCONV,
-       ODOTTYPE,
+       ODOTTYPE, OTYPESW,
        OBAD,
 
        OEXTEND,        // 6g internal
@@ -526,6 +526,7 @@ EXTERN      Node*   retnil;
 EXTERN Node*   fskel;
 
 EXTERN Node*   addtop;
+EXTERN Node*   typeswvar;
 
 EXTERN char*   context;
 EXTERN char*   pkgcontext;
index e5a8faf22e8998729487cdbc9fa592b80e390f14..7635e163c073eb9c28e9050b840d9a9f288b1e58 100644 (file)
@@ -18,7 +18,7 @@
 %token <sym>           LPACKAGE LIMPORT LDEFER
 %token <sym>           LMAP LCHAN LINTERFACE LFUNC LSTRUCT
 %token <sym>           LCOLAS LFALL LRETURN LDDD
-%token <sym>           LLEN LCAP LTYPEOF LPANIC LPANICN LPRINT LPRINTN
+%token <sym>           LLEN LCAP LPANIC LPANICN LPRINT LPRINTN
 %token <sym>           LVAR LTYPE LCONST LCONVERT LSELECT LMAKE LNEW
 %token <sym>           LFOR LIF LELSE LSWITCH LCASE LDEFAULT
 %token <sym>           LBREAK LCONTINUE LGO LGOTO LRANGE
@@ -419,6 +419,10 @@ simple_stmt:
        {
                if(addtop != N)
                        fatal("exprsym3_list_r LCOLAS expr_list");
+               if($3->op == OTYPESW) {
+                       $$ = nod(OTYPESW, $1, $3->left);
+                       break;
+               }
                $$ = rev($1);
                $$ = colas($$, $3);
                $$ = nod(OAS, $$, $3);
@@ -507,6 +511,18 @@ complex_stmt:
                $$ = nod(OXCASE, $$, N);
                addtotop($$);
        }
+|      LCASE type ':'
+       {
+               poptodcl();
+               if(typeswvar == N || typeswvar->right == N) {
+                       yyerror("type case not in a type switch");
+                       $$ = N;
+               } else
+                       $$ = old2new(typeswvar->right, $2);
+               $$ = nod(OTYPESW, $$, N);
+               $$ = nod(OXCASE, $$, N);
+               addtotop($$);
+       }
 |      LDEFAULT ':'
        {
                poptodcl();
@@ -648,10 +664,20 @@ if_header:
        }
 
 if_body:
-       if_header compound_stmt
+       if_header
+       {
+               Node *n;
+               n = $1->ntest;
+               if(n != N && n->op == OTYPESW)
+                       n = n->left;
+               else
+                       n = N;
+               typeswvar = nod(OLIST, typeswvar, n);
+       } compound_stmt
        {
                $$ = $1;
-               $$->nbody = $2;
+               $$->nbody = $3;
+               typeswvar = typeswvar->left;
        }
 
 if_stmt:
@@ -836,6 +862,10 @@ pexpr:
                $$ = nod(ODOTTYPE, $1, N);
                $$->type = $4;
        }
+|      pexpr '.' '(' LTYPE ')'
+       {
+               $$ = nod(OTYPESW, $1, N);
+       }
 |      pexpr '[' expr ']'
        {
                $$ = nod(OINDEX, $1, $3);
@@ -858,11 +888,6 @@ pexpr:
        {
                $$ = nod(OCAP, $3, N);
        }
-|      LTYPEOF '(' type ')'
-       {
-               $$ = nod(OTYPEOF, N, N);
-               $$->type = $3;
-       }
 |      LNEW '(' type ')'
        {
                $$ = nod(ONEW, N, N);
@@ -1001,7 +1026,6 @@ sym3:
 |      LNEW
 |      LMAKE
 |      LBASETYPE
-|      LTYPEOF
 
 /*
  * keywords that we can
index 3f7f2638be1f0def5869893dfebdf515c488254f..7c9c8957b42d621e610242dbcf086d8984a98df4 100644 (file)
@@ -1110,7 +1110,6 @@ static    struct
        "switch",       LSWITCH,        Txxx,
        "true",         LTRUE,          Txxx,
        "type",         LTYPE,          Txxx,
-       "typeof",       LTYPEOF,        Txxx,
        "var",          LVAR,           Txxx,
 
        "notwithstanding",              LIGNORE,        Txxx,
index aa8b01a53b5a0c6f5d9ab029a423e7ec904a10f1..0cf586eab8740ea4566288ec8ccee6c0fc0bf83c 100644 (file)
@@ -715,6 +715,7 @@ opnames[] =
        [OSELECT]       = "SELECT",
        [OSWITCH]       = "SWITCH",
        [OTYPE]         = "TYPE",
+       [OTYPESW]       = "TYPESW",
        [OVAR]          = "VAR",
        [OIMPORT]       = "IMPORT",
        [OXOR]          = "XOR",
index dc3266532381d3ac72507c98b9c5f4cad306afac..fb3e4b095bbf4c8b62272616837aad47ffce9a82 100644 (file)
@@ -4,19 +4,38 @@
 
 #include       "go.h"
 
+enum
+{
+       Snorm           = 0,
+       Strue,
+       Sfalse,
+       Stype,
+};
+
 /*
  * walktype
  */
 Type*
-sw0(Node *c, Type *place)
+sw0(Node *c, Type *place, int arg)
 {
        Node *r;
 
        if(c == N)
                return T;
-       if(c->op != OAS) {
+       switch(c->op) {
+       default:
+               if(arg == Stype) {
+                       yyerror("inappropriate case for a type switch");
+                       return T;
+               }
                walktype(c, Erv);
                return T;
+       case OTYPESW:
+               if(arg != Stype)
+                       yyerror("inappropriate type case");
+               return T;
+       case OAS:
+               break;
        }
        walktype(c->left, Elv);
 
@@ -47,6 +66,8 @@ sw0(Node *c, Type *place)
                break;
        }
        c->type = types[TBOOL];
+       if(arg != Strue)
+               goto bad;
        return T;
 
 bad:
@@ -58,7 +79,7 @@ bad:
  * return the first type
  */
 Type*
-sw1(Node *c, Type *place)
+sw1(Node *c, Type *place, int arg)
 {
        if(place == T)
                return c->type;
@@ -69,7 +90,7 @@ sw1(Node *c, Type *place)
  * return a suitable type
  */
 Type*
-sw2(Node *c, Type *place)
+sw2(Node *c, Type *place, int arg)
 {
        return types[TINT];     // botch
 }
@@ -79,7 +100,7 @@ sw2(Node *c, Type *place)
  * is compat with all the cases
  */
 Type*
-sw3(Node *c, Type *place)
+sw3(Node *c, Type *place, int arg)
 {
        if(place == T)
                return c->type;
@@ -97,7 +118,7 @@ sw3(Node *c, Type *place)
  * types to cases and switch
  */
 Type*
-walkcases(Node *sw, Type*(*call)(Node*, Type*))
+walkcases(Node *sw, Type*(*call)(Node*, Type*, int arg), int arg)
 {
        Iter save;
        Node *n;
@@ -105,10 +126,10 @@ walkcases(Node *sw, Type*(*call)(Node*, Type*))
        int32 lno;
 
        lno = setlineno(sw);
-       place = call(sw->ntest, T);
+       place = call(sw->ntest, T, arg);
 
        n = listfirst(&save, &sw->nbody->left);
-       if(n->op == OEMPTY)
+       if(n == N || n->op == OEMPTY)
                return T;
 
 loop:
@@ -122,7 +143,7 @@ loop:
 
        if(n->left != N) {
                setlineno(n->left);
-               place = call(n->left, place);
+               place = call(n->left, place, arg);
        }
        n = listnext(&save);
        goto loop;
@@ -190,6 +211,7 @@ loop:
                if(oc == N && os != N)
                        yyerror("first switch statement must be a case");
 
+               // botch - shouldnt fall thru declaration
                if(os != N && os->op == OXFALL)
                        os->op = OFALL;
                else
@@ -236,23 +258,17 @@ loop:
  * rebulid case statements into if .. goto
  */
 void
-prepsw(Node *sw)
+prepsw(Node *sw, int arg)
 {
        Iter save;
-       Node *name, *cas;
+       Node *name, *bool, *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) {
+       bool = N;
+
+       if(arg != Strue && arg != Sfalse) {
                name = nod(OXXX, N, N);
                tempname(name, sw->ntest->type);
                cas = nod(OAS, name, sw->ntest);
@@ -263,7 +279,6 @@ prepsw(Node *sw)
 loop:
        if(t == N) {
                sw->nbody->left = rev(cas);
-               walkstate(sw->nbody->left);
 //dump("case", sw->nbody->left);
                return;
        }
@@ -274,22 +289,40 @@ loop:
                goto loop;
        }
 
+       if(t->left->op == OAS) {
+               if(bool == N) {
+                       bool = nod(OXXX, N, N);
+                       tempname(bool, types[TBOOL]);
+               }
+//dump("oas", t);
+               t->left->left = nod(OLIST, t->left->left, bool);
+               cas = list(cas, t->left);               // v,bool = rhs
+
+               a = nod(OIF, N, N);
+               a->nbody = t->right;                    // then goto l
+               a->ntest = bool;
+               if(arg != Strue)
+                       a->ntest = nod(ONOT, bool, N);
+               cas = list(cas, a);                     // if bool goto l
+
+               t = listnext(&save);
+               goto loop;
+       }
+
        a = nod(OIF, N, N);
        a->nbody = t->right;                            // then goto l
 
-       switch(bool) {
+       switch(arg) {
        default:
                // not bool const
                a->ntest = nod(OEQ, name, t->left);     // if name == val
                break;
 
-       case 1:
-               // bool true
+       case Strue:
                a->ntest = t->left;                     // if val
                break;
 
-       case 2:
-               // bool false
+       case Sfalse:
                a->ntest = nod(ONOT, t->left, N);       // if !val
                break;
        }
@@ -299,35 +332,141 @@ loop:
        goto loop;
 }
 
+/*
+ * convert switch of the form
+ *     switch v := i.(type) { case t1: ..; case t2: ..; }
+ * into if statements
+ */
 void
-walkswitch(Node *n)
+typeswitch(Node *sw)
 {
-       Type *t;
+       Iter save;
+       Node *face, *bool, *cas;
+       Node *t, *a, *b;
 
-       casebody(n);
-       if(n->ntest == N)
-               n->ntest = booltrue;
+//dump("typeswitch", sw);
+
+       walktype(sw->ntest->right, Erv);
+       if(!istype(sw->ntest->right->type, TINTER)) {
+               yyerror("type switch must be on an interface");
+               return;
+       }
+       walkcases(sw, sw0, Stype);
 
-       walkstate(n->ninit);
-       walktype(n->ntest, Erv);
-       walkstate(n->nbody);
+       /*
+        * predeclare variables for the interface var
+        * and the boolean var
+        */
+       face = nod(OXXX, N, N);
+       tempname(face, sw->ntest->right->type);
+       cas = nod(OAS, face, sw->ntest->right);
 
-       // walktype
-       walkcases(n, sw0);
+       bool = nod(OXXX, N, N);
+       tempname(bool, types[TBOOL]);
 
-       // find common type
-       t = n->ntest->type;
-       if(t == T)
-               t = walkcases(n, sw1);
+       t = listfirst(&save, &sw->nbody->left);
 
-       // if that fails pick a type
-       if(t == T)
-               t = walkcases(n, sw2);
+loop:
+       if(t == N) {
+               sw->nbody->left = rev(cas);
+               walkstate(sw->nbody);
+//dump("done", sw->nbody->left);
+               return;
+       }
 
-       // set the type on all literals
-       if(t != T) {
-               walkcases(n, sw3);
-               convlit(n->ntest, t);
-               prepsw(n);
+       if(t->left == N) {
+               cas = list(cas, t->right);              // goto default
+               t = listnext(&save);
+               goto loop;
        }
+       if(t->left->op != OTYPESW) {
+               t = listnext(&save);
+               goto loop;
+       }
+
+       a = t->left->left;              // var
+       a = nod(OLIST, a, bool);        // var,bool
+
+       b = nod(ODOTTYPE, face, N);
+       b->type = t->left->left->type;  // interface.(type)
+
+       a = nod(OAS, a, b);             // var,bool = interface.(type)
+       cas = list(cas, a);
+
+       a = nod(OIF, N, N);
+       a->ntest = bool;
+       a->nbody = t->right;            // if bool { goto l }
+       cas = list(cas, a);
+
+       t = listnext(&save);
+       goto loop;
+}
+
+void
+walkswitch(Node *sw)
+{
+       Type *t;
+       int arg;
+
+//dump("walkswitch", sw);
+
+       /*
+        * reorder the body into (OLIST, cases, statements)
+        * cases have OGOTO into statements.
+        * both have inserted OBREAK statements
+        */
+       walkstate(sw->ninit);
+       if(sw->ntest == N)
+               sw->ntest = booltrue;
+       casebody(sw);
+
+       /*
+        * classify the switch test
+        * Strue or Sfalse if the test is a bool constant
+        *      this allows cases to be map/chan/interface assignments
+        *      as well as (boolean) expressions
+        * Stype if the test is v := interface.(type)
+        *      this forces all cases to be types
+        * Snorm otherwise
+        *      all cases are expressions
+        */
+       if(sw->ntest->op == OTYPESW) {
+               typeswitch(sw);
+               return;
+       }
+       arg = Snorm;
+       if(whatis(sw->ntest) == Wlitbool) {
+               arg = Strue;
+               if(sw->ntest->val.u.xval == 0)
+                       arg = Sfalse;
+       }
+
+       /*
+        * init statement is nothing important
+        */
+       walktype(sw->ntest, Erv);
+//print("after walkwalks\n");
+
+       /*
+        * pass 0,1,2,3
+        * walk the cases as appropriate for switch type
+        */
+       walkcases(sw, sw0, arg);
+       t = sw->ntest->type;
+       if(t == T)
+               t = walkcases(sw, sw1, arg);
+       if(t == T)
+               t = walkcases(sw, sw2, arg);
+       if(t == T)
+               return;
+       walkcases(sw, sw3, arg);
+       convlit(sw->ntest, t);
+//print("after walkcases\n");
+
+       /*
+        * convert the switch into OIF statements
+        */
+       prepsw(sw, arg);
+       walkstate(sw->nbody);
+//print("normal done\n");
 }
index c0d3f75aabf5280684a7980a3834a5bbfdd091fd..34c4a2da8b60b4071262e28a68553c483c123d41 100644 (file)
@@ -315,7 +315,7 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
        ret = (byte*)(&i+1);
        alg = st->hash & 0xFF;
        wid = st->offset;
-       ok = (bool*)(ret+rnd(wid, 8));
+       ok = (bool*)(ret+rnd(wid, 1));
 
        if(iface_debug) {
                prints("I2T2 sigt=");