Skip to content

Commit

Permalink
go/types: fix method set computation if receiver is a named pointer
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
griesemer authored and gopherbot committed Jun 8, 2023
1 parent b9baf44 commit fd13444
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/go/types/methodset.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
41 changes: 41 additions & 0 deletions src/go/types/methodset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package types_test

import (
"strings"
"testing"

"go/ast"
Expand Down Expand Up @@ -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)
}
}
}
}

0 comments on commit fd13444

Please sign in to comment.