Source file
src/go/types/instantiate_test.go
1
2
3
4
5
6
7 package types_test
8
9 import (
10 . "go/types"
11 "strings"
12 "testing"
13 )
14
15 func TestInstantiateEquality(t *testing.T) {
16 emptySignature := NewSignatureType(nil, nil, nil, nil, nil, false)
17 tests := []struct {
18 src string
19 name1 string
20 targs1 []Type
21 name2 string
22 targs2 []Type
23 wantEqual bool
24 }{
25 {
26 "package basictype; type T[P any] int",
27 "T", []Type{Typ[Int]},
28 "T", []Type{Typ[Int]},
29 true,
30 },
31 {
32 "package differenttypeargs; type T[P any] int",
33 "T", []Type{Typ[Int]},
34 "T", []Type{Typ[String]},
35 false,
36 },
37 {
38 "package typeslice; type T[P any] int",
39 "T", []Type{NewSlice(Typ[Int])},
40 "T", []Type{NewSlice(Typ[Int])},
41 true,
42 },
43 {
44
45 "package equivalentinterfaces; type T[P any] int",
46 "T", []Type{
47 NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
48 },
49 "T", []Type{
50 NewInterfaceType(
51 nil,
52 []Type{
53 NewInterfaceType([]*Func{NewFunc(nopos, nil, "M", emptySignature)}, nil),
54 },
55 ),
56 },
57 true,
58 },
59 {
60
61 "package equivalenttypesets; type T[P any] int",
62 "T", []Type{
63 NewInterfaceType(nil, []Type{
64 NewUnion([]*Term{NewTerm(false, Typ[Int]), NewTerm(false, Typ[String])}),
65 }),
66 },
67 "T", []Type{
68 NewInterfaceType(nil, []Type{
69 NewUnion([]*Term{NewTerm(false, Typ[String]), NewTerm(false, Typ[Int])}),
70 }),
71 },
72 true,
73 },
74 {
75 "package basicfunc; func F[P any]() {}",
76 "F", []Type{Typ[Int]},
77 "F", []Type{Typ[Int]},
78 true,
79 },
80 {
81 "package funcslice; func F[P any]() {}",
82 "F", []Type{NewSlice(Typ[Int])},
83 "F", []Type{NewSlice(Typ[Int])},
84 true,
85 },
86 {
87 "package funcwithparams; func F[P any](x string) float64 { return 0 }",
88 "F", []Type{Typ[Int]},
89 "F", []Type{Typ[Int]},
90 true,
91 },
92 {
93 "package differentfuncargs; func F[P any](x string) float64 { return 0 }",
94 "F", []Type{Typ[Int]},
95 "F", []Type{Typ[String]},
96 false,
97 },
98 {
99 "package funcequality; func F1[P any](x int) {}; func F2[Q any](x int) {}",
100 "F1", []Type{Typ[Int]},
101 "F2", []Type{Typ[Int]},
102 false,
103 },
104 {
105 "package funcsymmetry; func F1[P any](x P) {}; func F2[Q any](x Q) {}",
106 "F1", []Type{Typ[Int]},
107 "F2", []Type{Typ[Int]},
108 false,
109 },
110 }
111
112 for _, test := range tests {
113 pkg := mustTypecheck(test.src, nil, nil)
114
115 t.Run(pkg.Name(), func(t *testing.T) {
116 ctxt := NewContext()
117
118 T1 := pkg.Scope().Lookup(test.name1).Type()
119 res1, err := Instantiate(ctxt, T1, test.targs1, false)
120 if err != nil {
121 t.Fatal(err)
122 }
123
124 T2 := pkg.Scope().Lookup(test.name2).Type()
125 res2, err := Instantiate(ctxt, T2, test.targs2, false)
126 if err != nil {
127 t.Fatal(err)
128 }
129
130 if gotEqual := res1 == res2; gotEqual != test.wantEqual {
131 t.Errorf("%s == %s: %t, want %t", res1, res2, gotEqual, test.wantEqual)
132 }
133 })
134 }
135 }
136
137 func TestInstantiateNonEquality(t *testing.T) {
138 const src = "package p; type T[P any] int"
139 pkg1 := mustTypecheck(src, nil, nil)
140 pkg2 := mustTypecheck(src, nil, nil)
141
142
143 T1 := pkg1.Scope().Lookup("T").Type().(*Named)
144 T2 := pkg2.Scope().Lookup("T").Type().(*Named)
145 ctxt := NewContext()
146 res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
147 if err != nil {
148 t.Fatal(err)
149 }
150 res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
151 if err != nil {
152 t.Fatal(err)
153 }
154 if res1 == res2 {
155 t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
156 }
157 if Identical(res1, res2) {
158 t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
159 }
160 }
161
162 func TestMethodInstantiation(t *testing.T) {
163 const prefix = `package p
164
165 type T[P any] struct{}
166
167 var X T[int]
168
169 `
170 tests := []struct {
171 decl string
172 want string
173 }{
174 {"func (r T[P]) m() P", "func (T[int]).m() int"},
175 {"func (r T[P]) m(P)", "func (T[int]).m(int)"},
176 {"func (r *T[P]) m(P)", "func (*T[int]).m(int)"},
177 {"func (r T[P]) m() T[P]", "func (T[int]).m() T[int]"},
178 {"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
179 {"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
180 {"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
181 }
182
183 for _, test := range tests {
184 src := prefix + test.decl
185 pkg := mustTypecheck(src, nil, nil)
186 typ := NewPointer(pkg.Scope().Lookup("X").Type())
187 sel, ok := LookupSelection(typ, false, pkg, "m")
188 if !ok {
189 t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
190 }
191 if got := ObjectString(sel.Obj(), RelativeTo(pkg)); got != test.want {
192 t.Errorf("instantiated %q, want %q", got, test.want)
193 }
194 }
195 }
196
197 func TestImmutableSignatures(t *testing.T) {
198 const src = `package p
199
200 type T[P any] struct{}
201
202 func (T[P]) m() {}
203
204 var _ T[int]
205 `
206 pkg := mustTypecheck(src, nil, nil)
207 typ := pkg.Scope().Lookup("T").Type().(*Named)
208 sel, ok := LookupSelection(typ, false, pkg, "m")
209 if !ok {
210 t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
211 }
212
213
214
215 want := "func (T[P]).m()"
216 if got := stripAnnotations(ObjectString(sel.Obj(), RelativeTo(pkg))); got != want {
217 t.Errorf("instantiated %q, want %q", got, want)
218 }
219 }
220
221
222 func stripAnnotations(s string) string {
223 var buf strings.Builder
224 for _, r := range s {
225
226 if r < '₀' || '₀'+10 <= r {
227 buf.WriteRune(r)
228 }
229 }
230 if buf.Len() < len(s) {
231 return buf.String()
232 }
233 return s
234 }
235
View as plain text