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