Skip to content

Commit 8b6c7f3

Browse files
cosmos72ianlancetaylor
authored andcommitted
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 Change-Id: I5a71bf5ff4bbb2585a5b84072cb59af9e9d16518 Reviewed-on: https://go-review.googlesource.com/115577 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 8f957be commit 8b6c7f3

File tree

2 files changed

+33
-20
lines changed

2 files changed

+33
-20
lines changed

libgo/go/reflect/all_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,8 +3928,8 @@ func TestOverflow(t *testing.T) {
39283928
}
39293929
}
39303930

3931-
func checkSameType(t *testing.T, x, y interface{}) {
3932-
if TypeOf(x) != TypeOf(y) {
3931+
func checkSameType(t *testing.T, x Type, y interface{}) {
3932+
if x != TypeOf(y) || TypeOf(Zero(x).Interface()) != TypeOf(y) {
39333933
t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))
39343934
}
39353935
}
@@ -4058,7 +4058,7 @@ func TestArrayOf(t *testing.T) {
40584058

40594059
// check that type already in binary is found
40604060
type T int
4061-
checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
4061+
checkSameType(t, ArrayOf(5, TypeOf(T(1))), [5]T{})
40624062
}
40634063

40644064
func TestArrayOfGC(t *testing.T) {
@@ -4195,7 +4195,7 @@ func TestSliceOf(t *testing.T) {
41954195

41964196
// check that type already in binary is found
41974197
type T1 int
4198-
checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{})
4198+
checkSameType(t, SliceOf(TypeOf(T1(1))), []T1{})
41994199
}
42004200

42014201
func TestSliceOverflow(t *testing.T) {
@@ -4410,7 +4410,7 @@ func TestStructOf(t *testing.T) {
44104410
})
44114411
})
44124412
// check that type already in binary is found
4413-
checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{})
4413+
checkSameType(t, StructOf(fields[2:3]), struct{ Y uint64 }{})
44144414
}
44154415

44164416
func TestStructOfExportRules(t *testing.T) {
@@ -4963,7 +4963,7 @@ func TestChanOf(t *testing.T) {
49634963

49644964
// check that type already in binary is found
49654965
type T1 int
4966-
checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
4966+
checkSameType(t, ChanOf(BothDir, TypeOf(T1(1))), (chan T1)(nil))
49674967
}
49684968

49694969
func TestChanOfDir(t *testing.T) {
@@ -4974,8 +4974,8 @@ func TestChanOfDir(t *testing.T) {
49744974

49754975
// check that type already in binary is found
49764976
type T1 int
4977-
checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil))
4978-
checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil))
4977+
checkSameType(t, ChanOf(RecvDir, TypeOf(T1(1))), (<-chan T1)(nil))
4978+
checkSameType(t, ChanOf(SendDir, TypeOf(T1(1))), (chan<- T1)(nil))
49794979

49804980
// check String form of ChanDir
49814981
if crt.ChanDir().String() != "<-chan" {
@@ -5051,7 +5051,7 @@ func TestMapOf(t *testing.T) {
50515051
}
50525052

50535053
// check that type already in binary is found
5054-
checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil))
5054+
checkSameType(t, MapOf(TypeOf(V(0)), TypeOf(K(""))), map[V]K(nil))
50555055

50565056
// check that invalid key type panics
50575057
shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) })
@@ -5181,7 +5181,7 @@ func TestFuncOf(t *testing.T) {
51815181
{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
51825182
}
51835183
for _, tt := range testCases {
5184-
checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want)
5184+
checkSameType(t, FuncOf(tt.in, tt.out, tt.variadic), tt.want)
51855185
}
51865186

51875187
// check that variadic requires last element be a slice.

libgo/go/reflect/type.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,8 +1475,10 @@ func ChanOf(dir ChanDir, t Type) Type {
14751475
ch.uncommonType = nil
14761476
ch.ptrToThis = nil
14771477

1478-
ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
1479-
return ti.(Type)
1478+
// Canonicalize before storing in lookupCache
1479+
ti := toType(&ch.rtype)
1480+
lookupCache.Store(ckey, ti.(*rtype))
1481+
return ti
14801482
}
14811483

14821484
func ismapkey(*rtype) bool // implemented in runtime
@@ -1537,8 +1539,10 @@ func MapOf(key, elem Type) Type {
15371539
mt.reflexivekey = isReflexive(ktyp)
15381540
mt.needkeyupdate = needKeyUpdate(ktyp)
15391541

1540-
ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
1541-
return ti.(Type)
1542+
// Canonicalize before storing in lookupCache
1543+
ti := toType(&mt.rtype)
1544+
lookupCache.Store(ckey, ti.(*rtype))
1545+
return ti
15421546
}
15431547

15441548
// FuncOf returns the function type with the given argument and result types.
@@ -1621,7 +1625,10 @@ func FuncOf(in, out []Type, variadic bool) Type {
16211625
ft.string = &str
16221626
ft.uncommonType = nil
16231627
ft.ptrToThis = nil
1624-
return addToCache(&ft.rtype)
1628+
1629+
// Canonicalize before storing in funcLookupCache
1630+
tc := toType(&ft.rtype)
1631+
return addToCache(tc.(*rtype))
16251632
}
16261633

16271634
// funcStr builds a string representation of a funcType.
@@ -1855,8 +1862,10 @@ func SliceOf(t Type) Type {
18551862
slice.uncommonType = nil
18561863
slice.ptrToThis = nil
18571864

1858-
ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
1859-
return ti.(Type)
1865+
// Canonicalize before storing in lookupCache
1866+
ti := toType(&slice.rtype)
1867+
lookupCache.Store(ckey, ti.(*rtype))
1868+
return ti
18601869
}
18611870

18621871
// The structLookupCache caches StructOf lookups.
@@ -2172,7 +2181,9 @@ func StructOf(fields []StructField) Type {
21722181
typ.uncommonType = nil
21732182
typ.ptrToThis = nil
21742183

2175-
return addToCache(&typ.rtype)
2184+
// Canonicalize before storing in structLookupCache
2185+
ti := toType(&typ.rtype)
2186+
return addToCache(ti.(*rtype))
21762187
}
21772188

21782189
func runtimeStructField(field StructField) structField {
@@ -2400,8 +2411,10 @@ func ArrayOf(count int, elem Type) Type {
24002411
}
24012412
}
24022413

2403-
ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
2404-
return ti.(Type)
2414+
// Canonicalize before storing in lookupCache
2415+
ti := toType(&array.rtype)
2416+
lookupCache.Store(ckey, ti.(*rtype))
2417+
return ti
24052418
}
24062419

24072420
func appendVarint(x []byte, v uintptr) []byte {

0 commit comments

Comments
 (0)