1
0
mirror of https://github.com/golang/go synced 2024-11-25 08:07:57 -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:
Russ Cox 2009-01-26 09:56:42 -08:00
parent 18b05c1a8d
commit a7f6d4066e
15 changed files with 284 additions and 143 deletions

View File

@ -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
};

View File

@ -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;
}

View File

@ -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));

View File

@ -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");
}

View File

@ -404,12 +404,33 @@ 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=");
printiface(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

View File

@ -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 },
};

View File

@ -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*);

View File

@ -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
View 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
View 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
View 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
View 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
View 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;
}

View File

@ -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'

View File

@ -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 {