1
0
mirror of https://github.com/golang/go synced 2024-11-22 03:04:41 -07:00

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>
This commit is contained in:
Michael Anthony Knyszek 2024-08-21 14:38:30 +00:00 committed by Michael Knyszek
parent f38d42f2c4
commit 755c18ecdf
4 changed files with 13 additions and 3 deletions

View 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 {

View 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) {

View 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

View 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