mirror of https://github.com/golang/go.git
go/types, types2: document deterministic method index order and add test
Fixes #61298. Change-Id: Ie2f930752867710884ace3990447866e785ebf1c Reviewed-on: https://go-review.googlesource.com/c/go/+/562347 Reviewed-by: 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> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
1400b26852
commit
210f051d6b
|
|
@ -335,6 +335,12 @@ func (t *Named) NumMethods() int {
|
|||
// For an ordinary or instantiated type t, the receiver base type of this
|
||||
// method is the named type t. For an uninstantiated generic type t, each
|
||||
// method receiver is instantiated with its receiver type parameters.
|
||||
//
|
||||
// Methods are numbered deterministically: given the same list of source files
|
||||
// presented to the type checker, or the same sequence of NewMethod and AddMethod
|
||||
// calls, the mapping from method index to corresponding method remains the same.
|
||||
// But the specific ordering is not specified and must not be relied on as it may
|
||||
// change in the future.
|
||||
func (t *Named) Method(i int) *Func {
|
||||
t.resolve()
|
||||
|
||||
|
|
|
|||
|
|
@ -112,3 +112,51 @@ type Inst = *Tree[int]
|
|||
t.Errorf("Duplicate instances in cycle: %s (%p) -> %s (%p) -> %s (%p)", Inst, Inst, Node, Node, Tree, Tree)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodOrdering is a simple test verifying that the indices of methods of
|
||||
// a named type remain the same as long as the same source and AddMethod calls
|
||||
// are presented to the type checker in the same order (go.dev/issue/61298).
|
||||
func TestMethodOrdering(t *testing.T) {
|
||||
const src = `
|
||||
package p
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (T) a() {}
|
||||
func (T) c() {}
|
||||
func (T) b() {}
|
||||
`
|
||||
// should get the same method order each time
|
||||
var methods []string
|
||||
for i := 0; i < 5; i++ {
|
||||
// collect T methods as provided in src
|
||||
pkg := mustTypecheck(src, nil, nil)
|
||||
T := pkg.Scope().Lookup("T").Type().(*Named)
|
||||
|
||||
// add a few more methods manually
|
||||
for _, name := range []string{"foo", "bar", "bal"} {
|
||||
m := NewFunc(nopos, pkg, name, nil /* don't care about signature */)
|
||||
T.AddMethod(m)
|
||||
}
|
||||
|
||||
// check method order
|
||||
if i == 0 {
|
||||
// first round: collect methods in given order
|
||||
methods = make([]string, T.NumMethods())
|
||||
for j := range methods {
|
||||
methods[j] = T.Method(j).Name()
|
||||
}
|
||||
} else {
|
||||
// successive rounds: methods must appear in the same order
|
||||
if got := T.NumMethods(); got != len(methods) {
|
||||
t.Errorf("got %d methods, want %d", got, len(methods))
|
||||
continue
|
||||
}
|
||||
for j, m := range methods {
|
||||
if got := T.Method(j).Name(); got != m {
|
||||
t.Errorf("got method %s, want %s", got, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,6 +337,12 @@ func (t *Named) NumMethods() int {
|
|||
// For an ordinary or instantiated type t, the receiver base type of this
|
||||
// method is the named type t. For an uninstantiated generic type t, each
|
||||
// method receiver is instantiated with its receiver type parameters.
|
||||
//
|
||||
// Methods are numbered deterministically: given the same list of source files
|
||||
// presented to the type checker, or the same sequence of NewMethod and AddMethod
|
||||
// calls, the mapping from method index to corresponding method remains the same.
|
||||
// But the specific ordering is not specified and must not be relied on as it may
|
||||
// change in the future.
|
||||
func (t *Named) Method(i int) *Func {
|
||||
t.resolve()
|
||||
|
||||
|
|
|
|||
|
|
@ -127,3 +127,51 @@ type Inst = *Tree[int]
|
|||
t.Errorf("Duplicate instances in cycle: %s (%p) -> %s (%p) -> %s (%p)", Inst, Inst, Node, Node, Tree, Tree)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodOrdering is a simple test verifying that the indices of methods of
|
||||
// a named type remain the same as long as the same source and AddMethod calls
|
||||
// are presented to the type checker in the same order (go.dev/issue/61298).
|
||||
func TestMethodOrdering(t *testing.T) {
|
||||
const src = `
|
||||
package p
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (T) a() {}
|
||||
func (T) c() {}
|
||||
func (T) b() {}
|
||||
`
|
||||
// should get the same method order each time
|
||||
var methods []string
|
||||
for i := 0; i < 5; i++ {
|
||||
// collect T methods as provided in src
|
||||
pkg := mustTypecheck(src, nil, nil)
|
||||
T := pkg.Scope().Lookup("T").Type().(*Named)
|
||||
|
||||
// add a few more methods manually
|
||||
for _, name := range []string{"foo", "bar", "bal"} {
|
||||
m := NewFunc(nopos, pkg, name, nil /* don't care about signature */)
|
||||
T.AddMethod(m)
|
||||
}
|
||||
|
||||
// check method order
|
||||
if i == 0 {
|
||||
// first round: collect methods in given order
|
||||
methods = make([]string, T.NumMethods())
|
||||
for j := range methods {
|
||||
methods[j] = T.Method(j).Name()
|
||||
}
|
||||
} else {
|
||||
// successive rounds: methods must appear in the same order
|
||||
if got := T.NumMethods(); got != len(methods) {
|
||||
t.Errorf("got %d methods, want %d", got, len(methods))
|
||||
continue
|
||||
}
|
||||
for j, m := range methods {
|
||||
if got := T.Method(j).Name(); got != m {
|
||||
t.Errorf("got method %s, want %s", got, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue