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  }