github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/internal/gcimporter/iexport_go118_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.18 6 // +build go1.18 7 8 package gcimporter_test 9 10 import ( 11 "bytes" 12 "fmt" 13 "go/ast" 14 "go/importer" 15 "go/parser" 16 "go/token" 17 "go/types" 18 "os" 19 "path/filepath" 20 "runtime" 21 "strings" 22 "testing" 23 24 "github.com/powerman/golang-tools/go/internal/gcimporter" 25 ) 26 27 // TODO(rfindley): migrate this to testdata, as has been done in the standard library. 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 // This package only handles gc export data. 71 if runtime.Compiler != "gc" { 72 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) 73 } 74 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) 86 } 87 88 // export 89 version := gcimporter.IExportVersion 90 data, err := iexport(fset, version, pkg) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 testPkgData(t, fset, version, pkg, data) 96 } 97 98 func TestImportTypeparamTests(t *testing.T) { 99 // Check go files in test/typeparam. 100 rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam") 101 list, err := os.ReadDir(rootDir) 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 if isUnifiedBuilder() { 107 t.Skip("unified export data format is currently unsupported") 108 } 109 110 for _, entry := range list { 111 if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") { 112 // For now, only consider standalone go files. 113 continue 114 } 115 116 t.Run(entry.Name(), func(t *testing.T) { 117 filename := filepath.Join(rootDir, entry.Name()) 118 src, err := os.ReadFile(filename) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) { 124 // We're bypassing the logic of run.go here, so be conservative about 125 // the files we consider in an attempt to make this test more robust to 126 // changes in test/typeparams. 127 t.Skipf("not detected as a run test") 128 } 129 130 testExportSrc(t, src) 131 }) 132 } 133 } 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 }