Skip to content

Commit 40370f8

Browse files
committed
go/internal/gcimporter: add a test case for issue 51219
Based on CL 387814, construct a reproducer for issue 51219 using x/tools/go/internal/gcimporter. Confirmed that this fails without the fix in CL 392475. Additionally, this CL includes some minor cleanup: - no need to take two passes in testExportSrc, as IExportVersionGenerics and IExportVersionGo1_18 are the same - remove skips that are no longer needed. Fixes golang/go#51219 Change-Id: Ia76fe9038aab7a2b9efc8429dc211b03adbb5560 Reviewed-on: https://go-review.googlesource.com/c/tools/+/392734 Trust: Robert Findley <[email protected]> Run-TryBot: Robert Findley <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 24806f2 commit 40370f8

File tree

1 file changed

+140
-38
lines changed

1 file changed

+140
-38
lines changed

go/internal/gcimporter/iexport_go118_test.go

Lines changed: 140 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package gcimporter_test
99

1010
import (
1111
"bytes"
12+
"fmt"
1213
"go/ast"
1314
"go/importer"
1415
"go/parser"
@@ -71,39 +72,27 @@ func testExportSrc(t *testing.T, src []byte) {
7172
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
7273
}
7374

74-
// Test at both stages of the 1.18 export data format change.
75-
tests := []struct {
76-
name string
77-
version int
78-
}{
79-
{"legacy generics", gcimporter.IExportVersionGenerics},
80-
{"go1.18", gcimporter.IExportVersionGo1_18},
75+
fset := token.NewFileSet()
76+
f, err := parser.ParseFile(fset, "g.go", src, 0)
77+
if err != nil {
78+
t.Fatal(err)
79+
}
80+
conf := types.Config{
81+
Importer: importer.Default(),
82+
}
83+
pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
84+
if err != nil {
85+
t.Fatal(err)
8186
}
8287

83-
for _, test := range tests {
84-
t.Run(test.name, func(t *testing.T) {
85-
fset := token.NewFileSet()
86-
f, err := parser.ParseFile(fset, "g.go", src, 0)
87-
if err != nil {
88-
t.Fatal(err)
89-
}
90-
conf := types.Config{
91-
Importer: importer.Default(),
92-
}
93-
pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
94-
if err != nil {
95-
t.Fatal(err)
96-
}
97-
98-
// export
99-
data, err := iexport(fset, test.version, pkg)
100-
if err != nil {
101-
t.Fatal(err)
102-
}
103-
104-
testPkgData(t, fset, test.version, pkg, data)
105-
})
88+
// export
89+
version := gcimporter.IExportVersion
90+
data, err := iexport(fset, version, pkg)
91+
if err != nil {
92+
t.Fatal(err)
10693
}
94+
95+
testPkgData(t, fset, version, pkg, data)
10796
}
10897

10998
func TestImportTypeparamTests(t *testing.T) {
@@ -118,21 +107,13 @@ func TestImportTypeparamTests(t *testing.T) {
118107
t.Skip("unified export data format is currently unsupported")
119108
}
120109

121-
skip := map[string]string{
122-
"issue48424.go": "go/types support missing", // TODO: need to implement this if #48424 is accepted
123-
}
124-
125110
for _, entry := range list {
126111
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
127112
// For now, only consider standalone go files.
128113
continue
129114
}
130115

131116
t.Run(entry.Name(), func(t *testing.T) {
132-
if reason, ok := skip[entry.Name()]; ok {
133-
t.Skip(reason)
134-
}
135-
136117
filename := filepath.Join(rootDir, entry.Name())
137118
src, err := os.ReadFile(filename)
138119
if err != nil {
@@ -150,3 +131,124 @@ func TestImportTypeparamTests(t *testing.T) {
150131
})
151132
}
152133
}
134+
135+
func TestRecursiveExport_Issue51219(t *testing.T) {
136+
const srca = `
137+
package a
138+
139+
type Interaction[DataT InteractionDataConstraint] struct {
140+
}
141+
142+
type InteractionDataConstraint interface {
143+
[]byte |
144+
UserCommandInteractionData
145+
}
146+
147+
type UserCommandInteractionData struct {
148+
resolvedInteractionWithOptions
149+
}
150+
151+
type resolvedInteractionWithOptions struct {
152+
Resolved Resolved
153+
}
154+
155+
type Resolved struct {
156+
Users ResolvedData[User]
157+
}
158+
159+
type ResolvedData[T ResolvedDataConstraint] map[uint64]T
160+
161+
type ResolvedDataConstraint interface {
162+
User | Message
163+
}
164+
165+
type User struct{}
166+
167+
type Message struct {
168+
Interaction *Interaction[[]byte]
169+
}
170+
`
171+
172+
const srcb = `
173+
package b
174+
175+
import (
176+
"a"
177+
)
178+
179+
// InteractionRequest is an incoming request Interaction
180+
type InteractionRequest[T a.InteractionDataConstraint] struct {
181+
a.Interaction[T]
182+
}
183+
`
184+
185+
const srcp = `
186+
package p
187+
188+
import (
189+
"b"
190+
)
191+
192+
// ResponseWriterMock mocks corde's ResponseWriter interface
193+
type ResponseWriterMock struct {
194+
x b.InteractionRequest[[]byte]
195+
}
196+
`
197+
198+
importer := &testImporter{
199+
src: map[string][]byte{
200+
"a": []byte(srca),
201+
"b": []byte(srcb),
202+
"p": []byte(srcp),
203+
},
204+
pkgs: make(map[string]*types.Package),
205+
}
206+
_, err := importer.Import("p")
207+
if err != nil {
208+
t.Fatal(err)
209+
}
210+
}
211+
212+
// testImporter is a helper to test chains of imports using export data.
213+
type testImporter struct {
214+
src map[string][]byte // original source
215+
pkgs map[string]*types.Package // memoized imported packages
216+
}
217+
218+
func (t *testImporter) Import(path string) (*types.Package, error) {
219+
if pkg, ok := t.pkgs[path]; ok {
220+
return pkg, nil
221+
}
222+
src, ok := t.src[path]
223+
if !ok {
224+
return nil, fmt.Errorf("unknown path %v", path)
225+
}
226+
227+
// Type-check, but don't return this package directly.
228+
fset := token.NewFileSet()
229+
f, err := parser.ParseFile(fset, path+".go", src, 0)
230+
if err != nil {
231+
return nil, err
232+
}
233+
conf := types.Config{
234+
Importer: t,
235+
}
236+
pkg, err := conf.Check(path, fset, []*ast.File{f}, nil)
237+
if err != nil {
238+
return nil, err
239+
}
240+
241+
// Export and import to get the package imported from export data.
242+
exportdata, err := iexport(fset, gcimporter.IExportVersion, pkg)
243+
if err != nil {
244+
return nil, err
245+
}
246+
imports := make(map[string]*types.Package)
247+
fset2 := token.NewFileSet()
248+
_, pkg2, err := gcimporter.IImportData(fset2, imports, exportdata, pkg.Path())
249+
if err != nil {
250+
return nil, err
251+
}
252+
t.pkgs[path] = pkg2
253+
return pkg2, nil
254+
}

0 commit comments

Comments
 (0)