Skip to content

Commit

Permalink
skip all type parameters in recordType
Browse files Browse the repository at this point in the history
We only did this for Container in the type switch, but not for Struct.
The added test case panics otherwise.
Just like in the previous case, we still don't need to recurse
into type parameters for fieldToStruct to be filled correctly.

Fixes #899
  • Loading branch information
lu4p authored and mvdan committed Jan 19, 2025
1 parent e6c0aef commit 166adb0
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 11 deletions.
21 changes: 12 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1683,21 +1683,23 @@ func computeFieldToStruct(info *types.Info) map[*types.Var]*types.Struct {
// Since types can be recursive, we need a map to avoid cycles.
// We only need to track named types as done, as all cycles must use them.
func recordType(used, origin types.Type, done map[*types.Named]bool, fieldToStruct map[*types.Var]*types.Struct) {
used = types.Unalias(used)
if origin == nil {
origin = used
}
origin = types.Unalias(origin)
used = types.Unalias(used)
type Container interface{ Elem() types.Type }
switch used := used.(type) {
case Container:
// origin may be a *types.TypeParam, which is not a Container.
} else {
origin = types.Unalias(origin)
// origin may be a [*types.TypeParam].
// For now, we haven't found a need to recurse in that case.
// We can edit this code in the future if we find an example,
// because we panic if a field is not in fieldToStruct.
if origin, ok := origin.(Container); ok {
recordType(used.Elem(), origin.Elem(), done, fieldToStruct)
if _, ok := origin.(*types.TypeParam); ok {
return
}
}
type Container interface{ Elem() types.Type }
switch used := used.(type) {
case Container:
recordType(used.Elem(), origin.(Container).Elem(), done, fieldToStruct)
case *types.Named:
if done[used] {
return
Expand All @@ -1714,6 +1716,7 @@ func recordType(used, origin types.Type, done map[*types.Named]bool, fieldToStru
recordType(used.Underlying(), used.Origin().Underlying(), done, fieldToStruct)
case *types.Struct:
origin := origin.(*types.Struct)

for i := range used.NumFields() {
field := used.Field(i)
fieldToStruct[field] = origin
Expand Down
8 changes: 6 additions & 2 deletions testdata/script/typeparams.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type GenericVector[GenericParamT any] []GenericParamT

type GenericGraph[T any] struct {
Content T
Edges []GenericGraph[T]
Edges []GenericGraph[T]
}

type PredeclaredSignedInteger interface {
Expand All @@ -40,7 +40,7 @@ type StringableSignedInteger interface {
type CombineEmbeds interface {
string | int

interface { EmbeddedMethod() }
interface{ EmbeddedMethod() }
RegularMethod()
}

Expand All @@ -49,3 +49,7 @@ type Slice[T any] []T
func sliceOfPointer() Slice[*any] {
return []*any{}
}

type Map[K, V comparable] map[K]V

var _ = Map[string, struct{}]{}

0 comments on commit 166adb0

Please sign in to comment.