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, PRIME10 = 10093,
AUNK = 100, AUNK = 100,
// these values are known by runtime // these values are known by runtime
ASIMP = 0, AMEM = 0,
ANOEQ,
ASTRING, ASTRING,
APTR,
AINTER, AINTER,
ASLICE,
ASTRUCT,
BADWIDTH = -1000000000 BADWIDTH = -1000000000
}; };

View file

@ -291,26 +291,16 @@ algtype(Type *t)
{ {
int a; int a;
a = AUNK; if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN)
if(issimple[t->etype]) a = AMEM; // just bytes (int, ptr, etc)
a = ASIMP; // simple mem
else else
if(t->etype == TSTRING) if(t->etype == TSTRING)
a = ASTRING; // string a = ASTRING; // string
else else
if(isptr[simtype[t->etype]]) if(t->etype == TINTER)
a = APTR; // pointer
else
if(isslice(t))
a = ASLICE;
else
if(t->etype == TSTRUCT)
a = ASTRUCT;
else
if(isinter(t))
a = AINTER; // interface a = AINTER; // interface
// else else
// fatal("algtype: cant find type %T", t); a = ANOEQ; // just bytes, but no hash/eq
return a; return a;
} }

View file

@ -88,17 +88,9 @@ sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
Hchan *c; Hchan *c;
int32 i; int32 i;
switch(elemalg){ if(elemalg >= nelem(algarray)) {
case ASIMP:
case ASTRING:
case APTR:
case AINTER:
case AARRAY:
case ASTRUCT:
break;
default:
printf("chan(alg=%d)\n", elemalg); printf("chan(alg=%d)\n", elemalg);
throw("sys·newchan: unsupported channel element type"); throw("sys·newchan: unsupported elem type");
} }
c = mal(sizeof(*c)); c = mal(sizeof(*c));

View file

@ -663,28 +663,12 @@ sys·newmap(uint32 keysize, uint32 valsize,
{ {
Hmap *h; Hmap *h;
switch(keyalg) { if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
case ASIMP:
case ASTRING:
case APTR:
case AINTER:
case AARRAY:
case ASTRUCT:
break;
default:
printf("map(keyalg=%d)\n", keyalg); printf("map(keyalg=%d)\n", keyalg);
throw("sys·newmap: unsupported map key type"); throw("sys·newmap: unsupported map key type");
} }
switch(valalg) { if(valalg >= nelem(algarray)) {
case ASIMP:
case ASTRING:
case APTR:
case AINTER:
case AARRAY:
case ASTRUCT:
break;
default:
printf("map(valalg=%d)\n", valalg); printf("map(valalg=%d)\n", valalg);
throw("sys·newmap: unsupported map value type"); throw("sys·newmap: unsupported map value type");
} }

View file

@ -404,11 +404,32 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
FLUSH(&ok); FLUSH(&ok);
} }
// ifaceeq(i1 any, i2 any) (ret bool); uint64
void ifacehash(Iface a)
sys·ifaceeq(Iface i1, Iface i2, bool ret)
{ {
int32 alg, wid; 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) { if(iface_debug) {
prints("Ieq i1="); prints("Ieq i1=");
@ -438,6 +459,13 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret)
if(wid != i2.type->sigt->offset) if(wid != i2.type->sigt->offset)
goto no; 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(wid <= sizeof i1.data) {
if(!algarray[alg].equal(wid, &i1.data, &i2.data)) if(!algarray[alg].equal(wid, &i1.data, &i2.data))
goto no; goto no;
@ -454,6 +482,14 @@ no:
sys·printbool(ret); sys·printbool(ret);
prints("\n"); 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); FLUSH(&ret);
} }
@ -526,7 +562,7 @@ fakesigt(string type, bool indir)
sigt = mal(2*sizeof sigt[0]); sigt = mal(2*sizeof sigt[0]);
sigt[0].name = mal(type->len + 1); sigt[0].name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len); mcpy(sigt[0].name, type->str, type->len);
sigt[0].hash = ASIMP; // alg sigt[0].hash = AMEM; // alg
if(indir) if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width sigt[0].offset = 2*sizeof(niliface.data); // big width
else else

View file

@ -328,57 +328,52 @@ strprint(uint32 s, string *a)
sys·printstring(*a); sys·printstring(*a);
} }
static void static uint64
strcopy(uint32 s, string *a, string *b) interhash(uint32 s, Iface *a)
{ {
USED(s); USED(s);
if(b == nil) { return ifacehash(*a);
*a = nil;
return;
}
*a = *b;
} }
static uint64 static void
ptrhash(uint32 s, void **a) interprint(uint32 s, Iface *a)
{ {
return memhash(s, *a); USED(s);
sys·printinter(*a);
} }
static uint32 static uint32
ptrequal(uint32 s, void **a, void **b) interequal(uint32 s, Iface *a, Iface *b)
{ {
USED(s, a, b); USED(s);
prints("ptrequal\n"); return ifaceeq(*a, *b);
}
uint64
nohash(uint32 s, void *a)
{
USED(s);
USED(a);
throw("hash of unhashable type");
return 0; return 0;
} }
static void uint32
ptrprint(uint32 s, void **a) noequal(uint32 s, void *a, void *b)
{
USED(s, a);
prints("ptrprint\n");
}
static void
ptrcopy(uint32 s, void **a, void **b)
{ {
USED(s); USED(s);
if(b == nil) { USED(a);
*a = nil; USED(b);
return; throw("comparing uncomparable types");
} return 0;
*a = *b;
} }
Alg Alg
algarray[] = algarray[] =
{ {
[ASIMP] { memhash, memequal, memprint, memcopy }, [AMEM] { memhash, memequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, strcopy }, [ANOEQ] { nohash, noequal, memprint, memcopy },
[APTR] { memhash, memequal, memprint, memcopy }, // TODO: ptr routines [ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { memhash, memequal, memprint, memcopy }, // TODO: interface routines [AINTER] { interhash, interequal, interprint, memcopy },
[ASTRUCT] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
[AARRAY] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
}; };

View file

@ -226,18 +226,17 @@ struct Func
*/ */
enum enum
{ {
ASIMP = 0, AMEM,
ANOEQ,
ASTRING, ASTRING,
APTR,
AINTER, AINTER,
AARRAY, Amax
ASTRUCT,
}; };
/* /*
* external data * external data
*/ */
extern Alg algarray[]; extern Alg algarray[Amax];
extern string emptystring; extern string emptystring;
G* allg; G* allg;
int32 goidgen; int32 goidgen;
@ -299,6 +298,10 @@ void* stackalloc(uint32);
void stackfree(void*); void stackfree(void*);
MCache* allocmcache(void); MCache* allocmcache(void);
void mallocinit(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 #pragma varargck argpos printf 1
@ -366,6 +369,7 @@ void notewakeup(Note*);
#define sys_printfloat sys·printfloat #define sys_printfloat sys·printfloat
#define sys_printhex sys·printhex #define sys_printhex sys·printhex
#define sys_printint sys·printint #define sys_printint sys·printint
#define sys_printinter sys·printinter
#define sys_printpc sys·printpc #define sys_printpc sys·printpc
#define sys_printpointer sys·printpointer #define sys_printpointer sys·printpointer
#define sys_printstring sys·printstring #define sys_printstring sys·printstring
@ -393,6 +397,7 @@ void* sys_getcallerpc(void*);
void sys_printbool(bool); void sys_printbool(bool);
void sys_printfloat(float64); void sys_printfloat(float64);
void sys_printint(int64); void sys_printint(int64);
void sys_printinter(Iface);
void sys_printstring(string); void sys_printstring(string);
void sys_printpc(void*); void sys_printpc(void*);
void sys_printpointer(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 ct = make(chan T)
var ca = make(chan []int) var ca = make(chan []int)
@ -136,7 +117,6 @@ func interfacetest() {
func main() { func main() {
arraycmptest(); arraycmptest();
maptest(); maptest();
maptest2();
chantest(); chantest();
interfacetest(); 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 =========== ./convlit.go
BUG: errchk: ./convlit.go: missing expected error message on line 16: 'conver|incompatible' BUG: errchk: ./convlit.go: missing expected error message on line 16: 'conver|incompatible'
errchk: ./convlit.go: missing expected error message on line 22: 'convert' errchk: ./convlit.go: missing expected error message on line 22: 'convert'

View file

@ -52,7 +52,7 @@ func main() {
mipT := make(map[int] *T); mipT := make(map[int] *T);
mpTi := make(map[*T] int); mpTi := make(map[*T] int);
mit := make(map[int] T); mit := make(map[int] T);
mti := make(map[T] int); // mti := make(map[T] int);
type M map[int] int; type M map[int] int;
mipM := make(map[int] M); mipM := make(map[int] M);
@ -88,7 +88,7 @@ func main() {
mpTi[apT[i]] = i; mpTi[apT[i]] = i;
mipM[i] = m; mipM[i] = m;
mit[i] = t; mit[i] = t;
mti[t] = i; // mti[t] = i;
} }
// test len // test len
@ -122,15 +122,15 @@ func main() {
if len(mpTi) != count { if len(mpTi) != count {
fmt.Printf("len(mpTi) = %d\n", len(mpTi)); fmt.Printf("len(mpTi) = %d\n", len(mpTi));
} }
if len(mti) != count { // if len(mti) != count {
fmt.Printf("len(mti) = %d\n", len(mti)); // fmt.Printf("len(mti) = %d\n", len(mti));
} // }
if len(mipM) != count { if len(mipM) != count {
fmt.Printf("len(mipM) = %d\n", len(mipM)); fmt.Printf("len(mipM) = %d\n", len(mipM));
} }
if len(mti) != count { // if len(mti) != count {
fmt.Printf("len(mti) = %d\n", len(mti)); // fmt.Printf("len(mti) = %d\n", len(mti));
} // }
if len(mit) != count { if len(mit) != count {
fmt.Printf("len(mit) = %d\n", len(mit)); fmt.Printf("len(mit) = %d\n", len(mit));
} }
@ -174,15 +174,15 @@ func main() {
if(mpTi[apT[i]] != i) { if(mpTi[apT[i]] != i) {
fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]); fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]);
} }
if(mti[t] != i) { // if(mti[t] != i) {
fmt.Printf("mti[%s] = %s\n", s, mti[t]); // fmt.Printf("mti[%s] = %s\n", s, mti[t]);
} // }
if (mipM[i][i] != i + 1) { if (mipM[i][i] != i + 1) {
fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]); fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]);
} }
if(mti[t] != i) { // if(mti[t] != i) {
fmt.Printf("mti[%v] = %d\n", t, mti[t]); // fmt.Printf("mti[%v] = %d\n", t, mti[t]);
} // }
if(mit[i].i != int64(i) || mit[i].f != f) { if(mit[i].i != int64(i) || mit[i].f != f) {
fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].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); fmt.Printf("tuple existence assign: mit[%d]\n", i);
} }
} }
{ // {
a, b := mti[t]; // a, b := mti[t];
if !b { // if !b {
fmt.Printf("tuple existence decl: mti[%d]\n", i); // fmt.Printf("tuple existence decl: mti[%d]\n", i);
} // }
a, b = mti[t]; // a, b = mti[t];
if !b { // if !b {
fmt.Printf("tuple existence assign: mti[%d]\n", i); // fmt.Printf("tuple existence assign: mti[%d]\n", i);
} // }
} // }
} }
// test nonexistence with tuple check // test nonexistence with tuple check
@ -442,16 +442,16 @@ func main() {
fmt.Printf("tuple nonexistence assign: mipM[%d]", i); fmt.Printf("tuple nonexistence assign: mipM[%d]", i);
} }
} }
{ // {
a, b := mti[t]; // a, b := mti[t];
if b { // if b {
fmt.Printf("tuple nonexistence decl: mti[%d]", i); // fmt.Printf("tuple nonexistence decl: mti[%d]", i);
} // }
a, b = mti[t]; // a, b = mti[t];
if b { // if b {
fmt.Printf("tuple nonexistence assign: mti[%d]", i); // fmt.Printf("tuple nonexistence assign: mti[%d]", i);
} // }
} // }
{ {
a, b := mit[i]; a, b := mit[i];
if b { if b {