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 obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
188 m, _ := obj.(*Func)
189 if m == nil {
190 t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
191 }
192 if got := ObjectString(m, RelativeTo(pkg)); got != test.want {
193 t.Errorf("instantiated %q, want %q", got, test.want)
194 }
195 }
196 }
197
198 func TestImmutableSignatures(t *testing.T) {
199 const src = `package p
200
201 type T[P any] struct{}
202
203 func (T[P]) m() {}
204
205 var _ T[int]
206 `
207 pkg := mustTypecheck(src, nil, nil)
208 typ := pkg.Scope().Lookup("T").Type().(*Named)
209 obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
210 if obj == nil {
211 t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
212 }
213
214
215
216 want := "func (T[P]).m()"
217 if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
218 t.Errorf("instantiated %q, want %q", got, want)
219 }
220 }
221
222
223 func stripAnnotations(s string) string {
224 var buf strings.Builder
225 for _, r := range s {
226
227 if r < '₀' || '₀'+10 <= r {
228 buf.WriteRune(r)
229 }
230 }
231 if buf.Len() < len(s) {
232 return buf.String()
233 }
234 return s
235 }
236
View as plain text