golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/typeparams/common_test.go (about) 1 // Copyright 2021 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 typeparams_test 6 7 import ( 8 "go/ast" 9 "go/parser" 10 "go/token" 11 "go/types" 12 "testing" 13 14 . "golang.org/x/tools/internal/typeparams" 15 ) 16 17 func TestGetIndexExprData(t *testing.T) { 18 x := &ast.Ident{} 19 i := &ast.Ident{} 20 21 want := &ast.IndexListExpr{X: x, Lbrack: 1, Indices: []ast.Expr{i}, Rbrack: 2} 22 tests := map[ast.Node]bool{ 23 &ast.IndexExpr{X: x, Lbrack: 1, Index: i, Rbrack: 2}: true, 24 want: true, 25 &ast.Ident{}: false, 26 } 27 28 for n, isIndexExpr := range tests { 29 X, lbrack, indices, rbrack := UnpackIndexExpr(n) 30 if got := X != nil; got != isIndexExpr { 31 t.Errorf("UnpackIndexExpr(%v) = %v, _, _, _; want nil: %t", n, x, !isIndexExpr) 32 } 33 if X == nil { 34 continue 35 } 36 if X != x || lbrack != 1 || indices[0] != i || rbrack != 2 { 37 t.Errorf("UnpackIndexExprData(%v) = %v, %v, %v, %v; want %+v", n, x, lbrack, indices, rbrack, want) 38 } 39 } 40 } 41 42 func TestFuncOriginRecursive(t *testing.T) { 43 src := `package p 44 45 type N[A any] int 46 47 func (r N[B]) m() { r.m(); r.n() } 48 49 func (r *N[C]) n() { } 50 ` 51 fset := token.NewFileSet() 52 f, err := parser.ParseFile(fset, "p.go", src, 0) 53 if err != nil { 54 t.Fatal(err) 55 } 56 info := types.Info{ 57 Defs: make(map[*ast.Ident]types.Object), 58 Uses: make(map[*ast.Ident]types.Object), 59 } 60 var conf types.Config 61 if _, err := conf.Check("p", fset, []*ast.File{f}, &info); err != nil { 62 t.Fatal(err) 63 } 64 65 // Collect objects from types.Info. 66 var m, n *types.Func // the 'origin' methods in Info.Defs 67 var mm, mn *types.Func // the methods used in the body of m 68 69 for _, decl := range f.Decls { 70 fdecl, ok := decl.(*ast.FuncDecl) 71 if !ok { 72 continue 73 } 74 def := info.Defs[fdecl.Name].(*types.Func) 75 switch fdecl.Name.Name { 76 case "m": 77 m = def 78 ast.Inspect(fdecl.Body, func(n ast.Node) bool { 79 if call, ok := n.(*ast.CallExpr); ok { 80 sel := call.Fun.(*ast.SelectorExpr) 81 use := info.Uses[sel.Sel].(*types.Func) 82 switch sel.Sel.Name { 83 case "m": 84 mm = use 85 case "n": 86 mn = use 87 } 88 } 89 return true 90 }) 91 case "n": 92 n = def 93 } 94 } 95 96 tests := []struct { 97 name string 98 input, want *types.Func 99 }{ 100 {"declared m", m, m}, 101 {"declared n", n, n}, 102 {"used m", mm, m}, 103 {"used n", mn, n}, 104 } 105 106 for _, test := range tests { 107 if got := test.input.Origin(); got != test.want { 108 t.Errorf("Origin(%q) = %v, want %v", test.name, test.input, test.want) 109 } 110 } 111 } 112 113 func TestFuncOriginUses(t *testing.T) { 114 115 tests := []string{ 116 `type T interface { m() }; func _(t T) { t.m() }`, 117 `type T[P any] interface { m() P }; func _[A any](t T[A]) { t.m() }`, 118 `type T[P any] interface { m() P }; func _(t T[int]) { t.m() }`, 119 `type T[P any] int; func (r T[A]) m() { r.m() }`, 120 `type T[P any] int; func (r *T[A]) m() { r.m() }`, 121 `type T[P any] int; func (r *T[A]) m() {}; func _(t T[int]) { t.m() }`, 122 `type T[P any] int; func (r *T[A]) m() {}; func _[A any](t T[A]) { t.m() }`, 123 } 124 125 for _, src := range tests { 126 fset := token.NewFileSet() 127 f, err := parser.ParseFile(fset, "p.go", "package p; "+src, 0) 128 if err != nil { 129 t.Fatal(err) 130 } 131 info := types.Info{ 132 Uses: make(map[*ast.Ident]types.Object), 133 } 134 var conf types.Config 135 pkg, err := conf.Check("p", fset, []*ast.File{f}, &info) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 // Look up func T.m. 141 T := pkg.Scope().Lookup("T").Type() 142 obj, _, _ := types.LookupFieldOrMethod(T, true, pkg, "m") 143 m := obj.(*types.Func) 144 145 // Assert that the origin of each t.m() call is p.T.m. 146 ast.Inspect(f, func(n ast.Node) bool { 147 if call, ok := n.(*ast.CallExpr); ok { 148 sel := call.Fun.(*ast.SelectorExpr) 149 use := info.Uses[sel.Sel].(*types.Func) 150 orig := use.Origin() 151 if orig != m { 152 t.Errorf("%s:\nUses[%v] = %v, want %v", src, types.ExprString(sel), use, m) 153 } 154 } 155 return true 156 }) 157 } 158 } 159 160 // Issue #60628 was a crash in gopls caused by inconsistency (#60634) between 161 // LookupFieldOrMethod and NewFileSet for methods with an illegal 162 // *T receiver type, where T itself is a pointer. 163 // This is a regression test for the workaround in the (now deleted) OriginMethod. 164 func TestFuncOrigin60628(t *testing.T) { 165 const src = `package p; type T[P any] *int; func (r *T[A]) f() {}` 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 // Expect type error: "invalid receiver type T[A] (pointer or interface type)". 173 info := types.Info{ 174 Uses: make(map[*ast.Ident]types.Object), 175 } 176 var conf types.Config 177 pkg, _ := conf.Check("p", fset, []*ast.File{f}, &info) // error expected 178 if pkg == nil { 179 t.Fatal("no package") 180 } 181 182 // Look up methodset of *T. 183 T := pkg.Scope().Lookup("T").Type() 184 mset := types.NewMethodSet(types.NewPointer(T)) 185 if mset.Len() == 0 { 186 t.Errorf("NewMethodSet(*T) is empty") 187 } 188 for i := 0; i < mset.Len(); i++ { 189 sel := mset.At(i) 190 m := sel.Obj().(*types.Func) 191 192 // TODO(adonovan): check the consistency property required to fix #60634. 193 if false { 194 m2, _, _ := types.LookupFieldOrMethod(T, true, m.Pkg(), m.Name()) 195 if m2 != m { 196 t.Errorf("LookupFieldOrMethod(%v, indirect=true, %v) = %v, want %v", 197 T, m, m2, m) 198 } 199 } 200 201 // Check the workaround. 202 if m.Origin() == nil { 203 t.Errorf("Origin(%v) = nil", m) 204 } 205 } 206 } 207 208 func TestGenericAssignableTo(t *testing.T) { 209 tests := []struct { 210 src string 211 want bool 212 }{ 213 // The inciting issue: golang/go#50887. 214 {` 215 type T[P any] interface { 216 Accept(P) 217 } 218 219 type V[Q any] struct { 220 Element Q 221 } 222 223 func (c V[Q]) Accept(q Q) { c.Element = q } 224 `, true}, 225 226 // Various permutations on constraints and signatures. 227 {`type T[P ~int] interface{ A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, true}, 228 {`type T[P int] interface{ A(P) }; type V[Q ~int] int; func (V[Q]) A(Q) {}`, false}, 229 {`type T[P int|string] interface{ A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, true}, 230 {`type T[P any] interface{ A(P) }; type V[Q any] int; func (V[Q]) A(Q, Q) {}`, false}, 231 {`type T[P any] interface{ int; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, false}, 232 233 // Various structural restrictions on T. 234 {`type T[P any] interface{ ~int; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, true}, 235 {`type T[P any] interface{ ~int|string; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, true}, 236 {`type T[P any] interface{ int; A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, false}, 237 238 // Various recursive constraints. 239 {`type T[P ~struct{ f *P }] interface{ A(P) }; type V[Q ~struct{ f *Q }] int; func (V[Q]) A(Q) {}`, true}, 240 {`type T[P ~struct{ f *P }] interface{ A(P) }; type V[Q ~struct{ g *Q }] int; func (V[Q]) A(Q) {}`, false}, 241 {`type T[P ~*X, X any] interface{ A(P) X }; type V[Q ~*Y, Y any] int; func (V[Q, Y]) A(Q) (y Y) { return }`, true}, 242 {`type T[P ~*X, X any] interface{ A(P) X }; type V[Q ~**Y, Y any] int; func (V[Q, Y]) A(Q) (y Y) { return }`, false}, 243 {`type T[P, X any] interface{ A(P) X }; type V[Q ~*Y, Y any] int; func (V[Q, Y]) A(Q) (y Y) { return }`, true}, 244 {`type T[P ~*X, X any] interface{ A(P) X }; type V[Q, Y any] int; func (V[Q, Y]) A(Q) (y Y) { return }`, false}, 245 {`type T[P, X any] interface{ A(P) X }; type V[Q, Y any] int; func (V[Q, Y]) A(Q) (y Y) { return }`, true}, 246 247 // In this test case, we reverse the type parameters in the signature of V.A 248 {`type T[P, X any] interface{ A(P) X }; type V[Q, Y any] int; func (V[Q, Y]) A(Y) (y Q) { return }`, false}, 249 // It would be nice to return true here: V can only be instantiated with 250 // [int, int], so the identity of the type parameters should not matter. 251 {`type T[P, X any] interface{ A(P) X }; type V[Q, Y int] int; func (V[Q, Y]) A(Y) (y Q) { return }`, false}, 252 } 253 254 for _, test := range tests { 255 fset := token.NewFileSet() 256 f, err := parser.ParseFile(fset, "p.go", "package p; "+test.src, 0) 257 if err != nil { 258 t.Fatalf("%s:\n%v", test.src, err) 259 } 260 var conf types.Config 261 pkg, err := conf.Check("p", fset, []*ast.File{f}, nil) 262 if err != nil { 263 t.Fatalf("%s:\n%v", test.src, err) 264 } 265 266 V := pkg.Scope().Lookup("V").Type() 267 T := pkg.Scope().Lookup("T").Type() 268 269 if types.AssignableTo(V, T) { 270 t.Fatal("AssignableTo") 271 } 272 273 if got := GenericAssignableTo(nil, V, T); got != test.want { 274 t.Fatalf("%s:\nGenericAssignableTo(%v, %v) = %v, want %v", test.src, V, T, got, test.want) 275 } 276 } 277 }