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/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; !slices.Equal(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 := mustParse(fset, src)
147
148 pkg := NewPackage("pkg", f.Name.Name)
149 if err := NewChecker(nil, fset, pkg, nil).Files([]*ast.File{f}); err != nil {
150 panic(err)
151 }
152
153 T := pkg.Scope().Lookup("Instance").Type()
154 _ = NewMethodSet(T)
155 }
156
157 func TestIssue60634(t *testing.T) {
158 const src = `
159 package p
160 type T *int
161 func (T) m() {} // expected error: invalid receiver type
162 `
163
164 fset := token.NewFileSet()
165 f := mustParse(fset, src)
166
167 var conf Config
168 pkg, err := conf.Check("p", fset, []*ast.File{f}, nil)
169 if err == nil || !strings.Contains(err.Error(), "invalid receiver type") {
170 t.Fatalf("missing or unexpected error: %v", err)
171 }
172
173
174 T := pkg.Scope().Lookup("T").Type()
175 name := "m"
176 for _, recv := range []Type{T, NewPointer(T)} {
177
178
179 obj1, _, _ := LookupFieldOrMethod(recv, false, pkg, name)
180 mset := NewMethodSet(recv)
181 if (obj1 != nil) != (mset.Len() == 1) {
182 t.Fatalf("lookup(%v.%s): got obj = %v, mset = %v", recv, name, obj1, mset)
183 }
184
185 if obj1 != nil {
186 obj2 := mset.At(0).Obj()
187 if obj1 != obj2 {
188 t.Fatalf("%v != %v", obj1, obj2)
189 }
190 }
191 }
192 }
193
View as plain text