github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 "github.com/powerman/golang-tools/internal/testenv" 15 . "github.com/powerman/golang-tools/internal/typeparams" 16 ) 17 18 func TestGetIndexExprData(t *testing.T) { 19 x := &ast.Ident{} 20 i := &ast.Ident{} 21 22 want := &IndexListExpr{X: x, Lbrack: 1, Indices: []ast.Expr{i}, Rbrack: 2} 23 tests := map[ast.Node]bool{ 24 &ast.IndexExpr{X: x, Lbrack: 1, Index: i, Rbrack: 2}: true, 25 want: true, 26 &ast.Ident{}: false, 27 } 28 29 for n, isIndexExpr := range tests { 30 X, lbrack, indices, rbrack := UnpackIndexExpr(n) 31 if got := X != nil; got != isIndexExpr { 32 t.Errorf("UnpackIndexExpr(%v) = %v, _, _, _; want nil: %t", n, x, !isIndexExpr) 33 } 34 if X == nil { 35 continue 36 } 37 if X != x || lbrack != 1 || indices[0] != i || rbrack != 2 { 38 t.Errorf("UnpackIndexExprData(%v) = %v, %v, %v, %v; want %+v", n, x, lbrack, indices, rbrack, want) 39 } 40 } 41 } 42 43 func TestOriginMethodRecursive(t *testing.T) { 44 testenv.NeedsGo1Point(t, 18) 45 src := `package p 46 47 type N[A any] int 48 49 func (r N[B]) m() { r.m(); r.n() } 50 51 func (r *N[C]) n() { } 52 ` 53 fset := token.NewFileSet() 54 f, err := parser.ParseFile(fset, "p.go", src, 0) 55 if err != nil { 56 t.Fatal(err) 57 } 58 info := types.Info{ 59 Defs: make(map[*ast.Ident]types.Object), 60 Uses: make(map[*ast.Ident]types.Object), 61 } 62 var conf types.Config 63 if _, err := conf.Check("p", fset, []*ast.File{f}, &info); err != nil { 64 t.Fatal(err) 65 } 66 67 // Collect objects from types.Info. 68 var m, n *types.Func // the 'origin' methods in Info.Defs 69 var mm, mn *types.Func // the methods used in the body of m 70 71 for _, decl := range f.Decls { 72 fdecl, ok := decl.(*ast.FuncDecl) 73 if !ok { 74 continue 75 } 76 def := info.Defs[fdecl.Name].(*types.Func) 77 switch fdecl.Name.Name { 78 case "m": 79 m = def 80 ast.Inspect(fdecl.Body, func(n ast.Node) bool { 81 if call, ok := n.(*ast.CallExpr); ok { 82 sel := call.Fun.(*ast.SelectorExpr) 83 use := info.Uses[sel.Sel].(*types.Func) 84 switch sel.Sel.Name { 85 case "m": 86 mm = use 87 case "n": 88 mn = use 89 } 90 } 91 return true 92 }) 93 case "n": 94 n = def 95 } 96 } 97 98 tests := []struct { 99 name string 100 input, want *types.Func 101 }{ 102 {"declared m", m, m}, 103 {"declared n", n, n}, 104 {"used m", mm, m}, 105 {"used n", mn, n}, 106 } 107 108 for _, test := range tests { 109 if got := OriginMethod(test.input); got != test.want { 110 t.Errorf("OriginMethod(%q) = %v, want %v", test.name, test.input, test.want) 111 } 112 } 113 } 114 115 func TestOriginMethodUses(t *testing.T) { 116 testenv.NeedsGo1Point(t, 18) 117 118 tests := []string{ 119 `type T interface { m() }; func _(t T) { t.m() }`, 120 `type T[P any] interface { m() P }; func _[A any](t T[A]) { t.m() }`, 121 `type T[P any] interface { m() P }; func _(t T[int]) { t.m() }`, 122 `type T[P any] int; func (r T[A]) m() { r.m() }`, 123 `type T[P any] int; func (r *T[A]) m() { r.m() }`, 124 `type T[P any] int; func (r *T[A]) m() {}; func _(t T[int]) { t.m() }`, 125 `type T[P any] int; func (r *T[A]) m() {}; func _[A any](t T[A]) { t.m() }`, 126 } 127 128 for _, src := range tests { 129 fset := token.NewFileSet() 130 f, err := parser.ParseFile(fset, "p.go", "package p; "+src, 0) 131 if err != nil { 132 t.Fatal(err) 133 } 134 info := types.Info{ 135 Uses: make(map[*ast.Ident]types.Object), 136 } 137 var conf types.Config 138 pkg, err := conf.Check("p", fset, []*ast.File{f}, &info) 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 T := pkg.Scope().Lookup("T").Type() 144 obj, _, _ := types.LookupFieldOrMethod(T, true, pkg, "m") 145 m := obj.(*types.Func) 146 147 ast.Inspect(f, func(n ast.Node) bool { 148 if call, ok := n.(*ast.CallExpr); ok { 149 sel := call.Fun.(*ast.SelectorExpr) 150 use := info.Uses[sel.Sel].(*types.Func) 151 orig := OriginMethod(use) 152 if orig != m { 153 t.Errorf("%s:\nUses[%v] = %v, want %v", src, types.ExprString(sel), use, m) 154 } 155 } 156 return true 157 }) 158 } 159 } 160 161 func TestGenericAssignableTo(t *testing.T) { 162 testenv.NeedsGo1Point(t, 18) 163 164 tests := []struct { 165 src string 166 want bool 167 }{ 168 // The inciting issue: golang/go#50887. 169 {` 170 type T[P any] interface { 171 Accept(P) 172 } 173 174 type V[Q any] struct { 175 Element Q 176 } 177 178 func (c V[Q]) Accept(q Q) { c.Element = q } 179 `, true}, 180 181 // Various permutations on constraints and signatures. 182 {`type T[P ~int] interface{ A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, true}, 183 {`type T[P int] interface{ A(P) }; type V[Q ~int] int; func (V[Q]) A(Q) {}`, false}, 184 {`type T[P int|string] interface{ A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, true}, 185 {`type T[P any] interface{ A(P) }; type V[Q any] int; func (V[Q]) A(Q, Q) {}`, false}, 186 {`type T[P any] interface{ int; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, false}, 187 188 // Various structural restrictions on T. 189 {`type T[P any] interface{ ~int; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, true}, 190 {`type T[P any] interface{ ~int|string; A(P) }; type V[Q any] int; func (V[Q]) A(Q) {}`, true}, 191 {`type T[P any] interface{ int; A(P) }; type V[Q int] int; func (V[Q]) A(Q) {}`, false}, 192 193 // Various recursive constraints. 194 {`type T[P ~struct{ f *P }] interface{ A(P) }; type V[Q ~struct{ f *Q }] int; func (V[Q]) A(Q) {}`, true}, 195 {`type T[P ~struct{ f *P }] interface{ A(P) }; type V[Q ~struct{ g *Q }] int; func (V[Q]) A(Q) {}`, false}, 196 {`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}, 197 {`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}, 198 {`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}, 199 {`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}, 200 {`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}, 201 202 // In this test case, we reverse the type parameters in the signature of V.A 203 {`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}, 204 // It would be nice to return true here: V can only be instantiated with 205 // [int, int], so the identity of the type parameters should not matter. 206 {`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}, 207 } 208 209 for _, test := range tests { 210 fset := token.NewFileSet() 211 f, err := parser.ParseFile(fset, "p.go", "package p; "+test.src, 0) 212 if err != nil { 213 t.Fatalf("%s:\n%v", test.src, err) 214 } 215 var conf types.Config 216 pkg, err := conf.Check("p", fset, []*ast.File{f}, nil) 217 if err != nil { 218 t.Fatalf("%s:\n%v", test.src, err) 219 } 220 221 V := pkg.Scope().Lookup("V").Type() 222 T := pkg.Scope().Lookup("T").Type() 223 224 if types.AssignableTo(V, T) { 225 t.Fatal("AssignableTo") 226 } 227 228 if got := GenericAssignableTo(nil, V, T); got != test.want { 229 t.Fatalf("%s:\nGenericAssignableTo(%v, %v) = %v, want %v", test.src, V, T, got, test.want) 230 } 231 } 232 }