Source file
src/go/types/methodset_test.go
1
2
3
4
5 package types_test
6
7 import (
8 "slices"
9 "strings"
10 "testing"
11
12 "go/ast"
13 "go/parser"
14 "go/token"
15 . "go/types"
16 )
17
18 func TestNewMethodSet(t *testing.T) {
19 type method struct {
20 name string
21 index []int
22 indirect bool
23 }
24
25
26
27 tests := map[string][]method{
28
29 "var a T; type T struct{}; func (T) f() {}": {{"f", []int{0}, false}},
30 "var a *T; type T struct{}; func (T) f() {}": {{"f", []int{0}, true}},
31 "var a T; type T struct{}; func (*T) f() {}": {},
32 "var a *T; type T struct{}; func (*T) f() {}": {{"f", []int{0}, true}},
33
34
35 "var a T[int]; type T[P any] struct{}; func (T[P]) f() {}": {{"f", []int{0}, false}},
36 "var a *T[int]; type T[P any] struct{}; func (T[P]) f() {}": {{"f", []int{0}, true}},
37 "var a T[int]; type T[P any] struct{}; func (*T[P]) f() {}": {},
38 "var a *T[int]; type T[P any] struct{}; func (*T[P]) f() {}": {{"f", []int{0}, true}},
39
40
41 "var a T; type T interface{ f() }": {{"f", []int{0}, true}},
42 "var a T1; type ( T1 T2; T2 interface{ f() } )": {{"f", []int{0}, true}},
43 "var a T1; type ( T1 interface{ T2 }; T2 interface{ f() } )": {{"f", []int{0}, true}},
44
45
46 "var a T[int]; type T[P any] interface{ f() }": {{"f", []int{0}, true}},
47 "var a T1[int]; type ( T1[P any] T2[P]; T2[P any] interface{ f() } )": {{"f", []int{0}, true}},
48 "var a T1[int]; type ( T1[P any] interface{ T2[P] }; T2[P any] interface{ f() } )": {{"f", []int{0}, true}},
49
50
51 "var a struct{ E }; type E interface{ f() }": {{"f", []int{0, 0}, true}},
52 "var a *struct{ E }; type E interface{ f() }": {{"f", []int{0, 0}, true}},
53 "var a struct{ E }; type E struct{}; func (E) f() {}": {{"f", []int{0, 0}, false}},
54 "var a struct{ *E }; type E struct{}; func (E) f() {}": {{"f", []int{0, 0}, true}},
55 "var a struct{ E }; type E struct{}; func (*E) f() {}": {},
56 "var a struct{ *E }; type E struct{}; func (*E) f() {}": {{"f", []int{0, 0}, true}},
57
58
59 "var a struct{ E[int] }; type E[P any] interface{ f() }": {{"f", []int{0, 0}, true}},
60 "var a *struct{ E[int] }; type E[P any] interface{ f() }": {{"f", []int{0, 0}, true}},
61 "var a struct{ E[int] }; type E[P any] struct{}; func (E[P]) f() {}": {{"f", []int{0, 0}, false}},
62 "var a struct{ *E[int] }; type E[P any] struct{}; func (E[P]) f() {}": {{"f", []int{0, 0}, true}},
63 "var a struct{ E[int] }; type E[P any] struct{}; func (*E[P]) f() {}": {},
64 "var a struct{ *E[int] }; type E[P any] struct{}; func (*E[P]) f() {}": {{"f", []int{0, 0}, true}},
65
66
67 "var a struct{ E1; *E2 }; type ( E1 interface{ f() }; E2 struct{ f int })": {},
68 "var a struct{ E1; *E2 }; type ( E1 struct{ f int }; E2 struct{} ); func (E2) f() {}": {},
69
70
71 "var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (N[P]) m() {}": {{"m", []int{0, 0}, true}},
72 "var a T[int]; type ( T[P any] struct { *N[P] }; N[P any] struct { *T[P] } ); func (T[P]) m() {}": {{"m", []int{0}, false}},
73 }
74
75 tParamTests := map[string][]method{
76
77 "type C interface{ f() }; func g[T C](a T){}": {{"f", []int{0}, true}},
78 "type C interface{ f() }; func g[T C]() { var a T; _ = a }": {{"f", []int{0}, true}},
79
80
81
82
83
84
85
86 }
87
88 check := func(src string, methods []method, generic bool) {
89 pkg := mustTypecheck("package p;"+src, nil, nil)
90
91 scope := pkg.Scope()
92 if generic {
93 fn := pkg.Scope().Lookup("g").(*Func)
94 scope = fn.Scope()
95 }
96 obj := scope.Lookup("a")
97 if obj == nil {
98 t.Errorf("%s: incorrect test case - no object a", src)
99 return
100 }
101
102 ms := NewMethodSet(obj.Type())
103 if got, want := ms.Len(), len(methods); got != want {
104 t.Errorf("%s: got %d methods, want %d", src, got, want)
105 return
106 }
107 for i, m := range methods {
108 sel := ms.At(i)
109 if got, want := sel.Obj().Name(), m.name; got != want {
110 t.Errorf("%s [method %d]: got name = %q at, want %q", src, i, got, want)
111 }
112 if got, want := sel.Index(), m.index; !slices.Equal(got, want) {
113 t.Errorf("%s [method %d]: got index = %v, want %v", src, i, got, want)
114 }
115 if got, want := sel.Indirect(), m.indirect; got != want {
116 t.Errorf("%s [method %d]: got indirect = %v, want %v", src, i, got, want)
117 }
118 }
119 }
120
121 for src, methods := range tests {
122 check(src, methods, false)
123 }
124
125 for src, methods := range tParamTests {
126 check(src, methods, true)
127 }
128 }
129
130
131 func TestNewMethodSet_RecursiveGeneric(t *testing.T) {
132 const src = `
133 package pkg
134
135 type Tree[T any] struct {
136 *Node[T]
137 }
138
139 type Node[T any] struct {
140 *Tree[T]
141 }
142
143 type Instance = *Tree[int]
144 `
145
146 fset := token.NewFileSet()
147 f, err := parser.ParseFile(fset, "foo.go", src, 0)
148 if err != nil {
149 panic(err)
150 }
151 pkg := NewPackage("pkg", f.Name.Name)
152 if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
153 panic(err)
154 }
155
156 T := pkg.Scope().Lookup("Instance").Type()
157 _ = NewMethodSet(T)
158 }
159
160 func TestIssue60634(t *testing.T) {
161 const src = `
162 package p
163 type T *int
164 func (T) m() {} // expected error: invalid receiver type
165 `
166
167 fset := token.NewFileSet()
168 f, err := parser.ParseFile(fset, "p.go", src, 0)
169 if err != nil {
170 t.Fatal(err)
171 }
172
173 var conf Config
174 pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
175 if err == nil || !strings.Contains(err.Error(), "invalid receiver type") {
176 t.Fatalf("missing or unexpected error: %v", err)
177 }
178
179
180 T := pkg.Scope().Lookup("T").Type()
181 name := "m"
182 for _, recv := range []Type{T, NewPointer(T)} {
183
184
185 obj1, _, _ := LookupFieldOrMethod(recv, false, pkg, name)
186 mset := NewMethodSet(recv)
187 if (obj1 != nil) != (mset.Len() == 1) {
188 t.Fatalf("lookup(%v.%s): got obj = %v, mset = %v", recv, name, obj1, mset)
189 }
190
191 if obj1 != nil {
192 obj2 := mset.At(0).Obj()
193 if obj1 != obj2 {
194 t.Fatalf("%v != %v", obj1, obj2)
195 }
196 }
197 }
198 }
199
View as plain text