1
2
3
4
5 package gcimporter_test
6
7
8
9 import (
10 "bytes"
11 "fmt"
12 "go/ast"
13 "go/importer"
14 "go/parser"
15 "go/token"
16 "go/types"
17 "os"
18 "path/filepath"
19 "runtime"
20 "strings"
21 "testing"
22
23 "golang.org/x/tools/internal/gcimporter"
24 "golang.org/x/tools/internal/testenv"
25 )
26
27
28 func TestGenericExport(t *testing.T) {
29 const src = `
30 package generic
31
32 type Any any
33
34 type T[A, B any] struct { Left A; Right B }
35
36 func (T[P, Q]) m() {}
37
38 var X T[int, string] = T[int, string]{1, "hi"}
39
40 func ToInt[P interface{ ~int }](p P) int { return int(p) }
41
42 var IntID = ToInt[int]
43
44 type G[C comparable] int
45
46 func ImplicitFunc[T ~int]() {}
47
48 type ImplicitType[T ~int] int
49
50 // Exercise constant import/export
51 const C1 = 42
52 const C2 int = 42
53 const C3 float64 = 42
54
55 type Constraint[T any] interface {
56 m(T)
57 }
58
59 // TODO(rfindley): revert to multiple blanks once the restriction on multiple
60 // blanks is removed from the type checker.
61 // type Blanks[_ any, _ Constraint[int]] int
62 // func (Blanks[_, _]) m() {}
63 type Blanks[_ any] int
64 func (Blanks[_]) m() {}
65 `
66 testExportSrc(t, []byte(src))
67 }
68
69 func testExportSrc(t *testing.T, src []byte) {
70
71 if runtime.Compiler != "gc" {
72 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
73 }
74 testenv.NeedsGoBuild(t)
75
76 fset := token.NewFileSet()
77 f, err := parser.ParseFile(fset, "g.go", src, 0)
78 if err != nil {
79 t.Fatal(err)
80 }
81 conf := types.Config{
82 Importer: importer.Default(),
83 }
84 pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
85 if err != nil {
86 t.Fatal(err)
87 }
88
89
90 version := gcimporter.IExportVersion
91 data, err := iexport(fset, version, pkg)
92 if err != nil {
93 t.Fatal(err)
94 }
95
96 testPkgData(t, fset, version, pkg, data)
97 }
98
99 func TestImportTypeparamTests(t *testing.T) {
100 testenv.NeedsGoBuild(t)
101
102
103 rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam")
104 list, err := os.ReadDir(rootDir)
105 if err != nil {
106 t.Fatal(err)
107 }
108
109 if isUnifiedBuilder() {
110 t.Skip("unified export data format is currently unsupported")
111 }
112
113 for _, entry := range list {
114 if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
115
116 continue
117 }
118
119 t.Run(entry.Name(), func(t *testing.T) {
120 filename := filepath.Join(rootDir, entry.Name())
121 src, err := os.ReadFile(filename)
122 if err != nil {
123 t.Fatal(err)
124 }
125
126 if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
127
128
129
130 t.Skipf("not detected as a run test")
131 }
132
133 testExportSrc(t, src)
134 })
135 }
136 }
137
138 func TestRecursiveExport_Issue51219(t *testing.T) {
139 const srca = `
140 package a
141
142 type Interaction[DataT InteractionDataConstraint] struct {
143 }
144
145 type InteractionDataConstraint interface {
146 []byte |
147 UserCommandInteractionData
148 }
149
150 type UserCommandInteractionData struct {
151 resolvedInteractionWithOptions
152 }
153
154 type resolvedInteractionWithOptions struct {
155 Resolved Resolved
156 }
157
158 type Resolved struct {
159 Users ResolvedData[User]
160 }
161
162 type ResolvedData[T ResolvedDataConstraint] map[uint64]T
163
164 type ResolvedDataConstraint interface {
165 User | Message
166 }
167
168 type User struct{}
169
170 type Message struct {
171 Interaction *Interaction[[]byte]
172 }
173 `
174
175 const srcb = `
176 package b
177
178 import (
179 "a"
180 )
181
182 // InteractionRequest is an incoming request Interaction
183 type InteractionRequest[T a.InteractionDataConstraint] struct {
184 a.Interaction[T]
185 }
186 `
187
188 const srcp = `
189 package p
190
191 import (
192 "b"
193 )
194
195 // ResponseWriterMock mocks corde's ResponseWriter interface
196 type ResponseWriterMock struct {
197 x b.InteractionRequest[[]byte]
198 }
199 `
200
201 importer := &testImporter{
202 src: map[string][]byte{
203 "a": []byte(srca),
204 "b": []byte(srcb),
205 "p": []byte(srcp),
206 },
207 pkgs: make(map[string]*types.Package),
208 }
209 _, err := importer.Import("p")
210 if err != nil {
211 t.Fatal(err)
212 }
213 }
214
215
216 type testImporter struct {
217 src map[string][]byte
218 pkgs map[string]*types.Package
219 }
220
221 func (t *testImporter) Import(path string) (*types.Package, error) {
222 if pkg, ok := t.pkgs[path]; ok {
223 return pkg, nil
224 }
225 src, ok := t.src[path]
226 if !ok {
227 return nil, fmt.Errorf("unknown path %v", path)
228 }
229
230
231 fset := token.NewFileSet()
232 f, err := parser.ParseFile(fset, path+".go", src, 0)
233 if err != nil {
234 return nil, err
235 }
236 conf := types.Config{
237 Importer: t,
238 }
239 pkg, err := conf.Check(path, fset, []*ast.File{f}, nil)
240 if err != nil {
241 return nil, err
242 }
243
244
245 exportdata, err := iexport(fset, gcimporter.IExportVersion, pkg)
246 if err != nil {
247 return nil, err
248 }
249 imports := make(map[string]*types.Package)
250 fset2 := token.NewFileSet()
251 _, pkg2, err := gcimporter.IImportData(fset2, imports, exportdata, pkg.Path())
252 if err != nil {
253 return nil, err
254 }
255 t.pkgs[path] = pkg2
256 return pkg2, nil
257 }
258
View as plain text