diff --git a/go/types/typeutil/map.go b/go/types/typeutil/map.go index 544246dac1c..e154be0bd60 100644 --- a/go/types/typeutil/map.go +++ b/go/types/typeutil/map.go @@ -12,6 +12,7 @@ import ( "go/types" "reflect" + "golang.org/x/tools/internal/aliases" "golang.org/x/tools/internal/typeparams" ) @@ -259,6 +260,9 @@ func (h Hasher) hashFor(t types.Type) uint32 { case *types.Basic: return uint32(t.Kind()) + case *aliases.Alias: + return h.Hash(t.Underlying()) + case *types.Array: return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) @@ -457,6 +461,9 @@ func (h Hasher) shallowHash(t types.Type) uint32 { // elements (mostly Slice, Pointer, Basic, Named), // so there's no need to optimize anything else. switch t := t.(type) { + case *aliases.Alias: + return h.shallowHash(t.Underlying()) + case *types.Signature: var hash uint32 = 604171 if t.Variadic() { diff --git a/go/types/typeutil/map_test.go b/go/types/typeutil/map_test.go index 4891f7687d5..2cc1de786dc 100644 --- a/go/types/typeutil/map_test.go +++ b/go/types/typeutil/map_test.go @@ -247,6 +247,15 @@ var Issue56048 = Issue56048_I.m type Issue56048_Ib interface{ m() chan []*interface { Issue56048_Ib } } var Issue56048b = Issue56048_Ib.m +// Non-generic alias +type NonAlias int +type Alias1 = NonAlias +type Alias2 = NonAlias + +// Generic alias (requires go1.23) +// type SetOfInt = map[int]bool +// type Set[T comparable] = map[K]bool +// type SetOfInt2 = Set[int] ` fset := token.NewFileSet() @@ -307,6 +316,16 @@ var Issue56048b = Issue56048_Ib.m Quux = scope.Lookup("Quux").Type() Issue56048 = scope.Lookup("Issue56048").Type() Issue56048b = scope.Lookup("Issue56048b").Type() + + // In go1.23 these will be *types.Alias; for now they are all int. + NonAlias = scope.Lookup("NonAlias").Type() + Alias1 = scope.Lookup("Alias1").Type() + Alias2 = scope.Lookup("Alias2").Type() + + // Requires go1.23. + // SetOfInt = scope.Lookup("SetOfInt").Type() + // Set = scope.Lookup("Set").Type().(*types.Alias) + // SetOfInt2 = scope.Lookup("SetOfInt2").Type() ) tmap := new(typeutil.Map) @@ -379,6 +398,16 @@ var Issue56048b = Issue56048_Ib.m {Issue56048, "Issue56048", true}, // (not actually about generics) {Issue56048b, "Issue56048b", true}, // (not actually about generics) + + // All three types are identical. + {NonAlias, "NonAlias", true}, + {Alias1, "Alias1", false}, + {Alias2, "Alias2", false}, + + // Generic aliases: requires go1.23. + // {SetOfInt, "SetOfInt", true}, + // {Set, "Set", false}, + // {SetOfInt2, "SetOfInt2", false}, } for _, step := range steps { diff --git a/go/types/typeutil/methodsetcache.go b/go/types/typeutil/methodsetcache.go index a5d9310830c..bd71aafaaa1 100644 --- a/go/types/typeutil/methodsetcache.go +++ b/go/types/typeutil/methodsetcache.go @@ -9,6 +9,8 @@ package typeutil import ( "go/types" "sync" + + "golang.org/x/tools/internal/aliases" ) // A MethodSetCache records the method set of each type T for which @@ -32,12 +34,12 @@ func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { cache.mu.Lock() defer cache.mu.Unlock() - switch T := T.(type) { + switch T := aliases.Unalias(T).(type) { case *types.Named: return cache.lookupNamed(T).value case *types.Pointer: - if N, ok := T.Elem().(*types.Named); ok { + if N, ok := aliases.Unalias(T.Elem()).(*types.Named); ok { return cache.lookupNamed(N).pointer } }