]> Cypherpunks repositories - gostls13.git/commitdiff
unique: use TypeFor instead of TypeOf to get type in Make
authorMichael Anthony Knyszek <mknyszek@google.com>
Wed, 21 Aug 2024 14:38:30 +0000 (14:38 +0000)
committerMichael Knyszek <mknyszek@google.com>
Wed, 21 Aug 2024 16:03:35 +0000 (16:03 +0000)
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>

src/internal/abi/type.go
src/unique/clone_test.go
src/unique/handle.go
src/unique/handle_test.go

index 598c919d0c87cbdc4a08b1bcf08f9c9a6fec8a78..df61400923859f624b1293c43e82ebed66cf69ad 100644 (file)
@@ -177,6 +177,15 @@ func TypeOf(a any) *Type {
        return (*Type)(NoEscape(unsafe.Pointer(eface.Type)))
 }
 
+// TypeFor returns the abi.Type for a type parameter.
+func TypeFor[T any]() *Type {
+       var v T
+       if t := TypeOf(v); t != nil {
+               return t // optimize for T being a non-interface kind
+       }
+       return TypeOf((*T)(nil)).Elem() // only for an interface kind
+}
+
 func (t *Type) Kind() Kind { return t.Kind_ & KindMask }
 
 func (t *Type) HasName() bool {
index 69a9a540c07fa0a7ed3e49c3b5ca10d4e8d7419d..b0ba5b312e1466dbfba5166d092e94dae1b489fd 100644 (file)
@@ -27,7 +27,7 @@ func cSeq(stringOffsets ...uintptr) cloneSeq {
 
 func testCloneSeq[T any](t *testing.T, want cloneSeq) {
        typName := reflect.TypeFor[T]().Name()
-       typ := abi.TypeOf(*new(T))
+       typ := abi.TypeFor[T]()
        t.Run(typName, func(t *testing.T) {
                got := makeCloneSeq(typ)
                if !reflect.DeepEqual(got, want) {
index 0842ae3185f2ccef5619eb79b6bae9af461f3d2f..96d8fedb0cabe6c519feab9132d1731f2b18f748 100644 (file)
@@ -31,7 +31,7 @@ func (h Handle[T]) Value() T {
 // are equal if and only if the values used to produce them are equal.
 func Make[T comparable](value T) Handle[T] {
        // Find the map for type T.
-       typ := abi.TypeOf(value)
+       typ := abi.TypeFor[T]()
        ma, ok := uniqueMaps.Load(typ)
        if !ok {
                // This is a good time to initialize cleanup, since we must go through
index dffe10ac728189b04e57413c66e7d12a9ec42a3e..b031bbf6852c6b33051ce4ecdfb4ff2fae8fd977 100644 (file)
@@ -41,6 +41,7 @@ func TestHandle(t *testing.T) {
                s: [2]testStringStruct{testStringStruct{"y"}, testStringStruct{"z"}},
        })
        testHandle[testStruct](t, testStruct{0.5, "184"})
+       testHandle[testEface](t, testEface("hello"))
 }
 
 func testHandle[T comparable](t *testing.T, value T) {
@@ -93,7 +94,7 @@ func drainMaps(t *testing.T) {
 
 func checkMapsFor[T comparable](t *testing.T, value T) {
        // Manually load the value out of the map.
-       typ := abi.TypeOf(value)
+       typ := abi.TypeFor[T]()
        a, ok := uniqueMaps.Load(typ)
        if !ok {
                return