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>
// 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()
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)
+ }
+ }
+ }
+ }
+}
// 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()
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)
+ }
+ }
+ }
+ }
+}