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 := mustTypecheck(test.src, nil, nil)
111
112 t.Run(pkg.Name(), func(t *testing.T) {
113 ctxt := NewContext()
114
115 T1 := pkg.Scope().Lookup(test.name1).Type()
116 res1, err := Instantiate(ctxt, T1, test.targs1, false)
117 if err != nil {
118 t.Fatal(err)
119 }
120
121 T2 := pkg.Scope().Lookup(test.name2).Type()
122 res2, err := Instantiate(ctxt, T2, test.targs2, false)
123 if err != nil {
124 t.Fatal(err)
125 }
126
127 if gotEqual := res1 == res2; gotEqual != test.wantEqual {
128 t.Errorf("%s == %s: %t, want %t", res1, res2, gotEqual, test.wantEqual)
129 }
130 })
131 }
132 }
133
134 func TestInstantiateNonEquality(t *testing.T) {
135 const src = "package p; type T[P any] int"
136 pkg1 := mustTypecheck(src, nil, nil)
137 pkg2 := mustTypecheck(src, nil, nil)
138
139
140 T1 := pkg1.Scope().Lookup("T").Type().(*Named)
141 T2 := pkg2.Scope().Lookup("T").Type().(*Named)
142 ctxt := NewContext()
143 res1, err := Instantiate(ctxt, T1, []Type{Typ[Int]}, false)
144 if err != nil {
145 t.Fatal(err)
146 }
147 res2, err := Instantiate(ctxt, T2, []Type{Typ[Int]}, false)
148 if err != nil {
149 t.Fatal(err)
150 }
151 if res1 == res2 {
152 t.Errorf("instance from pkg1 (%s) is pointer-equivalent to instance from pkg2 (%s)", res1, res2)
153 }
154 if Identical(res1, res2) {
155 t.Errorf("instance from pkg1 (%s) is identical to instance from pkg2 (%s)", res1, res2)
156 }
157 }
158
159 func TestMethodInstantiation(t *testing.T) {
160 const prefix = `package p
161
162 type T[P any] struct{}
163
164 var X T[int]
165
166 `
167 tests := []struct {
168 decl string
169 want string
170 }{
171 {"func (r T[P]) m() P", "func (T[int]).m() int"},
172 {"func (r T[P]) m(P)", "func (T[int]).m(int)"},
173 {"func (r *T[P]) m(P)", "func (*T[int]).m(int)"},
174 {"func (r T[P]) m() T[P]", "func (T[int]).m() T[int]"},
175 {"func (r T[P]) m(T[P])", "func (T[int]).m(T[int])"},
176 {"func (r T[P]) m(T[P], P, string)", "func (T[int]).m(T[int], int, string)"},
177 {"func (r T[P]) m(T[P], T[string], T[int])", "func (T[int]).m(T[int], T[string], T[int])"},
178 }
179
180 for _, test := range tests {
181 src := prefix + test.decl
182 pkg := mustTypecheck(src, nil, nil)
183 typ := NewPointer(pkg.Scope().Lookup("X").Type())
184 obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
185 m, _ := obj.(*Func)
186 if m == nil {
187 t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
188 }
189 if got := ObjectString(m, RelativeTo(pkg)); got != test.want {
190 t.Errorf("instantiated %q, want %q", got, test.want)
191 }
192 }
193 }
194
195 func TestImmutableSignatures(t *testing.T) {
196 const src = `package p
197
198 type T[P any] struct{}
199
200 func (T[P]) m() {}
201
202 var _ T[int]
203 `
204 pkg := mustTypecheck(src, nil, nil)
205 typ := pkg.Scope().Lookup("T").Type().(*Named)
206 obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
207 if obj == nil {
208 t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
209 }
210
211
212
213 want := "func (T[P]).m()"
214 if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
215 t.Errorf("instantiated %q, want %q", got, want)
216 }
217 }
218
219
220 func stripAnnotations(s string) string {
221 var buf strings.Builder
222 for _, r := range s {
223
224 if r < '₀' || '₀'+10 <= r {
225 buf.WriteRune(r)
226 }
227 }
228 if buf.Len() < len(s) {
229 return buf.String()
230 }
231 return s
232 }
233
View as plain text