Commit e0b195b5 by Ian Lance Taylor

reflect: canonicalize types returned by StructOf() and friends

    
    Background: since gccgo does not currently merge identical types at link time,
    the reflect function canonicalize() exists to choose a canonical specimen
    for each set of identical types.
    In this way, user code has the guarantee that identical types
    will always compare as ==
    
    Change: arrange reflect functions MapOf(), SliceOf(), StructOf() etc.
    to call canonicalize() on the types they create, before storing the types
    in internal lookup caches and returning them.
    
    This fixes known cases where canonicalize() is needed but was missing.
    Supersedes https://golang.org/cl/112575 and mostly fixes issue 25284.
    
    Updates golang/go#25284
    
    Reviewed-on: https://go-review.googlesource.com/115577

From-SVN: r261216
parent 6d02e2d9
8e74a218e11ef6eaaf7014a3ad1cd0b13359c607 8b6c7f3f9762366bab96ea95b966e93e2593be13
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -3928,8 +3928,8 @@ func TestOverflow(t *testing.T) { ...@@ -3928,8 +3928,8 @@ func TestOverflow(t *testing.T) {
} }
} }
func checkSameType(t *testing.T, x, y interface{}) { func checkSameType(t *testing.T, x Type, y interface{}) {
if TypeOf(x) != TypeOf(y) { if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) {
t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y)) t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))
} }
} }
...@@ -4058,7 +4058,7 @@ func TestArrayOf(t *testing.T) { ...@@ -4058,7 +4058,7 @@ func TestArrayOf(t *testing.T) {
// check that type already in binary is found // check that type already in binary is found
type T int type T int
checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) checkSameType(t, ArrayOf(5, TypeOf(T(1))), [5]T{})
} }
func TestArrayOfGC(t *testing.T) { func TestArrayOfGC(t *testing.T) {
...@@ -4195,7 +4195,7 @@ func TestSliceOf(t *testing.T) { ...@@ -4195,7 +4195,7 @@ func TestSliceOf(t *testing.T) {
// check that type already in binary is found // check that type already in binary is found
type T1 int type T1 int
checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{}) checkSameType(t, SliceOf(TypeOf(T1(1))), []T1{})
} }
func TestSliceOverflow(t *testing.T) { func TestSliceOverflow(t *testing.T) {
...@@ -4410,7 +4410,7 @@ func TestStructOf(t *testing.T) { ...@@ -4410,7 +4410,7 @@ func TestStructOf(t *testing.T) {
}) })
}) })
// check that type already in binary is found // check that type already in binary is found
checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{}) checkSameType(t, StructOf(fields[2:3]), struct{ Y uint64 }{})
} }
func TestStructOfExportRules(t *testing.T) { func TestStructOfExportRules(t *testing.T) {
...@@ -4963,7 +4963,7 @@ func TestChanOf(t *testing.T) { ...@@ -4963,7 +4963,7 @@ func TestChanOf(t *testing.T) {
// check that type already in binary is found // check that type already in binary is found
type T1 int type T1 int
checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) checkSameType(t, ChanOf(BothDir, TypeOf(T1(1))), (chan T1)(nil))
} }
func TestChanOfDir(t *testing.T) { func TestChanOfDir(t *testing.T) {
...@@ -4974,8 +4974,8 @@ func TestChanOfDir(t *testing.T) { ...@@ -4974,8 +4974,8 @@ func TestChanOfDir(t *testing.T) {
// check that type already in binary is found // check that type already in binary is found
type T1 int type T1 int
checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil)) checkSameType(t, ChanOf(RecvDir, TypeOf(T1(1))), (<-chan T1)(nil))
checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil)) checkSameType(t, ChanOf(SendDir, TypeOf(T1(1))), (chan<- T1)(nil))
// check String form of ChanDir // check String form of ChanDir
if crt.ChanDir().String() != "<-chan" { if crt.ChanDir().String() != "<-chan" {
...@@ -5051,7 +5051,7 @@ func TestMapOf(t *testing.T) { ...@@ -5051,7 +5051,7 @@ func TestMapOf(t *testing.T) {
} }
// check that type already in binary is found // check that type already in binary is found
checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil)) checkSameType(t, MapOf(TypeOf(V(0)), TypeOf(K(""))), map[V]K(nil))
// check that invalid key type panics // check that invalid key type panics
shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) }) shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) })
...@@ -5181,7 +5181,7 @@ func TestFuncOf(t *testing.T) { ...@@ -5181,7 +5181,7 @@ func TestFuncOf(t *testing.T) {
{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)}, {in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
} }
for _, tt := range testCases { for _, tt := range testCases {
checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want) checkSameType(t, FuncOf(tt.in, tt.out, tt.variadic), tt.want)
} }
// check that variadic requires last element be a slice. // check that variadic requires last element be a slice.
......
...@@ -1475,8 +1475,10 @@ func ChanOf(dir ChanDir, t Type) Type { ...@@ -1475,8 +1475,10 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.uncommonType = nil ch.uncommonType = nil
ch.ptrToThis = nil ch.ptrToThis = nil
ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype) // Canonicalize before storing in lookupCache
return ti.(Type) ti := toType(&ch.rtype)
lookupCache.Store(ckey, ti.(*rtype))
return ti
} }
func ismapkey(*rtype) bool // implemented in runtime func ismapkey(*rtype) bool // implemented in runtime
...@@ -1537,8 +1539,10 @@ func MapOf(key, elem Type) Type { ...@@ -1537,8 +1539,10 @@ func MapOf(key, elem Type) Type {
mt.reflexivekey = isReflexive(ktyp) mt.reflexivekey = isReflexive(ktyp)
mt.needkeyupdate = needKeyUpdate(ktyp) mt.needkeyupdate = needKeyUpdate(ktyp)
ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype) // Canonicalize before storing in lookupCache
return ti.(Type) ti := toType(&mt.rtype)
lookupCache.Store(ckey, ti.(*rtype))
return ti
} }
// FuncOf returns the function type with the given argument and result types. // FuncOf returns the function type with the given argument and result types.
...@@ -1621,7 +1625,10 @@ func FuncOf(in, out []Type, variadic bool) Type { ...@@ -1621,7 +1625,10 @@ func FuncOf(in, out []Type, variadic bool) Type {
ft.string = &str ft.string = &str
ft.uncommonType = nil ft.uncommonType = nil
ft.ptrToThis = nil ft.ptrToThis = nil
return addToCache(&ft.rtype)
// Canonicalize before storing in funcLookupCache
tc := toType(&ft.rtype)
return addToCache(tc.(*rtype))
} }
// funcStr builds a string representation of a funcType. // funcStr builds a string representation of a funcType.
...@@ -1855,8 +1862,10 @@ func SliceOf(t Type) Type { ...@@ -1855,8 +1862,10 @@ func SliceOf(t Type) Type {
slice.uncommonType = nil slice.uncommonType = nil
slice.ptrToThis = nil slice.ptrToThis = nil
ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype) // Canonicalize before storing in lookupCache
return ti.(Type) ti := toType(&slice.rtype)
lookupCache.Store(ckey, ti.(*rtype))
return ti
} }
// The structLookupCache caches StructOf lookups. // The structLookupCache caches StructOf lookups.
...@@ -2172,7 +2181,9 @@ func StructOf(fields []StructField) Type { ...@@ -2172,7 +2181,9 @@ func StructOf(fields []StructField) Type {
typ.uncommonType = nil typ.uncommonType = nil
typ.ptrToThis = nil typ.ptrToThis = nil
return addToCache(&typ.rtype) // Canonicalize before storing in structLookupCache
ti := toType(&typ.rtype)
return addToCache(ti.(*rtype))
} }
func runtimeStructField(field StructField) structField { func runtimeStructField(field StructField) structField {
...@@ -2400,8 +2411,10 @@ func ArrayOf(count int, elem Type) Type { ...@@ -2400,8 +2411,10 @@ func ArrayOf(count int, elem Type) Type {
} }
} }
ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype) // Canonicalize before storing in lookupCache
return ti.(Type) ti := toType(&array.rtype)
lookupCache.Store(ckey, ti.(*rtype))
return ti
} }
func appendVarint(x []byte, v uintptr) []byte { func appendVarint(x []byte, v uintptr) []byte {
......
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