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
This commit is contained in:
parent
6d02e2d960
commit
e0b195b58a
|
@ -1,4 +1,4 @@
|
|||
8e74a218e11ef6eaaf7014a3ad1cd0b13359c607
|
||||
8b6c7f3f9762366bab96ea95b966e93e2593be13
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -3928,8 +3928,8 @@ func TestOverflow(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkSameType(t *testing.T, x, y interface{}) {
|
||||
if TypeOf(x) != TypeOf(y) {
|
||||
func checkSameType(t *testing.T, x Type, y interface{}) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -4058,7 +4058,7 @@ func TestArrayOf(t *testing.T) {
|
|||
|
||||
// check that type already in binary is found
|
||||
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) {
|
||||
|
@ -4195,7 +4195,7 @@ func TestSliceOf(t *testing.T) {
|
|||
|
||||
// check that type already in binary is found
|
||||
type T1 int
|
||||
checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{})
|
||||
checkSameType(t, SliceOf(TypeOf(T1(1))), []T1{})
|
||||
}
|
||||
|
||||
func TestSliceOverflow(t *testing.T) {
|
||||
|
@ -4410,7 +4410,7 @@ func TestStructOf(t *testing.T) {
|
|||
})
|
||||
})
|
||||
// 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) {
|
||||
|
@ -4963,7 +4963,7 @@ func TestChanOf(t *testing.T) {
|
|||
|
||||
// check that type already in binary is found
|
||||
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) {
|
||||
|
@ -4974,8 +4974,8 @@ func TestChanOfDir(t *testing.T) {
|
|||
|
||||
// check that type already in binary is found
|
||||
type T1 int
|
||||
checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil))
|
||||
checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil))
|
||||
checkSameType(t, ChanOf(RecvDir, TypeOf(T1(1))), (<-chan T1)(nil))
|
||||
checkSameType(t, ChanOf(SendDir, TypeOf(T1(1))), (chan<- T1)(nil))
|
||||
|
||||
// check String form of ChanDir
|
||||
if crt.ChanDir().String() != "<-chan" {
|
||||
|
@ -5051,7 +5051,7 @@ func TestMapOf(t *testing.T) {
|
|||
}
|
||||
|
||||
// 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
|
||||
shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) })
|
||||
|
@ -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)},
|
||||
}
|
||||
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.
|
||||
|
|
|
@ -1475,8 +1475,10 @@ func ChanOf(dir ChanDir, t Type) Type {
|
|||
ch.uncommonType = nil
|
||||
ch.ptrToThis = nil
|
||||
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
|
||||
return ti.(Type)
|
||||
// Canonicalize before storing in lookupCache
|
||||
ti := toType(&ch.rtype)
|
||||
lookupCache.Store(ckey, ti.(*rtype))
|
||||
return ti
|
||||
}
|
||||
|
||||
func ismapkey(*rtype) bool // implemented in runtime
|
||||
|
@ -1537,8 +1539,10 @@ func MapOf(key, elem Type) Type {
|
|||
mt.reflexivekey = isReflexive(ktyp)
|
||||
mt.needkeyupdate = needKeyUpdate(ktyp)
|
||||
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
|
||||
return ti.(Type)
|
||||
// Canonicalize before storing in lookupCache
|
||||
ti := toType(&mt.rtype)
|
||||
lookupCache.Store(ckey, ti.(*rtype))
|
||||
return ti
|
||||
}
|
||||
|
||||
// FuncOf returns the function type with the given argument and result types.
|
||||
|
@ -1621,7 +1625,10 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
|||
ft.string = &str
|
||||
ft.uncommonType = 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.
|
||||
|
@ -1855,8 +1862,10 @@ func SliceOf(t Type) Type {
|
|||
slice.uncommonType = nil
|
||||
slice.ptrToThis = nil
|
||||
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
|
||||
return ti.(Type)
|
||||
// Canonicalize before storing in lookupCache
|
||||
ti := toType(&slice.rtype)
|
||||
lookupCache.Store(ckey, ti.(*rtype))
|
||||
return ti
|
||||
}
|
||||
|
||||
// The structLookupCache caches StructOf lookups.
|
||||
|
@ -2172,7 +2181,9 @@ func StructOf(fields []StructField) Type {
|
|||
typ.uncommonType = 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 {
|
||||
|
@ -2400,8 +2411,10 @@ func ArrayOf(count int, elem Type) Type {
|
|||
}
|
||||
}
|
||||
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
|
||||
return ti.(Type)
|
||||
// Canonicalize before storing in lookupCache
|
||||
ti := toType(&array.rtype)
|
||||
lookupCache.Store(ckey, ti.(*rtype))
|
||||
return ti
|
||||
}
|
||||
|
||||
func appendVarint(x []byte, v uintptr) []byte {
|
||||
|
|
Loading…
Reference in New Issue