...

Source file src/golang.org/x/tools/internal/gcimporter/iexport_go118_test.go

Documentation: golang.org/x/tools/internal/gcimporter

     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  package gcimporter_test
     6  
     7  // This file defines test of generics features introduce in go1.18.
     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  // 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  	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  	// 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  }
   258  

View as plain text