mirror of
https://github.com/golang/go
synced 2024-11-21 21:44:40 -07:00
implement new restrictions on what
can be compared/hashed. R=r DELTA=351 (201 added, 80 deleted, 70 changed) OCL=23423 CL=23481
This commit is contained in:
parent
18b05c1a8d
commit
a7f6d4066e
@ -37,13 +37,12 @@ enum
|
||||
PRIME10 = 10093,
|
||||
|
||||
AUNK = 100,
|
||||
|
||||
// these values are known by runtime
|
||||
ASIMP = 0,
|
||||
AMEM = 0,
|
||||
ANOEQ,
|
||||
ASTRING,
|
||||
APTR,
|
||||
AINTER,
|
||||
ASLICE,
|
||||
ASTRUCT,
|
||||
|
||||
BADWIDTH = -1000000000
|
||||
};
|
||||
|
@ -291,26 +291,16 @@ algtype(Type *t)
|
||||
{
|
||||
int a;
|
||||
|
||||
a = AUNK;
|
||||
if(issimple[t->etype])
|
||||
a = ASIMP; // simple mem
|
||||
if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN)
|
||||
a = AMEM; // just bytes (int, ptr, etc)
|
||||
else
|
||||
if(t->etype == TSTRING)
|
||||
a = ASTRING; // string
|
||||
else
|
||||
if(isptr[simtype[t->etype]])
|
||||
a = APTR; // pointer
|
||||
else
|
||||
if(isslice(t))
|
||||
a = ASLICE;
|
||||
else
|
||||
if(t->etype == TSTRUCT)
|
||||
a = ASTRUCT;
|
||||
else
|
||||
if(isinter(t))
|
||||
if(t->etype == TINTER)
|
||||
a = AINTER; // interface
|
||||
// else
|
||||
// fatal("algtype: cant find type %T", t);
|
||||
else
|
||||
a = ANOEQ; // just bytes, but no hash/eq
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -88,17 +88,9 @@ sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
|
||||
Hchan *c;
|
||||
int32 i;
|
||||
|
||||
switch(elemalg){
|
||||
case ASIMP:
|
||||
case ASTRING:
|
||||
case APTR:
|
||||
case AINTER:
|
||||
case AARRAY:
|
||||
case ASTRUCT:
|
||||
break;
|
||||
default:
|
||||
if(elemalg >= nelem(algarray)) {
|
||||
printf("chan(alg=%d)\n", elemalg);
|
||||
throw("sys·newchan: unsupported channel element type");
|
||||
throw("sys·newchan: unsupported elem type");
|
||||
}
|
||||
|
||||
c = mal(sizeof(*c));
|
||||
|
@ -663,28 +663,12 @@ sys·newmap(uint32 keysize, uint32 valsize,
|
||||
{
|
||||
Hmap *h;
|
||||
|
||||
switch(keyalg) {
|
||||
case ASIMP:
|
||||
case ASTRING:
|
||||
case APTR:
|
||||
case AINTER:
|
||||
case AARRAY:
|
||||
case ASTRUCT:
|
||||
break;
|
||||
default:
|
||||
if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
|
||||
printf("map(keyalg=%d)\n", keyalg);
|
||||
throw("sys·newmap: unsupported map key type");
|
||||
}
|
||||
|
||||
switch(valalg) {
|
||||
case ASIMP:
|
||||
case ASTRING:
|
||||
case APTR:
|
||||
case AINTER:
|
||||
case AARRAY:
|
||||
case ASTRUCT:
|
||||
break;
|
||||
default:
|
||||
if(valalg >= nelem(algarray)) {
|
||||
printf("map(valalg=%d)\n", valalg);
|
||||
throw("sys·newmap: unsupported map value type");
|
||||
}
|
||||
|
@ -404,11 +404,32 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
|
||||
FLUSH(&ok);
|
||||
}
|
||||
|
||||
// ifaceeq(i1 any, i2 any) (ret bool);
|
||||
void
|
||||
sys·ifaceeq(Iface i1, Iface i2, bool ret)
|
||||
uint64
|
||||
ifacehash(Iface a)
|
||||
{
|
||||
int32 alg, wid;
|
||||
|
||||
if(a.type == nil)
|
||||
return 0;
|
||||
alg = a.type->sigt->hash;
|
||||
wid = a.type->sigt->offset;
|
||||
if(algarray[alg].hash == nohash) {
|
||||
// calling nohash will throw too,
|
||||
// but we can print a better error.
|
||||
printf("hash of unhashable type %s\n", a.type->sigt->name);
|
||||
throw("interface hash");
|
||||
}
|
||||
if(wid <= sizeof a.data)
|
||||
return algarray[alg].hash(wid, &a.data);
|
||||
else
|
||||
return algarray[alg].hash(wid, a.data);
|
||||
}
|
||||
|
||||
bool
|
||||
ifaceeq(Iface i1, Iface i2)
|
||||
{
|
||||
int32 alg, wid;
|
||||
bool ret;
|
||||
|
||||
if(iface_debug) {
|
||||
prints("Ieq i1=");
|
||||
@ -438,6 +459,13 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret)
|
||||
if(wid != i2.type->sigt->offset)
|
||||
goto no;
|
||||
|
||||
if(algarray[alg].equal == noequal) {
|
||||
// calling noequal will throw too,
|
||||
// but we can print a better error.
|
||||
printf("comparing uncomparable type %s\n", i1.type->sigt->name);
|
||||
throw("interface compare");
|
||||
}
|
||||
|
||||
if(wid <= sizeof i1.data) {
|
||||
if(!algarray[alg].equal(wid, &i1.data, &i2.data))
|
||||
goto no;
|
||||
@ -454,6 +482,14 @@ no:
|
||||
sys·printbool(ret);
|
||||
prints("\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ifaceeq(i1 any, i2 any) (ret bool);
|
||||
void
|
||||
sys·ifaceeq(Iface i1, Iface i2, bool ret)
|
||||
{
|
||||
ret = ifaceeq(i1, i2);
|
||||
FLUSH(&ret);
|
||||
}
|
||||
|
||||
@ -526,7 +562,7 @@ fakesigt(string type, bool indir)
|
||||
sigt = mal(2*sizeof sigt[0]);
|
||||
sigt[0].name = mal(type->len + 1);
|
||||
mcpy(sigt[0].name, type->str, type->len);
|
||||
sigt[0].hash = ASIMP; // alg
|
||||
sigt[0].hash = AMEM; // alg
|
||||
if(indir)
|
||||
sigt[0].offset = 2*sizeof(niliface.data); // big width
|
||||
else
|
||||
|
@ -328,57 +328,52 @@ strprint(uint32 s, string *a)
|
||||
sys·printstring(*a);
|
||||
}
|
||||
|
||||
static void
|
||||
strcopy(uint32 s, string *a, string *b)
|
||||
static uint64
|
||||
interhash(uint32 s, Iface *a)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = nil;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
return ifacehash(*a);
|
||||
}
|
||||
|
||||
static uint64
|
||||
ptrhash(uint32 s, void **a)
|
||||
static void
|
||||
interprint(uint32 s, Iface *a)
|
||||
{
|
||||
return memhash(s, *a);
|
||||
USED(s);
|
||||
sys·printinter(*a);
|
||||
}
|
||||
|
||||
static uint32
|
||||
ptrequal(uint32 s, void **a, void **b)
|
||||
interequal(uint32 s, Iface *a, Iface *b)
|
||||
{
|
||||
USED(s, a, b);
|
||||
prints("ptrequal\n");
|
||||
USED(s);
|
||||
return ifaceeq(*a, *b);
|
||||
}
|
||||
|
||||
uint64
|
||||
nohash(uint32 s, void *a)
|
||||
{
|
||||
USED(s);
|
||||
USED(a);
|
||||
throw("hash of unhashable type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ptrprint(uint32 s, void **a)
|
||||
{
|
||||
USED(s, a);
|
||||
prints("ptrprint\n");
|
||||
}
|
||||
|
||||
static void
|
||||
ptrcopy(uint32 s, void **a, void **b)
|
||||
uint32
|
||||
noequal(uint32 s, void *a, void *b)
|
||||
{
|
||||
USED(s);
|
||||
if(b == nil) {
|
||||
*a = nil;
|
||||
return;
|
||||
}
|
||||
*a = *b;
|
||||
USED(a);
|
||||
USED(b);
|
||||
throw("comparing uncomparable types");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Alg
|
||||
algarray[] =
|
||||
{
|
||||
[ASIMP] { memhash, memequal, memprint, memcopy },
|
||||
[ASTRING] { strhash, strequal, strprint, strcopy },
|
||||
[APTR] { memhash, memequal, memprint, memcopy }, // TODO: ptr routines
|
||||
[AINTER] { memhash, memequal, memprint, memcopy }, // TODO: interface routines
|
||||
[ASTRUCT] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
|
||||
[AARRAY] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
|
||||
[AMEM] { memhash, memequal, memprint, memcopy },
|
||||
[ANOEQ] { nohash, noequal, memprint, memcopy },
|
||||
[ASTRING] { strhash, strequal, strprint, memcopy },
|
||||
[AINTER] { interhash, interequal, interprint, memcopy },
|
||||
};
|
||||
|
||||
|
@ -226,18 +226,17 @@ struct Func
|
||||
*/
|
||||
enum
|
||||
{
|
||||
ASIMP = 0,
|
||||
AMEM,
|
||||
ANOEQ,
|
||||
ASTRING,
|
||||
APTR,
|
||||
AINTER,
|
||||
AARRAY,
|
||||
ASTRUCT,
|
||||
Amax
|
||||
};
|
||||
|
||||
/*
|
||||
* external data
|
||||
*/
|
||||
extern Alg algarray[];
|
||||
extern Alg algarray[Amax];
|
||||
extern string emptystring;
|
||||
G* allg;
|
||||
int32 goidgen;
|
||||
@ -299,6 +298,10 @@ void* stackalloc(uint32);
|
||||
void stackfree(void*);
|
||||
MCache* allocmcache(void);
|
||||
void mallocinit(void);
|
||||
bool ifaceeq(Iface, Iface);
|
||||
uint64 ifacehash(Iface);
|
||||
uint64 nohash(uint32, void*);
|
||||
uint32 noequal(uint32, void*, void*);
|
||||
|
||||
#pragma varargck argpos printf 1
|
||||
|
||||
@ -366,6 +369,7 @@ void notewakeup(Note*);
|
||||
#define sys_printfloat sys·printfloat
|
||||
#define sys_printhex sys·printhex
|
||||
#define sys_printint sys·printint
|
||||
#define sys_printinter sys·printinter
|
||||
#define sys_printpc sys·printpc
|
||||
#define sys_printpointer sys·printpointer
|
||||
#define sys_printstring sys·printstring
|
||||
@ -393,6 +397,7 @@ void* sys_getcallerpc(void*);
|
||||
void sys_printbool(bool);
|
||||
void sys_printfloat(float64);
|
||||
void sys_printint(int64);
|
||||
void sys_printinter(Iface);
|
||||
void sys_printstring(string);
|
||||
void sys_printpc(void*);
|
||||
void sys_printpointer(void*);
|
||||
|
@ -62,25 +62,6 @@ func maptest() {
|
||||
}
|
||||
}
|
||||
|
||||
var mt1 = make(map[T]int)
|
||||
var ma1 = make(map[[]int] int)
|
||||
|
||||
func maptest2() {
|
||||
mt1[t] = 123;
|
||||
t1 := t;
|
||||
val, ok := mt1[t1];
|
||||
if val != 123 || !ok {
|
||||
println("fail: map key struct", val, ok);
|
||||
}
|
||||
|
||||
ma1[a] = 345;
|
||||
a1 := a;
|
||||
val, ok = ma1[a1];
|
||||
if val != 345 || !ok {
|
||||
panic("map key array", val, ok);
|
||||
}
|
||||
}
|
||||
|
||||
var ct = make(chan T)
|
||||
var ca = make(chan []int)
|
||||
|
||||
@ -136,7 +117,6 @@ func interfacetest() {
|
||||
func main() {
|
||||
arraycmptest();
|
||||
maptest();
|
||||
maptest2();
|
||||
chantest();
|
||||
interfacetest();
|
||||
}
|
||||
|
66
test/cmp1.go
Normal file
66
test/cmp1.go
Normal file
@ -0,0 +1,66 @@
|
||||
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func use(bool) { }
|
||||
|
||||
func stringptr(s string) uintptr {
|
||||
return *(&s).(unsafe.Pointer).(*uintptr);
|
||||
}
|
||||
|
||||
func isfalse(b bool) {
|
||||
if b { panicln("wanted false, got true") } // stack will explain where
|
||||
}
|
||||
|
||||
func istrue(b bool) {
|
||||
if !b { panicln("wanted true, got false") } // stack will explain where
|
||||
}
|
||||
|
||||
func main()
|
||||
{
|
||||
var a []int;
|
||||
var b map[string]int;
|
||||
|
||||
var c string = "hello";
|
||||
var d string = "hel"; // try to get different pointer
|
||||
d = d + "lo";
|
||||
if stringptr(c) == stringptr(d) {
|
||||
panic("compiler too smart -- got same string")
|
||||
}
|
||||
|
||||
var e = make(chan int);
|
||||
|
||||
var ia interface{} = a;
|
||||
var ib interface{} = b;
|
||||
var ic interface{} = c;
|
||||
var id interface{} = d;
|
||||
var ie interface{} = e;
|
||||
|
||||
// these comparisons are okay because
|
||||
// string compare is okay and the others
|
||||
// are comparisons where the types differ.
|
||||
isfalse(ia == ib);
|
||||
isfalse(ia == ic);
|
||||
isfalse(ia == id);
|
||||
isfalse(ib == ic);
|
||||
isfalse(ib == id);
|
||||
istrue(ic == id);
|
||||
istrue(ie == ie);
|
||||
|
||||
// map of interface should use == on interface values,
|
||||
// not memory.
|
||||
// TODO: should m[c], m[d] be valid here?
|
||||
var m = make(map[interface{}] int);
|
||||
m[ic] = 1;
|
||||
m[id] = 2;
|
||||
if m[ic] != 2 {
|
||||
panic("m[ic] = ", m[ic]);
|
||||
}
|
||||
}
|
||||
|
16
test/cmp2.go
Normal file
16
test/cmp2.go
Normal file
@ -0,0 +1,16 @@
|
||||
// $G $D/$F.go && $L $F.$A && ! ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func use(bool) { }
|
||||
|
||||
func main()
|
||||
{
|
||||
var a []int;
|
||||
var ia interface{} = a;
|
||||
use(ia == ia);
|
||||
}
|
16
test/cmp3.go
Normal file
16
test/cmp3.go
Normal file
@ -0,0 +1,16 @@
|
||||
// $G $D/$F.go && $L $F.$A && ! ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func use(bool) { }
|
||||
|
||||
func main()
|
||||
{
|
||||
var b map[string]int;
|
||||
var ib interface{} = b;
|
||||
use(ib == ib);
|
||||
}
|
15
test/cmp4.go
Normal file
15
test/cmp4.go
Normal file
@ -0,0 +1,15 @@
|
||||
// $G $D/$F.go && $L $F.$A && ! ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func main()
|
||||
{
|
||||
var a []int;
|
||||
var ia interface{} = a;
|
||||
var m = make(map[interface{}] int);
|
||||
m[ia] = 1;
|
||||
}
|
15
test/cmp5.go
Normal file
15
test/cmp5.go
Normal file
@ -0,0 +1,15 @@
|
||||
// $G $D/$F.go && $L $F.$A && ! ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func main()
|
||||
{
|
||||
var b map[string]int;
|
||||
var ib interface{} = b;
|
||||
var m = make(map[interface{}] int);
|
||||
m[ib] = 1;
|
||||
}
|
@ -1,4 +1,36 @@
|
||||
|
||||
=========== ./cmp2.go
|
||||
comparing uncomparable type []int
|
||||
throw: interface compare
|
||||
SIGSEGV: segmentation violation
|
||||
Faulting address: 0x0
|
||||
pc: xxx
|
||||
|
||||
|
||||
=========== ./cmp3.go
|
||||
comparing uncomparable type map[string] int
|
||||
throw: interface compare
|
||||
SIGSEGV: segmentation violation
|
||||
Faulting address: 0x0
|
||||
pc: xxx
|
||||
|
||||
|
||||
=========== ./cmp4.go
|
||||
hash of unhashable type []int
|
||||
throw: interface hash
|
||||
SIGSEGV: segmentation violation
|
||||
Faulting address: 0x0
|
||||
pc: xxx
|
||||
|
||||
|
||||
=========== ./cmp5.go
|
||||
hash of unhashable type map[string] int
|
||||
throw: interface hash
|
||||
SIGSEGV: segmentation violation
|
||||
Faulting address: 0x0
|
||||
pc: xxx
|
||||
|
||||
|
||||
=========== ./convlit.go
|
||||
BUG: errchk: ./convlit.go: missing expected error message on line 16: 'conver|incompatible'
|
||||
errchk: ./convlit.go: missing expected error message on line 22: 'convert'
|
||||
|
68
test/map.go
68
test/map.go
@ -52,7 +52,7 @@ func main() {
|
||||
mipT := make(map[int] *T);
|
||||
mpTi := make(map[*T] int);
|
||||
mit := make(map[int] T);
|
||||
mti := make(map[T] int);
|
||||
// mti := make(map[T] int);
|
||||
|
||||
type M map[int] int;
|
||||
mipM := make(map[int] M);
|
||||
@ -88,7 +88,7 @@ func main() {
|
||||
mpTi[apT[i]] = i;
|
||||
mipM[i] = m;
|
||||
mit[i] = t;
|
||||
mti[t] = i;
|
||||
// mti[t] = i;
|
||||
}
|
||||
|
||||
// test len
|
||||
@ -122,15 +122,15 @@ func main() {
|
||||
if len(mpTi) != count {
|
||||
fmt.Printf("len(mpTi) = %d\n", len(mpTi));
|
||||
}
|
||||
if len(mti) != count {
|
||||
fmt.Printf("len(mti) = %d\n", len(mti));
|
||||
}
|
||||
// if len(mti) != count {
|
||||
// fmt.Printf("len(mti) = %d\n", len(mti));
|
||||
// }
|
||||
if len(mipM) != count {
|
||||
fmt.Printf("len(mipM) = %d\n", len(mipM));
|
||||
}
|
||||
if len(mti) != count {
|
||||
fmt.Printf("len(mti) = %d\n", len(mti));
|
||||
}
|
||||
// if len(mti) != count {
|
||||
// fmt.Printf("len(mti) = %d\n", len(mti));
|
||||
// }
|
||||
if len(mit) != count {
|
||||
fmt.Printf("len(mit) = %d\n", len(mit));
|
||||
}
|
||||
@ -174,15 +174,15 @@ func main() {
|
||||
if(mpTi[apT[i]] != i) {
|
||||
fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]);
|
||||
}
|
||||
if(mti[t] != i) {
|
||||
fmt.Printf("mti[%s] = %s\n", s, mti[t]);
|
||||
}
|
||||
// if(mti[t] != i) {
|
||||
// fmt.Printf("mti[%s] = %s\n", s, mti[t]);
|
||||
// }
|
||||
if (mipM[i][i] != i + 1) {
|
||||
fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]);
|
||||
}
|
||||
if(mti[t] != i) {
|
||||
fmt.Printf("mti[%v] = %d\n", t, mti[t]);
|
||||
}
|
||||
// if(mti[t] != i) {
|
||||
// fmt.Printf("mti[%v] = %d\n", t, mti[t]);
|
||||
// }
|
||||
if(mit[i].i != int64(i) || mit[i].f != f) {
|
||||
fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f);
|
||||
}
|
||||
@ -314,16 +314,16 @@ func main() {
|
||||
fmt.Printf("tuple existence assign: mit[%d]\n", i);
|
||||
}
|
||||
}
|
||||
{
|
||||
a, b := mti[t];
|
||||
if !b {
|
||||
fmt.Printf("tuple existence decl: mti[%d]\n", i);
|
||||
}
|
||||
a, b = mti[t];
|
||||
if !b {
|
||||
fmt.Printf("tuple existence assign: mti[%d]\n", i);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// a, b := mti[t];
|
||||
// if !b {
|
||||
// fmt.Printf("tuple existence decl: mti[%d]\n", i);
|
||||
// }
|
||||
// a, b = mti[t];
|
||||
// if !b {
|
||||
// fmt.Printf("tuple existence assign: mti[%d]\n", i);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// test nonexistence with tuple check
|
||||
@ -442,16 +442,16 @@ func main() {
|
||||
fmt.Printf("tuple nonexistence assign: mipM[%d]", i);
|
||||
}
|
||||
}
|
||||
{
|
||||
a, b := mti[t];
|
||||
if b {
|
||||
fmt.Printf("tuple nonexistence decl: mti[%d]", i);
|
||||
}
|
||||
a, b = mti[t];
|
||||
if b {
|
||||
fmt.Printf("tuple nonexistence assign: mti[%d]", i);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// a, b := mti[t];
|
||||
// if b {
|
||||
// fmt.Printf("tuple nonexistence decl: mti[%d]", i);
|
||||
// }
|
||||
// a, b = mti[t];
|
||||
// if b {
|
||||
// fmt.Printf("tuple nonexistence assign: mti[%d]", i);
|
||||
// }
|
||||
// }
|
||||
{
|
||||
a, b := mit[i];
|
||||
if b {
|
||||
|
Loading…
Reference in New Issue
Block a user