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