mirror of https://github.com/golang/go.git
go/types: fix method set computation if receiver is a named pointer
Per the spec, methods cannot be associated with a named pointer type. Exit early with an empty method set in this case. This matches the corresponding check in LookupFieldOrMethod; the check is not present in (lowercase) lookupFieldOrMethod because it (the check) doesn't apply to struct fields. Fixes #60634. Change-Id: Ica6ca8be6b850ea0da6f0b441fbf5b99cb0b6b17 Reviewed-on: https://go-review.googlesource.com/c/go/+/501299 Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Run-TryBot: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
b9baf4452f
commit
fd13444b2b
|
|
@ -76,6 +76,14 @@ func NewMethodSet(T Type) *MethodSet {
|
|||
// TODO(rfindley) confirm that this code is in sync with lookupFieldOrMethod
|
||||
// with respect to type params.
|
||||
|
||||
// Methods cannot be associated with a named pointer type.
|
||||
// (spec: "The type denoted by T is called the receiver base type;
|
||||
// it must not be a pointer or interface type and it must be declared
|
||||
// in the same package as the method.").
|
||||
if t, _ := T.(*Named); t != nil && isPointer(t) {
|
||||
return &emptyMethodSet
|
||||
}
|
||||
|
||||
// method set up to the current depth, allocated lazily
|
||||
var base methodSet
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
package types_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go/ast"
|
||||
|
|
@ -154,3 +155,43 @@ type Instance = *Tree[int]
|
|||
T := pkg.Scope().Lookup("Instance").Type()
|
||||
_ = NewMethodSet(T) // verify that NewMethodSet terminates
|
||||
}
|
||||
|
||||
func TestIssue60634(t *testing.T) {
|
||||
const src = `
|
||||
package p
|
||||
type T *int
|
||||
func (T) m() {} // expected error: invalid receiver type
|
||||
`
|
||||
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, "p.go", src, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var conf Config
|
||||
pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid receiver type") {
|
||||
t.Fatalf("missing or unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// look up T.m and (*T).m
|
||||
T := pkg.Scope().Lookup("T").Type()
|
||||
name := "m"
|
||||
for _, recv := range []Type{T, NewPointer(T)} {
|
||||
// LookupFieldOrMethod and NewMethodSet must match:
|
||||
// either both find m or neither finds it.
|
||||
obj1, _, _ := LookupFieldOrMethod(recv, false, pkg, name)
|
||||
mset := NewMethodSet(recv)
|
||||
if (obj1 != nil) != (mset.Len() == 1) {
|
||||
t.Fatalf("lookup(%v.%s): got obj = %v, mset = %v", recv, name, obj1, mset)
|
||||
}
|
||||
// If the method exists, both must return the same object.
|
||||
if obj1 != nil {
|
||||
obj2 := mset.At(0).Obj()
|
||||
if obj1 != obj2 {
|
||||
t.Fatalf("%v != %v", obj1, obj2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue