]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1] cmd/gc: accept switches on comparable arrays.
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Fri, 21 Sep 2012 19:54:26 +0000 (05:54 +1000)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Fri, 21 Sep 2012 19:54:26 +0000 (05:54 +1000)
««« backport d68605d10a6b
cmd/gc: accept switches on comparable arrays.

The compiler is incorrectly rejecting switches on arrays of
comparable types. It also doesn't catch incomparable structs
when typechecking the switch, leading to unreadable errors
during typechecking of the generated code.

Fixes #3894.

R=rsc
CC=gobot, golang-dev, r, remy
https://golang.org/cl/6442074

»»»

src/cmd/gc/swt.c
test/switch.go
test/switch3.go

index 4079b67da29d101859f801efd5360ce60e22eb4d..aff1b5ea878f9c6cec105581bb86c69925df5563 100644 (file)
@@ -813,7 +813,7 @@ typecheckswitch(Node *n)
 {
        int top, lno, ptr;
        char *nilonly;
-       Type *t, *missing, *have;
+       Type *t, *badtype, *missing, *have;
        NodeList *l, *ll;
        Node *ncase, *nvar;
        Node *def;
@@ -839,10 +839,14 @@ typecheckswitch(Node *n)
                } else
                        t = types[TBOOL];
                if(t) {
-                       if(!okforeq[t->etype] || isfixedarray(t))
+                       if(!okforeq[t->etype])
                                yyerror("cannot switch on %lN", n->ntest);
-                       else if(t->etype == TARRAY)
+                       else if(t->etype == TARRAY && !isfixedarray(t))
                                nilonly = "slice";
+                       else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ)
+                               yyerror("cannot switch on %lN", n->ntest);
+                       else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ)
+                               yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype);
                        else if(t->etype == TFUNC)
                                nilonly = "func";
                        else if(t->etype == TMAP)
index 09bf4341a00d9dce7822d744d8b71df6d9ba7a36..a4242f25718d4ad276a99ca2fb584ed688f7346b 100644 (file)
@@ -284,6 +284,38 @@ func main() {
        default:
        }
 
+       // switch on interface.
+       switch i := interface{}("hello"); i {
+       case 42:
+               assert(false, `i should be "hello"`)
+       case "hello":
+               assert(true, "hello")
+       default:
+               assert(false, `i should be "hello"`)
+       }
+
+       // switch on array.
+       switch ar := [3]int{1, 2, 3}; ar {
+       case [3]int{1,2,3}:
+               assert(true, "[1 2 3]")
+       case [3]int{4,5,6}:
+               assert(false, "ar should be [1 2 3]")
+       default:
+               assert(false, "ar should be [1 2 3]")
+       }
+
+       // switch on channel
+       switch c1, c2 := make(chan int), make(chan int); c1 {
+       case nil:
+               assert(false, "c1 did not match itself")
+       case c2:
+               assert(false, "c1 did not match itself")
+       case c1:
+               assert(true, "chan")
+       default:
+               assert(false, "c1 did not match itself")
+       }
+
        i := 0
        switch x := 5; {
                case i < x:
index dcb6fff20846b675dc75df1ff390e7d9ed7ad3b3..28705e464ef2c20949e7298fe1072a24fe2ab2df 100644 (file)
@@ -45,6 +45,17 @@ func bad() {
        case f1: // ERROR "can only compare func f to nil|func can only be compared to nil"
        default:
        }
+
+       var ar, ar1 [4]func()
+       switch ar { // ERROR "cannot switch on"
+       case ar1:
+       default:
+       }
+
+       var st, st1 struct{ f func() }
+       switch st { // ERROR "cannot switch on"
+       case st1:
+       }
 }
 
 func good() {