]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: remove func, map compare
authorRuss Cox <rsc@golang.org>
Mon, 14 Nov 2011 03:58:08 +0000 (22:58 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 14 Nov 2011 03:58:08 +0000 (22:58 -0500)
R=ken, ken
CC=golang-dev
https://golang.org/cl/5373079

src/cmd/gc/align.c
src/cmd/gc/subr.c
src/cmd/gc/swt.c
src/cmd/gc/typecheck.c
test/closure.go
test/cmp6.go
test/fixedbugs/bug285.go
test/map1.go
test/switch.go
test/switch3.go
test/typeswitch.go

index f316c19e011966cb408b788598344f777676edb8..9766e088c68489e519e13054a1ab8f36440c1d79 100644 (file)
@@ -491,12 +491,12 @@ typeinit(void)
        okforeq[TPTR64] = 1;
        okforeq[TUNSAFEPTR] = 1;
        okforeq[TINTER] = 1;
-       okforeq[TMAP] = 1;
        okforeq[TCHAN] = 1;
-       okforeq[TFUNC] = 1;
        okforeq[TSTRING] = 1;
        okforeq[TBOOL] = 1;
-       okforeq[TARRAY] = 1;    // refined in typecheck
+       okforeq[TMAP] = 1;      // nil only; refined in typecheck
+       okforeq[TFUNC] = 1;     // nil only; refined in typecheck
+       okforeq[TARRAY] = 1;    // nil slice only; refined in typecheck
 
        okforcmp[TSTRING] = 1;
 
index adf8eb16c200b9e76f1b74a96f6194ba7ed02642..0df34c1a4fb6ecafe41ea541da91c8ed38466245 100644 (file)
@@ -547,6 +547,8 @@ maptype(Type *key, Type *val)
                switch(key->etype) {
                case TARRAY:
                case TSTRUCT:
+               case TMAP:
+               case TFUNC:
                        yyerror("invalid map key type %T", key);
                        break;
                case TFORW:
index 4d07970c71a975cf02cab774cfb8dbf52ee341fa..fb19129812027db2ee845f01d45fd2e68f9c690d 100644 (file)
@@ -811,6 +811,7 @@ void
 typecheckswitch(Node *n)
 {
        int top, lno, ptr;
+       char *nilonly;
        Type *t, *missing, *have;
        NodeList *l, *ll;
        Node *ncase, *nvar;
@@ -818,6 +819,7 @@ typecheckswitch(Node *n)
 
        lno = lineno;
        typechecklist(n->ninit, Etop);
+       nilonly = nil;
 
        if(n->ntest != N && n->ntest->op == OTYPESW) {
                // type switch
@@ -835,6 +837,16 @@ typecheckswitch(Node *n)
                        t = n->ntest->type;
                } else
                        t = types[TBOOL];
+               if(t) {
+                       if(!okforeq[t->etype] || isfixedarray(t))
+                               yyerror("cannot switch on %lN", n->ntest);
+                       else if(t->etype == TARRAY)
+                               nilonly = "slice";
+                       else if(t->etype == TFUNC)
+                               nilonly = "func";
+                       else if(t->etype == TMAP)
+                               nilonly = "map";
+               }
        }
        n->type = t;
 
@@ -865,6 +877,8 @@ typecheckswitch(Node *n)
                                                        yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
                                                else
                                                        yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t);
+                                       } else if(nilonly && !isconst(ll->n, CTNIL)) {
+                                               yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
                                        }
                                        break;
                                case Etype:     // type switch
index 34c241b06bcb04d180c85398e0a7d1a4fb080fd1..aaf836f8239c45997b5bc3c8edb55914520cff33 100644 (file)
@@ -445,8 +445,8 @@ reswitch:
                        yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(et));
                        goto error;
                }
-               // okfor allows any array == array;
-               // restrict to slice == nil and nil == slice.
+               // okfor allows any array == array, map == map, func == func.
+               // restrict to slice/map/func == nil and nil == slice/map/func.
                if(l->type->etype == TARRAY && !isslice(l->type))
                        goto notokfor;
                if(r->type->etype == TARRAY && !isslice(r->type))
@@ -455,6 +455,15 @@ reswitch:
                        yyerror("invalid operation: %N (slice can only be compared to nil)", n);
                        goto error;
                }
+               if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
+                       yyerror("invalid operation: %N (map can only be compared to nil)", n);
+                       goto error;
+               }
+               if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
+                       yyerror("invalid operation: %N (func can only be compared to nil)", n);
+                       goto error;
+               }
+               
                t = l->type;
                if(iscmp[n->op]) {
                        evconst(n);
index 3033c02ed8161c0f1e4a8cd6f010fba8fbc82ff9..191514def49e2b862633fad07f68bb30aa247234 100644 (file)
@@ -76,7 +76,6 @@ func h() {
 
 func newfunc() func(int) int { return func(x int) int { return x } }
 
-
 func main() {
        go f()
        check([]int{1, 4, 5, 4})
@@ -90,10 +89,6 @@ func main() {
        check([]int{100, 200, 101, 201, 500, 101, 201, 500})
 
        x, y := newfunc(), newfunc()
-       if x == y {
-               println("newfunc returned same func")
-               panic("fail")
-       }
        if x(1) != 1 || y(2) != 2 {
                println("newfunc returned broken funcs")
                panic("fail")
index b3ea8ffebfd502d60e89197dcf60d7fa834a9a77..6b13cac236ac6c8e33bc5c6546e73d129b57aec6 100644 (file)
@@ -11,7 +11,7 @@ func use(bool) {}
 type T1 *int
 type T2 *int
 
-type T3 struct {}
+type T3 struct{}
 
 var t3 T3
 
@@ -21,12 +21,12 @@ func main() {
        // so chan int can be compared against
        // directional channels but channel of different
        // direction cannot be compared against each other.
-       var c1 chan <-int
+       var c1 chan<- int
        var c2 <-chan int
        var c3 chan int
-       
-       use(c1 == c2)   // ERROR "invalid operation|incompatible"
-       use(c2 == c1)   // ERROR "invalid operation|incompatible"
+
+       use(c1 == c2) // ERROR "invalid operation|incompatible"
+       use(c2 == c1) // ERROR "invalid operation|incompatible"
        use(c1 == c3)
        use(c2 == c2)
        use(c3 == c1)
@@ -36,14 +36,22 @@ func main() {
        var p1 T1
        var p2 T2
        var p3 *int
-       
-       use(p1 == p2)   // ERROR "invalid operation|incompatible"
-       use(p2 == p1)   // ERROR "invalid operation|incompatible"
+
+       use(p1 == p2) // ERROR "invalid operation|incompatible"
+       use(p2 == p1) // ERROR "invalid operation|incompatible"
        use(p1 == p3)
        use(p2 == p2)
        use(p3 == p1)
        use(p3 == p2)
-       
+
        // Comparison of structs should have a good message
-       use(t3 == t3)   // ERROR "struct|expected"
+       use(t3 == t3) // ERROR "struct|expected"
+
+       // Slices, functions, and maps too.
+       var x []int
+       var f func()
+       var m map[int]int
+       use(x == x) // ERROR "slice can only be compared to nil"
+       use(f == f) // ERROR "func can only be compared to nil"
+       use(m == m) // ERROR "map can only be compared to nil"
 }
index 544d3487eff5c66adc99f3063afcf29cc3b390db..7eed8fb7abc2c0824b8ffdb57c33a17a5442afc9 100644 (file)
@@ -45,20 +45,6 @@ func main() {
        mp[p] = 42
        mp[&T{7}] = 42
 
-       type F func(x int)
-       f := func(x int) {}
-       mf := make(map[F]int)
-       mf[nil] = 42
-       mf[f] = 42
-       mf[func(x int) {}] = 42
-
-       type M map[int]int
-       m := make(M)
-       mm := make(map[M]int)
-       mm[nil] = 42
-       mm[m] = 42
-       mm[make(M)] = 42
-
        type C chan int
        c := make(C)
        mc := make(map[C]int)
index 3a56cf057dce3cb6dbcfeb839641635855dadffa..923e27e672f94ea619fe3e07ae923bc9cc62e753 100644 (file)
@@ -12,16 +12,16 @@ type v bool
 
 var (
        // valid
-       _ map[int8]v 
-       _ map[uint8]v 
-       _ map[int16]v 
-       _ map[uint16]v 
-       _ map[int32]v 
-       _ map[uint32]v 
-       _ map[int64]v 
-       _ map[uint64]v 
-       _ map[int]v 
-       _ map[uint]v 
+       _ map[int8]v
+       _ map[uint8]v
+       _ map[int16]v
+       _ map[uint16]v
+       _ map[int32]v
+       _ map[uint32]v
+       _ map[int64]v
+       _ map[uint64]v
+       _ map[int]v
+       _ map[uint]v
        _ map[uintptr]v
        _ map[float32]v
        _ map[float64]v
@@ -30,12 +30,12 @@ var (
        _ map[bool]v
        _ map[string]v
        _ map[chan int]v
-       _ map[func()]v
        _ map[*int]v
-       _ map[map[int]int]v
 
        // invalid
-       _ map[struct{}]v // ERROR "invalid map key"
-       _ map[[]int]v  // ERROR "invalid map key"
-       _ map[[10]int]v // ERROR "invalid map key"
+       _ map[struct{}]v    // ERROR "invalid map key"
+       _ map[[]int]v       // ERROR "invalid map key"
+       _ map[[10]int]v     // ERROR "invalid map key"
+       _ map[func()]v      // ERROR "invalid map key"
+       _ map[map[int]int]v // ERROR "invalid map key"
 )
index 0c253d6e2a7bdf238853ee40d5d4099575be2618..bed027ce85f6c9df79880dc18940a1be7756b6ad 100644 (file)
@@ -19,48 +19,75 @@ func main() {
        hello := "hello"
 
        switch true {
-       case i5 < 5: assert(false, "<")
-       case i5 == 5: assert(true, "!")
-       case i5 > 5: assert(false, ">")
+       case i5 < 5:
+               assert(false, "<")
+       case i5 == 5:
+               assert(true, "!")
+       case i5 > 5:
+               assert(false, ">")
        }
 
        switch {
-       case i5 < 5: assert(false, "<")
-       case i5 == 5: assert(true, "!")
-       case i5 > 5: assert(false, ">")
+       case i5 < 5:
+               assert(false, "<")
+       case i5 == 5:
+               assert(true, "!")
+       case i5 > 5:
+               assert(false, ">")
        }
 
        switch x := 5; true {
-       case i5 < x: assert(false, "<")
-       case i5 == x: assert(true, "!")
-       case i5 > x: assert(false, ">")
+       case i5 < x:
+               assert(false, "<")
+       case i5 == x:
+               assert(true, "!")
+       case i5 > x:
+               assert(false, ">")
        }
 
        switch x := 5; true {
-       case i5 < x: assert(false, "<")
-       case i5 == x: assert(true, "!")
-       case i5 > x: assert(false, ">")
+       case i5 < x:
+               assert(false, "<")
+       case i5 == x:
+               assert(true, "!")
+       case i5 > x:
+               assert(false, ">")
        }
 
        switch i5 {
-       case 0: assert(false, "0")
-       case 1: assert(false, "1")
-       case 2: assert(false, "2")
-       case 3: assert(false, "3")
-       case 4: assert(false, "4")
-       case 5: assert(true, "5")
-       case 6: assert(false, "6")
-       case 7: assert(false, "7")
-       case 8: assert(false, "8")
-       case 9: assert(false, "9")
-       default: assert(false, "default")
+       case 0:
+               assert(false, "0")
+       case 1:
+               assert(false, "1")
+       case 2:
+               assert(false, "2")
+       case 3:
+               assert(false, "3")
+       case 4:
+               assert(false, "4")
+       case 5:
+               assert(true, "5")
+       case 6:
+               assert(false, "6")
+       case 7:
+               assert(false, "7")
+       case 8:
+               assert(false, "8")
+       case 9:
+               assert(false, "9")
+       default:
+               assert(false, "default")
        }
 
        switch i5 {
-       case 0,1,2,3,4: assert(false, "4")
-       case 5: assert(true, "5")
-       case 6,7,8,9: assert(false, "9")
-       default: assert(false, "default")
+       case 0, 1, 2, 3, 4:
+               assert(false, "4")
+       case 5:
+               assert(true, "5")
+       case 6, 7, 8, 9:
+               assert(false, "9")
+       default:
+               assert(false, "default")
        }
 
        switch i5 {
@@ -68,72 +95,188 @@ func main() {
        case 1:
        case 2:
        case 3:
-       case 4: assert(false, "4")
-       case 5: assert(true, "5")
+       case 4:
+               assert(false, "4")
+       case 5:
+               assert(true, "5")
        case 6:
        case 7:
        case 8:
        case 9:
-       default: assert(i5 == 5, "good")
+       default:
+               assert(i5 == 5, "good")
        }
 
        switch i5 {
-       case 0: dummy := 0; _ = dummy; fallthrough
-       case 1: dummy := 0; _ = dummy; fallthrough
-       case 2: dummy := 0; _ = dummy; fallthrough
-       case 3: dummy := 0; _ = dummy; fallthrough
-       case 4: dummy := 0; _ = dummy; assert(false, "4")
-       case 5: dummy := 0; _ = dummy; fallthrough
-       case 6: dummy := 0; _ = dummy; fallthrough
-       case 7: dummy := 0; _ = dummy; fallthrough
-       case 8: dummy := 0; _ = dummy; fallthrough
-       case 9: dummy := 0; _ = dummy; fallthrough
-       default: dummy := 0; _ = dummy; assert(i5 == 5, "good")
+       case 0:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 1:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 2:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 3:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 4:
+               dummy := 0
+               _ = dummy
+               assert(false, "4")
+       case 5:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 6:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 7:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 8:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 9:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       default:
+               dummy := 0
+               _ = dummy
+               assert(i5 == 5, "good")
        }
 
        fired := false
        switch i5 {
-       case 0: dummy := 0; _ = dummy; fallthrough;  // tests scoping of cases
-       case 1: dummy := 0; _ = dummy; fallthrough
-       case 2: dummy := 0; _ = dummy; fallthrough
-       case 3: dummy := 0; _ = dummy; fallthrough
-       case 4: dummy := 0; _ = dummy; assert(false, "4")
-       case 5: dummy := 0; _ = dummy; fallthrough
-       case 6: dummy := 0; _ = dummy; fallthrough
-       case 7: dummy := 0; _ = dummy; fallthrough
-       case 8: dummy := 0; _ = dummy; fallthrough
-       case 9: dummy := 0; _ = dummy; fallthrough
-       default: dummy := 0; _ = dummy; fired = !fired; assert(i5 == 5, "good")
+       case 0:
+               dummy := 0
+               _ = dummy
+               fallthrough // tests scoping of cases
+       case 1:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 2:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 3:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 4:
+               dummy := 0
+               _ = dummy
+               assert(false, "4")
+       case 5:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 6:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 7:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 8:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       case 9:
+               dummy := 0
+               _ = dummy
+               fallthrough
+       default:
+               dummy := 0
+               _ = dummy
+               fired = !fired
+               assert(i5 == 5, "good")
        }
        assert(fired, "fired")
 
        count := 0
        switch i5 {
-       case 0: count = count + 1; fallthrough
-       case 1: count = count + 1; fallthrough
-       case 2: count = count + 1; fallthrough
-       case 3: count = count + 1; fallthrough
-       case 4: count = count + 1; assert(false, "4")
-       case 5: count = count + 1; fallthrough
-       case 6: count = count + 1; fallthrough
-       case 7: count = count + 1; fallthrough
-       case 8: count = count + 1; fallthrough
-       case 9: count = count + 1; fallthrough
-       default: assert(i5 == count, "good")
+       case 0:
+               count = count + 1
+               fallthrough
+       case 1:
+               count = count + 1
+               fallthrough
+       case 2:
+               count = count + 1
+               fallthrough
+       case 3:
+               count = count + 1
+               fallthrough
+       case 4:
+               count = count + 1
+               assert(false, "4")
+       case 5:
+               count = count + 1
+               fallthrough
+       case 6:
+               count = count + 1
+               fallthrough
+       case 7:
+               count = count + 1
+               fallthrough
+       case 8:
+               count = count + 1
+               fallthrough
+       case 9:
+               count = count + 1
+               fallthrough
+       default:
+               assert(i5 == count, "good")
        }
        assert(fired, "fired")
 
        switch hello {
-       case "wowie": assert(false, "wowie")
-       case "hello": assert(true, "hello")
-       case "jumpn": assert(false, "jumpn")
-       default: assert(false, "default")
+       case "wowie":
+               assert(false, "wowie")
+       case "hello":
+               assert(true, "hello")
+       case "jumpn":
+               assert(false, "jumpn")
+       default:
+               assert(false, "default")
        }
 
        fired = false
        switch i := i5 + 2; i {
-       case i7: fired = true
-       default: assert(false, "fail")
+       case i7:
+               fired = true
+       default:
+               assert(false, "fail")
        }
        assert(fired, "var")
+
+       // switch on nil-only comparison types
+       switch f := func() {}; f {
+       case nil:
+               assert(false, "f should not be nil")
+       default:
+       }
+
+       switch m := make(map[int]int); m {
+       case nil:
+               assert(false, "m should not be nil")
+       default:
+       }
+
+       switch a := make([]int, 1); a {
+       case nil:
+               assert(false, "m should not be nil")
+       default:
+       }
 }
index 95ff6ec3c2e449608e4e7d917907698388c9818b..e91499db096a1732f9dfc7205e0fc49b736505d5 100644 (file)
@@ -6,9 +6,8 @@
 
 package main
 
-
 type I interface {
-       M()
+       M()
 }
 
 func bad() {
@@ -16,11 +15,32 @@ func bad() {
        var s string
 
        switch i {
-       case s:  // ERROR "mismatched types string and I"
+       case s: // ERROR "mismatched types string and I"
        }
 
        switch s {
-       case i:  // ERROR "mismatched types I and string"
+       case i: // ERROR "mismatched types I and string"
+       }
+
+       var m, m1 map[int]int
+       switch m {
+       case nil:
+       case m1: // ERROR "can only compare map m to nil"
+       default:
+       }
+
+       var a, a1 []int
+       switch a {
+       case nil:
+       case a1: // ERROR "can only compare slice a to nil"
+       default:
+       }
+
+       var f, f1 func()
+       switch f {
+       case nil:
+       case f1: // ERROR "can only compare func f to nil"
+       default:
        }
 }
 
index 83fb0985a91e1a9eaf00b21c9df9c149ee9540de..aa911f9b621807dbf12f0f31f1814203a6d8db8e 100644 (file)
@@ -82,9 +82,9 @@ func main() {
                case []int:
                        assert(x[3] == 3 && i == Array, "array")
                case map[string]int:
-                       assert(x == m && i == Map, "map")
+                       assert(x != nil && i == Map, "map")
                case func(i int) interface{}:
-                       assert(x == f && i == Func, "fun")
+                       assert(x != nil && i == Func, "fun")
                default:
                        assert(false, "unknown")
                }
@@ -111,5 +111,4 @@ func main() {
        default:
                assert(false, "switch 4 unknown")
        }
-
 }