Skip to content

Commit 48c57e3

Browse files
committed
Go: Fix crash in getTypeParamParentLabel
1 parent e3007c3 commit 48c57e3

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

go/extractor/extractor.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,8 +1657,30 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label {
16571657
// parent scope, so they are not dealt with by `extractScopes`
16581658
for i := 0; i < origintp.NumMethods(); i++ {
16591659
meth := origintp.Method(i).Origin()
1660-
16611660
extractMethod(tw, meth)
1661+
1662+
// Consider a generic struct and a generic method:
1663+
//
1664+
// type S[P any] struct{}
1665+
// func (*S[P]) m[Q any](x Q) {}
1666+
//
1667+
// If we have a variable 's' of type 'S[int]' and the expression
1668+
// 's.m[string]("")', then the type of the selector expression 's.m'
1669+
// is ' func(Q)'. The method 'm' here is an instantiation of the
1670+
// declaration, which has its own type with type parameter 'Q'.
1671+
// As we do not extract method instantiations, 'populateTypeParamParents'
1672+
// does not automatically get called for the type parameter 'Q'
1673+
// from the instantiation of 'm'. To compensate, we add the type
1674+
// parameters here.
1675+
//
1676+
// As a parent we use the origin method. This suffices, as the name
1677+
// and index of the type parameter in the instantiation will be
1678+
// identical to those of the uninstantiated method, and as only
1679+
// these two properties will be extracted for a type parameter.
1680+
if tp.Method(i) != meth {
1681+
signature := tp.Method(i).Type().(*types.Signature)
1682+
populateTypeParamParents(signature.TypeParams(), meth, false)
1683+
}
16621684
}
16631685

16641686
underlyingInterface, underlyingIsInterface := underlying.(*types.Interface)

go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
| genericFunctions.go:141:6:141:41 | generic function instantiation expression | genericFunctions.go:141:6:141:33 | GenericFunctionInAnotherFile | 0 | genericFunctions.go:141:35:141:40 | string |
88
| genericFunctions.go:146:6:146:55 | generic function instantiation expression | genericFunctions.go:146:6:146:47 | selection of GenericFunctionInAnotherPackage | 0 | genericFunctions.go:146:49:146:54 | string |
99
| genericMethods.go:13:2:13:23 | generic function instantiation expression | genericMethods.go:13:2:13:18 | selection of GenericMethod1 | 0 | genericMethods.go:13:20:13:22 | int |
10+
| genericMethods.go:14:2:14:26 | generic function instantiation expression | genericMethods.go:14:2:14:18 | selection of GenericMethod2 | 0 | genericMethods.go:14:20:14:25 | string |

go/ql/test/library-tests/semmle/go/Function/genericMethods.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ func (*StructForGenericMethod2[P3]) GenericMethod2[P4 any](x P4) {}
1111
func generic_methods(s1 StructForGenericMethod1, s2 StructForGenericMethod2[int]) {
1212
// Call the generic method specifying the type
1313
s1.GenericMethod1[int](1)
14-
//s2.GenericMethod2[string]("hello")
14+
s2.GenericMethod2[string]("hello")
1515

1616
// Call the generic method without specifying the type
1717
s1.GenericMethod1("hello")
18-
//s2.GenericMethod2(42)
18+
s2.GenericMethod2(42)
1919
}

0 commit comments

Comments
 (0)