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