go/types, types2: complete methods on pointer receivers in missingMethod

We were not calling objDecl on methods on pointer receivers in
missingMethod. This may not have mattered before, but with lazy
completion of instance methods it is necessary.

Fixes #49579

Change-Id: Icddb1f3b16bef7d8017859734f9879a4f1cc18de
Reviewed-on: https://go-review.googlesource.com/c/go/+/364714
Trust: Robert Findley <rfindley@google.com>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Robert Findley 2021-11-17 09:35:57 -05:00
parent 17b7604ef6
commit 9bdbed1d96
4 changed files with 52 additions and 6 deletions

View File

@ -71,6 +71,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
// If checkFold is true, the lookup for methods will include looking for any method
// which case-folds to the same as 'name' (used for giving helpful error messages).
//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethod(T Type, addressable, checkFold bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
@ -352,14 +354,17 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
if obj == nil {
ptr := NewPointer(V)
obj, _, _ = lookupFieldOrMethod(ptr, false, false, m.pkg, m.name)
if obj != nil {
return m, obj.(*Func)
if obj == nil {
// If we didn't find the exact method (even with pointer
// receiver), look to see if there is a method that
// matches m.name with case-folding.
obj, _, _ = lookupFieldOrMethod(V, false, true, m.pkg, m.name)
}
// If we didn't find the exact method (even with pointer
// receiver), look to see if there is a method that
// matches m.name with case-folding.
obj, _, _ := lookupFieldOrMethod(V, false, true, m.pkg, m.name)
if obj != nil {
// methods may not have a fully set up signature yet
if check != nil {
check.objDecl(obj, nil)
}
return m, obj.(*Func)
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type I[F any] interface {
Q(*F)
}
func G[F any]() I[any] {
return g /* ERROR "missing method Q \(Q has pointer receiver\)" */ [F]{}
}
type g[F any] struct{}
func (*g[F]) Q(*any) {}

View File

@ -69,6 +69,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
// indirectly via different packages.)
// lookupFieldOrMethod should only be called by LookupFieldOrMethod and missingMethod.
//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
@ -346,7 +348,12 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
if obj == nil {
ptr := NewPointer(V)
obj, _, _ = lookupFieldOrMethod(ptr, false, m.pkg, m.name)
if obj != nil {
// methods may not have a fully set up signature yet
if check != nil {
check.objDecl(obj, nil)
}
return m, obj.(*Func)
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type I[F any] interface {
Q(*F)
}
func G[F any]() I[any] {
return g /* ERROR "missing method Q \(Q has pointer receiver\)" */ [F]{}
}
type g[F any] struct{}
func (*g[F]) Q(*any) {}