x/tools/go/ssa: instantiate sel.Recv() on MethodVal.

When a MethodVal selection receiver is a TypeParam while monomorphizing, use the method value from the substituted type.

Fixes golang/go#52835

Change-Id: Iaf174a02b62b0c3ed4aafefdfd2aca195781e9f9
Reviewed-on: https://go-review.googlesource.com/c/tools/+/405594
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Tim King 2022-05-10 15:47:25 -07:00
parent 28c754d415
commit 8ec40b5329
3 changed files with 40 additions and 1 deletions

View File

@ -814,6 +814,13 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
case types.MethodVal:
// e.f where e is an expression and f is a method.
// The result is a "bound".
if base := fn.typ(sel.Recv()); base != sel.Recv() {
// instantiate sel as sel.Recv is not equal after substitution.
pkg := fn.declaredPackage().Pkg
// mv is the instantiated method value.
sel = types.NewMethodSet(base).Lookup(pkg, sel.Obj().Name())
}
obj := sel.Obj().(*types.Func)
rt := fn.typ(recvType(obj))
wantAddr := isPointer(rt)

View File

@ -129,6 +129,12 @@ var testdataTests = []string{
"fixedbugs/issue52342.go",
}
func init() {
if typeparams.Enabled {
testdataTests = append(testdataTests, "fixedbugs/issue52835.go")
}
}
// Specific GOARCH to use for a test case in go.tools/go/ssa/interp/testdata/.
// Defaults to amd64 otherwise.
var testdataArchs = map[string]string{
@ -233,7 +239,6 @@ func TestTestdataFiles(t *testing.T) {
if err != nil {
log.Fatal(err)
}
var failures []string
for _, input := range testdataTests {
if !run(t, filepath.Join(cwd, "testdata", input)) {

View File

@ -0,0 +1,27 @@
package main
var called bool
type I interface {
Foo()
}
type A struct{}
func (a A) Foo() {
called = true
}
func lambda[X I]() func() func() {
return func() func() {
var x X
return x.Foo
}
}
func main() {
lambda[A]()()()
if !called {
panic(called)
}
}