golang.org/x/tools@v0.21.0/refactor/satisfy/find_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // This test exercises various operations on core types of type parameters. 23 // (It also provides pretty decent coverage of the non-generic operations.) 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]", // implicitly "forall T" quantified 174 "p.GI[T] <- p.Generic[T]", // implicitly "forall T" quantified 175 "p.GI[string] <- p.Gen2[T]", // implicitly "forall T" quantified 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 // parse 210 fset := token.NewFileSet() 211 f, err := parser.ParseFile(fset, "p.go", src, 0) 212 if err != nil { 213 t.Fatal(err) // parse error 214 } 215 files := []*ast.File{f} 216 217 // type-check 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) // type error 233 } 234 235 // gather constraints 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 }