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