Skip to content

Commit 755c18e

Browse files
committed
unique: use TypeFor instead of TypeOf to get type in Make
Currently the first thing Make does it get the abi.Type of its argument, and uses abi.TypeOf to do it. However, this has a problem for interface types, since the type of the value stored in the interface value will bleed through. This is a classic reflection mistake. Fix this by implementing and using a generic TypeFor which matches reflect.TypeFor. This gets the type of the type parameter, which is far less ambiguous and error-prone. Fixes #68990. Change-Id: Idd8d9a1095ef017e9cd7c7779314f7d4034f01a7 Reviewed-on: https://go-review.googlesource.com/c/go/+/607355 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent f38d42f commit 755c18e

File tree

4 files changed

+13
-3
lines changed

4 files changed

+13
-3
lines changed

‎src/internal/abi/type.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ func TypeOf(a any) *Type {
177177
return (*Type)(NoEscape(unsafe.Pointer(eface.Type)))
178178
}
179179

180+
// TypeFor returns the abi.Type for a type parameter.
181+
func TypeFor[T any]() *Type {
182+
var v T
183+
if t := TypeOf(v); t != nil {
184+
return t // optimize for T being a non-interface kind
185+
}
186+
return TypeOf((*T)(nil)).Elem() // only for an interface kind
187+
}
188+
180189
func (t *Type) Kind() Kind { return t.Kind_ & KindMask }
181190

182191
func (t *Type) HasName() bool {

‎src/unique/clone_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func cSeq(stringOffsets ...uintptr) cloneSeq {
2727

2828
func testCloneSeq[T any](t *testing.T, want cloneSeq) {
2929
typName := reflect.TypeFor[T]().Name()
30-
typ := abi.TypeOf(*new(T))
30+
typ := abi.TypeFor[T]()
3131
t.Run(typName, func(t *testing.T) {
3232
got := makeCloneSeq(typ)
3333
if !reflect.DeepEqual(got, want) {

‎src/unique/handle.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (h Handle[T]) Value() T {
3131
// are equal if and only if the values used to produce them are equal.
3232
func Make[T comparable](value T) Handle[T] {
3333
// Find the map for type T.
34-
typ := abi.TypeOf(value)
34+
typ := abi.TypeFor[T]()
3535
ma, ok := uniqueMaps.Load(typ)
3636
if !ok {
3737
// This is a good time to initialize cleanup, since we must go through

‎src/unique/handle_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func TestHandle(t *testing.T) {
4141
s: [2]testStringStruct{testStringStruct{"y"}, testStringStruct{"z"}},
4242
})
4343
testHandle[testStruct](t, testStruct{0.5, "184"})
44+
testHandle[testEface](t, testEface("hello"))
4445
}
4546

4647
func testHandle[T comparable](t *testing.T, value T) {
@@ -93,7 +94,7 @@ func drainMaps(t *testing.T) {
9394

9495
func checkMapsFor[T comparable](t *testing.T, value T) {
9596
// Manually load the value out of the map.
96-
typ := abi.TypeOf(value)
97+
typ := abi.TypeFor[T]()
9798
a, ok := uniqueMaps.Load(typ)
9899
if !ok {
99100
return

0 commit comments

Comments
 (0)