GoPLS Viewer

Home|gopls/internal/typeparams/common_test.go
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
5package typeparams_test
6
7import (
8    "go/ast"
9    "go/parser"
10    "go/token"
11    "go/types"
12    "testing"
13
14    "golang.org/x/tools/internal/testenv"
15    . "golang.org/x/tools/internal/typeparams"
16)
17
18func TestGetIndexExprData(t *testing.T) {
19    x := &ast.Ident{}
20    i := &ast.Ident{}
21
22    want := &IndexListExpr{XxLbrack1Indices: []ast.Expr{i}, Rbrack2}
23    tests := map[ast.Node]bool{
24        &ast.IndexExpr{XxLbrack1IndexiRbrack2}: true,
25        want:         true,
26        &ast.Ident{}: false,
27    }
28
29    for nisIndexExpr := range tests {
30        Xlbrackindicesrbrack := UnpackIndexExpr(n)
31        if got := X != nilgot != isIndexExpr {
32            t.Errorf("UnpackIndexExpr(%v) = %v, _, _, _; want nil: %t"nx, !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"nxlbrackindicesrbrackwant)
39        }
40    }
41}
42
43func TestOriginMethodRecursive(t *testing.T) {
44    testenv.NeedsGo1Point(t18)
45    src := `package p
46
47type N[A any] int
48
49func (r N[B]) m() { r.m(); r.n() }
50
51func (r *N[C]) n() { }
52`
53    fset := token.NewFileSet()
54    ferr := parser.ParseFile(fset"p.go"src0)
55    if err != nil {
56        t.Fatal(err)
57    }
58    info := types.Info{
59        Defsmake(map[*ast.Ident]types.Object),
60        Usesmake(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 mn *types.Func   // the 'origin' methods in Info.Defs
69    var mmmn *types.Func // the methods used in the body of m
70
71    for _decl := range f.Decls {
72        fdeclok := 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.Nodebool {
81                if callok := 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        inputwant *types.Func
101    }{
102        {"declared m"mm},
103        {"declared n"nn},
104        {"used m"mmm},
105        {"used n"mnn},
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.nametest.inputtest.want)
111        }
112    }
113}
114
115func TestOriginMethodUses(t *testing.T) {
116    testenv.NeedsGo1Point(t18)
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        ferr := parser.ParseFile(fset"p.go""package p; "+src0)
131        if err != nil {
132            t.Fatal(err)
133        }
134        info := types.Info{
135            Usesmake(map[*ast.Ident]types.Object),
136        }
137        var conf types.Config
138        pkgerr := 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(Ttruepkg"m")
145        m := obj.(*types.Func)
146
147        ast.Inspect(f, func(n ast.Nodebool {
148            if callok := 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"srctypes.ExprString(sel), usem)
154                }
155            }
156            return true
157        })
158    }
159}
160
161func TestGenericAssignableTo(t *testing.T) {
162    testenv.NeedsGo1Point(t18)
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        ferr := parser.ParseFile(fset"p.go""package p; "+test.src0)
212        if err != nil {
213            t.Fatalf("%s:\n%v"test.srcerr)
214        }
215        var conf types.Config
216        pkgerr := conf.Check("p"fset, []*ast.File{f}, nil)
217        if err != nil {
218            t.Fatalf("%s:\n%v"test.srcerr)
219        }
220
221        V := pkg.Scope().Lookup("V").Type()
222        T := pkg.Scope().Lookup("T").Type()
223
224        if types.AssignableTo(VT) {
225            t.Fatal("AssignableTo")
226        }
227
228        if got := GenericAssignableTo(nilVT); got != test.want {
229            t.Fatalf("%s:\nGenericAssignableTo(%v, %v) = %v, want %v"test.srcVTgottest.want)
230        }
231    }
232}
233
MembersX
TestOriginMethodRecursive
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.err
TestOriginMethodRecursive.conf
TestOriginMethodRecursive.n
TestOriginMethodUses.RangeStmt_3152.BlockStmt.err
TestGenericAssignableTo.tests
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.got
parser
TestOriginMethodUses.RangeStmt_3152.src
TestOriginMethodUses.RangeStmt_3152.BlockStmt.obj
TestGenericAssignableTo.RangeStmt_6422.test
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.f
TestGetIndexExprData.RangeStmt_638.BlockStmt.lbrack
TestOriginMethodRecursive.t
TestOriginMethodRecursive.src
TestOriginMethodRecursive.tests
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.V
TestOriginMethodUses.RangeStmt_3152.BlockStmt.info
TestOriginMethodUses.RangeStmt_3152.BlockStmt.conf
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.T
TestOriginMethodRecursive.f
TestGetIndexExprData.i
TestOriginMethodRecursive.err
TestOriginMethodRecursive.m
TestOriginMethodRecursive.RangeStmt_1739.decl
TestOriginMethodUses.t
TestOriginMethodUses.RangeStmt_3152.BlockStmt.pkg
TestOriginMethodUses.RangeStmt_3152.BlockStmt.T
TestOriginMethodUses.RangeStmt_3152.BlockStmt._
TestGenericAssignableTo
testing
TestOriginMethodRecursive.fset
TestOriginMethodRecursive.mm
TestOriginMethodRecursive.RangeStmt_2428.test
TestOriginMethodUses.RangeStmt_3152.BlockStmt.f
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.conf
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.pkg
TestGetIndexExprData.x
TestOriginMethodRecursive.RangeStmt_2428.BlockStmt.got
TestGenericAssignableTo.t
testenv
TestOriginMethodUses.RangeStmt_3152.BlockStmt.fset
.
TestGetIndexExprData.RangeStmt_638.isIndexExpr
TestGetIndexExprData.RangeStmt_638.BlockStmt.X
TestGetIndexExprData.RangeStmt_638.BlockStmt.indices
TestGetIndexExprData.RangeStmt_638.BlockStmt.rbrack
TestOriginMethodUses.RangeStmt_3152.BlockStmt.BlockStmt.BlockStmt.orig
TestGetIndexExprData.want
TestGetIndexExprData.RangeStmt_638.n
TestGetIndexExprData.tests
TestOriginMethodRecursive._
TestOriginMethodRecursive.mn
TestOriginMethodUses.tests
TestGetIndexExprData
TestGetIndexExprData.t
TestGenericAssignableTo.RangeStmt_6422.BlockStmt.fset
TestOriginMethodRecursive.info
TestOriginMethodUses
Members
X