github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 "golang.org/x/tools/internal/gcimporter" 25 "golang.org/x/tools/internal/testenv" 26 ) 27 28 // TODO(rfindley): migrate this to testdata, as has been done in the standard library. 29 func TestGenericExport(t *testing.T) { 30 const src = ` 31 package generic 32 33 type Any any 34 35 type T[A, B any] struct { Left A; Right B } 36 37 func (T[P, Q]) m() {} 38 39 var X T[int, string] = T[int, string]{1, "hi"} 40 41 func ToInt[P interface{ ~int }](p P) int { return int(p) } 42 43 var IntID = ToInt[int] 44 45 type G[C comparable] int 46 47 func ImplicitFunc[T ~int]() {} 48 49 type ImplicitType[T ~int] int 50 51 // Exercise constant import/export 52 const C1 = 42 53 const C2 int = 42 54 const C3 float64 = 42 55 56 type Constraint[T any] interface { 57 m(T) 58 } 59 60 // TODO(rfindley): revert to multiple blanks once the restriction on multiple 61 // blanks is removed from the type checker. 62 // type Blanks[_ any, _ Constraint[int]] int 63 // func (Blanks[_, _]) m() {} 64 type Blanks[_ any] int 65 func (Blanks[_]) m() {} 66 ` 67 testExportSrc(t, []byte(src)) 68 } 69 70 func testExportSrc(t *testing.T, src []byte) { 71 // This package only handles gc export data. 72 if runtime.Compiler != "gc" { 73 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) 74 } 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 // export 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) // to find stdlib export data in the build cache 101 102 // Check go files in test/typeparam. 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 // For now, only consider standalone go files. 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 // We're bypassing the logic of run.go here, so be conservative about 128 // the files we consider in an attempt to make this test more robust to 129 // changes in test/typeparams. 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 // testImporter is a helper to test chains of imports using export data. 216 type testImporter struct { 217 src map[string][]byte // original source 218 pkgs map[string]*types.Package // memoized imported packages 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 // Type-check, but don't return this package directly. 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 // Export and import to get the package imported from export data. 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 }