diff --git a/build/build.go b/build/build.go index 2ec712fc7..46786a30b 100644 --- a/build/build.go +++ b/build/build.go @@ -27,12 +27,14 @@ import ( "github.com/fsnotify/fsnotify" "github.com/gopherjs/gopherjs/compiler" "github.com/gopherjs/gopherjs/compiler/astutil" + "github.com/gopherjs/gopherjs/compiler/jsFile" + "github.com/gopherjs/gopherjs/compiler/sources" + "github.com/gopherjs/gopherjs/internal/errorList" + "github.com/gopherjs/gopherjs/internal/testmain" log "github.com/sirupsen/logrus" "github.com/neelance/sourcemap" "golang.org/x/tools/go/buildutil" - - "github.com/gopherjs/gopherjs/build/cache" ) // DefaultGOROOT is the default GOROOT value for builds. @@ -164,7 +166,7 @@ type overrideInfo struct { // - Otherwise for identifiers that exist in the original and the overrides, // the original is removed. // - New identifiers that don't exist in original package get added. -func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *token.FileSet) ([]*ast.File, []JSFile, error) { +func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *token.FileSet) ([]*ast.File, []jsFile.JSFile, error) { jsFiles, overlayFiles := parseOverlayFiles(xctx, pkg, isTest, fileSet) originalFiles, err := parserOriginalFiles(pkg, fileSet) @@ -193,7 +195,7 @@ func parseAndAugment(xctx XContext, pkg *PackageData, isTest bool, fileSet *toke // parseOverlayFiles loads and parses overlay files // to augment the original files with. -func parseOverlayFiles(xctx XContext, pkg *PackageData, isTest bool, fileSet *token.FileSet) ([]JSFile, []*ast.File) { +func parseOverlayFiles(xctx XContext, pkg *PackageData, isTest bool, fileSet *token.FileSet) ([]jsFile.JSFile, []*ast.File) { isXTest := strings.HasSuffix(pkg.ImportPath, "_test") importPath := pkg.ImportPath if isXTest { @@ -239,7 +241,7 @@ func parseOverlayFiles(xctx XContext, pkg *PackageData, isTest bool, fileSet *to // parserOriginalFiles loads and parses the original files to augment. func parserOriginalFiles(pkg *PackageData, fileSet *token.FileSet) ([]*ast.File, error) { var files []*ast.File - var errList compiler.ErrorList + var errList errorList.ErrorList for _, name := range pkg.GoFiles { if !filepath.IsAbs(name) { // name might be absolute if specified directly. E.g., `gopherjs build /abs/file.go`. name = filepath.Join(pkg.Dir, name) @@ -623,18 +625,11 @@ func (o *Options) PrintSuccess(format string, a ...interface{}) { fmt.Fprintf(os.Stderr, format, a...) } -// JSFile represents a *.inc.js file metadata and content. -type JSFile struct { - Path string // Full file path for the build context the file came from. - ModTime time.Time - Content []byte -} - // PackageData is an extension of go/build.Package with additional metadata // GopherJS requires. type PackageData struct { *build.Package - JSFiles []JSFile + JSFiles []jsFile.JSFile // IsTest is true if the package is being built for running tests. IsTest bool SrcModTime time.Time @@ -749,15 +744,28 @@ func (p *PackageData) InstallPath() string { // This is the main interface to GopherJS build system. Session lifetime is // roughly equivalent to a single GopherJS tool invocation. type Session struct { - options *Options - xctx XContext - buildCache cache.BuildCache + options *Options + xctx XContext + + // importPaths is a map of the resolved import paths given the + // source directory (first key) and the unresolved import path (second key). + // This is used to cache the resolved import returned from XContext.Import. + // XContent.Import can be slow, so we cache the resolved path that is used + // as the map key by parsedPackages and UpToDateArchives. + // This makes subsequent lookups faster during compilation when all we have + // is the unresolved import path and source directory. + importPaths map[string]map[string]string + + // sources is a map of parsed packages that have been built and augmented. + // This is keyed using resolved import paths. This is used to avoid + // rebuilding and augmenting packages that are imported by several packages. + // The files in these sources haven't been sorted nor simplified yet. + sources map[string]*sources.Sources // Binary archives produced during the current session and assumed to be // up to date with input sources and dependencies. In the -w ("watch") mode // must be cleared upon entering watching. UpToDateArchives map[string]*compiler.Archive - Types map[string]*types.Package Watcher *fsnotify.Watcher } @@ -767,6 +775,8 @@ func NewSession(options *Options) (*Session, error) { s := &Session{ options: options, + importPaths: make(map[string]map[string]string), + sources: make(map[string]*sources.Sources), UpToDateArchives: make(map[string]*compiler.Archive), } s.xctx = NewBuildContext(s.InstallSuffix(), s.options.BuildTags) @@ -777,16 +787,6 @@ func NewSession(options *Options) (*Session, error) { return nil, err } - s.buildCache = cache.BuildCache{ - GOOS: env.GOOS, - GOARCH: env.GOARCH, - GOROOT: env.GOROOT, - GOPATH: env.GOPATH, - BuildTags: append([]string{}, env.BuildTags...), - Minify: options.Minify, - TestedPackage: options.TestedPackage, - } - s.Types = make(map[string]*types.Package) if options.Watch { if out, err := exec.Command("ulimit", "-n").Output(); err == nil { if n, err := strconv.Atoi(strings.TrimSpace(string(out))); err == nil && n < 1024 { @@ -893,36 +893,107 @@ func (s *Session) BuildFiles(filenames []string, pkgObj string, cwd string) erro if err != nil { return fmt.Errorf("failed to stat %s: %w", file, err) } - pkg.JSFiles = append(pkg.JSFiles, JSFile{ + pkg.JSFiles = append(pkg.JSFiles, jsFile.JSFile{ Path: filepath.Join(pkg.Dir, filepath.Base(file)), ModTime: info.ModTime(), Content: content, }) } - archive, err := s.BuildPackage(pkg) + archive, err := s.BuildProject(pkg) if err != nil { return err } - if s.Types["main"].Name() != "main" { + if s.sources["main"].Package.Name() != "main" { return fmt.Errorf("cannot build/run non-main package") } return s.WriteCommandPackage(archive, pkgObj) } -// BuildImportPath loads and compiles package with the given import path. -// -// Relative paths are interpreted relative to the current working dir. -func (s *Session) BuildImportPath(path string) (*compiler.Archive, error) { - _, archive, err := s.buildImportPathWithSrcDir(path, "") - return archive, err +// BuildProject builds a command project (one with a main method) or +// builds a test project (one with a synthesized test main package). +func (s *Session) BuildProject(pkg *PackageData) (*compiler.Archive, error) { + // ensure that runtime for gopherjs is imported + pkg.Imports = append(pkg.Imports, `runtime`) + + // Load the project to get the sources for the parsed packages. + var rootSrcs *sources.Sources + var err error + if pkg.IsTest { + rootSrcs, err = s.loadTestPackage(pkg) + } else { + rootSrcs, err = s.loadPackages(pkg) + } + if err != nil { + return nil, err + } + + // TODO(grantnelson-wf): We could investigate caching the results of + // the sources prior to preparing them to avoid re-parsing the same + // sources and augmenting them when the files on disk haven't changed. + // This would require a way to determine if the sources are up-to-date + // which could be done with the left over srcModTime from when the archives + // were being cached. + + // Compile the project into Archives containing the generated JS. + return s.prepareAndCompilePackages(rootSrcs) } -// buildImportPathWithSrcDir builds the package specified by the import path. +// getSortedSources returns the sources sorted by import path. +// The files in the sources may still not be sorted yet. +func (s *Session) getSortedSources() []*sources.Sources { + allSources := make([]*sources.Sources, 0, len(s.sources)) + for _, srcs := range s.sources { + allSources = append(allSources, srcs) + } + sources.SortedSourcesSlice(allSources) + return allSources +} + +func (s *Session) loadTestPackage(pkg *PackageData) (*sources.Sources, error) { + _, err := s.loadPackages(pkg.TestPackage()) + if err != nil { + return nil, err + } + _, err = s.loadPackages(pkg.XTestPackage()) + if err != nil { + return nil, err + } + + // Generate a synthetic testmain package. + fset := token.NewFileSet() + tests := testmain.TestMain{Package: pkg.Package, Context: pkg.bctx} + tests.Scan(fset) + mainPkg, mainFile, err := tests.Synthesize(fset) + if err != nil { + return nil, fmt.Errorf("failed to generate testmain package for %s: %w", pkg.ImportPath, err) + } + + // Create the sources for parsed package for the testmain package. + srcs := &sources.Sources{ + ImportPath: mainPkg.ImportPath, + Dir: mainPkg.Dir, + Files: []*ast.File{mainFile}, + FileSet: fset, + } + s.sources[srcs.ImportPath] = srcs + + // Import dependencies for the testmain package. + for _, importedPkgPath := range srcs.UnresolvedImports() { + _, _, err := s.loadImportPathWithSrcDir(importedPkgPath, pkg.Dir) + if err != nil { + return nil, err + } + } + + return srcs, nil +} + +// loadImportPathWithSrcDir gets the parsed package specified by the import path. // -// Relative import paths are interpreted relative to the passed srcDir. If -// srcDir is empty, current working directory is assumed. -func (s *Session) buildImportPathWithSrcDir(path string, srcDir string) (*PackageData, *compiler.Archive, error) { +// Relative import paths are interpreted relative to the passed srcDir. +// If srcDir is empty, current working directory is assumed. +func (s *Session) loadImportPathWithSrcDir(path, srcDir string) (*PackageData, *sources.Sources, error) { pkg, err := s.xctx.Import(path, srcDir, 0) if s.Watcher != nil && pkg != nil { // add watch even on error s.Watcher.Add(pkg.Dir) @@ -931,12 +1002,25 @@ func (s *Session) buildImportPathWithSrcDir(path string, srcDir string) (*Packag return nil, nil, err } - archive, err := s.BuildPackage(pkg) + srcs, err := s.loadPackages(pkg) if err != nil { return nil, nil, err } - return pkg, archive, nil + s.cacheImportPath(path, srcDir, pkg.ImportPath) + return pkg, srcs, nil +} + +// cacheImportPath stores the resolved import path for the build package +// so we can look it up later without getting the whole build package. +// The given path and source directly are the ones passed into +// XContext.Import to the get the build package originally. +func (s *Session) cacheImportPath(path, srcDir, importPath string) { + if paths, ok := s.importPaths[srcDir]; ok { + paths[path] = importPath + } else { + s.importPaths[srcDir] = map[string]string{path: importPath} + } } // getExeModTime will determine the mod time of the GopherJS binary @@ -965,10 +1049,13 @@ var getExeModTime = func() func() time.Time { } }() -// BuildPackage compiles an already loaded package. -func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) { - if archive, ok := s.UpToDateArchives[pkg.ImportPath]; ok { - return archive, nil +// loadPackages will recursively load and parse the given package and +// its dependencies. This will return the sources for the given package. +// The returned source and sources for the dependencies will be added +// to the session's sources map. +func (s *Session) loadPackages(pkg *PackageData) (*sources.Sources, error) { + if srcs, ok := s.sources[pkg.ImportPath]; ok { + return srcs, nil } if exeModTime := getExeModTime(); exeModTime.After(pkg.SrcModTime) { @@ -979,7 +1066,7 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) { if importedPkgPath == "unsafe" { continue } - importedPkg, _, err := s.buildImportPathWithSrcDir(importedPkgPath, pkg.Dir) + importedPkg, _, err := s.loadImportPathWithSrcDir(importedPkgPath, pkg.Dir) if err != nil { return nil, err } @@ -993,16 +1080,7 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) { pkg.SrcModTime = fileModTime } - if !s.options.NoCache { - archive := s.buildCache.LoadArchive(pkg.ImportPath, pkg.SrcModTime, s.Types) - if archive != nil { - s.UpToDateArchives[pkg.ImportPath] = archive - // Existing archive is up to date, no need to build it from scratch. - return archive, nil - } - } - - // Existing archive is out of date or doesn't exist, let's build the package. + // Build the package by parsing and augmenting the original files with overlay files. fileSet := token.NewFileSet() files, overlayJsFiles, err := parseAndAugment(s.xctx, pkg, pkg.IsTest, fileSet) if err != nil { @@ -1016,40 +1094,125 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) { files = append(files, embed) } - importContext := &compiler.ImportContext{ - Packages: s.Types, - Import: s.ImportResolverFor(pkg), + srcs := &sources.Sources{ + ImportPath: pkg.ImportPath, + Dir: pkg.Dir, + Files: files, + FileSet: fileSet, + JSFiles: append(pkg.JSFiles, overlayJsFiles...), } - archive, err := compiler.Compile(pkg.ImportPath, files, fileSet, importContext, s.options.Minify) + s.sources[pkg.ImportPath] = srcs + + // Import dependencies from the augmented files, + // whilst skipping any that have been already imported. + for _, importedPkgPath := range srcs.UnresolvedImports(pkg.Imports...) { + _, _, err := s.loadImportPathWithSrcDir(importedPkgPath, pkg.Dir) + if err != nil { + return nil, err + } + } + + return srcs, nil +} + +func (s *Session) prepareAndCompilePackages(rootSrcs *sources.Sources) (*compiler.Archive, error) { + tContext := types.NewContext() + allSources := s.getSortedSources() + + // Prepare and analyze the source code. + // This will be performed recursively for all dependencies. + if err := compiler.PrepareAllSources(allSources, s.SourcesForImport, tContext); err != nil { + return nil, err + } + + // Compile all the sources into archives. + for _, srcs := range allSources { + if _, err := s.compilePackage(srcs, tContext); err != nil { + return nil, err + } + } + + rootArchive, ok := s.UpToDateArchives[rootSrcs.ImportPath] + if !ok { + // This is confirmation that the root package is in the sources map and got compiled. + return nil, fmt.Errorf(`root package %q was not found in archives`, rootSrcs.ImportPath) + } + return rootArchive, nil +} + +func (s *Session) compilePackage(srcs *sources.Sources, tContext *types.Context) (*compiler.Archive, error) { + if archive, ok := s.UpToDateArchives[srcs.ImportPath]; ok { + return archive, nil + } + + archive, err := compiler.Compile(srcs, tContext, s.options.Minify) if err != nil { return nil, err } - for _, jsFile := range append(pkg.JSFiles, overlayJsFiles...) { + for _, jsFile := range srcs.JSFiles { archive.IncJSCode = append(archive.IncJSCode, []byte("\t(function() {\n")...) archive.IncJSCode = append(archive.IncJSCode, jsFile.Content...) archive.IncJSCode = append(archive.IncJSCode, []byte("\n\t}).call($global);\n")...) } if s.options.Verbose { - fmt.Println(pkg.ImportPath) + fmt.Println(srcs.ImportPath) } - s.buildCache.StoreArchive(archive, time.Now()) - s.UpToDateArchives[pkg.ImportPath] = archive + s.UpToDateArchives[srcs.ImportPath] = archive return archive, nil } +func (s *Session) getImportPath(path, srcDir string) (string, error) { + // If path is for an xtest package, just return it. + if strings.HasSuffix(path, "_test") { + return path, nil + } + + // Check if the import path is already cached. + if importPath, ok := s.importPaths[srcDir][path]; ok { + return importPath, nil + } + + // Fall back to the slow import of the build package. + pkg, err := s.xctx.Import(path, srcDir, 0) + if err != nil { + return ``, err + } + s.cacheImportPath(path, srcDir, pkg.ImportPath) + return pkg.ImportPath, nil +} + +func (s *Session) SourcesForImport(path, srcDir string) (*sources.Sources, error) { + importPath, err := s.getImportPath(path, srcDir) + if err != nil { + return nil, err + } + + srcs, ok := s.sources[importPath] + if !ok { + return nil, fmt.Errorf(`sources for %q not found`, path) + } + + return srcs, nil +} + // ImportResolverFor returns a function which returns a compiled package archive // given an import path. -func (s *Session) ImportResolverFor(pkg *PackageData) func(string) (*compiler.Archive, error) { +func (s *Session) ImportResolverFor(srcDir string) func(string) (*compiler.Archive, error) { return func(path string) (*compiler.Archive, error) { - if archive, ok := s.UpToDateArchives[path]; ok { + importPath, err := s.getImportPath(path, srcDir) + if err != nil { + return nil, err + } + + if archive, ok := s.UpToDateArchives[importPath]; ok { return archive, nil } - _, archive, err := s.buildImportPathWithSrcDir(path, pkg.Dir) - return archive, err + + return nil, fmt.Errorf(`archive for %q not found`, importPath) } } @@ -1087,13 +1250,7 @@ func (s *Session) WriteCommandPackage(archive *compiler.Archive, pkgObj string) sourceMapFilter.MappingCallback = s.SourceMappingCallback(m) } - deps, err := compiler.ImportDependencies(archive, func(path string) (*compiler.Archive, error) { - if archive, ok := s.UpToDateArchives[path]; ok { - return archive, nil - } - _, archive, err := s.buildImportPathWithSrcDir(path, "") - return archive, err - }) + deps, err := compiler.ImportDependencies(archive, s.ImportResolverFor("")) if err != nil { return err } @@ -1143,8 +1300,9 @@ func hasGopathPrefix(file, gopath string) (hasGopathPrefix bool, prefixLen int) func (s *Session) WaitForChange() { // Will need to re-validate up-to-dateness of all archives, so flush them from // memory. + s.importPaths = map[string]map[string]string{} + s.sources = map[string]*sources.Sources{} s.UpToDateArchives = map[string]*compiler.Archive{} - s.Types = map[string]*types.Package{} s.options.PrintSuccess("watching for changes...\n") for { diff --git a/build/context.go b/build/context.go index 316bfb2bb..657300839 100644 --- a/build/context.go +++ b/build/context.go @@ -4,7 +4,6 @@ import ( "fmt" "go/build" "go/token" - "io" "net/http" "os" "os/exec" @@ -16,6 +15,7 @@ import ( _ "github.com/gopherjs/gopherjs/build/versionhack" // go/build release tags hack. "github.com/gopherjs/gopherjs/compiler" "github.com/gopherjs/gopherjs/compiler/gopherjspkg" + "github.com/gopherjs/gopherjs/compiler/jsFile" "github.com/gopherjs/gopherjs/compiler/natives" "golang.org/x/tools/go/buildutil" ) @@ -91,7 +91,7 @@ func (sc simpleCtx) Import(importPath string, srcDir string, mode build.ImportMo if err != nil { return nil, err } - jsFiles, err := jsFilesFromDir(&sc.bctx, pkg.Dir) + jsFiles, err := jsFile.JSFilesFromDir(&sc.bctx, pkg.Dir) if err != nil { return nil, fmt.Errorf("failed to enumerate .inc.js files in %s: %w", pkg.Dir, err) } @@ -440,40 +440,3 @@ func updateImports(sources []string, importPos map[string][]token.Position) (new sort.Strings(newImports) return newImports, newImportPos } - -// jsFilesFromDir finds and loads any *.inc.js packages in the build context -// directory. -func jsFilesFromDir(bctx *build.Context, dir string) ([]JSFile, error) { - files, err := buildutil.ReadDir(bctx, dir) - if err != nil { - return nil, err - } - var jsFiles []JSFile - for _, file := range files { - if !strings.HasSuffix(file.Name(), ".inc.js") || file.IsDir() { - continue - } - if file.Name()[0] == '_' || file.Name()[0] == '.' { - continue // Skip "hidden" files that are typically ignored by the Go build system. - } - - path := buildutil.JoinPath(bctx, dir, file.Name()) - f, err := buildutil.OpenFile(bctx, path) - if err != nil { - return nil, fmt.Errorf("failed to open %s from %v: %w", path, bctx, err) - } - defer f.Close() - - content, err := io.ReadAll(f) - if err != nil { - return nil, fmt.Errorf("failed to read %s from %v: %w", path, bctx, err) - } - - jsFiles = append(jsFiles, JSFile{ - Path: path, - ModTime: file.ModTime(), - Content: content, - }) - } - return jsFiles, nil -} diff --git a/build/embed.go b/build/embed.go index c749eeb50..a68fb9494 100644 --- a/build/embed.go +++ b/build/embed.go @@ -8,7 +8,7 @@ import ( "go/token" "strconv" - "github.com/visualfc/goembed" + "github.com/msvitok77/goembed" ) func buildIdent(name string) string { diff --git a/compiler/compiler.go b/compiler/compiler.go index 96ec390d8..e8264c946 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -18,6 +18,7 @@ import ( "time" "github.com/gopherjs/gopherjs/compiler/internal/dce" + "github.com/gopherjs/gopherjs/compiler/linkname" "github.com/gopherjs/gopherjs/compiler/prelude" "golang.org/x/tools/go/gcexportdata" ) @@ -59,7 +60,7 @@ type Archive struct { // Whether or not the package was compiled with minification enabled. Minified bool // A list of go:linkname directives encountered in the package. - GoLinknames []GoLinkname + GoLinknames []linkname.GoLinkname } func (a Archive) String() string { @@ -112,7 +113,7 @@ func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter, goVersion string) err minify := mainPkg.Minified // Aggregate all go:linkname directives in the program together. - gls := goLinknameSet{} + gls := linkname.GoLinknameSet{} for _, pkg := range pkgs { gls.Add(pkg.GoLinknames) } @@ -164,7 +165,7 @@ func WriteProgramCode(pkgs []*Archive, w *SourceMapFilter, goVersion string) err return nil } -func WritePkgCode(pkg *Archive, dceSelection map[*Decl]struct{}, gls goLinknameSet, minify bool, w *SourceMapFilter) error { +func WritePkgCode(pkg *Archive, dceSelection map[*Decl]struct{}, gls linkname.GoLinknameSet, minify bool, w *SourceMapFilter) error { if w.MappingCallback != nil && pkg.FileSet != nil { w.fileSet = pkg.FileSet } @@ -264,7 +265,7 @@ type serializableArchive struct { IncJSCode []byte FileSet []byte Minified bool - GoLinknames []GoLinkname + GoLinknames []linkname.GoLinkname BuildTime time.Time } diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index fe75880b1..88d8e525e 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -5,6 +5,7 @@ import ( "go/types" "regexp" "sort" + "strings" "testing" "time" @@ -12,6 +13,8 @@ import ( "golang.org/x/tools/go/packages" "github.com/gopherjs/gopherjs/compiler/internal/dce" + "github.com/gopherjs/gopherjs/compiler/linkname" + "github.com/gopherjs/gopherjs/compiler/sources" "github.com/gopherjs/gopherjs/internal/srctesting" ) @@ -611,6 +614,115 @@ func TestDeclNaming_VarsAndTypes(t *testing.T) { ) } +func Test_CrossPackageAnalysis(t *testing.T) { + src1 := ` + package main + import "github.com/gopherjs/gopherjs/compiler/stable" + + func main() { + m := map[string]int{ + "one": 1, + "two": 2, + "three": 3, + } + stable.Print(m) + }` + src2 := ` + package collections + import "github.com/gopherjs/gopherjs/compiler/cmp" + + func Keys[K cmp.Ordered, V any, M ~map[K]V](m M) []K { + keys := make([]K, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys + }` + src3 := ` + package collections + import "github.com/gopherjs/gopherjs/compiler/cmp" + + func Values[K cmp.Ordered, V any, M ~map[K]V](m M) []V { + values := make([]V, 0, len(m)) + for _, v := range m { + values = append(values, v) + } + return values + }` + src4 := ` + package sorts + import "github.com/gopherjs/gopherjs/compiler/cmp" + + func Pair[K cmp.Ordered, V any, SK ~[]K, SV ~[]V](k SK, v SV) { + Bubble(len(k), + func(i, j int) bool { return k[i] < k[j] }, + func(i, j int) { k[i], v[i], k[j], v[j] = k[j], v[j], k[i], v[i] }) + } + + func Bubble(length int, less func(i, j int) bool, swap func(i, j int)) { + for i := 0; i < length; i++ { + for j := i + 1; j < length; j++ { + if less(j, i) { + swap(i, j) + } + } + } + }` + src5 := ` + package stable + import ( + "github.com/gopherjs/gopherjs/compiler/collections" + "github.com/gopherjs/gopherjs/compiler/sorts" + "github.com/gopherjs/gopherjs/compiler/cmp" + ) + + func Print[K cmp.Ordered, V any, M ~map[K]V](m M) { + keys := collections.Keys(m) + values := collections.Values(m) + sorts.Pair(keys, values) + for i, k := range keys { + println(i, k, values[i]) + } + }` + src6 := ` + package cmp + type Ordered interface { ~int | ~uint | ~float64 | ~string }` + + root := srctesting.ParseSources(t, + []srctesting.Source{ + {Name: `main.go`, Contents: []byte(src1)}, + }, + []srctesting.Source{ + {Name: `collections/keys.go`, Contents: []byte(src2)}, + {Name: `collections/values.go`, Contents: []byte(src3)}, + {Name: `sorts/sorts.go`, Contents: []byte(src4)}, + {Name: `stable/print.go`, Contents: []byte(src5)}, + {Name: `cmp/ordered.go`, Contents: []byte(src6)}, + }) + + archives := compileProject(t, root, false) + checkForDeclFullNames(t, archives, + // collections + `funcVar:github.com/gopherjs/gopherjs/compiler/collections.Values`, + `func:github.com/gopherjs/gopherjs/compiler/collections.Values`, + `funcVar:github.com/gopherjs/gopherjs/compiler/collections.Keys`, + `func:github.com/gopherjs/gopherjs/compiler/collections.Keys`, + + // sorts + `funcVar:github.com/gopherjs/gopherjs/compiler/sorts.Pair`, + `func:github.com/gopherjs/gopherjs/compiler/sorts.Pair`, + `funcVar:github.com/gopherjs/gopherjs/compiler/sorts.Bubble`, + `func:github.com/gopherjs/gopherjs/compiler/sorts.Bubble`, + + // stable + `funcVar:github.com/gopherjs/gopherjs/compiler/stable.Print`, + `func:github.com/gopherjs/gopherjs/compiler/stable.Print`, + + // main + `init:main`, + ) +} + func TestArchiveSelectionAfterSerialization(t *testing.T) { src := ` package main @@ -638,6 +750,143 @@ func TestArchiveSelectionAfterSerialization(t *testing.T) { } } +func TestNestedConcreteTypeInGenericFunc(t *testing.T) { + // This is a test of a type defined inside a generic function + // that uses the type parameter of the function as a field type. + // The `T` type is unique for each instance of `F`. + // The use of `A` as a field is do demonstrate the difference in the types + // however even if T had no fields, the type would still be different. + // + // Change `print(F[?]())` to `fmt.Printf("%T\n", F[?]())` for + // golang playground to print the type of T in the different F instances. + // (I just didn't want this test to depend on `fmt` when it doesn't need to.) + + src := ` + package main + func F[A any]() any { + type T struct{ + a A + } + return T{} + } + func main() { + type Int int + print(F[int]()) + print(F[Int]()) + } + ` + + srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}} + root := srctesting.ParseSources(t, srcFiles, nil) + archives := compileProject(t, root, false) + mainPkg := archives[root.PkgPath] + insts := collectDeclInstances(t, mainPkg) + + exp := []string{ + `F[int]`, + `F[main.Int]`, // Go prints `F[main.Int·2]` + `T[int;]`, // `T` from `F[int]` (Go prints `T[int]`) + `T[main.Int;]`, // `T` from `F[main.Int]` (Go prints `T[main.Int·2]`) + } + if diff := cmp.Diff(exp, insts); len(diff) > 0 { + t.Errorf("the instances of generics are different:\n%s", diff) + } +} + +func TestNestedGenericTypeInGenericFunc(t *testing.T) { + // This is a subset of the type param nested test from the go repo. + // See https://github.com/golang/go/blob/go1.19.13/test/typeparam/nested.go + // The test is failing because nested types aren't being typed differently. + // For example the type of `T[int]` below is different based on `F[X]` + // instance for different `X` type parameters, hence Go prints the type as + // `T[X;int]` instead of `T[int]`. + + src := ` + package main + func F[A any]() any { + type T[B any] struct{ + a A + b B + } + return T[int]{} + } + func main() { + type Int int + print(F[int]()) + print(F[Int]()) + } + ` + + srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}} + root := srctesting.ParseSources(t, srcFiles, nil) + archives := compileProject(t, root, false) + mainPkg := archives[root.PkgPath] + insts := collectDeclInstances(t, mainPkg) + + exp := []string{ + `F[int]`, + `F[main.Int]`, + `T[int; int]`, + `T[main.Int; int]`, + } + if diff := cmp.Diff(exp, insts); len(diff) > 0 { + t.Errorf("the instances of generics are different:\n%s", diff) + } +} + +func TestNestedGenericTypeInGenericFuncWithSharedTArgs(t *testing.T) { + src := ` + package main + func F[A any]() any { + type T[B any] struct { + b B + } + return T[A]{} + } + func main() { + type Int int + print(F[int]()) + print(F[Int]()) + }` + + srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}} + root := srctesting.ParseSources(t, srcFiles, nil) + archives := compileProject(t, root, false) + mainPkg := archives[root.PkgPath] + insts := collectDeclInstances(t, mainPkg) + + exp := []string{ + `F[int]`, + `F[main.Int]`, + `T[int; int]`, + `T[main.Int; main.Int]`, + // Make sure that T[int;main.Int] and T[main.Int;int] aren't created. + } + if diff := cmp.Diff(exp, insts); len(diff) > 0 { + t.Errorf("the instances of generics are different:\n%s", diff) + } +} + +func collectDeclInstances(t *testing.T, pkg *Archive) []string { + t.Helper() + + // Regex to match strings like `Foo[42 /* bar */] =` and capture + // the name (`Foo`), the index (`42`), and the instance type (`bar`). + rex := regexp.MustCompile(`^\s*(\w+)\s*\[\s*(\d+)\s*\/\*(.+)\*\/\s*\]\s*\=`) + + // Collect all instances of generics (e.g. `Foo[bar] @ 2`) written to the decl code. + insts := []string{} + for _, decl := range pkg.Declarations { + if match := rex.FindAllStringSubmatch(string(decl.DeclCode), 1); len(match) > 0 { + instance := match[0][1] + `[` + strings.TrimSpace(match[0][3]) + `]` + instance = strings.ReplaceAll(instance, `command-line-arguments`, pkg.Name) + insts = append(insts, instance) + } + } + sort.Strings(insts) + return insts +} + func compareOrder(t *testing.T, sourceFiles []srctesting.Source, minify bool) { t.Helper() outputNormal := compile(t, sourceFiles, minify) @@ -677,37 +926,43 @@ func compileProject(t *testing.T, root *packages.Package, minify bool) map[strin pkgMap[pkg.PkgPath] = pkg }) - archiveCache := map[string]*Archive{} - var importContext *ImportContext - importContext = &ImportContext{ - Packages: map[string]*types.Package{}, - Import: func(path string) (*Archive, error) { - // find in local cache - if a, ok := archiveCache[path]; ok { - return a, nil - } - - pkg, ok := pkgMap[path] - if !ok { - t.Fatal(`package not found:`, path) - } - importContext.Packages[path] = pkg.Types + allSrcs := map[string]*sources.Sources{} + for _, pkg := range pkgMap { + srcs := &sources.Sources{ + ImportPath: pkg.PkgPath, + Dir: ``, + Files: pkg.Syntax, + FileSet: pkg.Fset, + } + allSrcs[pkg.PkgPath] = srcs + } - // compile package - a, err := Compile(path, pkg.Syntax, pkg.Fset, importContext, minify) - if err != nil { - return nil, err - } - archiveCache[path] = a - return a, nil - }, + importer := func(path, srcDir string) (*sources.Sources, error) { + srcs, ok := allSrcs[path] + if !ok { + t.Fatal(`package not found:`, path) + return nil, nil + } + return srcs, nil } - _, err := importContext.Import(root.PkgPath) - if err != nil { - t.Fatal(`failed to compile:`, err) + tContext := types.NewContext() + sortedSources := make([]*sources.Sources, 0, len(allSrcs)) + for _, srcs := range allSrcs { + sortedSources = append(sortedSources, srcs) } - return archiveCache + sources.SortedSourcesSlice(sortedSources) + PrepareAllSources(sortedSources, importer, tContext) + + archives := map[string]*Archive{} + for _, srcs := range allSrcs { + a, err := Compile(srcs, tContext, minify) + if err != nil { + t.Fatal(`failed to compile:`, err) + } + archives[srcs.ImportPath] = a + } + return archives } // newTime creates an arbitrary time.Time offset by the given number of seconds. @@ -722,6 +977,13 @@ func newTime(seconds float64) time.Time { func reloadCompiledProject(t *testing.T, archives map[string]*Archive, rootPkgPath string) map[string]*Archive { t.Helper() + // TODO(grantnelson-wf): The tests using this function are out-of-date + // since they are testing the old archive caching that has been disabled. + // At some point, these tests should be updated to test any new caching + // mechanism that is implemented or removed. As is this function is faking + // the old recursive archive loading that is no longer used since it + // doesn't allow cross package analysis for generings. + buildTime := newTime(5.0) serialized := map[string][]byte{} for path, a := range archives { @@ -734,10 +996,14 @@ func reloadCompiledProject(t *testing.T, archives map[string]*Archive, rootPkgPa srcModTime := newTime(0.0) reloadCache := map[string]*Archive{} + type ImportContext struct { + Packages map[string]*types.Package + ImportArchive func(path string) (*Archive, error) + } var importContext *ImportContext importContext = &ImportContext{ Packages: map[string]*types.Package{}, - Import: func(path string) (*Archive, error) { + ImportArchive: func(path string) (*Archive, error) { // find in local cache if a, ok := reloadCache[path]; ok { return a, nil @@ -757,7 +1023,7 @@ func reloadCompiledProject(t *testing.T, archives map[string]*Archive, rootPkgPa }, } - _, err := importContext.Import(rootPkgPath) + _, err := importContext.ImportArchive(rootPkgPath) if err != nil { t.Fatal(`failed to reload archives:`, err) } @@ -775,7 +1041,7 @@ func renderPackage(t *testing.T, archive *Archive, minify bool) string { buf := &bytes.Buffer{} - if err := WritePkgCode(archive, selection, goLinknameSet{}, minify, &SourceMapFilter{Writer: buf}); err != nil { + if err := WritePkgCode(archive, selection, linkname.GoLinknameSet{}, minify, &SourceMapFilter{Writer: buf}); err != nil { t.Fatal(err) } diff --git a/compiler/decls.go b/compiler/decls.go index e292ad07c..eb95cd2f7 100644 --- a/compiler/decls.go +++ b/compiler/decls.go @@ -16,6 +16,7 @@ import ( "github.com/gopherjs/gopherjs/compiler/internal/dce" "github.com/gopherjs/gopherjs/compiler/internal/symbol" "github.com/gopherjs/gopherjs/compiler/internal/typeparams" + "github.com/gopherjs/gopherjs/compiler/sources" "github.com/gopherjs/gopherjs/compiler/typesutil" ) @@ -81,7 +82,7 @@ func (d *Decl) Dce() *dce.Info { // topLevelObjects extracts package-level variables, functions and named types // from the package AST. -func (fc *funcContext) topLevelObjects(srcs sources) (vars []*types.Var, functions []*ast.FuncDecl, typeNames typesutil.TypeNames) { +func (fc *funcContext) topLevelObjects(srcs *sources.Sources) (vars []*types.Var, functions []*ast.FuncDecl, typeNames typesutil.TypeNames) { if !fc.isRoot() { panic(bailout(fmt.Errorf("functionContext.discoverObjects() must be only called on the package-level context"))) } @@ -432,7 +433,7 @@ func (fc *funcContext) newNamedTypeVarDecl(obj *types.TypeName) *Decl { FullName: typeVarDeclFullName(obj), Vars: []string{name}, } - if typeparams.HasTypeParams(obj.Type()) { + if fc.pkgCtx.instanceSet.Pkg(obj.Pkg()).ObjHasInstances(obj) { varDecl.DeclCode = fc.CatchOutput(0, func() { fc.Printf("%s = {};", name) }) @@ -450,16 +451,28 @@ func (fc *funcContext) newNamedTypeVarDecl(obj *types.TypeName) *Decl { func (fc *funcContext) newNamedTypeInstDecl(inst typeparams.Instance) (*Decl, error) { originType := inst.Object.Type().(*types.Named) - fc.typeResolver = typeparams.NewResolver(fc.pkgCtx.typesCtx, typeparams.ToSlice(originType.TypeParams()), inst.TArgs) + var nestResolver *typeparams.Resolver + if len(inst.TNest) > 0 { + fn := typeparams.FindNestingFunc(inst.Object) + tp := typeparams.SignatureTypeParams(fn.Type().(*types.Signature)) + nestResolver = typeparams.NewResolver(fc.pkgCtx.typesCtx, tp, inst.TNest, nil) + } + fc.typeResolver = typeparams.NewResolver(fc.pkgCtx.typesCtx, originType.TypeParams(), inst.TArgs, nestResolver) defer func() { fc.typeResolver = nil }() instanceType := originType if !inst.IsTrivial() { - instantiated, err := types.Instantiate(fc.pkgCtx.typesCtx, originType, inst.TArgs, true) - if err != nil { - return nil, fmt.Errorf("failed to instantiate type %v with args %v: %w", originType, inst.TArgs, err) + if len(inst.TArgs) > 0 { + instantiated, err := types.Instantiate(fc.pkgCtx.typesCtx, originType, inst.TArgs, true) + if err != nil { + return nil, fmt.Errorf("failed to instantiate type %v with args %v: %w", originType, inst.TArgs, err) + } + instanceType = instantiated.(*types.Named) + } + if len(inst.TNest) > 0 { + instantiated := nestResolver.Substitute(instanceType) + instanceType = instantiated.(*types.Named) } - instanceType = instantiated.(*types.Named) } underlying := instanceType.Underlying() @@ -540,7 +553,8 @@ func (fc *funcContext) structConstructor(t *types.Struct) string { // If no arguments were passed, zero-initialize all fields. fmt.Fprintf(constructor, "\t\tif (arguments.length === 0) {\n") for i := 0; i < t.NumFields(); i++ { - fmt.Fprintf(constructor, "\t\t\tthis.%s = %s;\n", fieldName(t, i), fc.translateExpr(fc.zeroValue(t.Field(i).Type())).String()) + zeroValue := fc.zeroValue(fc.fieldType(t, i)) + fmt.Fprintf(constructor, "\t\t\tthis.%s = %s;\n", fieldName(t, i), fc.translateExpr(zeroValue).String()) } fmt.Fprintf(constructor, "\t\t\treturn;\n") fmt.Fprintf(constructor, "\t\t}\n") diff --git a/compiler/expressions.go b/compiler/expressions.go index f1c2e68f5..781a37a3e 100644 --- a/compiler/expressions.go +++ b/compiler/expressions.go @@ -178,18 +178,18 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression { } if !isKeyValue { for i, element := range e.Elts { - elements[i] = fc.translateImplicitConversionWithCloning(element, t.Field(i).Type()).String() + elements[i] = fc.translateImplicitConversionWithCloning(element, fc.fieldType(t, i)).String() } } if isKeyValue { for i := range elements { - elements[i] = fc.translateExpr(fc.zeroValue(t.Field(i).Type())).String() + elements[i] = fc.translateExpr(fc.zeroValue(fc.fieldType(t, i))).String() } for _, element := range e.Elts { kve := element.(*ast.KeyValueExpr) for j := range elements { if kve.Key.(*ast.Ident).Name == t.Field(j).Name() { - elements[j] = fc.translateImplicitConversionWithCloning(kve.Value, t.Field(j).Type()).String() + elements[j] = fc.translateImplicitConversionWithCloning(kve.Value, fc.fieldType(t, j)).String() break } } @@ -801,7 +801,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression { switch t := exprType.Underlying().(type) { case *types.Basic: if t.Kind() != types.UnsafePointer { - panic("unexpected basic type") + panic(fmt.Errorf(`unexpected basic type: %v in %v`, t, e.Name)) } return fc.formatExpr("0") case *types.Slice, *types.Pointer: @@ -917,7 +917,7 @@ func (fc *funcContext) makeReceiver(e *ast.SelectorExpr) *expression { recvType = ptr.Elem() } s := recvType.Underlying().(*types.Struct) - recvType = s.Field(index).Type() + recvType = fc.fieldType(s, index) } fakeSel := &ast.SelectorExpr{X: x, Sel: ast.NewIdent("o")} @@ -1314,12 +1314,13 @@ func (fc *funcContext) loadStruct(array, target string, s *types.Struct) string var collectFields func(s *types.Struct, path string) collectFields = func(s *types.Struct, path string) { for i := 0; i < s.NumFields(); i++ { - field := s.Field(i) - if fs, isStruct := field.Type().Underlying().(*types.Struct); isStruct { - collectFields(fs, path+"."+fieldName(s, i)) + fieldName := path + "." + fieldName(s, i) + fieldType := fc.fieldType(s, i) + if fs, isStruct := fieldType.Underlying().(*types.Struct); isStruct { + collectFields(fs, fieldName) continue } - fields = append(fields, types.NewVar(0, nil, path+"."+fieldName(s, i), field.Type())) + fields = append(fields, types.NewVar(0, nil, fieldName, fieldType)) } } collectFields(s, target) diff --git a/compiler/functions.go b/compiler/functions.go index 592992efc..361c92f0f 100644 --- a/compiler/functions.go +++ b/compiler/functions.go @@ -49,9 +49,9 @@ func (fc *funcContext) nestedFunctionContext(info *analysis.FuncInfo, inst typep } if sig.TypeParams().Len() > 0 { - c.typeResolver = typeparams.NewResolver(c.pkgCtx.typesCtx, typeparams.ToSlice(sig.TypeParams()), inst.TArgs) + c.typeResolver = typeparams.NewResolver(c.pkgCtx.typesCtx, sig.TypeParams(), inst.TArgs, nil) } else if sig.RecvTypeParams().Len() > 0 { - c.typeResolver = typeparams.NewResolver(c.pkgCtx.typesCtx, typeparams.ToSlice(sig.RecvTypeParams()), inst.TArgs) + c.typeResolver = typeparams.NewResolver(c.pkgCtx.typesCtx, sig.RecvTypeParams(), inst.TArgs, nil) } if c.objectNames == nil { c.objectNames = map[types.Object]string{} diff --git a/compiler/internal/analysis/info.go b/compiler/internal/analysis/info.go index 803952b24..e400c870c 100644 --- a/compiler/internal/analysis/info.go +++ b/compiler/internal/analysis/info.go @@ -52,16 +52,20 @@ type Info struct { *types.Info Pkg *types.Package typeCtx *types.Context - instanceSets *typeparams.PackageInstanceSets + InstanceSets *typeparams.PackageInstanceSets HasPointer map[*types.Var]bool funcInstInfos *typeparams.InstanceMap[*FuncInfo] funcLitInfos map[*ast.FuncLit][]*FuncInfo InitFuncInfo *FuncInfo // Context for package variable initialization. - isImportedBlocking func(typeparams.Instance) bool // For functions from other packages. - allInfos []*FuncInfo + infoImporter InfoImporter // To get `Info` for other packages. + allInfos []*FuncInfo } +// InfoImporter is used to get the `Info` for another package. +// The path is the resolved import path of the package to get the `Info` for. +type InfoImporter func(path string) (*Info, error) + func (info *Info) newFuncInfo(n ast.Node, obj types.Object, typeArgs typesutil.TypeList, resolver *typeparams.Resolver) *FuncInfo { funcInfo := &FuncInfo{ pkgInfo: info, @@ -106,7 +110,7 @@ func (info *Info) newFuncInfo(n ast.Node, obj types.Object, typeArgs typesutil.T func (info *Info) newFuncInfoInstances(fd *ast.FuncDecl) []*FuncInfo { obj := info.Defs[fd.Name] - instances := info.instanceSets.Pkg(info.Pkg).ForObj(obj) + instances := info.InstanceSets.Pkg(info.Pkg).ForObj(obj) if len(instances) == 0 { if typeparams.HasTypeParams(obj.Type()) { // This is a generic function, but no instances were found, @@ -122,8 +126,8 @@ func (info *Info) newFuncInfoInstances(fd *ast.FuncDecl) []*FuncInfo { for _, inst := range instances { var resolver *typeparams.Resolver if sig, ok := obj.Type().(*types.Signature); ok { - tp := typeparams.ToSlice(typeparams.SignatureTypeParams(sig)) - resolver = typeparams.NewResolver(info.typeCtx, tp, inst.TArgs) + tp := typeparams.SignatureTypeParams(sig) + resolver = typeparams.NewResolver(info.typeCtx, tp, inst.TArgs, nil) } fi := info.newFuncInfo(fd, inst.Object, inst.TArgs, resolver) funcInfos = append(funcInfos, fi) @@ -132,11 +136,16 @@ func (info *Info) newFuncInfoInstances(fd *ast.FuncDecl) []*FuncInfo { } // IsBlocking returns true if the function may contain blocking calls or operations. -// If inst is from a different package, this will use the isImportedBlocking +// If inst is from a different package, this will use the getImportInfo function // to lookup the information from the other package. func (info *Info) IsBlocking(inst typeparams.Instance) bool { if inst.Object.Pkg() != info.Pkg { - return info.isImportedBlocking(inst) + path := inst.Object.Pkg().Path() + otherInfo, err := info.infoImporter(path) + if err != nil { + panic(fmt.Errorf(`failed to get info for package %q: %v`, path, err)) + } + return otherInfo.IsBlocking(inst) } if funInfo := info.FuncInfo(inst); funInfo != nil { return funInfo.IsBlocking() @@ -174,16 +183,21 @@ func (info *Info) VarsWithInitializers() map[*types.Var]bool { return result } -func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info, typeCtx *types.Context, typesPkg *types.Package, instanceSets *typeparams.PackageInstanceSets, isBlocking func(typeparams.Instance) bool) *Info { +// AnalyzePkg analyzes the given package for blocking calls, defers, etc. +// +// Note that at the end of this call the analysis information +// has NOT been propagated across packages yet. Once all the packages +// have been analyzed, call PropagateAnalysis to propagate the information. +func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info, typeCtx *types.Context, typesPkg *types.Package, instanceSets *typeparams.PackageInstanceSets, infoImporter InfoImporter) *Info { info := &Info{ - Info: typesInfo, - Pkg: typesPkg, - typeCtx: typeCtx, - instanceSets: instanceSets, - HasPointer: make(map[*types.Var]bool), - isImportedBlocking: isBlocking, - funcInstInfos: new(typeparams.InstanceMap[*FuncInfo]), - funcLitInfos: make(map[*ast.FuncLit][]*FuncInfo), + Info: typesInfo, + Pkg: typesPkg, + typeCtx: typeCtx, + InstanceSets: instanceSets, + HasPointer: make(map[*types.Var]bool), + infoImporter: infoImporter, + funcInstInfos: new(typeparams.InstanceMap[*FuncInfo]), + funcLitInfos: make(map[*ast.FuncLit][]*FuncInfo), } info.InitFuncInfo = info.newFuncInfo(nil, nil, nil, nil) @@ -193,13 +207,25 @@ func AnalyzePkg(files []*ast.File, fileSet *token.FileSet, typesInfo *types.Info ast.Walk(info.InitFuncInfo, file) } + return info +} + +// PropagateAnalysis will propagate analysis information across package +// boundaries to finish the analysis of a whole project. +func PropagateAnalysis(allInfo []*Info) { done := false for !done { - done = info.propagateFunctionBlocking() + done = true + for _, info := range allInfo { + if !info.propagateFunctionBlocking() { + done = false + } + } } - info.propagateControlStatementBlocking() - return info + for _, info := range allInfo { + info.propagateControlStatementBlocking() + } } // propagateFunctionBlocking propagates information about blocking calls diff --git a/compiler/internal/analysis/info_test.go b/compiler/internal/analysis/info_test.go index 957e346d9..0df26b0b9 100644 --- a/compiler/internal/analysis/info_test.go +++ b/compiler/internal/analysis/info_test.go @@ -1,6 +1,7 @@ package analysis import ( + "fmt" "go/ast" "go/types" "sort" @@ -381,6 +382,7 @@ func TestBlocking_Defers_WithMultipleReturns(t *testing.T) { // of which flow control statements (e.g. if-statements) are terminating // or not. Any defers added in a terminating control flow would not // propagate to returns that are not in that block. + // See golang.org/x/tools/go/ssa for flow control analysis. // // For now we simply build up the list of defers as we go making // the return on line 31 also blocking. @@ -1575,15 +1577,13 @@ func TestBlocking_IsImportBlocking_ForwardInstances(t *testing.T) { } func TestBlocking_IsImportBlocking_BackwardInstances(t *testing.T) { - t.Skip(`isImportedBlocking doesn't fully handle instances yet`) - // TODO(grantnelson-wf): This test is currently failing because the info - // for the test package is need while creating the instances for FooBaz - // while analyzing the other package. However the other package is analyzed - // first since the test package is dependent on it. One possible fix is that - // we add some mechanism similar to the localInstCallees but for remote - // instances then perform the blocking propagation steps for all packages - // including the localInstCallees propagation at the same time. After all the - // propagation of the calls then the flow control statements can be marked. + // This tests propagation of information across package boundaries. + // `FooBaz` has no instances in it until it is referenced in the `test` package. + // That instance information needs to propagate back across the package + // boundary to the `other` package. The information for `BazBlocker` and + // `BazNotBlocker` is propagated back to `FooBaz[BazBlocker]` and + // `FooBaz[BazNotBlocker]`. That information is then propagated forward + // to the `blocking` and `notBlocking` functions in the `test` package. otherSrc := `package other @@ -1629,8 +1629,9 @@ type blockingTest struct { func newBlockingTest(t *testing.T, src string) *blockingTest { f := srctesting.New(t) + tContext := types.NewContext() tc := typeparams.Collector{ - TContext: types.NewContext(), + TContext: tContext, Info: f.Info, Instances: &typeparams.PackageInstanceSets{}, } @@ -1639,11 +1640,11 @@ func newBlockingTest(t *testing.T, src string) *blockingTest { testInfo, testPkg := f.Check(`pkg/test`, file) tc.Scan(testPkg, file) - isImportBlocking := func(i typeparams.Instance) bool { - t.Fatalf(`isImportBlocking should not be called in this test, called with %v`, i) - return true + getImportInfo := func(path string) (*Info, error) { + return nil, fmt.Errorf(`getImportInfo should not be called in this test, called with %v`, path) } - pkgInfo := AnalyzePkg([]*ast.File{file}, f.FileSet, testInfo, types.NewContext(), testPkg, tc.Instances, isImportBlocking) + pkgInfo := AnalyzePkg([]*ast.File{file}, f.FileSet, testInfo, tContext, testPkg, tc.Instances, getImportInfo) + PropagateAnalysis([]*Info{pkgInfo}) return &blockingTest{ f: f, @@ -1654,19 +1655,19 @@ func newBlockingTest(t *testing.T, src string) *blockingTest { func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc string) *blockingTest { f := srctesting.New(t) + tContext := types.NewContext() tc := typeparams.Collector{ - TContext: types.NewContext(), + TContext: tContext, Info: f.Info, Instances: &typeparams.PackageInstanceSets{}, } - pkgInfo := map[*types.Package]*Info{} - isImportBlocking := func(i typeparams.Instance) bool { - if info, ok := pkgInfo[i.Object.Pkg()]; ok { - return info.IsBlocking(i) + pkgInfo := map[string]*Info{} + getImportInfo := func(path string) (*Info, error) { + if info, ok := pkgInfo[path]; ok { + return info, nil } - t.Fatalf(`unexpected package in isImportBlocking for %v`, i) - return true + return nil, fmt.Errorf(`unexpected package in getImportInfo for %v`, path) } otherFile := f.Parse(`other.go`, otherSrc) @@ -1677,11 +1678,13 @@ func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc stri _, testPkg := f.Check(`pkg/test`, testFile) tc.Scan(testPkg, testFile) - otherPkgInfo := AnalyzePkg([]*ast.File{otherFile}, f.FileSet, f.Info, types.NewContext(), otherPkg, tc.Instances, isImportBlocking) - pkgInfo[otherPkg] = otherPkgInfo + otherPkgInfo := AnalyzePkg([]*ast.File{otherFile}, f.FileSet, f.Info, tContext, otherPkg, tc.Instances, getImportInfo) + pkgInfo[otherPkg.Path()] = otherPkgInfo - testPkgInfo := AnalyzePkg([]*ast.File{testFile}, f.FileSet, f.Info, types.NewContext(), testPkg, tc.Instances, isImportBlocking) - pkgInfo[testPkg] = testPkgInfo + testPkgInfo := AnalyzePkg([]*ast.File{testFile}, f.FileSet, f.Info, tContext, testPkg, tc.Instances, getImportInfo) + pkgInfo[testPkg.Path()] = testPkgInfo + + PropagateAnalysis([]*Info{otherPkgInfo, testPkgInfo}) return &blockingTest{ f: f, diff --git a/compiler/internal/symbol/symbol.go b/compiler/internal/symbol/symbol.go index 851ca1ef6..d460ea86d 100644 --- a/compiler/internal/symbol/symbol.go +++ b/compiler/internal/symbol/symbol.go @@ -21,6 +21,11 @@ type Name struct { // New constructs SymName for a given named symbol. func New(o types.Object) Name { + pkgPath := `_` + if pkg := o.Pkg(); pkg != nil { + pkgPath = pkg.Path() + } + if fun, ok := o.(*types.Func); ok { sig := fun.Type().(*types.Signature) if recv := sig.Recv(); recv != nil { @@ -28,18 +33,18 @@ func New(o types.Object) Name { typ := recv.Type() if ptr, ok := typ.(*types.Pointer); ok { return Name{ - PkgPath: o.Pkg().Path(), + PkgPath: pkgPath, Name: "(*" + ptr.Elem().(*types.Named).Obj().Name() + ")." + o.Name(), } } return Name{ - PkgPath: o.Pkg().Path(), + PkgPath: pkgPath, Name: typ.(*types.Named).Obj().Name() + "." + o.Name(), } } } return Name{ - PkgPath: o.Pkg().Path(), + PkgPath: pkgPath, Name: o.Name(), } } diff --git a/compiler/internal/typeparams/collect.go b/compiler/internal/typeparams/collect.go index 723172d4f..940690e83 100644 --- a/compiler/internal/typeparams/collect.go +++ b/compiler/internal/typeparams/collect.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "go/types" + "strings" "github.com/gopherjs/gopherjs/compiler/typesutil" "github.com/gopherjs/gopherjs/internal/govendor/subst" @@ -12,27 +13,67 @@ import ( // Resolver translates types defined in terms of type parameters into concrete // types, given a mapping from type params to type arguments. type Resolver struct { + tParams *types.TypeParamList + tArgs []types.Type + parent *Resolver + + // subster is the substitution helper that will perform the actual + // substitutions. This maybe nil when there are no substitutions but + // will still usable when nil. subster *subst.Subster selMemo map[typesutil.Selection]typesutil.Selection } // NewResolver creates a new Resolver with tParams entries mapping to tArgs // entries with the same index. -func NewResolver(tc *types.Context, tParams []*types.TypeParam, tArgs []types.Type) *Resolver { +func NewResolver(tc *types.Context, tParams *types.TypeParamList, tArgs []types.Type, parent *Resolver) *Resolver { r := &Resolver{ + tParams: tParams, + tArgs: tArgs, + parent: parent, subster: subst.New(tc, tParams, tArgs), selMemo: map[typesutil.Selection]typesutil.Selection{}, } return r } +// TypeParams is the list of type parameters that this resolver +// (not any parent) will substitute. +func (r *Resolver) TypeParams() *types.TypeParamList { + if r == nil { + return nil + } + return r.tParams +} + +// TypeArgs is the list of type arguments that this resolver +// (not any parent) will resolve to. +func (r *Resolver) TypeArgs() []types.Type { + if r == nil { + return nil + } + return r.tArgs +} + +// Parent is the resolver for the function or method that this resolver +// is nested in. This may be nil if the context for this resolver is not +// nested in another generic function or method. +func (r *Resolver) Parent() *Resolver { + if r == nil { + return nil + } + return r.parent +} + // Substitute replaces references to type params in the provided type definition // with the corresponding concrete types. func (r *Resolver) Substitute(typ types.Type) types.Type { - if r == nil || r.subster == nil || typ == nil { + if r == nil || typ == nil { return typ // No substitutions to be made. } - return r.subster.Type(typ) + typ = r.subster.Type(typ) + typ = r.parent.Substitute(typ) + return typ } // SubstituteAll same as Substitute, but accepts a TypeList are returns @@ -49,7 +90,7 @@ func (r *Resolver) SubstituteAll(list *types.TypeList) []types.Type { // defined in terms of type parameters with a method selection on a concrete // instantiation of the type. func (r *Resolver) SubstituteSelection(sel typesutil.Selection) typesutil.Selection { - if r == nil || r.subster == nil || sel == nil { + if r == nil || sel == nil { return sel // No substitutions to be made. } if concrete, ok := r.selMemo[sel]; ok { @@ -82,13 +123,22 @@ func (r *Resolver) SubstituteSelection(sel typesutil.Selection) typesutil.Select } } -// ToSlice converts TypeParamList into a slice with the same order of entries. -func ToSlice(tpl *types.TypeParamList) []*types.TypeParam { - result := make([]*types.TypeParam, tpl.Len()) - for i := range result { - result[i] = tpl.At(i) +// String gets a strings representation of the resolver for debugging. +func (r *Resolver) String() string { + if r == nil { + return `{}` } - return result + + parts := make([]string, 0, len(r.tArgs)) + for i, ta := range r.tArgs { + parts = append(parts, fmt.Sprintf("%s->%s", r.tParams.At(i), ta)) + } + + nestStr := `` + if r.parent != nil { + nestStr = r.parent.String() + `:` + } + return nestStr + `{` + strings.Join(parts, `, `) + `}` } // visitor implements ast.Visitor and collects instances of generic types and @@ -101,24 +151,35 @@ type visitor struct { instances *PackageInstanceSets resolver *Resolver info *types.Info + tNest []types.Type // The type arguments for a nested context. } var _ ast.Visitor = &visitor{} -func (c *visitor) Visit(n ast.Node) (w ast.Visitor) { - w = c // Always traverse the full depth of the AST tree. +func (c *visitor) Visit(n ast.Node) ast.Visitor { + if ident, ok := n.(*ast.Ident); ok { + c.visitIdent(ident) + } + return c +} - ident, ok := n.(*ast.Ident) - if !ok { - return +func (c *visitor) visitIdent(ident *ast.Ident) { + if inst, ok := c.info.Instances[ident]; ok { + // Found the use of a generic type or function. + c.visitInstance(ident, inst) } - instance, ok := c.info.Instances[ident] - if !ok { - return + if len(c.resolver.TypeArgs()) > 0 { + if obj, ok := c.info.Defs[ident]; ok && obj != nil { + // Found instance of a type defined inside a generic context. + c.visitNestedType(obj) + } } +} - obj := c.info.ObjectOf(ident) +func (c *visitor) visitInstance(ident *ast.Ident, inst types.Instance) { + obj := c.info.Uses[ident] + tArgs := inst.TypeArgs // For types embedded in structs, the object the identifier resolves to is a // *types.Var representing the implicitly declared struct field. However, the @@ -131,9 +192,53 @@ func (c *visitor) Visit(n ast.Node) (w ast.Visitor) { if t, ok := typ.(*types.Named); ok { obj = t.Obj() } + + // If the object is defined in the same scope as the instance, + // then we apply the current nested type arguments. + var tNest []types.Type + if obj.Parent().Contains(ident.Pos()) { + tNest = c.tNest + } + + c.addInstance(obj, tArgs, tNest) +} + +func (c *visitor) visitNestedType(obj types.Object) { + if _, ok := obj.(*types.TypeName); !ok { + // Found a variable or function, not a type, so skip it. + return + } + + typ := obj.Type() + if ptr, ok := typ.(*types.Pointer); ok { + typ = ptr.Elem() + } + + t, ok := typ.(*types.Named) + if !ok || t.TypeParams().Len() > 0 { + // Found a generic type or an unnamed type (e.g. type parameter). + // Don't add generic types yet because they + // will be added when we find an instance of them. + return + } + + c.addInstance(obj, nil, c.resolver.TypeArgs()) +} + +func (c *visitor) addInstance(obj types.Object, tArgList *types.TypeList, tNest []types.Type) { + tArgs := c.resolver.SubstituteAll(tArgList) + if isGeneric(tArgs...) { + // Skip any instances that still have type parameters in them after + // substitution. This occurs when a type is defined while nested + // in a generic context and is not fully instantiated yet. + // We need to wait until we find a full instantiation of the type. + return + } + c.instances.Add(Instance{ Object: obj, - TArgs: c.resolver.SubstituteAll(instance.TypeArgs), + TArgs: tArgs, + TNest: tNest, }) if t, ok := obj.Type().(*types.Named); ok { @@ -141,11 +246,11 @@ func (c *visitor) Visit(n ast.Node) (w ast.Visitor) { method := t.Method(i) c.instances.Add(Instance{ Object: method.Origin(), - TArgs: c.resolver.SubstituteAll(instance.TypeArgs), + TArgs: tArgs, + TNest: tNest, }) } } - return } // seedVisitor implements ast.Visitor that collects information necessary to @@ -241,22 +346,49 @@ func (c *Collector) Scan(pkg *types.Package, files ...*ast.File) { for iset := c.Instances.Pkg(pkg); !iset.exhausted(); { inst, _ := iset.next() + switch typ := inst.Object.Type().(type) { case *types.Signature: - v := visitor{ - instances: c.Instances, - resolver: NewResolver(c.TContext, ToSlice(SignatureTypeParams(typ)), inst.TArgs), - info: c.Info, - } - ast.Walk(&v, objMap[inst.Object]) + c.scanSignature(inst, typ, objMap) + case *types.Named: - obj := typ.Obj() - v := visitor{ - instances: c.Instances, - resolver: NewResolver(c.TContext, ToSlice(typ.TypeParams()), inst.TArgs), - info: c.Info, - } - ast.Walk(&v, objMap[obj]) + c.scanNamed(inst, typ, objMap) } } } + +func (c *Collector) scanSignature(inst Instance, typ *types.Signature, objMap map[types.Object]ast.Node) { + tParams := SignatureTypeParams(typ) + v := visitor{ + instances: c.Instances, + resolver: NewResolver(c.TContext, tParams, inst.TArgs, nil), + info: c.Info, + tNest: inst.TArgs, + } + ast.Walk(&v, objMap[inst.Object]) +} + +func (c *Collector) scanNamed(inst Instance, typ *types.Named, objMap map[types.Object]ast.Node) { + obj := typ.Obj() + node := objMap[obj] + if node == nil { + // Types without an entry in objMap are concrete types + // that are defined in a generic context. Skip them. + return + } + + var nestResolver *Resolver + if len(inst.TNest) > 0 { + fn := FindNestingFunc(inst.Object) + tp := SignatureTypeParams(fn.Type().(*types.Signature)) + nestResolver = NewResolver(c.TContext, tp, inst.TNest, nil) + } + + v := visitor{ + instances: c.Instances, + resolver: NewResolver(c.TContext, typ.TypeParams(), inst.TArgs, nestResolver), + info: c.Info, + tNest: inst.TNest, + } + ast.Walk(&v, node) +} diff --git a/compiler/internal/typeparams/collect_test.go b/compiler/internal/typeparams/collect_test.go index 9bd5faee4..6864e5ead 100644 --- a/compiler/internal/typeparams/collect_test.go +++ b/compiler/internal/typeparams/collect_test.go @@ -2,7 +2,9 @@ package typeparams import ( "go/ast" + "go/token" "go/types" + "strings" "testing" "github.com/google/go-cmp/cmp" @@ -35,7 +37,11 @@ func TestVisitor(t *testing.T) { t := typ[int, A]{} t.method(0) (*typ[int32, A]).method(nil, 0) + type x struct{ T []typ[int64, A] } + type y[X any] struct{ T []typ[A, X] } + _ = y[int8]{} + _ = y[A]{} return } @@ -49,7 +55,11 @@ func TestVisitor(t *testing.T) { t := typ[int, T]{} t.method(0) (*typ[int32, T]).method(nil, 0) + type x struct{ T []typ[int64, T] } + type y[X any] struct{ T []typ[T, X] } + _ = y[int8]{} + _ = y[T]{} return } @@ -67,7 +77,11 @@ func TestVisitor(t *testing.T) { t := typ[int, T]{} t.method(0) (*typ[int32, T]).method(nil, 0) + type x struct{ T []typ[int64, T] } + type y[X any] struct{ T []typ[T, X] } + _ = y[int8]{} + _ = y[T]{} return } @@ -189,22 +203,50 @@ func TestVisitor(t *testing.T) { descr: "non-generic function", resolver: nil, node: lookupDecl("entry1"), - want: instancesInFunc(lookupType("A")), + want: append( + instancesInFunc(lookupType("A")), + Instance{ + Object: lookupObj("entry1.y"), + TArgs: []types.Type{types.Typ[types.Int8]}, + }, + Instance{ + Object: lookupObj("entry1.y"), + TArgs: []types.Type{lookupType("A")}, + }, + ), }, { descr: "generic function", resolver: NewResolver( types.NewContext(), - ToSlice(lookupType("entry2").(*types.Signature).TypeParams()), + lookupType("entry2").(*types.Signature).TypeParams(), []types.Type{lookupType("B")}, + nil, ), node: lookupDecl("entry2"), - want: instancesInFunc(lookupType("B")), + want: append( + instancesInFunc(lookupType("B")), + Instance{ + Object: lookupObj("entry2.x"), + TNest: []types.Type{lookupType("B")}, + }, + Instance{ + Object: lookupObj("entry1.y"), + TNest: []types.Type{lookupType("B")}, + TArgs: []types.Type{types.Typ[types.Int8]}, + }, + Instance{ + Object: lookupObj("entry2.y"), + TNest: []types.Type{lookupType("B")}, + TArgs: []types.Type{lookupType("B")}, + }, + ), }, { descr: "generic method", resolver: NewResolver( types.NewContext(), - ToSlice(lookupType("entry3.method").(*types.Signature).RecvTypeParams()), + lookupType("entry3.method").(*types.Signature).RecvTypeParams(), []types.Type{lookupType("C")}, + nil, ), node: lookupDecl("entry3.method"), want: append( @@ -217,13 +259,28 @@ func TestVisitor(t *testing.T) { Object: lookupObj("entry3.method"), TArgs: []types.Type{lookupType("C")}, }, + Instance{ + Object: lookupObj("entry3.method.x"), + TNest: []types.Type{lookupType("C")}, + }, + Instance{ + Object: lookupObj("entry3.method.y"), + TNest: []types.Type{lookupType("C")}, + TArgs: []types.Type{types.Typ[types.Int8]}, + }, + Instance{ + Object: lookupObj("entry3.method.y"), + TNest: []types.Type{lookupType("C")}, + TArgs: []types.Type{lookupType("C")}, + }, ), }, { descr: "generic type declaration", resolver: NewResolver( types.NewContext(), - ToSlice(lookupType("entry3").(*types.Named).TypeParams()), + lookupType("entry3").(*types.Named).TypeParams(), []types.Type{lookupType("D")}, + nil, ), node: lookupDecl("entry3"), want: instancesInType(lookupType("D")), @@ -256,6 +313,11 @@ func TestVisitor(t *testing.T) { resolver: test.resolver, info: info, } + if test.resolver != nil { + // Since we know all the tests are for functions and methods, + // set the nested type to the type parameter from the resolver. + v.tNest = test.resolver.tArgs + } ast.Walk(&v, test.node) got := v.instances.Pkg(pkg).Values() if diff := cmp.Diff(test.want, got, instanceOpts()); diff != "" { @@ -319,7 +381,7 @@ func TestSeedVisitor(t *testing.T) { } got := sv.instances.Pkg(pkg).Values() if diff := cmp.Diff(want, got, instanceOpts()); diff != "" { - t.Errorf("Instances from initialSeeder contain diff (-want,+got):\n%s", diff) + t.Errorf("Instances from seedVisitor contain diff (-want,+got):\n%s", diff) } } @@ -353,28 +415,333 @@ func TestCollector(t *testing.T) { } c.Scan(pkg, file) - inst := func(name string, tArg types.Type) Instance { + inst := func(name, tNest, tArg string) Instance { return Instance{ Object: srctesting.LookupObj(pkg, name), - TArgs: []types.Type{tArg}, + TNest: evalTypeArgs(t, f.FileSet, pkg, tNest), + TArgs: evalTypeArgs(t, f.FileSet, pkg, tArg), } } want := []Instance{ - inst("typ", types.Typ[types.Int]), - inst("typ.method", types.Typ[types.Int]), - inst("fun", types.Typ[types.Int8]), - inst("fun.nested", types.Typ[types.Int8]), - inst("typ", types.Typ[types.Int16]), - inst("typ.method", types.Typ[types.Int16]), - inst("typ", types.Typ[types.Int32]), - inst("typ.method", types.Typ[types.Int32]), - inst("fun", types.Typ[types.Int64]), - inst("fun.nested", types.Typ[types.Int64]), + inst(`typ`, ``, `int`), + inst(`typ.method`, ``, `int`), + inst(`fun`, ``, `int8`), + inst(`fun.nested`, `int8`, `int8`), + inst(`typ`, ``, `int16`), + inst(`typ.method`, ``, `int16`), + inst(`typ`, ``, `int32`), + inst(`typ.method`, ``, `int32`), + inst(`fun`, ``, `int64`), + inst(`fun.nested`, `int64`, `int64`), } got := c.Instances.Pkg(pkg).Values() if diff := cmp.Diff(want, got, instanceOpts()); diff != "" { - t.Errorf("Instances from initialSeeder contain diff (-want,+got):\n%s", diff) + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func TestCollector_MoreNesting(t *testing.T) { + src := `package test + + func fun[T any]() { + type nestedCon struct{ X T } + _ = nestedCon{} + + type nestedGen[U any] struct{ Y T; Z U } + _ = nestedGen[T]{} + _ = nestedGen[int8]{} + + type nestedCover[T any] struct{ W T } + _ = nestedCover[T]{} + _ = nestedCover[int16]{} + } + + func a() { + fun[int32]() + fun[int64]() + } + ` + + f := srctesting.New(t) + file := f.Parse(`test.go`, src) + info, pkg := f.Check(`pkg/test`, file) + + c := Collector{ + TContext: types.NewContext(), + Info: info, + Instances: &PackageInstanceSets{}, + } + c.Scan(pkg, file) + + inst := func(name, tNest, tArg string) Instance { + return Instance{ + Object: srctesting.LookupObj(pkg, name), + TNest: evalTypeArgs(t, f.FileSet, pkg, tNest), + TArgs: evalTypeArgs(t, f.FileSet, pkg, tArg), + } + } + want := []Instance{ + inst(`fun`, ``, `int32`), + inst(`fun`, ``, `int64`), + + inst(`fun.nestedCon`, `int32`, ``), + inst(`fun.nestedCon`, `int64`, ``), + + inst(`fun.nestedGen`, `int32`, `int32`), + inst(`fun.nestedGen`, `int32`, `int8`), + inst(`fun.nestedGen`, `int64`, `int64`), + inst(`fun.nestedGen`, `int64`, `int8`), + + inst(`fun.nestedCover`, `int32`, `int32`), + inst(`fun.nestedCover`, `int32`, `int16`), + inst(`fun.nestedCover`, `int64`, `int64`), + inst(`fun.nestedCover`, `int64`, `int16`), + } + got := c.Instances.Pkg(pkg).Values() + if diff := cmp.Diff(want, got, instanceOpts()); diff != `` { + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func TestCollector_NestingWithVars(t *testing.T) { + // This is loosely based off of go1.19.13/test/typeparam/issue47740b.go + // I was getting an error where `Q.print[int;]` was showing up when + // `Q.print` is not in a nesting context with `int` and this helped debug + // it. The problem was that `q` was being treated like a type not a var. + src := `package test + + type Q struct{ v any } + func (q Q) print() { + println(q.v) + } + + func newQ(v any) Q { + return Q{v} + } + + type S[T any] struct{ x T } + func (s S[T]) echo() { + q := newQ(s.x) + q.print() + } + + func a() { + s := S[int]{x: 0} + s.echo() + } + ` + + f := srctesting.New(t) + file := f.Parse(`test.go`, src) + info, pkg := f.Check(`pkg/test`, file) + + c := Collector{ + TContext: types.NewContext(), + Info: info, + Instances: &PackageInstanceSets{}, + } + c.Scan(pkg, file) + + inst := func(name, tNest, tArg string) Instance { + return Instance{ + Object: srctesting.LookupObj(pkg, name), + TNest: evalTypeArgs(t, f.FileSet, pkg, tNest), + TArgs: evalTypeArgs(t, f.FileSet, pkg, tArg), + } + } + want := []Instance{ + inst(`S`, ``, `int`), + inst(`S.echo`, ``, `int`), + } + got := c.Instances.Pkg(pkg).Values() + if diff := cmp.Diff(want, got, instanceOpts()); diff != `` { + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func TestCollector_RecursiveTypeParams(t *testing.T) { + // This is based off of part of go1.19.13/test/typeparam/nested.go + src := `package test + func F[A any]() {} + func main() { + type U[_ any] int + type X[A any] U[X[A]] + F[X[int]]() + } + ` + + f := srctesting.New(t) + file := f.Parse(`test.go`, src) + info, pkg := f.Check(`test`, file) + + c := Collector{ + TContext: types.NewContext(), + Info: info, + Instances: &PackageInstanceSets{}, + } + c.Scan(pkg, file) + + tInt := types.Typ[types.Int] + xAny := srctesting.LookupObj(pkg, `main.X`) + xInt, err := types.Instantiate(types.NewContext(), xAny.Type(), []types.Type{tInt}, true) + if err != nil { + t.Fatalf("Failed to instantiate X[int]: %v", err) + } + + want := []Instance{ + { + Object: srctesting.LookupObj(pkg, `F`), + TArgs: []types.Type{xInt}, + }, { + Object: srctesting.LookupObj(pkg, `main.U`), + TArgs: []types.Type{xInt}, + }, { + Object: xAny, + TArgs: []types.Type{tInt}, + }, + } + got := c.Instances.Pkg(pkg).Values() + if diff := cmp.Diff(want, got, instanceOpts()); diff != `` { + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func TestCollector_NestedRecursiveTypeParams(t *testing.T) { + t.Skip(`Skipping test due to known issue with nested recursive type parameters.`) + // TODO(grantnelson-wf): This test is failing because the type parameters + // inside of U are not being resolved to concrete types. This is because + // when instantiating X in the collector, we are not resolving the + // nested type of U that is X's type argument. This leave the A in U + // as a type parameter instead of resolving it to string. + + // This is based off of part of go1.19.13/test/typeparam/nested.go + src := `package test + func F[A any]() any { + type U[_ any] struct{ x A } + type X[B any] U[X[B]] + return X[int]{} + } + func main() { + print(F[string]()) + } + ` + + f := srctesting.New(t) + file := f.Parse(`test.go`, src) + info, pkg := f.Check(`test`, file) + + c := Collector{ + TContext: types.NewContext(), + Info: info, + Instances: &PackageInstanceSets{}, + } + c.Scan(pkg, file) + + xAny := srctesting.LookupObj(pkg, `F.X`) + xInt, err := types.Instantiate(types.NewContext(), xAny.Type(), []types.Type{types.Typ[types.Int]}, true) + if err != nil { + t.Fatalf("Failed to instantiate X[int]: %v", err) + } + // TODO(grantnelson-wf): Need to instantiate xInt to replace `A` with `int` in the struct. + if isGeneric(xInt) { + t.Errorf("Expected uInt to be non-generic, got %v", xInt.Underlying()) + } + + want := []Instance{ + { + Object: srctesting.LookupObj(pkg, `F`), + TArgs: []types.Type{types.Typ[types.String]}, + }, { + Object: srctesting.LookupObj(pkg, `F.U`), + TNest: []types.Type{types.Typ[types.String]}, + TArgs: []types.Type{xInt}, + }, { + Object: xAny, + TNest: []types.Type{types.Typ[types.String]}, + TArgs: []types.Type{types.Typ[types.Int]}, + }, + } + got := c.Instances.Pkg(pkg).Values() + if diff := cmp.Diff(want, got, instanceOpts()); diff != `` { + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func TestCollector_NestedTypeParams(t *testing.T) { + t.Skip(`Skipping test due to known issue with nested recursive type parameters.`) + // TODO(grantnelson-wf): This test is failing because the type parameters + // inside of U are not being resolved to concrete types. This is because + // when instantiating X in the collector, we are not resolving the + // nested type of U that is X's type argument. This leave the A in U + // as a type parameter instead of resolving it to string. + + // This is based off of part of go1.19.13/test/typeparam/nested.go + src := `package test + func F[A any]() any { + type T[B any] struct{} + type U[_ any] struct{ X A } + return T[U[A]]{} + } + func main() { + print(F[int]()) + } + ` + + f := srctesting.New(t) + file := f.Parse(`test.go`, src) + info, pkg := f.Check(`test`, file) + + c := Collector{ + TContext: types.NewContext(), + Info: info, + Instances: &PackageInstanceSets{}, + } + c.Scan(pkg, file) + + uAny := srctesting.LookupObj(pkg, `F.U`) + uInt, err := types.Instantiate(types.NewContext(), uAny.Type(), []types.Type{types.Typ[types.Int]}, true) + if err != nil { + t.Fatalf("Failed to instantiate U[int]: %v", err) + } + //TODO(grantnelson-wf): Need to instantiate uInt to replace `A` with `int` in the struct. + if isGeneric(uInt) { + t.Errorf("Expected uInt to be non-generic, got %v", uInt.Underlying()) + } + + want := []Instance{ + { + Object: srctesting.LookupObj(pkg, `F`), + TArgs: []types.Type{types.Typ[types.Int]}, + }, { + Object: srctesting.LookupObj(pkg, `F.U`), + TNest: []types.Type{types.Typ[types.Int]}, + TArgs: []types.Type{types.Typ[types.Int]}, + }, { + Object: srctesting.LookupObj(pkg, `F.T`), + TNest: []types.Type{types.Typ[types.Int]}, + TArgs: []types.Type{uInt}, + }, + } + got := c.Instances.Pkg(pkg).Values() + if diff := cmp.Diff(want, got, instanceOpts()); diff != `` { + t.Errorf("Instances from Collector contain diff (-want,+got):\n%s", diff) + } +} + +func evalTypeArgs(t *testing.T, fSet *token.FileSet, pkg *types.Package, expr string) []types.Type { + if len(expr) == 0 { + return nil + } + args := strings.Split(expr, ",") + targs := make([]types.Type, 0, len(args)) + for _, astr := range args { + tv, err := types.Eval(fSet, pkg, 0, astr) + if err != nil { + t.Fatalf("Eval(%s) failed: %v", astr, err) + } + targs = append(targs, tv.Type) } + return targs } func TestCollector_CrossPackage(t *testing.T) { @@ -492,7 +859,7 @@ func TestResolver_SubstituteSelection(t *testing.T) { info, pkg := f.Check("pkg/test", file) method := srctesting.LookupObj(pkg, "g.Method").(*types.Func).Type().(*types.Signature) - resolver := NewResolver(nil, ToSlice(method.RecvTypeParams()), []types.Type{srctesting.LookupObj(pkg, "x").Type()}) + resolver := NewResolver(nil, method.RecvTypeParams(), []types.Type{srctesting.LookupObj(pkg, "x").Type()}, nil) if l := len(info.Selections); l != 1 { t.Fatalf("Got: %d selections. Want: 1", l) diff --git a/compiler/internal/typeparams/instance.go b/compiler/internal/typeparams/instance.go index 3e4c04d2c..64c67b4b5 100644 --- a/compiler/internal/typeparams/instance.go +++ b/compiler/internal/typeparams/instance.go @@ -3,6 +3,7 @@ package typeparams import ( "fmt" "go/types" + "strings" "github.com/gopherjs/gopherjs/compiler/internal/symbol" "github.com/gopherjs/gopherjs/compiler/typesutil" @@ -15,39 +16,82 @@ import ( type Instance struct { Object types.Object // Object to be instantiated. TArgs typesutil.TypeList // Type params to instantiate with. + + // TNest is the type params of the function this object was nested with-in. + // e.g. In `func A[X any]() { type B[Y any] struct {} }` the `X` + // from `A` is the context of `B[Y]` thus creating `B[X;Y]`. + TNest typesutil.TypeList } // String returns a string representation of the Instance. // // Two semantically different instances may have the same string representation // if the instantiated object or its type arguments shadow other types. -func (i *Instance) String() string { - sym := symbol.New(i.Object).String() - if len(i.TArgs) == 0 { - return sym +func (i Instance) String() string { + return i.symbolicName() + i.TypeParamsString(`<`, `>`) +} + +// TypeString returns a Go type string representing the instance (suitable for %T verb). +func (i Instance) TypeString() string { + return i.qualifiedName() + i.TypeParamsString(`[`, `]`) +} + +// symbolicName returns a string representation of the instance's name +// including the package name and pointer indicators but +// excluding the type parameters. +func (i Instance) symbolicName() string { + if i.Object == nil { + return `` } + return symbol.New(i.Object).String() +} - return fmt.Sprintf("%s<%s>", sym, i.TArgs) +// qualifiedName returns a string representation of the instance's name +// including the package name but +// excluding the type parameters and pointer indicators. +func (i Instance) qualifiedName() string { + if i.Object == nil { + return `` + } + if i.Object.Pkg() == nil { + return i.Object.Name() + } + return fmt.Sprintf("%s.%s", i.Object.Pkg().Name(), i.Object.Name()) } -// TypeString returns a Go type string representing the instance (suitable for %T verb). -func (i *Instance) TypeString() string { - tArgs := "" - if len(i.TArgs) > 0 { - tArgs = "[" + i.TArgs.String() + "]" +// TypeParamsString returns part of a Go type string that represents the type +// parameters of the instance including the nesting type parameters, e.g. [X;Y,Z]. +func (i Instance) TypeParamsString(open, close string) string { + hasNest := len(i.TNest) > 0 + hasArgs := len(i.TArgs) > 0 + buf := strings.Builder{} + if hasNest || hasArgs { + buf.WriteString(open) + if hasNest { + buf.WriteString(i.TNest.String()) + buf.WriteRune(';') + if hasArgs { + buf.WriteRune(' ') + } + } + if hasArgs { + buf.WriteString(i.TArgs.String()) + } + buf.WriteString(close) } - return fmt.Sprintf("%s.%s%s", i.Object.Pkg().Name(), i.Object.Name(), tArgs) + return buf.String() } -// IsTrivial returns true if this is an instance of a non-generic object. -func (i *Instance) IsTrivial() bool { - return len(i.TArgs) == 0 +// IsTrivial returns true if this is an instance of a non-generic object +// and it is not nested in a generic function. +func (i Instance) IsTrivial() bool { + return len(i.TArgs) == 0 && len(i.TNest) == 0 } // Recv returns an instance of the receiver type of a method. // // Returns zero value if not a method. -func (i *Instance) Recv() Instance { +func (i Instance) Recv() Instance { sig, ok := i.Object.Type().(*types.Signature) if !ok { return Instance{} @@ -159,6 +203,17 @@ func (iset *InstanceSet) ForObj(obj types.Object) []Instance { return result } +// ObjHasInstances returns true if there are any instances (either trivial +// or non-trivial) that belong to the given object type, otherwise false. +func (iset *InstanceSet) ObjHasInstances(obj types.Object) bool { + for _, inst := range iset.values { + if inst.Object == obj { + return true + } + } + return false +} + // PackageInstanceSets stores an InstanceSet for each package in a program, keyed // by import path. type PackageInstanceSets map[string]*InstanceSet diff --git a/compiler/internal/typeparams/map.go b/compiler/internal/typeparams/map.go index dbe07a54e..7edbdc016 100644 --- a/compiler/internal/typeparams/map.go +++ b/compiler/internal/typeparams/map.go @@ -38,9 +38,9 @@ type InstanceMap[V any] struct { // If the given key isn't found, an empty bucket and -1 are returned. func (im *InstanceMap[V]) findIndex(key Instance) (mapBucket[V], int) { if im != nil && im.data != nil { - bucket := im.data[key.Object][typeHash(im.hasher, key.TArgs...)] + bucket := im.data[key.Object][typeHash(im.hasher, key.TNest, key.TArgs)] for i, candidate := range bucket { - if candidate != nil && candidate.key.TArgs.Equal(key.TArgs) { + if candidateArgsMatch(key, candidate) { return bucket, i } } @@ -82,7 +82,7 @@ func (im *InstanceMap[V]) Set(key Instance, value V) V { if _, ok := im.data[key.Object]; !ok { im.data[key.Object] = mapBuckets[V]{} } - bucketID := typeHash(im.hasher, key.TArgs...) + bucketID := typeHash(im.hasher, key.TNest, key.TArgs) // If there is already an identical key in the map, override the entry value. hole := -1 @@ -90,7 +90,7 @@ func (im *InstanceMap[V]) Set(key Instance, value V) V { for i, candidate := range bucket { if candidate == nil { hole = i - } else if candidate.key.TArgs.Equal(key.TArgs) { + } else if candidateArgsMatch(key, candidate) { old := candidate.value candidate.value = value return old @@ -180,13 +180,24 @@ func (im *InstanceMap[V]) String() string { return `{` + strings.Join(entries, `, `) + `}` } +// candidateArgsMatch checks if the candidate entry has the same type +// arguments as the given key. +func candidateArgsMatch[V any](key Instance, candidate *mapEntry[V]) bool { + return candidate != nil && + candidate.key.TNest.Equal(key.TNest) && + candidate.key.TArgs.Equal(key.TArgs) +} + // typeHash returns a combined hash of several types. // // Provided hasher is used to compute hashes of individual types, which are // xor'ed together. Xor preserves bit distribution property, so the combined // hash should be as good for bucketing, as the original. -func typeHash(hasher typeutil.Hasher, types ...types.Type) uint32 { +func typeHash(hasher typeutil.Hasher, nestTypes, types []types.Type) uint32 { var hash uint32 + for _, typ := range nestTypes { + hash ^= hasher.Hash(typ) + } for _, typ := range types { hash ^= hasher.Hash(typ) } diff --git a/compiler/internal/typeparams/map_test.go b/compiler/internal/typeparams/map_test.go index baa31f64a..d67a1884d 100644 --- a/compiler/internal/typeparams/map_test.go +++ b/compiler/internal/typeparams/map_test.go @@ -7,8 +7,10 @@ import ( ) func TestInstanceMap(t *testing.T) { + pkg := types.NewPackage(`testPkg`, `testPkg`) + i1 := Instance{ - Object: types.NewTypeName(token.NoPos, nil, "i1", nil), + Object: types.NewTypeName(token.NoPos, pkg, "i1", nil), TArgs: []types.Type{ types.Typ[types.Int], types.Typ[types.Int8], @@ -23,7 +25,7 @@ func TestInstanceMap(t *testing.T) { } i2 := Instance{ - Object: types.NewTypeName(token.NoPos, nil, "i2", nil), // Different pointer. + Object: types.NewTypeName(token.NoPos, pkg, "i2", nil), // Different pointer. TArgs: []types.Type{ types.Typ[types.Int], types.Typ[types.Int8], @@ -70,7 +72,7 @@ func TestInstanceMap(t *testing.T) { if got := m.Len(); got != 1 { t.Errorf("Got: map length %d. Want: 1.", got) } - if got, want := m.String(), `{{type i1 int, int8}:abc}`; got != want { + if got, want := m.String(), `{testPkg.i1:abc}`; got != want { t.Errorf("Got: map string %q. Want: map string %q.", got, want) } if got, want := m.Keys(), []Instance{i1}; !keysMatch(got, want) { @@ -95,7 +97,7 @@ func TestInstanceMap(t *testing.T) { if got := m.Get(i1clone); got != "def" { t.Errorf(`Got: getting set key returned %q. Want: "def"`, got) } - if got, want := m.String(), `{{type i1 int, int8}:def}`; got != want { + if got, want := m.String(), `{testPkg.i1:def}`; got != want { t.Errorf("Got: map string %q. Want: map string %q.", got, want) } if got, want := m.Keys(), []Instance{i1}; !keysMatch(got, want) { @@ -165,7 +167,7 @@ func TestInstanceMap(t *testing.T) { if got := m.Len(); got != 5 { t.Errorf("Got: map length %d. Want: 5.", got) } - if got, want := m.String(), `{{type i1 int, int8}:def, {type i1 int, int}:456, {type i1 string, string}:789, {type i1 }:ghi, {type i2 int, int8}:123}`; got != want { + if got, want := m.String(), `{testPkg.i1:ghi, testPkg.i1:def, testPkg.i1:456, testPkg.i1:789, testPkg.i2:123}`; got != want { t.Errorf("Got: map string %q. Want: map string %q.", got, want) } if got, want := m.Keys(), []Instance{i1, i2, i3, i4, i5}; !keysMatch(got, want) { diff --git a/compiler/internal/typeparams/utils.go b/compiler/internal/typeparams/utils.go index 6930fbf23..ea528314e 100644 --- a/compiler/internal/typeparams/utils.go +++ b/compiler/internal/typeparams/utils.go @@ -3,6 +3,7 @@ package typeparams import ( "errors" "fmt" + "go/token" "go/types" ) @@ -19,6 +20,31 @@ func SignatureTypeParams(sig *types.Signature) *types.TypeParamList { } } +// FindNestingFunc returns the function or method that the given object +// is nested in, or nil if the object was defined at the package level. +func FindNestingFunc(obj types.Object) *types.Func { + objPos := obj.Pos() + if objPos == token.NoPos { + return nil + } + + scope := obj.Parent() + for scope != nil { + // Iterate over all declarations in the scope. + for _, name := range scope.Names() { + decl := scope.Lookup(name) + if fn, ok := decl.(*types.Func); ok { + // Check if the object's position is within the function's scope. + if objPos >= fn.Pos() && objPos <= fn.Scope().End() { + return fn + } + } + } + scope = scope.Parent() + } + return nil +} + var ( errInstantiatesGenerics = errors.New("instantiates generic type or function") errDefinesGenerics = errors.New("defines generic type or function") @@ -58,3 +84,58 @@ func RequiresGenericsSupport(info *types.Info) error { return nil } + +// isGeneric will search all the given types and their subtypes for a +// *types.TypeParam. This will not check if a type could be generic, +// but if each instantiation is not completely concrete yet. +// +// This is useful to check for generics types like `X[B[T]]`, where +// `X` appears concrete because it is instantiated with the type argument `B[T]`, +// however the `T` inside `B[T]` is a type parameter making `X[B[T]]` a generic +// type since it required instantiation to a concrete type, e.g. `X[B[int]]`. +func isGeneric(typ ...types.Type) bool { + var containsTypeParam func(t types.Type) bool + + foreach := func(count int, getter func(index int) types.Type) bool { + for i := 0; i < count; i++ { + if containsTypeParam(getter(i)) { + return true + } + } + return false + } + + seen := make(map[types.Type]struct{}) + containsTypeParam = func(t types.Type) bool { + if _, ok := seen[t]; ok { + return false + } + seen[t] = struct{}{} + + switch t := t.(type) { + case *types.TypeParam: + return true + case *types.Named: + return t.TypeParams().Len() != t.TypeArgs().Len() || + foreach(t.TypeArgs().Len(), func(i int) types.Type { return t.TypeArgs().At(i) }) || + containsTypeParam(t.Underlying()) + case *types.Struct: + return foreach(t.NumFields(), func(i int) types.Type { return t.Field(i).Type() }) + case *types.Interface: + return foreach(t.NumMethods(), func(i int) types.Type { return t.Method(i).Type() }) + case *types.Signature: + return foreach(t.Params().Len(), func(i int) types.Type { return t.Params().At(i).Type() }) || + foreach(t.Results().Len(), func(i int) types.Type { return t.Results().At(i).Type() }) + case *types.Map: + return containsTypeParam(t.Key()) || containsTypeParam(t.Elem()) + case interface{ Elem() types.Type }: + // Handles *types.Pointer, *types.Slice, *types.Array, *types.Chan + return containsTypeParam(t.Elem()) + default: + // Other types (e.g., basic types) do not contain type parameters. + return false + } + } + + return foreach(len(typ), func(i int) types.Type { return typ[i] }) +} diff --git a/compiler/jsFile/jsFile.go b/compiler/jsFile/jsFile.go new file mode 100644 index 000000000..b8ae9421f --- /dev/null +++ b/compiler/jsFile/jsFile.go @@ -0,0 +1,55 @@ +package jsFile + +import ( + "fmt" + "go/build" + "io" + "strings" + "time" + + "golang.org/x/tools/go/buildutil" +) + +// JSFile represents a *.inc.js file metadata and content. +type JSFile struct { + Path string // Full file path for the build context the file came from. + ModTime time.Time + Content []byte +} + +// JSFilesFromDir finds and loads any *.inc.js packages in the build context +// directory. +func JSFilesFromDir(bctx *build.Context, dir string) ([]JSFile, error) { + files, err := buildutil.ReadDir(bctx, dir) + if err != nil { + return nil, err + } + var jsFiles []JSFile + for _, file := range files { + if !strings.HasSuffix(file.Name(), ".inc.js") || file.IsDir() { + continue + } + if file.Name()[0] == '_' || file.Name()[0] == '.' { + continue // Skip "hidden" files that are typically ignored by the Go build system. + } + + path := buildutil.JoinPath(bctx, dir, file.Name()) + f, err := buildutil.OpenFile(bctx, path) + if err != nil { + return nil, fmt.Errorf("failed to open %s from %v: %w", path, bctx, err) + } + defer f.Close() + + content, err := io.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("failed to read %s from %v: %w", path, bctx, err) + } + + jsFiles = append(jsFiles, JSFile{ + Path: path, + ModTime: file.ModTime(), + Content: content, + }) + } + return jsFiles, nil +} diff --git a/compiler/linkname.go b/compiler/linkname/linkname.go similarity index 87% rename from compiler/linkname.go rename to compiler/linkname/linkname.go index c4f15a23e..6c3a9623c 100644 --- a/compiler/linkname.go +++ b/compiler/linkname/linkname.go @@ -1,4 +1,4 @@ -package compiler +package linkname import ( "fmt" @@ -8,6 +8,7 @@ import ( "github.com/gopherjs/gopherjs/compiler/astutil" "github.com/gopherjs/gopherjs/compiler/internal/symbol" + "github.com/gopherjs/gopherjs/internal/errorList" ) // GoLinkname describes a go:linkname compiler directive found in the source code. @@ -21,7 +22,7 @@ type GoLinkname struct { Reference symbol.Name } -// parseGoLinknames processed comments in a source file and extracts //go:linkname +// ParseGoLinknames processed comments in a source file and extracts //go:linkname // compiler directive from the comments. // // The following directive format is supported: @@ -37,8 +38,8 @@ type GoLinkname struct { // - The local function referenced by the directive must have no body (in other // words, it can only "import" an external function implementation into the // local scope). -func parseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]GoLinkname, error) { - var errs ErrorList = nil +func ParseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]GoLinkname, error) { + var errs errorList.ErrorList = nil var directives []GoLinkname isUnsafe := astutil.ImportsUnsafe(file) @@ -107,7 +108,7 @@ func parseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]Go for _, cg := range file.Comments { for _, c := range cg.List { if err := processComment(c); err != nil { - errs = append(errs, ErrorAt(err, fset, c.Pos())) + errs = append(errs, errorAt(err, fset, c.Pos())) } } } @@ -115,15 +116,20 @@ func parseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]Go return directives, errs.ErrOrNil() } -// goLinknameSet is a utility that enables quick lookup of whether a decl is +// errorAt annotates an error with a position in the source code. +func errorAt(err error, fset *token.FileSet, pos token.Pos) error { + return fmt.Errorf("%s: %w", fset.Position(pos), err) +} + +// GoLinknameSet is a utility that enables quick lookup of whether a decl is // affected by any go:linkname directive in the program. -type goLinknameSet struct { +type GoLinknameSet struct { byImplementation map[symbol.Name][]GoLinkname byReference map[symbol.Name]GoLinkname } // Add more GoLinkname directives into the set. -func (gls *goLinknameSet) Add(entries []GoLinkname) error { +func (gls *GoLinknameSet) Add(entries []GoLinkname) error { if gls.byImplementation == nil { gls.byImplementation = map[symbol.Name][]GoLinkname{} } @@ -143,7 +149,7 @@ func (gls *goLinknameSet) Add(entries []GoLinkname) error { // IsImplementation returns true if there is a directive referencing this symbol // as an implementation. -func (gls *goLinknameSet) IsImplementation(sym symbol.Name) bool { +func (gls *GoLinknameSet) IsImplementation(sym symbol.Name) bool { _, found := gls.byImplementation[sym] return found } @@ -151,7 +157,7 @@ func (gls *goLinknameSet) IsImplementation(sym symbol.Name) bool { // FindImplementation returns a symbol name, which provides the implementation // for the given symbol. The second value indicates whether the implementation // was found. -func (gls *goLinknameSet) FindImplementation(sym symbol.Name) (symbol.Name, bool) { +func (gls *GoLinknameSet) FindImplementation(sym symbol.Name) (symbol.Name, bool) { directive, found := gls.byReference[sym] return directive.Implementation, found } diff --git a/compiler/linkname_test.go b/compiler/linkname/linkname_test.go similarity index 98% rename from compiler/linkname_test.go rename to compiler/linkname/linkname_test.go index 7f46c6cfb..e2abc2825 100644 --- a/compiler/linkname_test.go +++ b/compiler/linkname/linkname_test.go @@ -1,4 +1,4 @@ -package compiler +package linkname import ( "go/ast" @@ -151,7 +151,7 @@ func TestParseGoLinknames(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { file, fset := parseSource(t, test.src) - directives, err := parseGoLinknames(fset, "testcase", file) + directives, err := ParseGoLinknames(fset, "testcase", file) if test.wantError != "" { if err == nil { diff --git a/compiler/package.go b/compiler/package.go index ba018a66b..bb94962da 100644 --- a/compiler/package.go +++ b/compiler/package.go @@ -7,12 +7,14 @@ import ( "go/types" "strings" + "golang.org/x/tools/go/types/typeutil" + "github.com/gopherjs/gopherjs/compiler/internal/analysis" "github.com/gopherjs/gopherjs/compiler/internal/dce" "github.com/gopherjs/gopherjs/compiler/internal/typeparams" + "github.com/gopherjs/gopherjs/compiler/sources" "github.com/gopherjs/gopherjs/compiler/typesutil" - "github.com/gopherjs/gopherjs/internal/experiments" - "golang.org/x/tools/go/types/typeutil" + "github.com/gopherjs/gopherjs/internal/errorList" ) // pkgContext maintains compiler context for a specific package. @@ -35,7 +37,7 @@ type pkgContext struct { indentation int minify bool fileSet *token.FileSet - errList ErrorList + errList errorList.ErrorList instanceSet *typeparams.PackageInstanceSets } @@ -114,18 +116,11 @@ type funcContext struct { funcLitCounter int } -func newRootCtx(tContext *types.Context, srcs sources, typesInfo *types.Info, typesPkg *types.Package, isBlocking func(typeparams.Instance) bool, minify bool) *funcContext { - tc := typeparams.Collector{ - TContext: tContext, - Info: typesInfo, - Instances: &typeparams.PackageInstanceSets{}, - } - tc.Scan(typesPkg, srcs.Files...) - pkgInfo := analysis.AnalyzePkg(srcs.Files, srcs.FileSet, typesInfo, tContext, typesPkg, tc.Instances, isBlocking) +func newRootCtx(tContext *types.Context, srcs *sources.Sources, minify bool) *funcContext { funcCtx := &funcContext{ - FuncInfo: pkgInfo.InitFuncInfo, + FuncInfo: srcs.TypeInfo.InitFuncInfo, pkgCtx: &pkgContext{ - Info: pkgInfo, + Info: srcs.TypeInfo, additionalSelections: make(map[*ast.SelectorExpr]typesutil.Selection), typesCtx: tContext, @@ -135,7 +130,7 @@ func newRootCtx(tContext *types.Context, srcs sources, typesInfo *types.Info, ty indentation: 1, minify: minify, fileSet: srcs.FileSet, - instanceSet: tc.Instances, + instanceSet: srcs.TypeInfo.InstanceSets, }, allVars: make(map[string]int), flowDatas: map[*types.Label]*flowData{nil: {}}, @@ -155,48 +150,11 @@ type flowData struct { endCase int } -// ImportContext provides access to information about imported packages. -type ImportContext struct { - // Mapping for an absolute import path to the package type information. - Packages map[string]*types.Package - // Import returns a previously compiled Archive for a dependency package. If - // the Import() call was successful, the corresponding entry must be added to - // the Packages map. - Import func(importPath string) (*Archive, error) -} - -// isBlocking returns true if an _imported_ function is blocking. It will panic -// if the function decl is not found in the imported package or the package -// hasn't been compiled yet. -// -// Note: see analysis.FuncInfo.Blocking if you need to determine if a function -// in the _current_ package is blocking. Usually available via functionContext -// object. -func (ic *ImportContext) isBlocking(inst typeparams.Instance) bool { - f, ok := inst.Object.(*types.Func) - if !ok { - panic(bailout(fmt.Errorf("can't determine if instance %v is blocking: instance isn't for a function object", inst))) - } - - archive, err := ic.Import(f.Pkg().Path()) - if err != nil { - panic(err) - } - - fullName := funcDeclFullName(inst) - for _, d := range archive.Declarations { - if d.FullName == fullName { - return d.Blocking - } - } - panic(bailout(fmt.Errorf("can't determine if function %s is blocking: decl not found in package archive", fullName))) -} - // Compile the provided Go sources as a single package. // -// Import path must be the absolute import path for a package. Provided sources -// are always sorted by name to ensure reproducible JavaScript output. -func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, importContext *ImportContext, minify bool) (_ *Archive, err error) { +// Provided sources must be prepared so that the type information has been determined, +// and the source files have been sorted by name to ensure reproducible JavaScript output. +func Compile(srcs *sources.Sources, tContext *types.Context, minify bool) (_ *Archive, err error) { defer func() { e := recover() if e == nil { @@ -204,39 +162,15 @@ func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, impor } if fe, ok := bailingOut(e); ok { // Orderly bailout, return whatever clues we already have. - fmt.Fprintf(fe, `building package %q`, importPath) + fmt.Fprintf(fe, `building package %q`, srcs.ImportPath) err = fe return } // Some other unexpected panic, catch the stack trace and return as an error. - err = bailout(fmt.Errorf("unexpected compiler panic while building package %q: %v", importPath, e)) + err = bailout(fmt.Errorf("unexpected compiler panic while building package %q: %v", srcs.ImportPath, e)) }() - srcs := sources{ - ImportPath: importPath, - Files: files, - FileSet: fileSet, - }.Sort() - - tContext := types.NewContext() - typesInfo, typesPkg, err := srcs.TypeCheck(importContext, tContext) - if err != nil { - return nil, err - } - if genErr := typeparams.RequiresGenericsSupport(typesInfo); genErr != nil && !experiments.Env.Generics { - return nil, fmt.Errorf("package %s requires generics support (https://github.com/gopherjs/gopherjs/issues/1013): %w", importPath, genErr) - } - importContext.Packages[srcs.ImportPath] = typesPkg - - // Extract all go:linkname compiler directives from the package source. - goLinknames, err := srcs.ParseGoLinknames() - if err != nil { - return nil, err - } - - srcs = srcs.Simplified(typesInfo) - - rootCtx := newRootCtx(tContext, srcs, typesInfo, typesPkg, importContext.isBlocking, minify) + rootCtx := newRootCtx(tContext, srcs, minify) importedPaths, importDecls := rootCtx.importDecls() @@ -280,16 +214,74 @@ func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, impor return &Archive{ ImportPath: srcs.ImportPath, - Name: typesPkg.Name(), + Name: srcs.Package.Name(), Imports: importedPaths, - Package: typesPkg, + Package: srcs.Package, Declarations: allDecls, FileSet: srcs.FileSet, Minified: minify, - GoLinknames: goLinknames, + GoLinknames: srcs.GoLinknames, }, nil } +// PrepareAllSources prepares all sources for compilation by +// parsing go linknames, type checking, sorting, simplifying, and +// performing cross package analysis. +// The results are stored in the provided sources. +// +// All sources must be given at the same time for cross package analysis to +// work correctly. For consistency, the sources should be sorted by import path. +func PrepareAllSources(allSources []*sources.Sources, importer sources.Importer, tContext *types.Context) error { + // Sort the files by name in each source to ensure consistent order of processing. + for _, srcs := range allSources { + srcs.Sort() + } + + // This will be performed recursively for all dependencies + // to get the packages for the sources. + // Since some packages might not be recursively reached via the root sources, + // e.g. runtime, we need to try to TypeCheck all of them here. + // Any sources that have already been type checked will no-op. + for _, srcs := range allSources { + if err := srcs.TypeCheck(importer, sizes32, tContext); err != nil { + return err + } + } + + // Extract all go:linkname compiler directives from the package source. + for _, srcs := range allSources { + if err := srcs.ParseGoLinknames(); err != nil { + return err + } + } + + // Simply the source files. + for _, srcs := range allSources { + srcs.Simplify() + } + + // Collect all the generic type instances from all the packages. + // This must be done for all sources prior to any analysis. + instances := &typeparams.PackageInstanceSets{} + for _, srcs := range allSources { + srcs.CollectInstances(tContext, instances) + } + + // Analyze the package to determine type parameters instances, blocking, + // and other type information. This will not populate the information. + for _, srcs := range allSources { + srcs.Analyze(importer, tContext, instances) + } + + // Propagate the analysis information across all packages. + allInfo := make([]*analysis.Info, len(allSources)) + for i, src := range allSources { + allInfo[i] = src.TypeInfo + } + analysis.PropagateAnalysis(allInfo) + return nil +} + func (fc *funcContext) initArgs(ty types.Type) string { switch t := ty.(type) { case *types.Array: @@ -331,11 +323,17 @@ func (fc *funcContext) initArgs(ty types.Type) string { if !field.Exported() { pkgPath = field.Pkg().Path() } - fields[i] = fmt.Sprintf(`{prop: "%s", name: %s, embedded: %t, exported: %t, typ: %s, tag: %s}`, fieldName(t, i), encodeString(field.Name()), field.Anonymous(), field.Exported(), fc.typeName(field.Type()), encodeString(t.Tag(i))) + ft := fc.fieldType(t, i) + fields[i] = fmt.Sprintf(`{prop: "%s", name: %s, embedded: %t, exported: %t, typ: %s, tag: %s}`, + fieldName(t, i), encodeString(field.Name()), field.Anonymous(), field.Exported(), fc.typeName(ft), encodeString(t.Tag(i))) } return fmt.Sprintf(`"%s", [%s]`, pkgPath, strings.Join(fields, ", ")) case *types.TypeParam: - err := bailout(fmt.Errorf(`%v has unexpected generic type parameter %T`, ty, ty)) + tr := fc.typeResolver.Substitute(ty) + if tr != ty { + return fc.initArgs(tr) + } + err := bailout(fmt.Errorf(`"%v" has unexpected generic type parameter %T`, ty, ty)) panic(err) default: err := bailout(fmt.Errorf("%v has unexpected type %T", ty, ty)) diff --git a/compiler/sources.go b/compiler/sources.go deleted file mode 100644 index e6c3710f4..000000000 --- a/compiler/sources.go +++ /dev/null @@ -1,123 +0,0 @@ -package compiler - -import ( - "go/ast" - "go/token" - "go/types" - "sort" - - "github.com/neelance/astrewrite" -) - -// sources is a slice of parsed Go sources. -// -// Note that the sources would normally belong to a single logical Go package, -// but they don't have to be a real Go package (i.e. found on the file system) -// or represent a complete package (i.e. it could be only a few source files -// compiled by `gopherjs build foo.go bar.go`). -type sources struct { - // ImportPath representing the sources, if exists. May be empty for "virtual" - // packages like testmain or playground-generated package. - ImportPath string - Files []*ast.File - FileSet *token.FileSet -} - -// Sort the Files slice by the original source name to ensure consistent order -// of processing. This is required for reproducible JavaScript output. -// -// Note this function mutates the original slice. -func (s sources) Sort() sources { - sort.Slice(s.Files, func(i, j int) bool { - return s.FileSet.File(s.Files[i].Pos()).Name() > s.FileSet.File(s.Files[j].Pos()).Name() - }) - return s -} - -// Simplified returns a new sources instance with each Files entry processed by -// astrewrite.Simplify. -func (s sources) Simplified(typesInfo *types.Info) sources { - simplified := sources{ - ImportPath: s.ImportPath, - FileSet: s.FileSet, - } - for _, file := range s.Files { - simplified.Files = append(simplified.Files, astrewrite.Simplify(file, typesInfo, false)) - } - return simplified -} - -// TypeCheck the sources. Returns information about declared package types and -// type information for the supplied AST. -func (s sources) TypeCheck(importContext *ImportContext, tContext *types.Context) (*types.Info, *types.Package, error) { - const errLimit = 10 // Max number of type checking errors to return. - - typesInfo := &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Implicits: make(map[ast.Node]types.Object), - Selections: make(map[*ast.SelectorExpr]*types.Selection), - Scopes: make(map[ast.Node]*types.Scope), - Instances: make(map[*ast.Ident]types.Instance), - } - - var typeErrs ErrorList - - importer := packageImporter{ImportContext: importContext} - - config := &types.Config{ - Context: tContext, - Importer: &importer, - Sizes: sizes32, - Error: func(err error) { typeErrs = typeErrs.AppendDistinct(err) }, - } - typesPkg, err := config.Check(s.ImportPath, s.FileSet, s.Files, typesInfo) - // If we encountered any import errors, it is likely that the other type errors - // are not meaningful and would be resolved by fixing imports. Return them - // separately, if any. https://github.com/gopherjs/gopherjs/issues/119. - if importer.Errors.ErrOrNil() != nil { - return nil, nil, importer.Errors.Trim(errLimit).ErrOrNil() - } - // Return any other type errors. - if typeErrs.ErrOrNil() != nil { - return nil, nil, typeErrs.Trim(errLimit).ErrOrNil() - } - // Any general errors that may have occurred during type checking. - if err != nil { - return nil, nil, err - } - return typesInfo, typesPkg, nil -} - -// ParseGoLinknames extracts all //go:linkname compiler directive from the sources. -func (s sources) ParseGoLinknames() ([]GoLinkname, error) { - goLinknames := []GoLinkname{} - var errs ErrorList - for _, file := range s.Files { - found, err := parseGoLinknames(s.FileSet, s.ImportPath, file) - errs = errs.Append(err) - goLinknames = append(goLinknames, found...) - } - return goLinknames, errs.ErrOrNil() -} - -// packageImporter implements go/types.Importer interface. -type packageImporter struct { - ImportContext *ImportContext - Errors ErrorList -} - -func (pi *packageImporter) Import(path string) (*types.Package, error) { - if path == "unsafe" { - return types.Unsafe, nil - } - - a, err := pi.ImportContext.Import(path) - if err != nil { - pi.Errors = pi.Errors.AppendDistinct(err) - return nil, err - } - - return pi.ImportContext.Packages[a.ImportPath], nil -} diff --git a/compiler/sources/sources.go b/compiler/sources/sources.go new file mode 100644 index 000000000..8e2d12946 --- /dev/null +++ b/compiler/sources/sources.go @@ -0,0 +1,284 @@ +package sources + +import ( + "fmt" + "go/ast" + "go/token" + "go/types" + "sort" + "strings" + + "github.com/neelance/astrewrite" + + "github.com/gopherjs/gopherjs/compiler/internal/analysis" + "github.com/gopherjs/gopherjs/compiler/internal/typeparams" + "github.com/gopherjs/gopherjs/compiler/jsFile" + "github.com/gopherjs/gopherjs/compiler/linkname" + "github.com/gopherjs/gopherjs/internal/errorList" + "github.com/gopherjs/gopherjs/internal/experiments" +) + +// Sources is a slice of parsed Go sources and additional data for a package. +// +// Note that the sources would normally belong to a single logical Go package, +// but they don't have to be a real Go package (i.e. found on the file system) +// or represent a complete package (i.e. it could be only a few source files +// compiled by `gopherjs build foo.go bar.go`). +type Sources struct { + // ImportPath representing the sources, if exists. + // + // May be empty for "virtual" + // packages like testmain or playground-generated package. + // Otherwise this must be the absolute import path for a package. + ImportPath string + + // Dir is the directory containing package sources + Dir string + + // Files is the parsed and augmented Go AST files for the package. + Files []*ast.File + + // FileSet is the file set for the parsed files. + FileSet *token.FileSet + + // JSFiles is the JavaScript files that are part of the package. + JSFiles []jsFile.JSFile + + // TypeInfo is the type information this package. + // This is nil until set by Analyze. + TypeInfo *analysis.Info + + // baseInfo is the base type information this package. + // This is nil until set by TypeCheck. + baseInfo *types.Info + + // Package is the types package for these source files. + // This is nil until set by TypeCheck. + Package *types.Package + + // GoLinknames is the set of Go linknames for this package. + // This is nil until set by ParseGoLinknames. + GoLinknames []linkname.GoLinkname +} + +type Importer func(path, srcDir string) (*Sources, error) + +// sort the Go files slice by the original source name to ensure consistent order +// of processing. This is required for reproducible JavaScript output. +// +// Note this function mutates the original Files slice. +func (s *Sources) Sort() { + sort.Slice(s.Files, func(i, j int) bool { + return s.getFileName(s.Files[i]) > s.getFileName(s.Files[j]) + }) +} + +func (s *Sources) getFileName(file *ast.File) string { + return s.FileSet.File(file.Pos()).Name() +} + +// Simplify processed each Files entry with astrewrite.Simplify. +// +// Note this function mutates the original Files slice. +// This must be called after TypeCheck and before analyze since +// this will change the pointers in the AST. For example, the pointers +// to function literals will change, making it impossible to find them +// in the type information, if analyze is called first. +func (s *Sources) Simplify() { + for i, file := range s.Files { + s.Files[i] = astrewrite.Simplify(file, s.baseInfo, false) + } +} + +// TypeCheck the sources. Returns information about declared package types and +// type information for the supplied AST. +// This will set the Package field on the Sources. +// +// If the Package field is not nil, e.g. this function has already been run, +// this will be a no-op. +// +// This must be called prior to simplify to get the types.Info used by simplify. +func (s *Sources) TypeCheck(importer Importer, sizes types.Sizes, tContext *types.Context) error { + if s.Package != nil && s.baseInfo != nil { + // type checking has already been done so return early. + return nil + } + + const errLimit = 10 // Max number of type checking errors to return. + + typesInfo := &types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + Implicits: make(map[ast.Node]types.Object), + Selections: make(map[*ast.SelectorExpr]*types.Selection), + Scopes: make(map[ast.Node]*types.Scope), + Instances: make(map[*ast.Ident]types.Instance), + } + + var typeErrs errorList.ErrorList + + pkgImporter := &packageImporter{ + srcDir: s.Dir, + importer: importer, + sizes: sizes, + tContext: tContext, + } + + config := &types.Config{ + Context: tContext, + Importer: pkgImporter, + Sizes: sizes, + Error: func(err error) { typeErrs = typeErrs.AppendDistinct(err) }, + } + typesPkg, err := config.Check(s.ImportPath, s.FileSet, s.Files, typesInfo) + // If we encountered any import errors, it is likely that the other type errors + // are not meaningful and would be resolved by fixing imports. Return them + // separately, if any. https://github.com/gopherjs/gopherjs/issues/119. + if pkgImporter.Errors.ErrOrNil() != nil { + return pkgImporter.Errors.Trim(errLimit).ErrOrNil() + } + // Return any other type errors. + if typeErrs.ErrOrNil() != nil { + return typeErrs.Trim(errLimit).ErrOrNil() + } + // Any general errors that may have occurred during type checking. + if err != nil { + return err + } + + // If generics are not enabled, ensure the package does not requires generics support. + if !experiments.Env.Generics { + if genErr := typeparams.RequiresGenericsSupport(typesInfo); genErr != nil { + return fmt.Errorf("some packages requires generics support (https://github.com/gopherjs/gopherjs/issues/1013): %w", genErr) + } + } + + s.baseInfo = typesInfo + s.Package = typesPkg + return nil +} + +// CollectInstances will determine the type parameters instances for the package. +// +// This must be called before Analyze to have the type parameters instances +// needed during analysis. +func (s *Sources) CollectInstances(tContext *types.Context, instances *typeparams.PackageInstanceSets) { + tc := typeparams.Collector{ + TContext: tContext, + Info: s.baseInfo, + Instances: instances, + } + tc.Scan(s.Package, s.Files...) +} + +// Analyze will determine the type parameters instances, blocking, +// and other type information for the package. +// This will set the TypeInfo and Instances fields on the Sources. +// +// This must be called after to simplify to ensure the pointers +// in the AST are still valid. +// The instances must be collected prior to this call. +// +// Note that at the end of this call the analysis information +// has NOT been propagated across packages yet. +func (s *Sources) Analyze(importer Importer, tContext *types.Context, instances *typeparams.PackageInstanceSets) { + infoImporter := func(path string) (*analysis.Info, error) { + srcs, err := importer(path, s.Dir) + if err != nil { + return nil, err + } + return srcs.TypeInfo, nil + } + s.TypeInfo = analysis.AnalyzePkg(s.Files, s.FileSet, s.baseInfo, tContext, s.Package, instances, infoImporter) +} + +// ParseGoLinknames extracts all //go:linkname compiler directive from the sources. +// +// This will set the GoLinknames field on the Sources. +func (s *Sources) ParseGoLinknames() error { + goLinknames := []linkname.GoLinkname{} + var errs errorList.ErrorList + for _, file := range s.Files { + found, err := linkname.ParseGoLinknames(s.FileSet, s.ImportPath, file) + errs = errs.Append(err) + goLinknames = append(goLinknames, found...) + } + if err := errs.ErrOrNil(); err != nil { + return err + } + s.GoLinknames = goLinknames + return nil +} + +// UnresolvedImports calculates the import paths of the package's dependencies +// based on all the imports in the augmented Go AST files. +// +// This is used to determine the unresolved imports that weren't in the +// PackageData.Imports slice since they were added during augmentation or +// during template generation. +// +// The given skip paths (typically those imports from PackageData.Imports) +// will not be returned in the results. +// This will not return any `*_test` packages in the results. +func (s *Sources) UnresolvedImports(skip ...string) []string { + seen := make(map[string]struct{}) + for _, sk := range skip { + seen[sk] = struct{}{} + } + imports := []string{} + for _, file := range s.Files { + for _, imp := range file.Imports { + path := strings.Trim(imp.Path.Value, `"`) + if _, ok := seen[path]; !ok { + if !strings.HasSuffix(path, "_test") { + imports = append(imports, path) + } + seen[path] = struct{}{} + } + } + } + sort.Strings(imports) + return imports +} + +// packageImporter implements go/types.Importer interface and +// wraps it to collect import errors. +type packageImporter struct { + srcDir string + importer Importer + sizes types.Sizes + tContext *types.Context + Errors errorList.ErrorList +} + +func (pi *packageImporter) Import(path string) (*types.Package, error) { + if path == "unsafe" { + return types.Unsafe, nil + } + + srcs, err := pi.importer(path, pi.srcDir) + if err != nil { + pi.Errors = pi.Errors.AppendDistinct(err) + return nil, err + } + + // If the sources doesn't have the package determined yet, get it now, + // otherwise this will be a no-op. + // This will recursively get the packages for all of it's dependencies too. + err = srcs.TypeCheck(pi.importer, pi.sizes, pi.tContext) + if err != nil { + pi.Errors = pi.Errors.AppendDistinct(err) + return nil, err + } + + return srcs.Package, nil +} + +// SortedSourcesSlice in place sorts the given slice of Sources by ImportPath. +// This will not change the order of the files within any Sources. +func SortedSourcesSlice(sourcesSlice []*Sources) { + sort.Slice(sourcesSlice, func(i, j int) bool { + return sourcesSlice[i].ImportPath < sourcesSlice[j].ImportPath + }) +} diff --git a/compiler/utils.go b/compiler/utils.go index 5d2cb4629..7d286f447 100644 --- a/compiler/utils.go +++ b/compiler/utils.go @@ -198,7 +198,7 @@ func (fc *funcContext) translateSelection(sel typesutil.Selection, pos token.Pos jsFieldName := s.Field(index).Name() for { fields = append(fields, fieldName(s, 0)) - ft := s.Field(0).Type() + ft := fc.fieldType(s, 0) if typesutil.IsJsObject(ft) { return fields, jsTag } @@ -215,7 +215,7 @@ func (fc *funcContext) translateSelection(sel typesutil.Selection, pos token.Pos } } fields = append(fields, fieldName(s, index)) - t = s.Field(index).Type() + t = fc.fieldType(s, index) } return fields, "" } @@ -441,13 +441,16 @@ func (fc *funcContext) objectName(o types.Object) string { // knownInstances returns a list of known instantiations of the object. // -// For objects without type params always returns a single trivial instance. +// For objects without type params and not nested in a generic function or +// method, this always returns a single trivial instance. +// If the object is generic, or in a generic function or method, but there are +// no instances, then the object is unused and an empty list is returned. func (fc *funcContext) knownInstances(o types.Object) []typeparams.Instance { - if !typeparams.HasTypeParams(o.Type()) { + instances := fc.pkgCtx.instanceSet.Pkg(o.Pkg()).ForObj(o) + if len(instances) == 0 && !typeparams.HasTypeParams(o.Type()) { return []typeparams.Instance{{Object: o}} } - - return fc.pkgCtx.instanceSet.Pkg(o.Pkg()).ForObj(o) + return instances } // instName returns a JS expression that refers to the provided instance of a @@ -459,7 +462,8 @@ func (fc *funcContext) instName(inst typeparams.Instance) string { return objName } fc.pkgCtx.DeclareDCEDep(inst.Object, inst.TArgs...) - return fmt.Sprintf("%s[%d /* %v */]", objName, fc.pkgCtx.instanceSet.ID(inst), inst.TArgs) + label := inst.TypeParamsString(` /* `, ` */`) + return fmt.Sprintf("%s[%d%s]", objName, fc.pkgCtx.instanceSet.ID(inst), label) } // methodName returns a JS identifier (specifically, object property name) @@ -504,14 +508,31 @@ func (fc *funcContext) typeName(ty types.Type) string { return "$error" } inst := typeparams.Instance{Object: t.Obj()} + + // Get type arguments for the type if there are any. for i := 0; i < t.TypeArgs().Len(); i++ { inst.TArgs = append(inst.TArgs, t.TypeArgs().At(i)) } + + // Get the nesting type arguments if there are any. + if fn := typeparams.FindNestingFunc(t.Obj()); fn != nil { + if fn.Scope().Contains(t.Obj().Pos()) { + tp := typeparams.SignatureTypeParams(fn.Type().(*types.Signature)) + tNest := make([]types.Type, tp.Len()) + for i := 0; i < tp.Len(); i++ { + tNest[i] = fc.typeResolver.Substitute(tp.At(i)) + } + inst.TNest = typesutil.TypeList(tNest) + } + } + return fc.instName(inst) case *types.Interface: if t.Empty() { return "$emptyInterface" } + case *types.TypeParam: + panic(fmt.Errorf("unexpected type parameter: %v", t)) } // For anonymous composite types, generate a synthetic package-level type @@ -575,6 +596,12 @@ func (fc *funcContext) typeOf(expr ast.Expr) types.Type { return fc.typeResolver.Substitute(typ) } +// fieldType returns the type of the i-th field of the given struct +// after substituting type parameters with concrete types for nested context. +func (fc *funcContext) fieldType(t *types.Struct, i int) types.Type { + return fc.typeResolver.Substitute(t.Field(i).Type()) +} + func (fc *funcContext) selectionOf(e *ast.SelectorExpr) (typesutil.Selection, bool) { if sel, ok := fc.pkgCtx.Selections[e]; ok { return fc.typeResolver.SubstituteSelection(sel), true @@ -933,11 +960,6 @@ func formatJSStructTagVal(jsTag string) string { return "." + jsTag } -// ErrorAt annotates an error with a position in the source code. -func ErrorAt(err error, fset *token.FileSet, pos token.Pos) error { - return fmt.Errorf("%s: %w", fset.Position(pos), err) -} - // FatalError is an error compiler panics with when it encountered a fatal error. // // FatalError implements io.Writer, which can be used to record any free-form diff --git a/go.mod b/go.mod index bf9d40d8e..faa94f070 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,16 @@ module github.com/gopherjs/gopherjs go 1.18 require ( - github.com/evanw/esbuild v0.18.0 + github.com/evanw/esbuild v0.25.4 github.com/fsnotify/fsnotify v1.5.1 github.com/google/go-cmp v0.5.8 + github.com/msvitok77/goembed v0.3.5 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 github.com/sirupsen/logrus v1.8.1 - github.com/spf13/cobra v1.2.1 - github.com/spf13/pflag v1.0.5 - github.com/visualfc/goembed v0.3.3 + github.com/spf13/cobra v1.9.1 + github.com/spf13/pflag v1.0.6 golang.org/x/sync v0.5.0 golang.org/x/sys v0.10.0 golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 @@ -20,6 +20,6 @@ require ( ) require ( - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect golang.org/x/mod v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 5c6b0d919..29dc8900b 100644 --- a/go.sum +++ b/go.sum @@ -1,599 +1,45 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanw/esbuild v0.18.0 h1:zJrquhC5ZiricRVQxMQTWqO8zYcV7F7OfUXstB9Ucbg= -github.com/evanw/esbuild v0.18.0/go.mod h1:iINY06rn799hi48UqEnaQvVfZWe6W9bET78LbvN8VWk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/evanw/esbuild v0.25.4 h1:k1bTSim+usBG27w7BfOCorhgx3tO+6bAfMj5pR+6SKg= +github.com/evanw/esbuild v0.25.4/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/msvitok77/goembed v0.3.5 h1:SNdkLLipv4YGNVWCVCn+/N01aSp7Ga6/YOcB+kYxnhk= +github.com/msvitok77/goembed v0.3.5/go.mod h1:ycBNmh+53HrsZPQfWOJHYXbu7vLwb1QYdJISOyKlnnc= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c h1:bY6ktFuJkt+ZXkX0RChQch2FtHpWQLVS8Qo1YasiIVk= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/visualfc/goembed v0.3.3 h1:pOL02L715tHKsLQVMcZz06tTzRDAHkJKJLRnCA22G9Q= -github.com/visualfc/goembed v0.3.3/go.mod h1:jCVCz/yTJGyslo6Hta+pYxWWBuq9ADCcIVZBTQ0/iVI= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/compiler/errors.go b/internal/errorList/errorList.go similarity index 98% rename from compiler/errors.go rename to internal/errorList/errorList.go index 48aed48ec..531a0f4e0 100644 --- a/compiler/errors.go +++ b/internal/errorList/errorList.go @@ -1,4 +1,4 @@ -package compiler +package errorList import ( "errors" diff --git a/internal/govendor/subst/export.go b/internal/govendor/subst/export.go index 38e394bda..00a77ca49 100644 --- a/internal/govendor/subst/export.go +++ b/internal/govendor/subst/export.go @@ -4,6 +4,7 @@ package subst import ( + "fmt" "go/types" ) @@ -17,33 +18,33 @@ type Subster struct { } // New creates a new Subster with a given list of type parameters and matching args. -func New(tc *types.Context, tParams []*types.TypeParam, tArgs []types.Type) *Subster { - assert(len(tParams) == len(tArgs), "New() argument count must match") +func New(tc *types.Context, tParams *types.TypeParamList, tArgs []types.Type) *Subster { + if tParams.Len() != len(tArgs) { + panic(fmt.Errorf("number of type parameters and arguments must match: %d => %d", tParams.Len(), len(tArgs))) + } - if len(tParams) == 0 { + if tParams.Len() == 0 && len(tArgs) == 0 { return nil } - subst := &subster{ - replacements: make(map[*types.TypeParam]types.Type, len(tParams)), - cache: make(map[types.Type]types.Type), - ctxt: tc, - scope: nil, - debug: false, - } - for i := 0; i < len(tParams); i++ { - subst.replacements[tParams[i]] = tArgs[i] - } - return &Subster{ - impl: subst, - } + subst := makeSubster(tc, nil, tParams, tArgs, false) + return &Subster{impl: subst} } -// Type returns a version of typ with all references to type parameters replaced -// with the corresponding type arguments. +// Type returns a version of typ with all references to type parameters +// replaced with the corresponding type arguments. func (s *Subster) Type(typ types.Type) types.Type { if s == nil { return typ } return s.impl.typ(typ) } + +// Types returns a version of ts with all references to type parameters +// replaced with the corresponding type arguments. +func (s *Subster) Types(ts []types.Type) []types.Type { + if s == nil { + return ts + } + return s.impl.types(ts) +} diff --git a/internal/govendor/subst/subst.go b/internal/govendor/subst/subst.go index 9020e94f9..825e3c7f1 100644 --- a/internal/govendor/subst/subst.go +++ b/internal/govendor/subst/subst.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Copy of https://cs.opensource.google/go/x/tools/+/refs/tags/v0.17.0:go/ssa/subst.go +// Any changes to this copy are labelled with GOPHERJS. package subst import ( @@ -81,9 +83,12 @@ func (subst *subster) typ(t types.Type) (res types.Type) { // fall through if result r will be identical to t, types.Identical(r, t). switch t := t.(type) { case *types.TypeParam: - r := subst.replacements[t] - assert(r != nil, "type param without replacement encountered") - return r + // GOPHERJS: Replaced an assert that was causing a panic for nested types with code from + // https://cs.opensource.google/go/x/tools/+/refs/tags/v0.33.0:go/ssa/subst.go;l=92 + if r := subst.replacements[t]; r != nil { + return r + } + return t case *types.Basic: return t diff --git a/internal/govendor/subst/subst_test.go b/internal/govendor/subst/subst_test.go index 53fadbcf0..832f0ebd4 100644 --- a/internal/govendor/subst/subst_test.go +++ b/internal/govendor/subst/subst_test.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Copy of https://cs.opensource.google/go/x/tools/+/refs/tags/v0.17.0:go/ssa/subst_test.go package subst import ( diff --git a/internal/govendor/subst/util.go b/internal/govendor/subst/util.go index 22072e39f..5b55c0310 100644 --- a/internal/govendor/subst/util.go +++ b/internal/govendor/subst/util.go @@ -6,18 +6,16 @@ package subst import "go/types" -// This file defines a number of miscellaneous utility functions. - -//// Sanity checking utilities - // assert panics with the mesage msg if p is false. // Avoid combining with expensive string formatting. +// From https://cs.opensource.google/go/x/tools/+/refs/tags/v0.17.0:go/ssa/util.go;l=27 func assert(p bool, msg string) { if !p { panic(msg) } } +// From https://cs.opensource.google/go/x/tools/+/refs/tags/v0.33.0:go/ssa/wrappers.go;l=262 func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignatureType(recv, nil, nil, s.Params(), s.Results(), s.Variadic()) } diff --git a/internal/srctesting/srctesting.go b/internal/srctesting/srctesting.go index 83499c6dd..e4242991c 100644 --- a/internal/srctesting/srctesting.go +++ b/internal/srctesting/srctesting.go @@ -158,6 +158,9 @@ func LookupObj(pkg *types.Package, name string) types.Object { for len(path) > 0 { obj = scope.Lookup(path[0]) + if obj == nil { + panic(fmt.Sprintf("failed to find %q in %q", path[0], name)) + } path = path[1:] if fun, ok := obj.(*types.Func); ok { @@ -170,6 +173,9 @@ func LookupObj(pkg *types.Package, name string) types.Object { if len(path) > 0 { obj, _, _ = types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), path[0]) path = path[1:] + if fun, ok := obj.(*types.Func); ok { + scope = fun.Scope() + } } } return obj @@ -187,9 +193,9 @@ type Source struct { // root package. At least one source file must be given. // The root package's path will be `command-line-arguments`. // -// The auxillary files can be for different packages but should have paths +// The auxiliary files can be for different packages but should have paths // added to the source name so that they can be grouped together by package. -// To import an auxillary package, the path should be prepended by +// To import an auxiliary package, the path should be prepended by // `github.com/gopherjs/gopherjs/compiler`. func ParseSources(t *testing.T, sourceFiles []Source, auxFiles []Source) *packages.Package { t.Helper() diff --git a/internal/testmain/testmain.go b/internal/testmain/testmain.go index f1b3257d5..3de87d382 100644 --- a/internal/testmain/testmain.go +++ b/internal/testmain/testmain.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" "go/ast" - gobuild "go/build" + "go/build" "go/doc" "go/parser" "go/token" @@ -16,7 +16,6 @@ import ( "unicode" "unicode/utf8" - "github.com/gopherjs/gopherjs/build" "golang.org/x/tools/go/buildutil" ) @@ -66,7 +65,8 @@ func (ef ExampleFunc) Executable() bool { // TestMain is a helper type responsible for generation of the test main package. type TestMain struct { - Package *build.PackageData + Package *build.Package + Context *build.Context Tests []TestFunc Benchmarks []TestFunc Fuzz []TestFunc @@ -88,7 +88,7 @@ func (tm *TestMain) Scan(fset *token.FileSet) error { func (tm *TestMain) scanPkg(fset *token.FileSet, files []string, loc FuncLocation) error { for _, name := range files { srcPath := path.Join(tm.Package.Dir, name) - f, err := buildutil.OpenFile(tm.Package.InternalBuildContext(), srcPath) + f, err := buildutil.OpenFile(tm.Context, srcPath) if err != nil { return fmt.Errorf("failed to open source file %q: %w", srcPath, err) } @@ -158,7 +158,7 @@ func (tm *TestMain) scanFile(f *ast.File, loc FuncLocation) error { } // Synthesize main package for the tests. -func (tm *TestMain) Synthesize(fset *token.FileSet) (*build.PackageData, *ast.File, error) { +func (tm *TestMain) Synthesize(fset *token.FileSet) (*build.Package, *ast.File, error) { buf := &bytes.Buffer{} if err := testmainTmpl.Execute(buf, tm); err != nil { return nil, nil, fmt.Errorf("failed to generate testmain source for package %s: %w", tm.Package.ImportPath, err) @@ -167,12 +167,10 @@ func (tm *TestMain) Synthesize(fset *token.FileSet) (*build.PackageData, *ast.Fi if err != nil { return nil, nil, fmt.Errorf("failed to parse testmain source for package %s: %w", tm.Package.ImportPath, err) } - pkg := &build.PackageData{ - Package: &gobuild.Package{ - ImportPath: tm.Package.ImportPath + ".testmain", - Name: "main", - GoFiles: []string{"_testmain.go"}, - }, + pkg := &build.Package{ + ImportPath: tm.Package.ImportPath + ".testmain", + Name: "main", + GoFiles: []string{"_testmain.go"}, } return pkg, src, nil } diff --git a/internal/testmain/testmain_test.go b/internal/testmain/testmain_test.go index 01c92cc76..8e0b268d2 100644 --- a/internal/testmain/testmain_test.go +++ b/internal/testmain/testmain_test.go @@ -7,6 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/gopherjs/gopherjs/build" "github.com/gopherjs/gopherjs/internal/srctesting" . "github.com/gopherjs/gopherjs/internal/testmain" @@ -21,7 +22,10 @@ func TestScan(t *testing.T) { fset := token.NewFileSet() - got := TestMain{Package: pkg} + got := TestMain{ + Package: pkg.Package, + Context: pkg.InternalBuildContext(), + } if err := got.Scan(fset); err != nil { t.Fatalf("Got: tm.Scan() returned error: %s. Want: no error.", err) } @@ -47,6 +51,7 @@ func TestScan(t *testing.T) { } opts := cmp.Options{ cmpopts.IgnoreFields(TestMain{}, "Package"), // Inputs. + cmpopts.IgnoreFields(TestMain{}, "Context"), } if diff := cmp.Diff(want, got, opts...); diff != "" { t.Errorf("List of test function is different from expected (-want,+got):\n%s", diff) @@ -54,9 +59,7 @@ func TestScan(t *testing.T) { } func TestSynthesize(t *testing.T) { - pkg := &build.PackageData{ - Package: &gobuild.Package{ImportPath: "foo/bar"}, - } + pkg := &gobuild.Package{ImportPath: "foo/bar"} tests := []struct { descr string diff --git a/tool.go b/tool.go index d72e187c6..46d6a6edc 100644 --- a/tool.go +++ b/tool.go @@ -4,10 +4,8 @@ import ( "bytes" "errors" "fmt" - "go/ast" "go/build" "go/scanner" - "go/token" "go/types" "io" "net" @@ -28,8 +26,8 @@ import ( gbuild "github.com/gopherjs/gopherjs/build" "github.com/gopherjs/gopherjs/build/cache" "github.com/gopherjs/gopherjs/compiler" + "github.com/gopherjs/gopherjs/internal/errorList" "github.com/gopherjs/gopherjs/internal/sysutil" - "github.com/gopherjs/gopherjs/internal/testmain" "github.com/neelance/sourcemap" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -147,7 +145,7 @@ func main() { if err != nil { return err } - archive, err := s.BuildPackage(pkg) + archive, err := s.BuildProject(pkg) if err != nil { return err } @@ -214,8 +212,7 @@ func main() { if err != nil { return err } - - archive, err := s.BuildPackage(pkg) + archive, err := s.BuildProject(pkg) if err != nil { return err } @@ -371,27 +368,8 @@ func main() { return err } - _, err = s.BuildPackage(pkg.TestPackage()) - if err != nil { - return err - } - _, err = s.BuildPackage(pkg.XTestPackage()) - if err != nil { - return err - } - - fset := token.NewFileSet() - tests := testmain.TestMain{Package: pkg} - tests.Scan(fset) - mainPkg, mainFile, err := tests.Synthesize(fset) - if err != nil { - return fmt.Errorf("failed to generate testmain package for %s: %w", pkg.ImportPath, err) - } - importContext := &compiler.ImportContext{ - Packages: s.Types, - Import: s.ImportResolverFor(mainPkg), - } - mainPkgArchive, err := compiler.Compile(mainPkg.ImportPath, []*ast.File{mainFile}, fset, importContext, options.Minify) + pkg.IsTest = true + mainPkgArchive, err := s.BuildProject(pkg) if err != nil { return fmt.Errorf("failed to compile testmain package for %s: %w", pkg.ImportPath, err) } @@ -664,7 +642,7 @@ func (fs serveCommandFileSystem) Open(requestName string) (http.File, error) { buf := new(bytes.Buffer) browserErrors := new(bytes.Buffer) err := func() error { - archive, err := s.BuildPackage(pkg) + archive, err := s.BuildProject(pkg) if err != nil { return err } @@ -673,7 +651,7 @@ func (fs serveCommandFileSystem) Open(requestName string) (http.File, error) { m := &sourcemap.Map{File: base + ".js"} sourceMapFilter.MappingCallback = s.SourceMappingCallback(m) - deps, err := compiler.ImportDependencies(archive, s.BuildImportPath) + deps, err := compiler.ImportDependencies(archive, s.ImportResolverFor("")) if err != nil { return err } @@ -789,7 +767,7 @@ func handleError(err error, options *gbuild.Options, browserErrors *bytes.Buffer switch err := err.(type) { case nil: return 0 - case compiler.ErrorList: + case errorList.ErrorList: for _, entry := range err { printError(entry, options, browserErrors) }