Commit 5bb54b8e authored by Russ Cox's avatar Russ Cox

gc: remove func, map compare

R=ken, ken
CC=golang-dev
https://golang.org/cl/5373079
parent efb74460
...@@ -491,12 +491,12 @@ typeinit(void) ...@@ -491,12 +491,12 @@ typeinit(void)
okforeq[TPTR64] = 1; okforeq[TPTR64] = 1;
okforeq[TUNSAFEPTR] = 1; okforeq[TUNSAFEPTR] = 1;
okforeq[TINTER] = 1; okforeq[TINTER] = 1;
okforeq[TMAP] = 1;
okforeq[TCHAN] = 1; okforeq[TCHAN] = 1;
okforeq[TFUNC] = 1;
okforeq[TSTRING] = 1; okforeq[TSTRING] = 1;
okforeq[TBOOL] = 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; okforcmp[TSTRING] = 1;
......
...@@ -547,6 +547,8 @@ maptype(Type *key, Type *val) ...@@ -547,6 +547,8 @@ maptype(Type *key, Type *val)
switch(key->etype) { switch(key->etype) {
case TARRAY: case TARRAY:
case TSTRUCT: case TSTRUCT:
case TMAP:
case TFUNC:
yyerror("invalid map key type %T", key); yyerror("invalid map key type %T", key);
break; break;
case TFORW: case TFORW:
......
...@@ -811,6 +811,7 @@ void ...@@ -811,6 +811,7 @@ void
typecheckswitch(Node *n) typecheckswitch(Node *n)
{ {
int top, lno, ptr; int top, lno, ptr;
char *nilonly;
Type *t, *missing, *have; Type *t, *missing, *have;
NodeList *l, *ll; NodeList *l, *ll;
Node *ncase, *nvar; Node *ncase, *nvar;
...@@ -818,6 +819,7 @@ typecheckswitch(Node *n) ...@@ -818,6 +819,7 @@ typecheckswitch(Node *n)
lno = lineno; lno = lineno;
typechecklist(n->ninit, Etop); typechecklist(n->ninit, Etop);
nilonly = nil;
if(n->ntest != N && n->ntest->op == OTYPESW) { if(n->ntest != N && n->ntest->op == OTYPESW) {
// type switch // type switch
...@@ -835,6 +837,16 @@ typecheckswitch(Node *n) ...@@ -835,6 +837,16 @@ typecheckswitch(Node *n)
t = n->ntest->type; t = n->ntest->type;
} else } else
t = types[TBOOL]; 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; n->type = t;
...@@ -865,6 +877,8 @@ typecheckswitch(Node *n) ...@@ -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); yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
else else
yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, n->ntest, ll->n->type, t); 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; break;
case Etype: // type switch case Etype: // type switch
......
...@@ -445,8 +445,8 @@ reswitch: ...@@ -445,8 +445,8 @@ reswitch:
yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(et)); yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(et));
goto error; goto error;
} }
// okfor allows any array == array; // okfor allows any array == array, map == map, func == func.
// restrict to slice == nil and nil == slice. // restrict to slice/map/func == nil and nil == slice/map/func.
if(l->type->etype == TARRAY && !isslice(l->type)) if(l->type->etype == TARRAY && !isslice(l->type))
goto notokfor; goto notokfor;
if(r->type->etype == TARRAY && !isslice(r->type)) if(r->type->etype == TARRAY && !isslice(r->type))
...@@ -455,6 +455,15 @@ reswitch: ...@@ -455,6 +455,15 @@ reswitch:
yyerror("invalid operation: %N (slice can only be compared to nil)", n); yyerror("invalid operation: %N (slice can only be compared to nil)", n);
goto error; 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; t = l->type;
if(iscmp[n->op]) { if(iscmp[n->op]) {
evconst(n); evconst(n);
......
...@@ -76,7 +76,6 @@ func h() { ...@@ -76,7 +76,6 @@ func h() {
func newfunc() func(int) int { return func(x int) int { return x } } func newfunc() func(int) int { return func(x int) int { return x } }
func main() { func main() {
go f() go f()
check([]int{1, 4, 5, 4}) check([]int{1, 4, 5, 4})
...@@ -90,10 +89,6 @@ func main() { ...@@ -90,10 +89,6 @@ func main() {
check([]int{100, 200, 101, 201, 500, 101, 201, 500}) check([]int{100, 200, 101, 201, 500, 101, 201, 500})
x, y := newfunc(), newfunc() x, y := newfunc(), newfunc()
if x == y {
println("newfunc returned same func")
panic("fail")
}
if x(1) != 1 || y(2) != 2 { if x(1) != 1 || y(2) != 2 {
println("newfunc returned broken funcs") println("newfunc returned broken funcs")
panic("fail") panic("fail")
......
...@@ -11,7 +11,7 @@ func use(bool) {} ...@@ -11,7 +11,7 @@ func use(bool) {}
type T1 *int type T1 *int
type T2 *int type T2 *int
type T3 struct {} type T3 struct{}
var t3 T3 var t3 T3
...@@ -21,7 +21,7 @@ func main() { ...@@ -21,7 +21,7 @@ func main() {
// so chan int can be compared against // so chan int can be compared against
// directional channels but channel of different // directional channels but channel of different
// direction cannot be compared against each other. // direction cannot be compared against each other.
var c1 chan <-int var c1 chan<- int
var c2 <-chan int var c2 <-chan int
var c3 chan int var c3 chan int
...@@ -46,4 +46,12 @@ func main() { ...@@ -46,4 +46,12 @@ func main() {
// Comparison of structs should have a good message // 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"
} }
...@@ -45,20 +45,6 @@ func main() { ...@@ -45,20 +45,6 @@ func main() {
mp[p] = 42 mp[p] = 42
mp[&T{7}] = 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 type C chan int
c := make(C) c := make(C)
mc := make(map[C]int) mc := make(map[C]int)
......
...@@ -30,12 +30,12 @@ var ( ...@@ -30,12 +30,12 @@ var (
_ map[bool]v _ map[bool]v
_ map[string]v _ map[string]v
_ map[chan int]v _ map[chan int]v
_ map[func()]v
_ map[*int]v _ map[*int]v
_ map[map[int]int]v
// invalid // invalid
_ map[struct{}]v // ERROR "invalid map key" _ map[struct{}]v // ERROR "invalid map key"
_ map[[]int]v // ERROR "invalid map key" _ map[[]int]v // ERROR "invalid map key"
_ map[[10]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"
) )
...@@ -19,48 +19,75 @@ func main() { ...@@ -19,48 +19,75 @@ func main() {
hello := "hello" hello := "hello"
switch true { switch true {
case i5 < 5: assert(false, "<") case i5 < 5:
case i5 == 5: assert(true, "!") assert(false, "<")
case i5 > 5: assert(false, ">") case i5 == 5:
assert(true, "!")
case i5 > 5:
assert(false, ">")
} }
switch { switch {
case i5 < 5: assert(false, "<") case i5 < 5:
case i5 == 5: assert(true, "!") assert(false, "<")
case i5 > 5: assert(false, ">") case i5 == 5:
assert(true, "!")
case i5 > 5:
assert(false, ">")
} }
switch x := 5; true { switch x := 5; true {
case i5 < x: assert(false, "<") case i5 < x:
case i5 == x: assert(true, "!") assert(false, "<")
case i5 > x: assert(false, ">") case i5 == x:
assert(true, "!")
case i5 > x:
assert(false, ">")
} }
switch x := 5; true { switch x := 5; true {
case i5 < x: assert(false, "<") case i5 < x:
case i5 == x: assert(true, "!") assert(false, "<")
case i5 > x: assert(false, ">") case i5 == x:
assert(true, "!")
case i5 > x:
assert(false, ">")
} }
switch i5 { switch i5 {
case 0: assert(false, "0") case 0:
case 1: assert(false, "1") assert(false, "0")
case 2: assert(false, "2") case 1:
case 3: assert(false, "3") assert(false, "1")
case 4: assert(false, "4") case 2:
case 5: assert(true, "5") assert(false, "2")
case 6: assert(false, "6") case 3:
case 7: assert(false, "7") assert(false, "3")
case 8: assert(false, "8") case 4:
case 9: assert(false, "9") assert(false, "4")
default: assert(false, "default") 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 { switch i5 {
case 0,1,2,3,4: assert(false, "4") case 0, 1, 2, 3, 4:
case 5: assert(true, "5") assert(false, "4")
case 6,7,8,9: assert(false, "9") case 5:
default: assert(false, "default") assert(true, "5")
case 6, 7, 8, 9:
assert(false, "9")
default:
assert(false, "default")
} }
switch i5 { switch i5 {
...@@ -68,72 +95,188 @@ func main() { ...@@ -68,72 +95,188 @@ func main() {
case 1: case 1:
case 2: case 2:
case 3: case 3:
case 4: assert(false, "4") case 4:
case 5: assert(true, "5") assert(false, "4")
case 5:
assert(true, "5")
case 6: case 6:
case 7: case 7:
case 8: case 8:
case 9: case 9:
default: assert(i5 == 5, "good") default:
assert(i5 == 5, "good")
} }
switch i5 { switch i5 {
case 0: dummy := 0; _ = dummy; fallthrough case 0:
case 1: dummy := 0; _ = dummy; fallthrough dummy := 0
case 2: dummy := 0; _ = dummy; fallthrough _ = dummy
case 3: dummy := 0; _ = dummy; fallthrough fallthrough
case 4: dummy := 0; _ = dummy; assert(false, "4") case 1:
case 5: dummy := 0; _ = dummy; fallthrough dummy := 0
case 6: dummy := 0; _ = dummy; fallthrough _ = dummy
case 7: dummy := 0; _ = dummy; fallthrough fallthrough
case 8: dummy := 0; _ = dummy; fallthrough case 2:
case 9: dummy := 0; _ = dummy; fallthrough dummy := 0
default: dummy := 0; _ = dummy; assert(i5 == 5, "good") _ = 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 fired := false
switch i5 { switch i5 {
case 0: dummy := 0; _ = dummy; fallthrough; // tests scoping of cases case 0:
case 1: dummy := 0; _ = dummy; fallthrough dummy := 0
case 2: dummy := 0; _ = dummy; fallthrough _ = dummy
case 3: dummy := 0; _ = dummy; fallthrough fallthrough // tests scoping of cases
case 4: dummy := 0; _ = dummy; assert(false, "4") case 1:
case 5: dummy := 0; _ = dummy; fallthrough dummy := 0
case 6: dummy := 0; _ = dummy; fallthrough _ = dummy
case 7: dummy := 0; _ = dummy; fallthrough fallthrough
case 8: dummy := 0; _ = dummy; fallthrough case 2:
case 9: dummy := 0; _ = dummy; fallthrough dummy := 0
default: dummy := 0; _ = dummy; fired = !fired; assert(i5 == 5, "good") _ = 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") assert(fired, "fired")
count := 0 count := 0
switch i5 { switch i5 {
case 0: count = count + 1; fallthrough case 0:
case 1: count = count + 1; fallthrough count = count + 1
case 2: count = count + 1; fallthrough fallthrough
case 3: count = count + 1; fallthrough case 1:
case 4: count = count + 1; assert(false, "4") count = count + 1
case 5: count = count + 1; fallthrough fallthrough
case 6: count = count + 1; fallthrough case 2:
case 7: count = count + 1; fallthrough count = count + 1
case 8: count = count + 1; fallthrough fallthrough
case 9: count = count + 1; fallthrough case 3:
default: assert(i5 == count, "good") 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") assert(fired, "fired")
switch hello { switch hello {
case "wowie": assert(false, "wowie") case "wowie":
case "hello": assert(true, "hello") assert(false, "wowie")
case "jumpn": assert(false, "jumpn") case "hello":
default: assert(false, "default") assert(true, "hello")
case "jumpn":
assert(false, "jumpn")
default:
assert(false, "default")
} }
fired = false fired = false
switch i := i5 + 2; i { switch i := i5 + 2; i {
case i7: fired = true case i7:
default: assert(false, "fail") fired = true
default:
assert(false, "fail")
} }
assert(fired, "var") 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:
}
} }
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
package main package main
type I interface { type I interface {
M() M()
} }
...@@ -22,6 +21,27 @@ func bad() { ...@@ -22,6 +21,27 @@ func bad() {
switch s { 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:
}
} }
func good() { func good() {
......
...@@ -82,9 +82,9 @@ func main() { ...@@ -82,9 +82,9 @@ func main() {
case []int: case []int:
assert(x[3] == 3 && i == Array, "array") assert(x[3] == 3 && i == Array, "array")
case map[string]int: case map[string]int:
assert(x == m && i == Map, "map") assert(x != nil && i == Map, "map")
case func(i int) interface{}: case func(i int) interface{}:
assert(x == f && i == Func, "fun") assert(x != nil && i == Func, "fun")
default: default:
assert(false, "unknown") assert(false, "unknown")
} }
...@@ -111,5 +111,4 @@ func main() { ...@@ -111,5 +111,4 @@ func main() {
default: default:
assert(false, "switch 4 unknown") assert(false, "switch 4 unknown")
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment