1
2
3
4
5 package satisfy_test
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/importer"
11 "go/parser"
12 "go/token"
13 "go/types"
14 "reflect"
15 "sort"
16 "testing"
17
18 "golang.org/x/tools/internal/versions"
19 "golang.org/x/tools/refactor/satisfy"
20 )
21
22
23
24 func TestGenericCoreOperations(t *testing.T) {
25 const src = `package foo
26
27 import "unsafe"
28
29 type I interface { f() }
30
31 type impl struct{}
32 func (impl) f() {}
33
34 // A big pile of single-serving types that implement I.
35 type A struct{impl}
36 type B struct{impl}
37 type C struct{impl}
38 type D struct{impl}
39 type E struct{impl}
40 type F struct{impl}
41 type G struct{impl}
42 type H struct{impl}
43 type J struct{impl}
44 type K struct{impl}
45 type L struct{impl}
46 type M struct{impl}
47 type N struct{impl}
48 type O struct{impl}
49 type P struct{impl}
50 type Q struct{impl}
51 type R struct{impl}
52 type S struct{impl}
53 type T struct{impl}
54 type U struct{impl}
55 type V struct{impl}
56 type W struct{impl}
57 type X struct{impl}
58
59 type Generic[T any] struct{impl}
60 func (Generic[T]) g(T) {}
61
62 type GI[T any] interface{
63 g(T)
64 }
65
66 func _[Slice interface{ []I }](s Slice) Slice {
67 s[0] = L{} // I <- L
68 return append(s, A{}) // I <- A
69 }
70
71 func _[Func interface{ func(I) B }](fn Func) {
72 b := fn(C{}) // I <- C
73 var _ I = b // I <- B
74 }
75
76 func _[Chan interface{ chan D }](ch Chan) {
77 var i I
78 for i = range ch {} // I <- D
79 _ = i
80 }
81
82 func _[Chan interface{ chan E }](ch Chan) {
83 var _ I = <-ch // I <- E
84 }
85
86 func _[Chan interface{ chan I }](ch Chan) {
87 ch <- F{} // I <- F
88 }
89
90 func _[Map interface{ map[G]H }](m Map) {
91 var k, v I
92 for k, v = range m {} // I <- G, I <- H
93 _, _ = k, v
94 }
95
96 func _[Map interface{ map[I]K }](m Map) {
97 var _ I = m[J{}] // I <- J, I <- K
98 delete(m, R{}) // I <- R
99 _, _ = m[J{}]
100 }
101
102 func _[Array interface{ [1]I }](a Array) {
103 a[0] = M{} // I <- M
104 }
105
106 func _[Array interface{ [1]N }](a Array) {
107 var _ I = a[0] // I <- N
108 }
109
110 func _[Array interface{ [1]O }](a Array) {
111 var v I
112 for _, v = range a {} // I <- O
113 _ = v
114 }
115
116 func _[ArrayPtr interface{ *[1]P }](a ArrayPtr) {
117 var v I
118 for _, v = range a {} // I <- P
119 _ = v
120 }
121
122 func _[Slice interface{ []Q }](s Slice) {
123 var v I
124 for _, v = range s {} // I <- Q
125 _ = v
126 }
127
128 func _[Func interface{ func() (S, bool) }](fn Func) {
129 var i I
130 i, _ = fn() // I <- S
131 _ = i
132 }
133
134 func _() I {
135 var _ I = T{} // I <- T
136 var _ I = Generic[T]{} // I <- Generic[T]
137 var _ I = Generic[string]{} // I <- Generic[string]
138 return U{} // I <- U
139 }
140
141 var _ GI[string] = Generic[string]{} // GI[string] <- Generic[string]
142
143 // universally quantified constraints:
144 // the type parameter may appear on the left, the right, or both sides.
145
146 func _[T any](g Generic[T]) GI[T] {
147 return g // GI[T] <- Generic[T]
148 }
149
150 func _[T any]() {
151 type GI2[T any] interface{ g(string) }
152 var _ GI2[T] = Generic[string]{} // GI2[T] <- Generic[string]
153 }
154
155 type Gen2[T any] struct{}
156 func (f Gen2[T]) g(string) { global = f } // GI[string] <- Gen2[T]
157
158 var global GI[string]
159
160 func _() {
161 var x [3]V
162 // golang/go#56227: the finder should visit calls in the unsafe package.
163 _ = unsafe.Slice(&x[0], func() int { var _ I = x[0]; return 3 }()) // I <- V
164 }
165
166 func _[P ~struct{F I}]() {
167 _ = P{W{}}
168 _ = P{F: X{}}
169 }
170 `
171 got := constraints(t, src)
172 want := []string{
173 "p.GI2[T] <- p.Generic[string]",
174 "p.GI[T] <- p.Generic[T]",
175 "p.GI[string] <- p.Gen2[T]",
176 "p.GI[string] <- p.Generic[string]",
177 "p.I <- p.A",
178 "p.I <- p.B",
179 "p.I <- p.C",
180 "p.I <- p.D",
181 "p.I <- p.E",
182 "p.I <- p.F",
183 "p.I <- p.G",
184 "p.I <- p.Generic[p.T]",
185 "p.I <- p.Generic[string]",
186 "p.I <- p.H",
187 "p.I <- p.J",
188 "p.I <- p.K",
189 "p.I <- p.L",
190 "p.I <- p.M",
191 "p.I <- p.N",
192 "p.I <- p.O",
193 "p.I <- p.P",
194 "p.I <- p.Q",
195 "p.I <- p.R",
196 "p.I <- p.S",
197 "p.I <- p.T",
198 "p.I <- p.U",
199 "p.I <- p.V",
200 "p.I <- p.W",
201 "p.I <- p.X",
202 }
203 if !reflect.DeepEqual(got, want) {
204 t.Fatalf("found unexpected constraints: got %s, want %s", got, want)
205 }
206 }
207
208 func constraints(t *testing.T, src string) []string {
209
210 fset := token.NewFileSet()
211 f, err := parser.ParseFile(fset, "p.go", src, 0)
212 if err != nil {
213 t.Fatal(err)
214 }
215 files := []*ast.File{f}
216
217
218 info := &types.Info{
219 Types: make(map[ast.Expr]types.TypeAndValue),
220 Defs: make(map[*ast.Ident]types.Object),
221 Uses: make(map[*ast.Ident]types.Object),
222 Implicits: make(map[ast.Node]types.Object),
223 Instances: make(map[*ast.Ident]types.Instance),
224 Scopes: make(map[ast.Node]*types.Scope),
225 Selections: make(map[*ast.SelectorExpr]*types.Selection),
226 }
227 versions.InitFileVersions(info)
228 conf := types.Config{
229 Importer: importer.Default(),
230 }
231 if _, err := conf.Check("p", fset, files, info); err != nil {
232 t.Fatal(err)
233 }
234
235
236 var finder satisfy.Finder
237 finder.Find(info, files)
238 var constraints []string
239 for c := range finder.Result {
240 constraints = append(constraints, fmt.Sprintf("%v <- %v", c.LHS, c.RHS))
241 }
242 sort.Strings(constraints)
243 return constraints
244 }
245
View as plain text