aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2023-12-07 10:55:03 +0100
committerTaras Madan <tarasmadan@google.com>2023-12-07 10:05:49 +0000
commit0a02ce36aee886cafdc6907db66a49859cf17caf (patch)
treef8da32141fee0c968938f30c09d033dd3bd90a0a
parente3299f55e91df371c35ba414e53898a130068a0e (diff)
Revert "mod: do: bump golang.org/x/tools from 0.14.0 to 0.16.0"
This reverts commit e3299f55e91df371c35ba414e53898a130068a0e.
-rw-r--r--go.mod4
-rw-r--r--go.sum8
-rw-r--r--vendor/golang.org/x/mod/modfile/rule.go12
-rw-r--r--vendor/golang.org/x/sys/execabs/execabs.go102
-rw-r--r--vendor/golang.org/x/sys/execabs/execabs_go118.go17
-rw-r--r--vendor/golang.org/x/sys/execabs/execabs_go119.go20
-rw-r--r--vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go26
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go10
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go3
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go16
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go32
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go49
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go30
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go3
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go9
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go7
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go4
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go10
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go16
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go54
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go13
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go33
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go14
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go7
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go13
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go11
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go9
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go2
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go277
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go96
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go8
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go21
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go18
-rw-r--r--vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go4
-rw-r--r--vendor/golang.org/x/tools/go/analysis/validate.go2
-rw-r--r--vendor/golang.org/x/tools/go/internal/cgo/cgo.go3
-rw-r--r--vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go2
-rw-r--r--vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go15
-rw-r--r--vendor/golang.org/x/tools/go/loader/loader.go2
-rw-r--r--vendor/golang.org/x/tools/go/packages/external.go2
-rw-r--r--vendor/golang.org/x/tools/go/packages/golist.go76
-rw-r--r--vendor/golang.org/x/tools/go/packages/golist_overlay.go492
-rw-r--r--vendor/golang.org/x/tools/go/packages/packages.go177
-rw-r--r--vendor/golang.org/x/tools/go/ssa/builder.go837
-rw-r--r--vendor/golang.org/x/tools/go/ssa/create.go171
-rw-r--r--vendor/golang.org/x/tools/go/ssa/doc.go3
-rw-r--r--vendor/golang.org/x/tools/go/ssa/emit.go96
-rw-r--r--vendor/golang.org/x/tools/go/ssa/func.go171
-rw-r--r--vendor/golang.org/x/tools/go/ssa/identical.go12
-rw-r--r--vendor/golang.org/x/tools/go/ssa/identical_17.go12
-rw-r--r--vendor/golang.org/x/tools/go/ssa/instantiate.go169
-rw-r--r--vendor/golang.org/x/tools/go/ssa/lift.go7
-rw-r--r--vendor/golang.org/x/tools/go/ssa/methods.go396
-rw-r--r--vendor/golang.org/x/tools/go/ssa/parameterized.go48
-rw-r--r--vendor/golang.org/x/tools/go/ssa/sanity.go3
-rw-r--r--vendor/golang.org/x/tools/go/ssa/source.go39
-rw-r--r--vendor/golang.org/x/tools/go/ssa/ssa.go129
-rw-r--r--vendor/golang.org/x/tools/go/ssa/ssautil/load.go39
-rw-r--r--vendor/golang.org/x/tools/go/ssa/ssautil/visit.go144
-rw-r--r--vendor/golang.org/x/tools/go/ssa/util.go31
-rw-r--r--vendor/golang.org/x/tools/go/ssa/wrappers.go205
-rw-r--r--vendor/golang.org/x/tools/go/types/objectpath/objectpath.go117
-rw-r--r--vendor/golang.org/x/tools/internal/diff/unified.go27
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go196
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go119
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go14
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go15
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go14
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go29
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go41
-rw-r--r--vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go153
-rw-r--r--vendor/golang.org/x/tools/internal/gocommand/invoke.go27
-rw-r--r--vendor/golang.org/x/tools/internal/gopathwalk/walk.go227
-rw-r--r--vendor/golang.org/x/tools/internal/packagesinternal/packages.go8
-rw-r--r--vendor/golang.org/x/tools/internal/testenv/testenv.go32
-rw-r--r--vendor/golang.org/x/tools/internal/typesinternal/objectpath.go24
-rw-r--r--vendor/golang.org/x/tools/internal/versions/gover.go172
-rw-r--r--vendor/golang.org/x/tools/internal/versions/types.go19
-rw-r--r--vendor/golang.org/x/tools/internal/versions/types_go121.go20
-rw-r--r--vendor/golang.org/x/tools/internal/versions/types_go122.go24
-rw-r--r--vendor/golang.org/x/tools/internal/versions/versions_go121.go49
-rw-r--r--vendor/golang.org/x/tools/internal/versions/versions_go122.go38
-rw-r--r--vendor/modules.txt7
83 files changed, 3169 insertions, 2444 deletions
diff --git a/go.mod b/go.mod
index d83c1f61e..8e4bd4e0a 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
golang.org/x/perf v0.0.0-20230221235046-aebcfb61e84c
golang.org/x/sync v0.5.0
golang.org/x/sys v0.15.0
- golang.org/x/tools v0.16.0
+ golang.org/x/tools v0.14.0
google.golang.org/api v0.153.0
google.golang.org/appengine/v2 v2.0.5
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17
@@ -208,7 +208,7 @@ require (
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect
golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect
- golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/mod v0.13.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
diff --git a/go.sum b/go.sum
index 9fbae9d9e..e1ec58157 100644
--- a/go.sum
+++ b/go.sum
@@ -742,8 +742,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-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/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
+golang.org/x/mod v0.13.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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -976,8 +976,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-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/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
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=
diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go
index 35fd1f534..e0869fa38 100644
--- a/vendor/golang.org/x/mod/modfile/rule.go
+++ b/vendor/golang.org/x/mod/modfile/rule.go
@@ -542,7 +542,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V
if strings.Contains(ns, "@") {
return nil, errorf("replacement module must match format 'path version', not 'path@version'")
}
- return nil, errorf("replacement module without version must be directory path (rooted or starting with . or ..)")
+ return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)")
}
if filepath.Separator == '/' && strings.Contains(ns, `\`) {
return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)")
@@ -555,6 +555,7 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V
}
if IsDirectoryPath(ns) {
return nil, errorf("replacement module directory path %q cannot have version", ns)
+
}
}
return &Replace{
@@ -678,15 +679,14 @@ func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string,
}
}
-// IsDirectoryPath reports whether the given path should be interpreted as a directory path.
-// Just like on the go command line, relative paths starting with a '.' or '..' path component
+// IsDirectoryPath reports whether the given path should be interpreted
+// as a directory path. Just like on the go command line, relative paths
// and rooted paths are directory paths; the rest are module paths.
func IsDirectoryPath(ns string) bool {
// Because go.mod files can move from one system to another,
// we check all known path syntaxes, both Unix and Windows.
- return ns == "." || strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, `.\`) ||
- ns == ".." || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, `..\`) ||
- strings.HasPrefix(ns, "/") || strings.HasPrefix(ns, `\`) ||
+ return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") ||
+ strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) ||
len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':'
}
diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go
new file mode 100644
index 000000000..3bf40fdfe
--- /dev/null
+++ b/vendor/golang.org/x/sys/execabs/execabs.go
@@ -0,0 +1,102 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package execabs is a drop-in replacement for os/exec
+// that requires PATH lookups to find absolute paths.
+// That is, execabs.Command("cmd") runs the same PATH lookup
+// as exec.Command("cmd"), but if the result is a path
+// which is relative, the Run and Start methods will report
+// an error instead of running the executable.
+//
+// See https://blog.golang.org/path-security for more information
+// about when it may be necessary or appropriate to use this package.
+package execabs
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "unsafe"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+// It is an alias for exec.ErrNotFound.
+var ErrNotFound = exec.ErrNotFound
+
+// Cmd represents an external command being prepared or run.
+// It is an alias for exec.Cmd.
+type Cmd = exec.Cmd
+
+// Error is returned by LookPath when it fails to classify a file as an executable.
+// It is an alias for exec.Error.
+type Error = exec.Error
+
+// An ExitError reports an unsuccessful exit by a command.
+// It is an alias for exec.ExitError.
+type ExitError = exec.ExitError
+
+func relError(file, path string) error {
+ return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path)
+}
+
+// LookPath searches for an executable named file in the directories
+// named by the PATH environment variable. If file contains a slash,
+// it is tried directly and the PATH is not consulted. The result will be
+// an absolute path.
+//
+// LookPath differs from exec.LookPath in its handling of PATH lookups,
+// which are used for file names without slashes. If exec.LookPath's
+// PATH lookup would have returned an executable from the current directory,
+// LookPath instead returns an error.
+func LookPath(file string) (string, error) {
+ path, err := exec.LookPath(file)
+ if err != nil && !isGo119ErrDot(err) {
+ return "", err
+ }
+ if filepath.Base(file) == file && !filepath.IsAbs(path) {
+ return "", relError(file, path)
+ }
+ return path, nil
+}
+
+func fixCmd(name string, cmd *exec.Cmd) {
+ if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) && !isGo119ErrFieldSet(cmd) {
+ // exec.Command was called with a bare binary name and
+ // exec.LookPath returned a path which is not absolute.
+ // Set cmd.lookPathErr and clear cmd.Path so that it
+ // cannot be run.
+ lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
+ if *lookPathErr == nil {
+ *lookPathErr = relError(name, cmd.Path)
+ }
+ cmd.Path = ""
+ }
+}
+
+// CommandContext is like Command but includes a context.
+//
+// The provided context is used to kill the process (by calling os.Process.Kill)
+// if the context becomes done before the command completes on its own.
+func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
+ cmd := exec.CommandContext(ctx, name, arg...)
+ fixCmd(name, cmd)
+ return cmd
+
+}
+
+// Command returns the Cmd struct to execute the named program with the given arguments.
+// See exec.Command for most details.
+//
+// Command differs from exec.Command in its handling of PATH lookups,
+// which are used when the program name contains no slashes.
+// If exec.Command would have returned an exec.Cmd configured to run an
+// executable from the current directory, Command instead
+// returns an exec.Cmd that will return an error from Start or Run.
+func Command(name string, arg ...string) *exec.Cmd {
+ cmd := exec.Command(name, arg...)
+ fixCmd(name, cmd)
+ return cmd
+}
diff --git a/vendor/golang.org/x/sys/execabs/execabs_go118.go b/vendor/golang.org/x/sys/execabs/execabs_go118.go
new file mode 100644
index 000000000..5627d70e3
--- /dev/null
+++ b/vendor/golang.org/x/sys/execabs/execabs_go118.go
@@ -0,0 +1,17 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.19
+
+package execabs
+
+import "os/exec"
+
+func isGo119ErrDot(err error) bool {
+ return false
+}
+
+func isGo119ErrFieldSet(cmd *exec.Cmd) bool {
+ return false
+}
diff --git a/vendor/golang.org/x/sys/execabs/execabs_go119.go b/vendor/golang.org/x/sys/execabs/execabs_go119.go
new file mode 100644
index 000000000..d60ab1b41
--- /dev/null
+++ b/vendor/golang.org/x/sys/execabs/execabs_go119.go
@@ -0,0 +1,20 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.19
+
+package execabs
+
+import (
+ "errors"
+ "os/exec"
+)
+
+func isGo119ErrDot(err error) bool {
+ return errors.Is(err, exec.ErrDot)
+}
+
+func isGo119ErrFieldSet(cmd *exec.Cmd) bool {
+ return cmd.Err != nil
+}
diff --git a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go
index 3c8935008..33ca77a06 100644
--- a/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go
+++ b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go
@@ -342,28 +342,20 @@ func applyFixes(roots []*action) error {
for _, edit := range sf.TextEdits {
// Validate the edit.
// Any error here indicates a bug in the analyzer.
- start, end := edit.Pos, edit.End
- file := act.pkg.Fset.File(start)
+ file := act.pkg.Fset.File(edit.Pos)
if file == nil {
return fmt.Errorf("analysis %q suggests invalid fix: missing file info for pos (%v)",
- act.a.Name, start)
+ act.a.Name, edit.Pos)
}
- if !end.IsValid() {
- end = start
- }
- if start > end {
+ if edit.Pos > edit.End {
return fmt.Errorf("analysis %q suggests invalid fix: pos (%v) > end (%v)",
- act.a.Name, start, end)
+ act.a.Name, edit.Pos, edit.End)
}
- if eof := token.Pos(file.Base() + file.Size()); end > eof {
+ if eof := token.Pos(file.Base() + file.Size()); edit.End > eof {
return fmt.Errorf("analysis %q suggests invalid fix: end (%v) past end of file (%v)",
- act.a.Name, end, eof)
- }
- edit := diff.Edit{
- Start: file.Offset(start),
- End: file.Offset(end),
- New: string(edit.NewText),
+ act.a.Name, edit.End, eof)
}
+ edit := diff.Edit{Start: file.Offset(edit.Pos), End: file.Offset(edit.End), New: string(edit.NewText)}
editsForTokenFile[file] = append(editsForTokenFile[file], edit)
}
}
@@ -493,11 +485,11 @@ func diff3Conflict(path string, xlabel, ylabel string, xedits, yedits []diff.Edi
}
oldlabel, old := "base", string(contents)
- xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits, diff.DefaultContextLines)
+ xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits)
if err != nil {
return err
}
- ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits, diff.DefaultContextLines)
+ ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits)
if err != nil {
return err
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
index 6976f0d90..f0b90a492 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/appends/appends.go
@@ -15,7 +15,6 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/go/types/typeutil"
)
//go:embed doc.go
@@ -37,9 +36,12 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
- b, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Builtin)
- if ok && b.Name() == "append" && len(call.Args) == 1 {
- pass.ReportRangef(call, "append with no values")
+ if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "append" {
+ if _, ok := pass.TypesInfo.Uses[ident].(*types.Builtin); ok {
+ if len(call.Args) == 1 {
+ pass.ReportRangef(call, "append with no values")
+ }
+ }
}
})
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
index 3bfd50122..10489bea1 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/assign/assign.go
@@ -18,7 +18,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
)
@@ -78,7 +77,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
// isMapIndex returns true if e is a map index expression.
func isMapIndex(info *types.Info, e ast.Expr) bool {
- if idx, ok := astutil.Unparen(e).(*ast.IndexExpr); ok {
+ if idx, ok := analysisutil.Unparen(e).(*ast.IndexExpr); ok {
if typ := info.Types[idx.X].Type; typ != nil {
_, ok := typ.Underlying().(*types.Map)
return ok
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
index 931f9ca75..b40e081ec 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
@@ -8,12 +8,12 @@ import (
_ "embed"
"go/ast"
"go/token"
+ "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/go/types/typeutil"
)
//go:embed doc.go
@@ -52,8 +52,18 @@ func run(pass *analysis.Pass) (interface{}, error) {
if !ok {
continue
}
- fn := typeutil.StaticCallee(pass.TypesInfo, call)
- if analysisutil.IsFunctionNamed(fn, "sync/atomic", "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr") {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ continue
+ }
+ pkgIdent, _ := sel.X.(*ast.Ident)
+ pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName)
+ if !ok || pkgName.Imported().Path() != "sync/atomic" {
+ continue
+ }
+
+ switch sel.Sel.Name {
+ case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
checkAtomicAddAssignment(pass, n.Lhs[i], call)
}
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go
index aff6d25b3..01683e45a 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go
@@ -18,7 +18,6 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/go/types/typeutil"
)
const Doc = "check for non-64-bits-aligned arguments to sync/atomic functions"
@@ -43,20 +42,31 @@ func run(pass *analysis.Pass) (interface{}, error) {
nodeFilter := []ast.Node{
(*ast.CallExpr)(nil),
}
- funcNames := []string{
- "AddInt64", "AddUint64",
- "LoadInt64", "LoadUint64",
- "StoreInt64", "StoreUint64",
- "SwapInt64", "SwapUint64",
- "CompareAndSwapInt64", "CompareAndSwapUint64",
- }
inspect.Preorder(nodeFilter, func(node ast.Node) {
call := node.(*ast.CallExpr)
- fn := typeutil.StaticCallee(pass.TypesInfo, call)
- if analysisutil.IsFunctionNamed(fn, "sync/atomic", funcNames...) {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ pkgIdent, ok := sel.X.(*ast.Ident)
+ if !ok {
+ return
+ }
+ pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName)
+ if !ok || pkgName.Imported().Path() != "sync/atomic" {
+ return
+ }
+
+ switch sel.Sel.Name {
+ case "AddInt64", "AddUint64",
+ "LoadInt64", "LoadUint64",
+ "StoreInt64", "StoreUint64",
+ "SwapInt64", "SwapUint64",
+ "CompareAndSwapInt64", "CompareAndSwapUint64":
+
// For all the listed functions, the expression to check is always the first function argument.
- check64BitAlignment(pass, fn.Name(), call.Args[0])
+ check64BitAlignment(pass, sel.Sel.Name, call.Args[0])
}
})
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
index 564329774..4219f087b 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
@@ -14,7 +14,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
)
@@ -84,7 +83,7 @@ func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[*
i := 0
var sets [][]ast.Expr
for j := 0; j <= len(exprs); j++ {
- if j == len(exprs) || analysisutil.HasSideEffects(info, exprs[j]) {
+ if j == len(exprs) || hasSideEffects(info, exprs[j]) {
if i < j {
sets = append(sets, exprs[i:j])
}
@@ -163,13 +162,46 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) {
}
}
+// hasSideEffects reports whether evaluation of e has side effects.
+func hasSideEffects(info *types.Info, e ast.Expr) bool {
+ safe := true
+ ast.Inspect(e, func(node ast.Node) bool {
+ switch n := node.(type) {
+ case *ast.CallExpr:
+ typVal := info.Types[n.Fun]
+ switch {
+ case typVal.IsType():
+ // Type conversion, which is safe.
+ case typVal.IsBuiltin():
+ // Builtin func, conservatively assumed to not
+ // be safe for now.
+ safe = false
+ return false
+ default:
+ // A non-builtin func or method call.
+ // Conservatively assume that all of them have
+ // side effects for now.
+ safe = false
+ return false
+ }
+ case *ast.UnaryExpr:
+ if n.Op == token.ARROW {
+ safe = false
+ return false
+ }
+ }
+ return true
+ })
+ return !safe
+}
+
// split returns a slice of all subexpressions in e that are connected by op.
// For example, given 'a || (b || c) || d' with the or op,
// split returns []{d, c, b, a}.
// seen[e] is already true; any newly processed exprs are added to seen.
func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.Expr) {
for {
- e = astutil.Unparen(e)
+ e = unparen(e)
if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
seen[b] = true
exprs = append(exprs, op.split(b.Y, seen)...)
@@ -181,3 +213,14 @@ func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.E
}
return
}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+ for {
+ p, ok := e.(*ast.ParenExpr)
+ if !ok {
+ return e
+ }
+ e = p.X
+ }
+}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go
index f077ea282..881b8fd67 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go
@@ -26,13 +26,15 @@ var Analyzer = &analysis.Analyzer{
}
// SSA provides SSA-form intermediate representation for all the
-// source functions in the current package.
+// non-blank source functions in the current package.
type SSA struct {
Pkg *ssa.Package
SrcFuncs []*ssa.Function
}
func run(pass *analysis.Pass) (interface{}, error) {
+ // Plundered from ssautil.BuildPackage.
+
// We must create a new Program for each Package because the
// analysis API provides no place to hang a Program shared by
// all Packages. Consequently, SSA Packages and Functions do not
@@ -49,10 +51,20 @@ func run(pass *analysis.Pass) (interface{}, error) {
prog := ssa.NewProgram(pass.Fset, mode)
- // Create SSA packages for direct imports.
- for _, p := range pass.Pkg.Imports() {
- prog.CreatePackage(p, nil, nil, true)
+ // Create SSA packages for all imports.
+ // Order is not significant.
+ created := make(map[*types.Package]bool)
+ var createAll func(pkgs []*types.Package)
+ createAll = func(pkgs []*types.Package) {
+ for _, p := range pkgs {
+ if !created[p] {
+ created[p] = true
+ prog.CreatePackage(p, nil, nil, true)
+ createAll(p.Imports())
+ }
+ }
}
+ createAll(pass.Pkg.Imports())
// Create and build the primary package.
ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false)
@@ -64,6 +76,16 @@ func run(pass *analysis.Pass) (interface{}, error) {
for _, f := range pass.Files {
for _, decl := range f.Decls {
if fdecl, ok := decl.(*ast.FuncDecl); ok {
+
+ // SSA will not build a Function
+ // for a FuncDecl named blank.
+ // That's arguably too strict but
+ // relaxing it would break uniqueness of
+ // names of package members.
+ if fdecl.Name.Name == "_" {
+ continue
+ }
+
// (init functions have distinct Func
// objects named "init" and distinct
// ssa.Functions named "init#1", ...)
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
index 4e8643975..98d9a777a 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
@@ -19,7 +19,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
)
const debug = false
@@ -65,7 +64,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t
// Is this a C.f() call?
var name string
- if sel, ok := astutil.Unparen(call.Fun).(*ast.SelectorExpr); ok {
+ if sel, ok := analysisutil.Unparen(call.Fun).(*ast.SelectorExpr); ok {
if id, ok := sel.X.(*ast.Ident); ok && id.Name == "C" {
name = sel.Sel.Name
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
index 2eeb0a330..ec7727de7 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
@@ -16,7 +16,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/typeparams"
)
@@ -224,7 +223,7 @@ func (path typePath) String() string {
}
func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
- x = astutil.Unparen(x) // ignore parens on rhs
+ x = analysisutil.Unparen(x) // ignore parens on rhs
if _, ok := x.(*ast.CompositeLit); ok {
return nil
@@ -234,7 +233,7 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
return nil
}
if star, ok := x.(*ast.StarExpr); ok {
- if _, ok := astutil.Unparen(star.X).(*ast.CallExpr); ok {
+ if _, ok := analysisutil.Unparen(star.X).(*ast.CallExpr); ok {
// A call may return a pointer to a zero value.
return nil
}
@@ -320,7 +319,9 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
// In go1.10, sync.noCopy did not implement Locker.
// (The Unlock method was added only in CL 121876.)
// TODO(adonovan): remove workaround when we drop go1.10.
- if analysisutil.IsNamedType(typ, "sync", "noCopy") {
+ if named, ok := typ.(*types.Named); ok &&
+ named.Obj().Name() == "noCopy" &&
+ named.Obj().Pkg().Path() == "sync" {
return []string{typ.String()}
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go
index 1a83bddbc..3a1818764 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go
@@ -46,8 +46,11 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
- fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
- if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) {
+ fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
+ if !ok {
+ return
+ }
+ if fn.FullName() == "reflect.DeepEqual" && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) {
pass.ReportRangef(call, "avoid using reflect.DeepEqual with errors")
}
})
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
index 5e8e80a6a..ed2a122f2 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/defers/defers.go
@@ -7,6 +7,7 @@ package defers
import (
_ "embed"
"go/ast"
+ "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -35,7 +36,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
checkDeferCall := func(node ast.Node) bool {
switch v := node.(type) {
case *ast.CallExpr:
- if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") {
+ fn, ok := typeutil.Callee(pass.TypesInfo, v).(*types.Func)
+ if ok && fn.Name() == "Since" && fn.Pkg().Path() == "time" {
pass.Reportf(v.Pos(), "call to time.Since is not deferred")
}
case *ast.FuncLit:
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
index 7f62ad4c8..2fcbdfafb 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
@@ -51,12 +51,15 @@ func run(pass *analysis.Pass) (interface{}, error) {
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
fn := typeutil.StaticCallee(pass.TypesInfo, call)
- if !analysisutil.IsFunctionNamed(fn, "errors", "As") {
- return
+ if fn == nil {
+ return // not a static call
}
if len(call.Args) < 2 {
return // not enough arguments, e.g. called with return values of another function
}
+ if fn.FullName() != "errors.As" {
+ return
+ }
if err := checkAsTarget(pass, call.Args[1]); err != nil {
pass.ReportRangef(call, "%v", err)
}
@@ -66,6 +69,9 @@ func run(pass *analysis.Pass) (interface{}, error) {
var errorType = types.Universe.Lookup("error").Type()
+// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error,
+// or is the empty interface.
+
// checkAsTarget reports an error if the second argument to errors.As is invalid.
func checkAsTarget(pass *analysis.Pass, e ast.Expr) error {
t := pass.TypesInfo.Types[e].Type
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
index c6b6c81b4..61c3b764f 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
@@ -116,7 +116,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
if res.Len() != 2 {
return false // the function called does not return two values.
}
- if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !analysisutil.IsNamedType(ptr.Elem(), "net/http", "Response") {
+ if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") {
return false // the first return type is not *http.Response.
}
@@ -131,11 +131,11 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
return ok && id.Name == "http" // function in net/http package.
}
- if analysisutil.IsNamedType(typ, "net/http", "Client") {
+ if isNamedType(typ, "net/http", "Client") {
return true // method on http.Client.
}
ptr, ok := typ.(*types.Pointer)
- return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
+ return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
}
// restOfBlock, given a traversal stack, finds the innermost containing
@@ -171,3 +171,13 @@ func rootIdent(n ast.Node) *ast.Ident {
return nil
}
}
+
+// isNamedType reports whether t is the named type path.name.
+func isNamedType(t types.Type, path, name string) bool {
+ n, ok := t.(*types.Named)
+ if !ok {
+ return false
+ }
+ obj := n.Obj()
+ return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path
+}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
index c0060753f..a8d84034d 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/internal/analysisutil/util.go
@@ -55,6 +55,17 @@ func HasSideEffects(info *types.Info, e ast.Expr) bool {
return !safe
}
+// Unparen returns e with any enclosing parentheses stripped.
+func Unparen(e ast.Expr) ast.Expr {
+ for {
+ p, ok := e.(*ast.ParenExpr)
+ if !ok {
+ return e
+ }
+ e = p.X
+ }
+}
+
// ReadFile reads a file and adds it to the FileSet
// so that we can report errors against it using lineStart.
func ReadFile(fset *token.FileSet, filename string) ([]byte, *token.File, error) {
@@ -107,46 +118,3 @@ func Imports(pkg *types.Package, path string) bool {
}
return false
}
-
-// IsNamedType reports whether t is the named type with the given package path
-// and one of the given names.
-// This function avoids allocating the concatenation of "pkg.Name",
-// which is important for the performance of syntax matching.
-func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
- n, ok := t.(*types.Named)
- if !ok {
- return false
- }
- obj := n.Obj()
- if obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != pkgPath {
- return false
- }
- name := obj.Name()
- for _, n := range names {
- if name == n {
- return true
- }
- }
- return false
-}
-
-// IsFunctionNamed reports whether f is a top-level function defined in the
-// given package and has one of the given names.
-// It returns false if f is nil or a method.
-func IsFunctionNamed(f *types.Func, pkgPath string, names ...string) bool {
- if f == nil {
- return false
- }
- if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
- return false
- }
- if f.Type().(*types.Signature).Recv() != nil {
- return false
- }
- for _, n := range names {
- if f.Name() == n {
- return true
- }
- }
- return false
-}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go
index c95b1c1c9..dc544df1b 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go
@@ -14,12 +14,8 @@
// in such a way (e.g. with go or defer) that it may outlive the loop
// iteration and possibly observe the wrong value of the variable.
//
-// Note: An iteration variable can only outlive a loop iteration in Go versions <=1.21.
-// In Go 1.22 and later, the loop variable lifetimes changed to create a new
-// iteration variable per loop iteration. (See go.dev/issue/60078.)
-//
// In this example, all the deferred functions run after the loop has
-// completed, so all observe the final value of v [<go1.22].
+// completed, so all observe the final value of v.
//
// for _, v := range list {
// defer func() {
@@ -36,10 +32,7 @@
// }()
// }
//
-// After Go version 1.22, the previous two for loops are equivalent
-// and both are correct.
-//
-// The next example uses a go statement and has a similar problem [<go1.22].
+// The next example uses a go statement and has a similar problem.
// In addition, it has a data race because the loop updates v
// concurrent with the goroutines accessing it.
//
@@ -63,7 +56,7 @@
// }
//
// The t.Parallel() call causes the rest of the function to execute
-// concurrent with the loop [<go1.22].
+// concurrent with the loop.
//
// The analyzer reports references only in the last statement,
// as it is not deep enough to understand the effects of subsequent
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
index 4724c9f3b..5620c35fa 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
@@ -14,7 +14,6 @@ import (
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
- "golang.org/x/tools/internal/versions"
)
//go:embed doc.go
@@ -32,15 +31,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
- (*ast.File)(nil),
(*ast.RangeStmt)(nil),
(*ast.ForStmt)(nil),
}
- inspect.Nodes(nodeFilter, func(n ast.Node, push bool) bool {
- if !push {
- // inspect.Nodes is slightly suboptimal as we only use push=true.
- return true
- }
+ inspect.Preorder(nodeFilter, func(n ast.Node) {
// Find the variables updated by the loop statement.
var vars []types.Object
addVar := func(expr ast.Expr) {
@@ -52,11 +46,6 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
var body *ast.BlockStmt
switch n := n.(type) {
- case *ast.File:
- // Only traverse the file if its goversion is strictly before go1.22.
- goversion := versions.Lang(versions.FileVersions(pass.TypesInfo, n))
- // goversion is empty for older go versions (or the version is invalid).
- return goversion == "" || versions.Compare(goversion, "go1.22") < 0
case *ast.RangeStmt:
body = n.Body
addVar(n.Key)
@@ -75,7 +64,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
}
if vars == nil {
- return true
+ return
}
// Inspect statements to find function literals that may be run outside of
@@ -124,7 +113,6 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
}
}
- return true
})
return nil, nil
}
@@ -371,5 +359,20 @@ func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method str
if ptr, ok := recv.Type().(*types.Pointer); ok {
rtype = ptr.Elem()
}
- return analysisutil.IsNamedType(rtype, pkgPath, typeName)
+ named, ok := rtype.(*types.Named)
+ if !ok {
+ return false
+ }
+ if named.Obj().Name() != typeName {
+ return false
+ }
+ pkg := f.Pkg()
+ if pkg == nil {
+ return false
+ }
+ if pkg.Path() != pkgPath {
+ return false
+ }
+
+ return true
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go b/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go
index c4999f7a9..d1ca0748e 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/nilness/nilness.go
@@ -38,15 +38,11 @@ func run(pass *analysis.Pass) (interface{}, error) {
func runFunc(pass *analysis.Pass, fn *ssa.Function) {
reportf := func(category string, pos token.Pos, format string, args ...interface{}) {
- // We ignore nil-checking ssa.Instructions
- // that don't correspond to syntax.
- if pos.IsValid() {
- pass.Report(analysis.Diagnostic{
- Pos: pos,
- Category: category,
- Message: fmt.Sprintf(format, args...),
- })
- }
+ pass.Report(analysis.Diagnostic{
+ Pos: pos,
+ Category: category,
+ Message: fmt.Sprintf(format, args...),
+ })
}
// notNil reports an error if v is provably nil.
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
index 070654f01..b2b8c67c7 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
@@ -511,10 +511,15 @@ func isFormatter(typ types.Type) bool {
sig := fn.Type().(*types.Signature)
return sig.Params().Len() == 2 &&
sig.Results().Len() == 0 &&
- analysisutil.IsNamedType(sig.Params().At(0).Type(), "fmt", "State") &&
+ isNamed(sig.Params().At(0).Type(), "fmt", "State") &&
types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune])
}
+func isNamed(T types.Type, pkgpath, name string) bool {
+ named, ok := T.(*types.Named)
+ return ok && named.Obj().Pkg().Path() == pkgpath && named.Obj().Name() == name
+}
+
// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
// It is constructed by parsePrintfVerb.
type formatState struct {
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
index 6789d7357..27677139e 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/reflectvaluecompare/reflectvaluecompare.go
@@ -49,8 +49,11 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
}
case *ast.CallExpr:
- fn, _ := typeutil.Callee(pass.TypesInfo, n).(*types.Func)
- if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && (isReflectValue(pass, n.Args[0]) || isReflectValue(pass, n.Args[1])) {
+ fn, ok := typeutil.Callee(pass.TypesInfo, n).(*types.Func)
+ if !ok {
+ return
+ }
+ if fn.FullName() == "reflect.DeepEqual" && (isReflectValue(pass, n.Args[0]) || isReflectValue(pass, n.Args[1])) {
pass.ReportRangef(n, "avoid using reflect.DeepEqual with reflect.Value")
}
}
@@ -65,7 +68,11 @@ func isReflectValue(pass *analysis.Pass, e ast.Expr) bool {
return false
}
// See if the type is reflect.Value
- if !analysisutil.IsNamedType(tv.Type, "reflect", "Value") {
+ named, ok := tv.Type.(*types.Named)
+ if !ok {
+ return false
+ }
+ if obj := named.Obj(); obj == nil || obj.Pkg() == nil || obj.Pkg().Path() != "reflect" || obj.Name() != "Value" {
return false
}
if _, ok := e.(*ast.CompositeLit); ok {
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go b/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
index a1323c3e6..92c1da8ef 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/slog/slog.go
@@ -139,7 +139,7 @@ func run(pass *analysis.Pass) (any, error) {
}
func isAttr(t types.Type) bool {
- return analysisutil.IsNamedType(t, "log/slog", "Attr")
+ return isNamed(t, "log/slog", "Attr")
}
// shortName returns a name for the function that is shorter than FullName.
@@ -232,3 +232,12 @@ func isMethodExpr(info *types.Info, c *ast.CallExpr) bool {
sel := info.Selections[s]
return sel != nil && sel.Kind() == types.MethodExpr
}
+
+// isNamed reports whether t is exactly a named type in a package with a given path.
+func isNamed(t types.Type, path, name string) bool {
+ if n, ok := t.(*types.Named); ok {
+ obj := n.Obj()
+ return obj.Pkg() != nil && obj.Pkg().Path() == path && obj.Name() == name
+ }
+ return false
+}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go b/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go
index 6c151a02c..1fe206b0f 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/sortslice/analyzer.go
@@ -47,7 +47,12 @@ func run(pass *analysis.Pass) (interface{}, error) {
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
- if !analysisutil.IsFunctionNamed(fn, "sort", "Slice", "SliceStable", "SliceIsSorted") {
+ if fn == nil {
+ return
+ }
+
+ fnName := fn.FullName()
+ if fnName != "sort.Slice" && fnName != "sort.SliceStable" && fnName != "sort.SliceIsSorted" {
return
}
@@ -126,7 +131,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
pass.Report(analysis.Diagnostic{
Pos: call.Pos(),
End: call.End(),
- Message: fmt.Sprintf("%s's argument must be a slice; is called with %s", fn.FullName(), typ.String()),
+ Message: fmt.Sprintf("%s's argument must be a slice; is called with %s", fnName, typ.String()),
SuggestedFixes: fixes,
})
})
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go
index 4cd5b71e9..a68adb12b 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/doc.go
@@ -7,7 +7,7 @@
//
// # Analyzer testinggoroutine
//
-// testinggoroutine: report calls to (*testing.T).Fatal from goroutines started by a test
+// testinggoroutine: report calls to (*testing.T).Fatal from goroutines started by a test.
//
// Functions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and
// Skip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
index dc5307a15..907b71503 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/testinggoroutine.go
@@ -6,28 +6,18 @@ package testinggoroutine
import (
_ "embed"
- "fmt"
"go/ast"
- "go/token"
- "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
- "golang.org/x/tools/go/types/typeutil"
+ "golang.org/x/tools/internal/typeparams"
)
//go:embed doc.go
var doc string
-var reportSubtest bool
-
-func init() {
- Analyzer.Flags.BoolVar(&reportSubtest, "subtest", false, "whether to check if t.Run subtest is terminated correctly; experimental")
-}
-
var Analyzer = &analysis.Analyzer{
Name: "testinggoroutine",
Doc: analysisutil.MustExtractDoc(doc, "testinggoroutine"),
@@ -36,6 +26,15 @@ var Analyzer = &analysis.Analyzer{
Run: run,
}
+var forbidden = map[string]bool{
+ "FailNow": true,
+ "Fatal": true,
+ "Fatalf": true,
+ "Skip": true,
+ "Skipf": true,
+ "SkipNow": true,
+}
+
func run(pass *analysis.Pass) (interface{}, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
@@ -43,90 +42,38 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
- toDecl := localFunctionDecls(pass.TypesInfo, pass.Files)
-
- // asyncs maps nodes whose statements will be executed concurrently
- // with respect to some test function, to the call sites where they
- // are invoked asynchronously. There may be multiple such call sites
- // for e.g. test helpers.
- asyncs := make(map[ast.Node][]*asyncCall)
- var regions []ast.Node
- addCall := func(c *asyncCall) {
- if c != nil {
- r := c.region
- if asyncs[r] == nil {
- regions = append(regions, r)
- }
- asyncs[r] = append(asyncs[r], c)
- }
+ // Filter out anything that isn't a function declaration.
+ onlyFuncs := []ast.Node{
+ (*ast.FuncDecl)(nil),
}
- // Collect all of the go callee() and t.Run(name, callee) extents.
- inspect.Nodes([]ast.Node{
- (*ast.FuncDecl)(nil),
- (*ast.GoStmt)(nil),
- (*ast.CallExpr)(nil),
- }, func(node ast.Node, push bool) bool {
- if !push {
+ inspect.Nodes(onlyFuncs, func(node ast.Node, push bool) bool {
+ fnDecl, ok := node.(*ast.FuncDecl)
+ if !ok {
return false
}
- switch node := node.(type) {
- case *ast.FuncDecl:
- return hasBenchmarkOrTestParams(node)
-
- case *ast.GoStmt:
- c := goAsyncCall(pass.TypesInfo, node, toDecl)
- addCall(c)
- case *ast.CallExpr:
- c := tRunAsyncCall(pass.TypesInfo, node)
- addCall(c)
+ if !hasBenchmarkOrTestParams(fnDecl) {
+ return false
}
- return true
- })
- // Check for t.Forbidden() calls within each region r that is a
- // callee in some go r() or a t.Run("name", r).
- //
- // Also considers a special case when r is a go t.Forbidden() call.
- for _, region := range regions {
- ast.Inspect(region, func(n ast.Node) bool {
- if n == region {
- return true // always descend into the region itself.
- } else if asyncs[n] != nil {
- return false // will be visited by another region.
- }
-
- call, ok := n.(*ast.CallExpr)
+ // Now traverse the benchmark/test's body and check that none of the
+ // forbidden methods are invoked in the goroutines within the body.
+ ast.Inspect(fnDecl, func(n ast.Node) bool {
+ goStmt, ok := n.(*ast.GoStmt)
if !ok {
return true
}
- x, sel, fn := forbiddenMethod(pass.TypesInfo, call)
- if x == nil {
- return true
- }
- for _, e := range asyncs[region] {
- if !withinScope(e.scope, x) {
- forbidden := formatMethod(sel, fn) // e.g. "(*testing.T).Forbidden
+ checkGoStmt(pass, goStmt)
- var context string
- var where analysis.Range = e.async // Put the report at the go fun() or t.Run(name, fun).
- if _, local := e.fun.(*ast.FuncLit); local {
- where = call // Put the report at the t.Forbidden() call.
- } else if id, ok := e.fun.(*ast.Ident); ok {
- context = fmt.Sprintf(" (%s calls %s)", id.Name, forbidden)
- }
- if _, ok := e.async.(*ast.GoStmt); ok {
- pass.ReportRangef(where, "call to %s from a non-test goroutine%s", forbidden, context)
- } else if reportSubtest {
- pass.ReportRangef(where, "call to %s on %s defined outside of the subtest%s", forbidden, x.Name(), context)
- }
- }
- }
- return true
+ // No need to further traverse the GoStmt since right
+ // above we manually traversed it in the ast.Inspect(goStmt, ...)
+ return false
})
- }
+
+ return false
+ })
return nil, nil
}
@@ -153,6 +100,7 @@ func typeIsTestingDotTOrB(expr ast.Expr) (string, bool) {
if !ok {
return "", false
}
+
varPkg := selExpr.X.(*ast.Ident)
if varPkg.Name != "testing" {
return "", false
@@ -163,116 +111,73 @@ func typeIsTestingDotTOrB(expr ast.Expr) (string, bool) {
return varTypeName, ok
}
-// asyncCall describes a region of code that needs to be checked for
-// t.Forbidden() calls as it is started asynchronously from an async
-// node go fun() or t.Run(name, fun).
-type asyncCall struct {
- region ast.Node // region of code to check for t.Forbidden() calls.
- async ast.Node // *ast.GoStmt or *ast.CallExpr (for t.Run)
- scope ast.Node // Report t.Forbidden() if t is not declared within scope.
- fun ast.Expr // fun in go fun() or t.Run(name, fun)
-}
-
-// withinScope returns true if x.Pos() is in [scope.Pos(), scope.End()].
-func withinScope(scope ast.Node, x *types.Var) bool {
- if scope != nil {
- return x.Pos() != token.NoPos && scope.Pos() <= x.Pos() && x.Pos() <= scope.End()
- }
- return false
-}
-
-// goAsyncCall returns the extent of a call from a go fun() statement.
-func goAsyncCall(info *types.Info, goStmt *ast.GoStmt, toDecl func(*types.Func) *ast.FuncDecl) *asyncCall {
- call := goStmt.Call
-
- fun := astutil.Unparen(call.Fun)
- if id := funcIdent(fun); id != nil {
- if lit := funcLitInScope(id); lit != nil {
- return &asyncCall{region: lit, async: goStmt, scope: nil, fun: fun}
+// goStmtFunc returns the ast.Node of a call expression
+// that was invoked as a go statement. Currently, only
+// function literals declared in the same function, and
+// static calls within the same package are supported.
+func goStmtFun(goStmt *ast.GoStmt) ast.Node {
+ switch fun := goStmt.Call.Fun.(type) {
+ case *ast.IndexExpr, *typeparams.IndexListExpr:
+ x, _, _, _ := typeparams.UnpackIndexExpr(fun)
+ id, _ := x.(*ast.Ident)
+ if id == nil {
+ break
}
- }
-
- if fn := typeutil.StaticCallee(info, call); fn != nil { // static call or method in the package?
- if decl := toDecl(fn); decl != nil {
- return &asyncCall{region: decl, async: goStmt, scope: nil, fun: fun}
+ if id.Obj == nil {
+ break
}
- }
-
- // Check go statement for go t.Forbidden() or go func(){t.Forbidden()}().
- return &asyncCall{region: goStmt, async: goStmt, scope: nil, fun: fun}
-}
-
-// tRunAsyncCall returns the extent of a call from a t.Run("name", fun) expression.
-func tRunAsyncCall(info *types.Info, call *ast.CallExpr) *asyncCall {
- if len(call.Args) != 2 {
- return nil
- }
- run := typeutil.Callee(info, call)
- if run, ok := run.(*types.Func); !ok || !isMethodNamed(run, "testing", "Run") {
- return nil
- }
-
- fun := astutil.Unparen(call.Args[1])
- if lit, ok := fun.(*ast.FuncLit); ok { // function lit?
- return &asyncCall{region: lit, async: call, scope: lit, fun: fun}
- }
-
- if id := funcIdent(fun); id != nil {
- if lit := funcLitInScope(id); lit != nil { // function lit in variable?
- return &asyncCall{region: lit, async: call, scope: lit, fun: fun}
+ if funDecl, ok := id.Obj.Decl.(ast.Node); ok {
+ return funDecl
+ }
+ case *ast.Ident:
+ // TODO(cuonglm): improve this once golang/go#48141 resolved.
+ if fun.Obj == nil {
+ break
+ }
+ if funDecl, ok := fun.Obj.Decl.(ast.Node); ok {
+ return funDecl
}
+ case *ast.FuncLit:
+ return goStmt.Call.Fun
}
-
- // Check within t.Run(name, fun) for calls to t.Forbidden,
- // e.g. t.Run(name, func(t *testing.T){ t.Forbidden() })
- return &asyncCall{region: call, async: call, scope: fun, fun: fun}
-}
-
-var forbidden = []string{
- "FailNow",
- "Fatal",
- "Fatalf",
- "Skip",
- "Skipf",
- "SkipNow",
+ return goStmt.Call
}
-// forbiddenMethod decomposes a call x.m() into (x, x.m, m) where
-// x is a variable, x.m is a selection, and m is the static callee m.
-// Returns (nil, nil, nil) if call is not of this form.
-func forbiddenMethod(info *types.Info, call *ast.CallExpr) (*types.Var, *types.Selection, *types.Func) {
- // Compare to typeutil.StaticCallee.
- fun := astutil.Unparen(call.Fun)
- selExpr, ok := fun.(*ast.SelectorExpr)
- if !ok {
- return nil, nil, nil
- }
- sel := info.Selections[selExpr]
- if sel == nil {
- return nil, nil, nil
- }
-
- var x *types.Var
- if id, ok := astutil.Unparen(selExpr.X).(*ast.Ident); ok {
- x, _ = info.Uses[id].(*types.Var)
- }
- if x == nil {
- return nil, nil, nil
- }
+// checkGoStmt traverses the goroutine and checks for the
+// use of the forbidden *testing.(B, T) methods.
+func checkGoStmt(pass *analysis.Pass, goStmt *ast.GoStmt) {
+ fn := goStmtFun(goStmt)
+ // Otherwise examine the goroutine to check for the forbidden methods.
+ ast.Inspect(fn, func(n ast.Node) bool {
+ selExpr, ok := n.(*ast.SelectorExpr)
+ if !ok {
+ return true
+ }
- fn, _ := sel.Obj().(*types.Func)
- if fn == nil || !isMethodNamed(fn, "testing", forbidden...) {
- return nil, nil, nil
- }
- return x, sel, fn
-}
+ _, bad := forbidden[selExpr.Sel.Name]
+ if !bad {
+ return true
+ }
-func formatMethod(sel *types.Selection, fn *types.Func) string {
- var ptr string
- rtype := sel.Recv()
- if p, ok := rtype.(*types.Pointer); ok {
- ptr = "*"
- rtype = p.Elem()
- }
- return fmt.Sprintf("(%s%s).%s", ptr, rtype.String(), fn.Name())
+ // Now filter out false positives by the import-path/type.
+ ident, ok := selExpr.X.(*ast.Ident)
+ if !ok {
+ return true
+ }
+ if ident.Obj == nil || ident.Obj.Decl == nil {
+ return true
+ }
+ field, ok := ident.Obj.Decl.(*ast.Field)
+ if !ok {
+ return true
+ }
+ if typeName, ok := typeIsTestingDotTOrB(field.Type); ok {
+ var fnRange analysis.Range = goStmt
+ if _, ok := fn.(*ast.FuncLit); ok {
+ fnRange = selExpr
+ }
+ pass.ReportRangef(fnRange, "call to (*%s).%s from a non-test goroutine", typeName, selExpr.Sel)
+ }
+ return true
+ })
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go b/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
deleted file mode 100644
index 805ccf49e..000000000
--- a/vendor/golang.org/x/tools/go/analysis/passes/testinggoroutine/util.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package testinggoroutine
-
-import (
- "go/ast"
- "go/types"
-
- "golang.org/x/tools/go/ast/astutil"
- "golang.org/x/tools/internal/typeparams"
-)
-
-// AST and types utilities that not specific to testinggoroutines.
-
-// localFunctionDecls returns a mapping from *types.Func to *ast.FuncDecl in files.
-func localFunctionDecls(info *types.Info, files []*ast.File) func(*types.Func) *ast.FuncDecl {
- var fnDecls map[*types.Func]*ast.FuncDecl // computed lazily
- return func(f *types.Func) *ast.FuncDecl {
- if f != nil && fnDecls == nil {
- fnDecls = make(map[*types.Func]*ast.FuncDecl)
- for _, file := range files {
- for _, decl := range file.Decls {
- if fnDecl, ok := decl.(*ast.FuncDecl); ok {
- if fn, ok := info.Defs[fnDecl.Name].(*types.Func); ok {
- fnDecls[fn] = fnDecl
- }
- }
- }
- }
- }
- // TODO: once we only support go1.19+, set f = f.Origin() here.
- return fnDecls[f]
- }
-}
-
-// isMethodNamed returns true if f is a method defined
-// in package with the path pkgPath with a name in names.
-func isMethodNamed(f *types.Func, pkgPath string, names ...string) bool {
- if f == nil {
- return false
- }
- if f.Pkg() == nil || f.Pkg().Path() != pkgPath {
- return false
- }
- if f.Type().(*types.Signature).Recv() == nil {
- return false
- }
- for _, n := range names {
- if f.Name() == n {
- return true
- }
- }
- return false
-}
-
-func funcIdent(fun ast.Expr) *ast.Ident {
- switch fun := astutil.Unparen(fun).(type) {
- case *ast.IndexExpr, *typeparams.IndexListExpr:
- x, _, _, _ := typeparams.UnpackIndexExpr(fun) // necessary?
- id, _ := x.(*ast.Ident)
- return id
- case *ast.Ident:
- return fun
- default:
- return nil
- }
-}
-
-// funcLitInScope returns a FuncLit that id is at least initially assigned to.
-//
-// TODO: This is closely tied to id.Obj which is deprecated.
-func funcLitInScope(id *ast.Ident) *ast.FuncLit {
- // Compare to (*ast.Object).Pos().
- if id.Obj == nil {
- return nil
- }
- var rhs ast.Expr
- switch d := id.Obj.Decl.(type) {
- case *ast.AssignStmt:
- for i, x := range d.Lhs {
- if ident, isIdent := x.(*ast.Ident); isIdent && ident.Name == id.Name && i < len(d.Rhs) {
- rhs = d.Rhs[i]
- }
- }
- case *ast.ValueSpec:
- for i, n := range d.Names {
- if n.Name == id.Name && i < len(d.Values) {
- rhs = d.Values[i]
- }
- }
- }
- lit, _ := rhs.(*ast.FuncLit)
- return lit
-}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go b/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
index d0b0ebb10..9589a46a5 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/tests/tests.go
@@ -257,7 +257,13 @@ func isTestingType(typ types.Type, testingType string) bool {
if !ok {
return false
}
- return analysisutil.IsNamedType(ptr.Elem(), "testing", testingType)
+ named, ok := ptr.Elem().(*types.Named)
+ if !ok {
+ return false
+ }
+ obj := named.Obj()
+ // obj.Pkg is nil for the error type.
+ return obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "testing" && obj.Name() == testingType
}
// Validate that fuzz target function's arguments are of accepted types.
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
index eb84502bd..c45b9fa54 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/timeformat/timeformat.go
@@ -88,16 +88,29 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
func isTimeDotFormat(f *types.Func) bool {
- if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" {
+ if f.Name() != "Format" || f.Pkg().Path() != "time" {
+ return false
+ }
+ sig, ok := f.Type().(*types.Signature)
+ if !ok {
return false
}
// Verify that the receiver is time.Time.
- recv := f.Type().(*types.Signature).Recv()
- return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time")
+ recv := sig.Recv()
+ if recv == nil {
+ return false
+ }
+ named, ok := recv.Type().(*types.Named)
+ return ok && named.Obj().Name() == "Time"
}
func isTimeDotParse(f *types.Func) bool {
- return analysisutil.IsFunctionNamed(f, "time", "Parse")
+ if f.Name() != "Parse" || f.Pkg().Path() != "time" {
+ return false
+ }
+ // Verify that there is no receiver.
+ sig, ok := f.Type().(*types.Signature)
+ return ok && sig.Recv() == nil
}
// badFormatAt return the start of a bad format in e or -1 if no bad format is found.
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
index 32e71ef97..e43ac2078 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
@@ -15,7 +15,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
)
@@ -69,7 +68,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
// Check unsafe.Pointer safety rules according to
// https://golang.org/pkg/unsafe/#Pointer.
- switch x := astutil.Unparen(x).(type) {
+ switch x := analysisutil.Unparen(x).(type) {
case *ast.SelectorExpr:
// "(6) Conversion of a reflect.SliceHeader or
// reflect.StringHeader Data field to or from Pointer."
@@ -105,7 +104,8 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
}
switch sel.Sel.Name {
case "Pointer", "UnsafeAddr":
- if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "Value") {
+ t, ok := info.Types[sel.X].Type.(*types.Named)
+ if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
return true
}
}
@@ -118,7 +118,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
// isSafeArith reports whether x is a pointer arithmetic expression that is safe
// to convert to unsafe.Pointer.
func isSafeArith(info *types.Info, x ast.Expr) bool {
- switch x := astutil.Unparen(x).(type) {
+ switch x := analysisutil.Unparen(x).(type) {
case *ast.CallExpr:
// Base case: initial conversion from unsafe.Pointer to uintptr.
return len(x.Args) == 1 &&
@@ -153,5 +153,13 @@ func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool {
// isReflectHeader reports whether t is reflect.SliceHeader or reflect.StringHeader.
func isReflectHeader(t types.Type) bool {
- return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader")
+ if named, ok := t.(*types.Named); ok {
+ if obj := named.Obj(); obj.Pkg() != nil && obj.Pkg().Path() == "reflect" {
+ switch obj.Name() {
+ case "SliceHeader", "StringHeader":
+ return true
+ }
+ }
+ }
+ return false
}
diff --git a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
index 7f79b4a75..cb487a217 100644
--- a/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
+++ b/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
@@ -24,7 +24,6 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
- "golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
)
@@ -83,7 +82,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
(*ast.ExprStmt)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
- call, ok := astutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
+ call, ok := analysisutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
if !ok {
return // not a call statement
}
@@ -93,6 +92,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
if !ok {
return // e.g. var or builtin
}
+
if sig := fn.Type().(*types.Signature); sig.Recv() != nil {
// method (e.g. foo.String())
if types.Identical(sig, sigNoArgsStringResult) {
diff --git a/vendor/golang.org/x/tools/go/analysis/validate.go b/vendor/golang.org/x/tools/go/analysis/validate.go
index 4f2c40456..9da5692af 100644
--- a/vendor/golang.org/x/tools/go/analysis/validate.go
+++ b/vendor/golang.org/x/tools/go/analysis/validate.go
@@ -19,8 +19,6 @@ import (
// that the Requires graph is acyclic;
// that analyzer fact types are unique;
// that each fact type is a pointer.
-//
-// Analyzer names need not be unique, though this may be confusing.
func Validate(analyzers []*Analyzer) error {
// Map each fact type to its sole generating analyzer.
factTypes := make(map[reflect.Type]*Analyzer)
diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
index 697974bb9..38d5c6c7c 100644
--- a/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
+++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo.go
@@ -59,10 +59,11 @@ import (
"go/token"
"log"
"os"
- "os/exec"
"path/filepath"
"regexp"
"strings"
+
+ exec "golang.org/x/sys/execabs"
)
// ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses
diff --git a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go
index b5bb95a63..7d94bbc1e 100644
--- a/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go
+++ b/vendor/golang.org/x/tools/go/internal/cgo/cgo_pkgconfig.go
@@ -8,7 +8,7 @@ import (
"errors"
"fmt"
"go/build"
- "os/exec"
+ exec "golang.org/x/sys/execabs"
"strings"
)
diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
index 333676b7c..0454cdd78 100644
--- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
+++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
@@ -13,17 +13,16 @@ import (
"golang.org/x/tools/internal/gocommand"
)
+var debug = false
+
func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (string, string, error) {
inv.Verb = "list"
inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}
stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
var goarch, compiler string
if rawErr != nil {
- rawErrMsg := rawErr.Error()
- if strings.Contains(rawErrMsg, "cannot find main module") ||
- strings.Contains(rawErrMsg, "go.mod file not found") {
- // User's running outside of a module.
- // All bets are off. Get GOARCH and guess compiler is gc.
+ if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") {
+ // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
// TODO(matloob): Is this a problem in practice?
inv.Verb = "env"
inv.Args = []string{"GOARCH"}
@@ -33,12 +32,8 @@ func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdR
}
goarch = strings.TrimSpace(envout.String())
compiler = "gc"
- } else if friendlyErr != nil {
- return "", "", friendlyErr
} else {
- // This should be unreachable, but be defensive
- // in case RunRaw's error results are inconsistent.
- return "", "", rawErr
+ return "", "", friendlyErr
}
} else {
fields := strings.Fields(stdout.String())
diff --git a/vendor/golang.org/x/tools/go/loader/loader.go b/vendor/golang.org/x/tools/go/loader/loader.go
index 41ee08b9b..edf62c2cc 100644
--- a/vendor/golang.org/x/tools/go/loader/loader.go
+++ b/vendor/golang.org/x/tools/go/loader/loader.go
@@ -24,7 +24,6 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/internal/cgo"
"golang.org/x/tools/internal/typeparams"
- "golang.org/x/tools/internal/versions"
)
var ignoreVendor build.ImportMode
@@ -1041,7 +1040,6 @@ func (imp *importer) newPackageInfo(path, dir string) *PackageInfo {
dir: dir,
}
typeparams.InitInstanceInfo(&info.Info)
- versions.InitFileVersions(&info.Info)
// Copy the types.Config so we can vary it across PackageInfos.
tc := imp.conf.TypeChecker
diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go
index 7db1d1293..7242a0a7d 100644
--- a/vendor/golang.org/x/tools/go/packages/external.go
+++ b/vendor/golang.org/x/tools/go/packages/external.go
@@ -12,8 +12,8 @@ import (
"bytes"
"encoding/json"
"fmt"
+ exec "golang.org/x/sys/execabs"
"os"
- "os/exec"
"strings"
)
diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go
index cd375fbc3..1f1eade0a 100644
--- a/vendor/golang.org/x/tools/go/packages/golist.go
+++ b/vendor/golang.org/x/tools/go/packages/golist.go
@@ -11,7 +11,6 @@ import (
"fmt"
"log"
"os"
- "os/exec"
"path"
"path/filepath"
"reflect"
@@ -21,6 +20,7 @@ import (
"sync"
"unicode"
+ exec "golang.org/x/sys/execabs"
"golang.org/x/tools/go/internal/packagesdriver"
"golang.org/x/tools/internal/gocommand"
"golang.org/x/tools/internal/packagesinternal"
@@ -208,6 +208,62 @@ extractQueries:
}
}
+ // Only use go/packages' overlay processing if we're using a Go version
+ // below 1.16. Otherwise, go list handles it.
+ if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 {
+ modifiedPkgs, needPkgs, err := state.processGolistOverlay(response)
+ if err != nil {
+ return nil, err
+ }
+
+ var containsCandidates []string
+ if len(containFiles) > 0 {
+ containsCandidates = append(containsCandidates, modifiedPkgs...)
+ containsCandidates = append(containsCandidates, needPkgs...)
+ }
+ if err := state.addNeededOverlayPackages(response, needPkgs); err != nil {
+ return nil, err
+ }
+ // Check candidate packages for containFiles.
+ if len(containFiles) > 0 {
+ for _, id := range containsCandidates {
+ pkg, ok := response.seenPackages[id]
+ if !ok {
+ response.addPackage(&Package{
+ ID: id,
+ Errors: []Error{{
+ Kind: ListError,
+ Msg: fmt.Sprintf("package %s expected but not seen", id),
+ }},
+ })
+ continue
+ }
+ for _, f := range containFiles {
+ for _, g := range pkg.GoFiles {
+ if sameFile(f, g) {
+ response.addRoot(id)
+ }
+ }
+ }
+ }
+ }
+ // Add root for any package that matches a pattern. This applies only to
+ // packages that are modified by overlays, since they are not added as
+ // roots automatically.
+ for _, pattern := range restPatterns {
+ match := matchPattern(pattern)
+ for _, pkgID := range modifiedPkgs {
+ pkg, ok := response.seenPackages[pkgID]
+ if !ok {
+ continue
+ }
+ if match(pkg.PkgPath) {
+ response.addRoot(pkg.ID)
+ }
+ }
+ }
+ }
+
sizeswg.Wait()
if sizeserr != nil {
return nil, sizeserr
@@ -215,6 +271,24 @@ extractQueries:
return response.dr, nil
}
+func (state *golistState) addNeededOverlayPackages(response *responseDeduper, pkgs []string) error {
+ if len(pkgs) == 0 {
+ return nil
+ }
+ dr, err := state.createDriverResponse(pkgs...)
+ if err != nil {
+ return err
+ }
+ for _, pkg := range dr.Packages {
+ response.addPackage(pkg)
+ }
+ _, needPkgs, err := state.processGolistOverlay(response)
+ if err != nil {
+ return err
+ }
+ return state.addNeededOverlayPackages(response, needPkgs)
+}
+
func (state *golistState) runContainsQueries(response *responseDeduper, queries []string) error {
for _, query := range queries {
// TODO(matloob): Do only one query per directory.
diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go
index d823c474a..9576b472f 100644
--- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go
+++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go
@@ -6,11 +6,314 @@ package packages
import (
"encoding/json"
+ "fmt"
+ "go/parser"
+ "go/token"
+ "os"
"path/filepath"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
"golang.org/x/tools/internal/gocommand"
)
+// processGolistOverlay provides rudimentary support for adding
+// files that don't exist on disk to an overlay. The results can be
+// sometimes incorrect.
+// TODO(matloob): Handle unsupported cases, including the following:
+// - determining the correct package to add given a new import path
+func (state *golistState) processGolistOverlay(response *responseDeduper) (modifiedPkgs, needPkgs []string, err error) {
+ havePkgs := make(map[string]string) // importPath -> non-test package ID
+ needPkgsSet := make(map[string]bool)
+ modifiedPkgsSet := make(map[string]bool)
+
+ pkgOfDir := make(map[string][]*Package)
+ for _, pkg := range response.dr.Packages {
+ // This is an approximation of import path to id. This can be
+ // wrong for tests, vendored packages, and a number of other cases.
+ havePkgs[pkg.PkgPath] = pkg.ID
+ dir, err := commonDir(pkg.GoFiles)
+ if err != nil {
+ return nil, nil, err
+ }
+ if dir != "" {
+ pkgOfDir[dir] = append(pkgOfDir[dir], pkg)
+ }
+ }
+
+ // If no new imports are added, it is safe to avoid loading any needPkgs.
+ // Otherwise, it's hard to tell which package is actually being loaded
+ // (due to vendoring) and whether any modified package will show up
+ // in the transitive set of dependencies (because new imports are added,
+ // potentially modifying the transitive set of dependencies).
+ var overlayAddsImports bool
+
+ // If both a package and its test package are created by the overlay, we
+ // need the real package first. Process all non-test files before test
+ // files, and make the whole process deterministic while we're at it.
+ var overlayFiles []string
+ for opath := range state.cfg.Overlay {
+ overlayFiles = append(overlayFiles, opath)
+ }
+ sort.Slice(overlayFiles, func(i, j int) bool {
+ iTest := strings.HasSuffix(overlayFiles[i], "_test.go")
+ jTest := strings.HasSuffix(overlayFiles[j], "_test.go")
+ if iTest != jTest {
+ return !iTest // non-tests are before tests.
+ }
+ return overlayFiles[i] < overlayFiles[j]
+ })
+ for _, opath := range overlayFiles {
+ contents := state.cfg.Overlay[opath]
+ base := filepath.Base(opath)
+ dir := filepath.Dir(opath)
+ var pkg *Package // if opath belongs to both a package and its test variant, this will be the test variant
+ var testVariantOf *Package // if opath is a test file, this is the package it is testing
+ var fileExists bool
+ isTestFile := strings.HasSuffix(opath, "_test.go")
+ pkgName, ok := extractPackageName(opath, contents)
+ if !ok {
+ // Don't bother adding a file that doesn't even have a parsable package statement
+ // to the overlay.
+ continue
+ }
+ // If all the overlay files belong to a different package, change the
+ // package name to that package.
+ maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir])
+ nextPackage:
+ for _, p := range response.dr.Packages {
+ if pkgName != p.Name && p.ID != "command-line-arguments" {
+ continue
+ }
+ for _, f := range p.GoFiles {
+ if !sameFile(filepath.Dir(f), dir) {
+ continue
+ }
+ // Make sure to capture information on the package's test variant, if needed.
+ if isTestFile && !hasTestFiles(p) {
+ // TODO(matloob): Are there packages other than the 'production' variant
+ // of a package that this can match? This shouldn't match the test main package
+ // because the file is generated in another directory.
+ testVariantOf = p
+ continue nextPackage
+ } else if !isTestFile && hasTestFiles(p) {
+ // We're examining a test variant, but the overlaid file is
+ // a non-test file. Because the overlay implementation
+ // (currently) only adds a file to one package, skip this
+ // package, so that we can add the file to the production
+ // variant of the package. (https://golang.org/issue/36857
+ // tracks handling overlays on both the production and test
+ // variant of a package).
+ continue nextPackage
+ }
+ if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath {
+ // We have already seen the production version of the
+ // for which p is a test variant.
+ if hasTestFiles(p) {
+ testVariantOf = pkg
+ }
+ }
+ pkg = p
+ if filepath.Base(f) == base {
+ fileExists = true
+ }
+ }
+ }
+ // The overlay could have included an entirely new package or an
+ // ad-hoc package. An ad-hoc package is one that we have manually
+ // constructed from inadequate `go list` results for a file= query.
+ // It will have the ID command-line-arguments.
+ if pkg == nil || pkg.ID == "command-line-arguments" {
+ // Try to find the module or gopath dir the file is contained in.
+ // Then for modules, add the module opath to the beginning.
+ pkgPath, ok, err := state.getPkgPath(dir)
+ if err != nil {
+ return nil, nil, err
+ }
+ if !ok {
+ break
+ }
+ var forTest string // only set for x tests
+ isXTest := strings.HasSuffix(pkgName, "_test")
+ if isXTest {
+ forTest = pkgPath
+ pkgPath += "_test"
+ }
+ id := pkgPath
+ if isTestFile {
+ if isXTest {
+ id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest)
+ } else {
+ id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath)
+ }
+ }
+ if pkg != nil {
+ // TODO(rstambler): We should change the package's path and ID
+ // here. The only issue is that this messes with the roots.
+ } else {
+ // Try to reclaim a package with the same ID, if it exists in the response.
+ for _, p := range response.dr.Packages {
+ if reclaimPackage(p, id, opath, contents) {
+ pkg = p
+ break
+ }
+ }
+ // Otherwise, create a new package.
+ if pkg == nil {
+ pkg = &Package{
+ PkgPath: pkgPath,
+ ID: id,
+ Name: pkgName,
+ Imports: make(map[string]*Package),
+ }
+ response.addPackage(pkg)
+ havePkgs[pkg.PkgPath] = id
+ // Add the production package's sources for a test variant.
+ if isTestFile && !isXTest && testVariantOf != nil {
+ pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...)
+ pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...)
+ // Add the package under test and its imports to the test variant.
+ pkg.forTest = testVariantOf.PkgPath
+ for k, v := range testVariantOf.Imports {
+ pkg.Imports[k] = &Package{ID: v.ID}
+ }
+ }
+ if isXTest {
+ pkg.forTest = forTest
+ }
+ }
+ }
+ }
+ if !fileExists {
+ pkg.GoFiles = append(pkg.GoFiles, opath)
+ // TODO(matloob): Adding the file to CompiledGoFiles can exhibit the wrong behavior
+ // if the file will be ignored due to its build tags.
+ pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, opath)
+ modifiedPkgsSet[pkg.ID] = true
+ }
+ imports, err := extractImports(opath, contents)
+ if err != nil {
+ // Let the parser or type checker report errors later.
+ continue
+ }
+ for _, imp := range imports {
+ // TODO(rstambler): If the package is an x test and the import has
+ // a test variant, make sure to replace it.
+ if _, found := pkg.Imports[imp]; found {
+ continue
+ }
+ overlayAddsImports = true
+ id, ok := havePkgs[imp]
+ if !ok {
+ var err error
+ id, err = state.resolveImport(dir, imp)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ pkg.Imports[imp] = &Package{ID: id}
+ // Add dependencies to the non-test variant version of this package as well.
+ if testVariantOf != nil {
+ testVariantOf.Imports[imp] = &Package{ID: id}
+ }
+ }
+ }
+
+ // toPkgPath guesses the package path given the id.
+ toPkgPath := func(sourceDir, id string) (string, error) {
+ if i := strings.IndexByte(id, ' '); i >= 0 {
+ return state.resolveImport(sourceDir, id[:i])
+ }
+ return state.resolveImport(sourceDir, id)
+ }
+
+ // Now that new packages have been created, do another pass to determine
+ // the new set of missing packages.
+ for _, pkg := range response.dr.Packages {
+ for _, imp := range pkg.Imports {
+ if len(pkg.GoFiles) == 0 {
+ return nil, nil, fmt.Errorf("cannot resolve imports for package %q with no Go files", pkg.PkgPath)
+ }
+ pkgPath, err := toPkgPath(filepath.Dir(pkg.GoFiles[0]), imp.ID)
+ if err != nil {
+ return nil, nil, err
+ }
+ if _, ok := havePkgs[pkgPath]; !ok {
+ needPkgsSet[pkgPath] = true
+ }
+ }
+ }
+
+ if overlayAddsImports {
+ needPkgs = make([]string, 0, len(needPkgsSet))
+ for pkg := range needPkgsSet {
+ needPkgs = append(needPkgs, pkg)
+ }
+ }
+ modifiedPkgs = make([]string, 0, len(modifiedPkgsSet))
+ for pkg := range modifiedPkgsSet {
+ modifiedPkgs = append(modifiedPkgs, pkg)
+ }
+ return modifiedPkgs, needPkgs, err
+}
+
+// resolveImport finds the ID of a package given its import path.
+// In particular, it will find the right vendored copy when in GOPATH mode.
+func (state *golistState) resolveImport(sourceDir, importPath string) (string, error) {
+ env, err := state.getEnv()
+ if err != nil {
+ return "", err
+ }
+ if env["GOMOD"] != "" {
+ return importPath, nil
+ }
+
+ searchDir := sourceDir
+ for {
+ vendorDir := filepath.Join(searchDir, "vendor")
+ exists, ok := state.vendorDirs[vendorDir]
+ if !ok {
+ info, err := os.Stat(vendorDir)
+ exists = err == nil && info.IsDir()
+ state.vendorDirs[vendorDir] = exists
+ }
+
+ if exists {
+ vendoredPath := filepath.Join(vendorDir, importPath)
+ if info, err := os.Stat(vendoredPath); err == nil && info.IsDir() {
+ // We should probably check for .go files here, but shame on anyone who fools us.
+ path, ok, err := state.getPkgPath(vendoredPath)
+ if err != nil {
+ return "", err
+ }
+ if ok {
+ return path, nil
+ }
+ }
+ }
+
+ // We know we've hit the top of the filesystem when we Dir / and get /,
+ // or C:\ and get C:\, etc.
+ next := filepath.Dir(searchDir)
+ if next == searchDir {
+ break
+ }
+ searchDir = next
+ }
+ return importPath, nil
+}
+
+func hasTestFiles(p *Package) bool {
+ for _, f := range p.GoFiles {
+ if strings.HasSuffix(f, "_test.go") {
+ return true
+ }
+ }
+ return false
+}
+
// determineRootDirs returns a mapping from absolute directories that could
// contain code to their corresponding import path prefixes.
func (state *golistState) determineRootDirs() (map[string]string, error) {
@@ -81,3 +384,192 @@ func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) {
}
return m, nil
}
+
+func extractImports(filename string, contents []byte) ([]string, error) {
+ f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset?
+ if err != nil {
+ return nil, err
+ }
+ var res []string
+ for _, imp := range f.Imports {
+ quotedPath := imp.Path.Value
+ path, err := strconv.Unquote(quotedPath)
+ if err != nil {
+ return nil, err
+ }
+ res = append(res, path)
+ }
+ return res, nil
+}
+
+// reclaimPackage attempts to reuse a package that failed to load in an overlay.
+//
+// If the package has errors and has no Name, GoFiles, or Imports,
+// then it's possible that it doesn't yet exist on disk.
+func reclaimPackage(pkg *Package, id string, filename string, contents []byte) bool {
+ // TODO(rstambler): Check the message of the actual error?
+ // It differs between $GOPATH and module mode.
+ if pkg.ID != id {
+ return false
+ }
+ if len(pkg.Errors) != 1 {
+ return false
+ }
+ if pkg.Name != "" || pkg.ExportFile != "" {
+ return false
+ }
+ if len(pkg.GoFiles) > 0 || len(pkg.CompiledGoFiles) > 0 || len(pkg.OtherFiles) > 0 {
+ return false
+ }
+ if len(pkg.Imports) > 0 {
+ return false
+ }
+ pkgName, ok := extractPackageName(filename, contents)
+ if !ok {
+ return false
+ }
+ pkg.Name = pkgName
+ pkg.Errors = nil
+ return true
+}
+
+func extractPackageName(filename string, contents []byte) (string, bool) {
+ // TODO(rstambler): Check the message of the actual error?
+ // It differs between $GOPATH and module mode.
+ f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.PackageClauseOnly) // TODO(matloob): reuse fileset?
+ if err != nil {
+ return "", false
+ }
+ return f.Name.Name, true
+}
+
+// commonDir returns the directory that all files are in, "" if files is empty,
+// or an error if they aren't in the same directory.
+func commonDir(files []string) (string, error) {
+ seen := make(map[string]bool)
+ for _, f := range files {
+ seen[filepath.Dir(f)] = true
+ }
+ if len(seen) > 1 {
+ return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen)
+ }
+ for k := range seen {
+ // seen has only one element; return it.
+ return k, nil
+ }
+ return "", nil // no files
+}
+
+// It is possible that the files in the disk directory dir have a different package
+// name from newName, which is deduced from the overlays. If they all have a different
+// package name, and they all have the same package name, then that name becomes
+// the package name.
+// It returns true if it changes the package name, false otherwise.
+func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) {
+ names := make(map[string]int)
+ for _, p := range pkgsOfDir {
+ names[p.Name]++
+ }
+ if len(names) != 1 {
+ // some files are in different packages
+ return
+ }
+ var oldName string
+ for k := range names {
+ oldName = k
+ }
+ if newName == oldName {
+ return
+ }
+ // We might have a case where all of the package names in the directory are
+ // the same, but the overlay file is for an x test, which belongs to its
+ // own package. If the x test does not yet exist on disk, we may not yet
+ // have its package name on disk, but we should not rename the packages.
+ //
+ // We use a heuristic to determine if this file belongs to an x test:
+ // The test file should have a package name whose package name has a _test
+ // suffix or looks like "newName_test".
+ maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test")
+ if isTestFile && maybeXTest {
+ return
+ }
+ for _, p := range pkgsOfDir {
+ p.Name = newName
+ }
+}
+
+// This function is copy-pasted from
+// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360.
+// It should be deleted when we remove support for overlays from go/packages.
+//
+// NOTE: This does not handle any ./... or ./ style queries, as this function
+// doesn't know the working directory.
+//
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+// Unfortunately, there are two special cases. Quoting "go help packages":
+//
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separated pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+func matchPattern(pattern string) func(name string) bool {
+ // Convert pattern to regular expression.
+ // The strategy for the trailing /... is to nest it in an explicit ? expression.
+ // The strategy for the vendor exclusion is to change the unmatchable
+ // vendor strings to a disallowed code point (vendorChar) and to use
+ // "(anything but that codepoint)*" as the implementation of the ... wildcard.
+ // This is a bit complicated but the obvious alternative,
+ // namely a hand-written search like in most shell glob matchers,
+ // is too easy to make accidentally exponential.
+ // Using package regexp guarantees linear-time matching.
+
+ const vendorChar = "\x00"
+
+ if strings.Contains(pattern, vendorChar) {
+ return func(name string) bool { return false }
+ }
+
+ re := regexp.QuoteMeta(pattern)
+ re = replaceVendor(re, vendorChar)
+ switch {
+ case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
+ re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case re == vendorChar+`/\.\.\.`:
+ re = `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case strings.HasSuffix(re, `/\.\.\.`):
+ re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
+ }
+ re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`)
+
+ reg := regexp.MustCompile(`^` + re + `$`)
+
+ return func(name string) bool {
+ if strings.Contains(name, vendorChar) {
+ return false
+ }
+ return reg.MatchString(replaceVendor(name, vendorChar))
+ }
+}
+
+// replaceVendor returns the result of replacing
+// non-trailing vendor path elements in x with repl.
+func replaceVendor(x, repl string) string {
+ if !strings.Contains(x, "vendor") {
+ return x
+ }
+ elem := strings.Split(x, "/")
+ for i := 0; i < len(elem)-1; i++ {
+ if elem[i] == "vendor" {
+ elem[i] = repl
+ }
+ }
+ return strings.Join(elem, "/")
+}
diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go
index bd79efc1a..ece0e7c60 100644
--- a/vendor/golang.org/x/tools/go/packages/packages.go
+++ b/vendor/golang.org/x/tools/go/packages/packages.go
@@ -29,7 +29,6 @@ import (
"golang.org/x/tools/internal/packagesinternal"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
- "golang.org/x/tools/internal/versions"
)
// A LoadMode controls the amount of detail to return when loading.
@@ -259,52 +258,31 @@ type driverResponse struct {
// proceeding with further analysis. The PrintErrors function is
// provided for convenient display of all errors.
func Load(cfg *Config, patterns ...string) ([]*Package, error) {
- ld := newLoader(cfg)
- response, external, err := defaultDriver(&ld.Config, patterns...)
+ l := newLoader(cfg)
+ response, err := defaultDriver(&l.Config, patterns...)
if err != nil {
return nil, err
}
-
- ld.sizes = types.SizesFor(response.Compiler, response.Arch)
- if ld.sizes == nil && ld.Config.Mode&(NeedTypes|NeedTypesSizes|NeedTypesInfo) != 0 {
- // Type size information is needed but unavailable.
- if external {
- // An external driver may fail to populate the Compiler/GOARCH fields,
- // especially since they are relatively new (see #63700).
- // Provide a sensible fallback in this case.
- ld.sizes = types.SizesFor("gc", runtime.GOARCH)
- if ld.sizes == nil { // gccgo-only arch
- ld.sizes = types.SizesFor("gc", "amd64")
- }
- } else {
- // Go list should never fail to deliver accurate size information.
- // Reject the whole Load since the error is the same for every package.
- return nil, fmt.Errorf("can't determine type sizes for compiler %q on GOARCH %q",
- response.Compiler, response.Arch)
- }
- }
-
- return ld.refine(response)
+ l.sizes = types.SizesFor(response.Compiler, response.Arch)
+ return l.refine(response)
}
// defaultDriver is a driver that implements go/packages' fallback behavior.
// It will try to request to an external driver, if one exists. If there's
// no external driver, or the driver returns a response with NotHandled set,
// defaultDriver will fall back to the go list driver.
-// The boolean result indicates that an external driver handled the request.
-func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, bool, error) {
- if driver := findExternalDriver(cfg); driver != nil {
- response, err := driver(cfg, patterns...)
- if err != nil {
- return nil, false, err
- } else if !response.NotHandled {
- return response, true, nil
- }
- // (fall through)
+func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
+ driver := findExternalDriver(cfg)
+ if driver == nil {
+ driver = goListDriver
}
-
- response, err := goListDriver(cfg, patterns...)
- return response, false, err
+ response, err := driver(cfg, patterns...)
+ if err != nil {
+ return response, err
+ } else if response.NotHandled {
+ return goListDriver(cfg, patterns...)
+ }
+ return response, nil
}
// A Package describes a loaded Go package.
@@ -433,6 +411,12 @@ func init() {
packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError {
return p.(*Package).depsErrors
}
+ packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner {
+ return config.(*Config).gocmdRunner
+ }
+ packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {
+ config.(*Config).gocmdRunner = runner
+ }
packagesinternal.SetModFile = func(config interface{}, value string) {
config.(*Config).modFile = value
}
@@ -569,7 +553,7 @@ type loaderPackage struct {
type loader struct {
pkgs map[string]*loaderPackage
Config
- sizes types.Sizes // non-nil if needed by mode
+ sizes types.Sizes
parseCache map[string]*parseValue
parseCacheMu sync.Mutex
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
@@ -694,38 +678,39 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
}
}
- if ld.Mode&NeedImports != 0 {
- // Materialize the import graph.
-
- const (
- white = 0 // new
- grey = 1 // in progress
- black = 2 // complete
- )
-
- // visit traverses the import graph, depth-first,
- // and materializes the graph as Packages.Imports.
- //
- // Valid imports are saved in the Packages.Import map.
- // Invalid imports (cycles and missing nodes) are saved in the importErrors map.
- // Thus, even in the presence of both kinds of errors,
- // the Import graph remains a DAG.
- //
- // visit returns whether the package needs src or has a transitive
- // dependency on a package that does. These are the only packages
- // for which we load source code.
- var stack []*loaderPackage
- var visit func(lpkg *loaderPackage) bool
- visit = func(lpkg *loaderPackage) bool {
- switch lpkg.color {
- case black:
- return lpkg.needsrc
- case grey:
- panic("internal error: grey node")
- }
- lpkg.color = grey
- stack = append(stack, lpkg) // push
- stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports
+ // Materialize the import graph.
+
+ const (
+ white = 0 // new
+ grey = 1 // in progress
+ black = 2 // complete
+ )
+
+ // visit traverses the import graph, depth-first,
+ // and materializes the graph as Packages.Imports.
+ //
+ // Valid imports are saved in the Packages.Import map.
+ // Invalid imports (cycles and missing nodes) are saved in the importErrors map.
+ // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG.
+ //
+ // visit returns whether the package needs src or has a transitive
+ // dependency on a package that does. These are the only packages
+ // for which we load source code.
+ var stack []*loaderPackage
+ var visit func(lpkg *loaderPackage) bool
+ var srcPkgs []*loaderPackage
+ visit = func(lpkg *loaderPackage) bool {
+ switch lpkg.color {
+ case black:
+ return lpkg.needsrc
+ case grey:
+ panic("internal error: grey node")
+ }
+ lpkg.color = grey
+ stack = append(stack, lpkg) // push
+ stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports
+ // If NeedImports isn't set, the imports fields will all be zeroed out.
+ if ld.Mode&NeedImports != 0 {
lpkg.Imports = make(map[string]*Package, len(stubs))
for importPath, ipkg := range stubs {
var importErr error
@@ -749,39 +734,40 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
}
lpkg.Imports[importPath] = imp.Package
}
+ }
+ if lpkg.needsrc {
+ srcPkgs = append(srcPkgs, lpkg)
+ }
+ if ld.Mode&NeedTypesSizes != 0 {
+ lpkg.TypesSizes = ld.sizes
+ }
+ stack = stack[:len(stack)-1] // pop
+ lpkg.color = black
- // Complete type information is required for the
- // immediate dependencies of each source package.
- if lpkg.needsrc && ld.Mode&NeedTypes != 0 {
- for _, ipkg := range lpkg.Imports {
- ld.pkgs[ipkg.ID].needtypes = true
- }
- }
-
- // NeedTypeSizes causes TypeSizes to be set even
- // on packages for which types aren't needed.
- if ld.Mode&NeedTypesSizes != 0 {
- lpkg.TypesSizes = ld.sizes
- }
- stack = stack[:len(stack)-1] // pop
- lpkg.color = black
+ return lpkg.needsrc
+ }
- return lpkg.needsrc
+ if ld.Mode&NeedImports == 0 {
+ // We do this to drop the stub import packages that we are not even going to try to resolve.
+ for _, lpkg := range initial {
+ lpkg.Imports = nil
}
-
+ } else {
// For each initial package, create its import DAG.
for _, lpkg := range initial {
visit(lpkg)
}
-
- } else {
- // !NeedImports: drop the stub (ID-only) import packages
- // that we are not even going to try to resolve.
- for _, lpkg := range initial {
- lpkg.Imports = nil
+ }
+ if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 {
+ for _, lpkg := range srcPkgs {
+ // Complete type information is required for the
+ // immediate dependencies of each source package.
+ for _, ipkg := range lpkg.Imports {
+ imp := ld.pkgs[ipkg.ID]
+ imp.needtypes = true
+ }
}
}
-
// Load type data and syntax if needed, starting at
// the initial packages (roots of the import DAG).
if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 {
@@ -1019,7 +1005,6 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
typeparams.InitInstanceInfo(lpkg.TypesInfo)
- versions.InitFileVersions(lpkg.TypesInfo)
lpkg.TypesSizes = ld.sizes
importer := importerFunc(func(path string) (*types.Package, error) {
@@ -1057,7 +1042,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial,
Error: appendError,
- Sizes: ld.sizes, // may be nil
+ Sizes: ld.sizes,
}
if lpkg.Module != nil && lpkg.Module.GoVersion != "" {
typesinternal.SetGoVersion(tc, "go"+lpkg.Module.GoVersion)
diff --git a/vendor/golang.org/x/tools/go/ssa/builder.go b/vendor/golang.org/x/tools/go/ssa/builder.go
index 92465b8dc..0e49537d0 100644
--- a/vendor/golang.org/x/tools/go/ssa/builder.go
+++ b/vendor/golang.org/x/tools/go/ssa/builder.go
@@ -4,73 +4,106 @@
package ssa
-// This file defines the builder, which builds SSA-form IR for function bodies.
+// This file implements the BUILD phase of SSA construction.
//
-// SSA construction has two phases, "create" and "build". First, one
-// or more packages are created in any order by a sequence of calls to
-// CreatePackage, either from syntax or from mere type information.
-// Each created package has a complete set of Members (const, var,
-// type, func) that can be accessed through methods like
-// Program.FuncValue.
+// SSA construction has two phases, CREATE and BUILD. In the CREATE phase
+// (create.go), all packages are constructed and type-checked and
+// definitions of all package members are created, method-sets are
+// computed, and wrapper methods are synthesized.
+// ssa.Packages are created in arbitrary order.
//
-// It is not necessary to call CreatePackage for all dependencies of
-// each syntax package, only for its direct imports. (In future
-// perhaps even this restriction may be lifted.)
+// In the BUILD phase (builder.go), the builder traverses the AST of
+// each Go source function and generates SSA instructions for the
+// function body. Initializer expressions for package-level variables
+// are emitted to the package's init() function in the order specified
+// by go/types.Info.InitOrder, then code for each function in the
+// package is generated in lexical order.
+// The BUILD phases for distinct packages are independent and are
+// executed in parallel.
//
-// Second, packages created from syntax are built, by one or more
-// calls to Package.Build, which may be concurrent; or by a call to
-// Program.Build, which builds all packages in parallel. Building
-// traverses the type-annotated syntax tree of each function body and
-// creates SSA-form IR, a control-flow graph of instructions,
-// populating fields such as Function.Body, .Params, and others.
+// TODO(adonovan): indeed, building functions is now embarrassingly parallel.
+// Audit for concurrency then benchmark using more goroutines.
//
-// Building may create additional methods, including:
-// - wrapper methods (e.g. for embeddding, or implicit &recv)
-// - bound method closures (e.g. for use(recv.f))
-// - thunks (e.g. for use(I.f) or use(T.f))
-// - generic instances (e.g. to produce f[int] from f[any]).
-// As these methods are created, they are added to the build queue,
-// and then processed in turn, until a fixed point is reached,
-// Since these methods might belong to packages that were not
-// created (by a call to CreatePackage), their Pkg field is unset.
+// State:
//
-// Instances of generic functions may be either instantiated (f[int]
-// is a copy of f[T] with substitutions) or wrapped (f[int] delegates
-// to f[T]), depending on the availability of generic syntax and the
-// InstantiateGenerics mode flag.
+// The Package's and Program's indices (maps) are populated and
+// mutated during the CREATE phase, but during the BUILD phase they
+// remain constant. The sole exception is Prog.methodSets and its
+// related maps, which are protected by a dedicated mutex.
//
-// Each package has an initializer function named "init" that calls
-// the initializer functions of each direct import, computes and
-// assigns the initial value of each global variable, and calls each
-// source-level function named "init". (These generate SSA functions
-// named "init#1", "init#2", etc.)
+// Generic functions declared in a package P can be instantiated from functions
+// outside of P. This happens independently of the CREATE and BUILD phase of P.
//
-// Runtime types
+// Locks:
//
-// Each MakeInterface operation is a conversion from a non-interface
-// type to an interface type. The semantics of this operation requires
-// a runtime type descriptor, which is the type portion of an
-// interface, and the value abstracted by reflect.Type.
+// Mutexes are currently acquired according to the following order:
+// Prog.methodsMu ⊃ canonizer.mu ⊃ printMu
+// where x ⊃ y denotes that y can be acquired while x is held
+// and x cannot be acquired while y is held.
//
-// The program accumulates all non-parameterized types that are
-// encountered as MakeInterface operands, along with all types that
-// may be derived from them using reflection. This set is available as
-// Program.RuntimeTypes, and the methods of these types may be
-// reachable via interface calls or reflection even if they are never
-// referenced from the SSA IR. (In practice, algorithms such as RTA
-// that compute reachability from package main perform their own
-// tracking of runtime types at a finer grain, so this feature is not
-// very useful.)
+// Synthetics:
//
-// Function literals
+// During the BUILD phase new functions can be created and built. These include:
+// - wrappers (wrappers, bounds, thunks)
+// - generic function instantiations
+// These functions do not belong to a specific Pkg (Pkg==nil). Instead the
+// Package that led to them being CREATED is obligated to ensure these
+// are BUILT during the BUILD phase of the Package.
//
-// Anonymous functions must be built as soon as they are encountered,
-// as it may affect locals of the enclosing function, but they are not
-// marked 'built' until the end of the outermost enclosing function.
-// (Among other things, this causes them to be logged in top-down order.)
+// Runtime types:
//
-// The Function.build fields determines the algorithm for building the
-// function body. It is cleared to mark that building is complete.
+// A concrete type is a type that is fully monomorphized with concrete types,
+// i.e. it cannot reach a TypeParam type.
+// Some concrete types require full runtime type information. Cases
+// include checking whether a type implements an interface or
+// interpretation by the reflect package. All such types that may require
+// this information will have all of their method sets built and will be added to Prog.methodSets.
+// A type T is considered to require runtime type information if it is
+// a runtime type and has a non-empty method set and either:
+// - T flows into a MakeInterface instructions,
+// - T appears in a concrete exported member, or
+// - T is a type reachable from a type S that has non-empty method set.
+// For any such type T, method sets must be created before the BUILD
+// phase of the package is done.
+//
+// Function literals:
+//
+// The BUILD phase of a function literal (anonymous function) is tied to the
+// BUILD phase of the enclosing parent function. The FreeVars of an anonymous
+// function are discovered by building the anonymous function. This in turn
+// changes which variables must be bound in a MakeClosure instruction in the
+// parent. Anonymous functions also track where they are referred to in their
+// parent function.
+//
+// Happens-before:
+//
+// The above discussion leads to the following happens-before relation for
+// the BUILD and CREATE phases.
+// The happens-before relation (with X<Y denoting X happens-before Y) are:
+// - CREATE fn < fn.startBody() < fn.finishBody() < fn.built
+// for any function fn.
+// - anon.parent.startBody() < CREATE anon, and
+// anon.finishBody() < anon.parent().finishBody() < anon.built < fn.built
+// for an anonymous function anon (i.e. anon.parent() != nil).
+// - CREATE fn.Pkg < CREATE fn
+// for a declared function fn (i.e. fn.Pkg != nil)
+// - fn.built < BUILD pkg done
+// for any function fn created during the CREATE or BUILD phase of a package
+// pkg. This includes declared and synthetic functions.
+//
+// Program.MethodValue:
+//
+// Program.MethodValue may trigger new wrapper and instantiation functions to
+// be created. It has the same obligation to BUILD created functions as a
+// Package.
+//
+// Program.NewFunction:
+//
+// This is a low level operation for creating functions that do not exist in
+// the source. Use with caution.
+//
+// TODO(taking): Use consistent terminology for "concrete".
+// TODO(taking): Use consistent terminology for "monomorphization"/"instantiate"/"expand".
import (
"fmt"
@@ -82,7 +115,6 @@ import (
"sync"
"golang.org/x/tools/internal/typeparams"
- "golang.org/x/tools/internal/versions"
)
type opaqueType struct {
@@ -118,6 +150,7 @@ type builder struct {
// Invariant: 0 <= rtypes <= finished <= created.Len()
created *creator // functions created during building
finished int // Invariant: create[i].built holds for i in [0,finished)
+ rtypes int // Invariant: all of the runtime types for create[i] have been added for i in [0,rtypes)
}
// cond emits to fn code to evaluate boolean condition e and jump
@@ -290,8 +323,10 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
// treat make([]T, n, m) as new([m]T)[:n]
cap := m.Int64()
at := types.NewArray(ct.Elem(), cap)
+ alloc := emitNew(fn, at, pos)
+ alloc.Comment = "makeslice"
v := &Slice{
- X: emitNew(fn, at, pos, "makeslice"),
+ X: alloc,
High: n,
}
v.setPos(pos)
@@ -328,7 +363,9 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
}
case "new":
- return emitNew(fn, mustDeref(typ), pos, "new")
+ alloc := emitNew(fn, mustDeref(typ), pos)
+ alloc.Comment = "new"
+ return alloc
case "len", "cap":
// Special case: len or cap of an array or *array is
@@ -382,7 +419,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
if isBlankIdent(e) {
return blank{}
}
- obj := fn.objectOf(e).(*types.Var)
+ obj := fn.objectOf(e)
var v Value
if g := fn.Prog.packageLevelMember(obj); g != nil {
v = g.(*Global) // var (address)
@@ -395,10 +432,11 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
typ, _ := deref(fn.typeOf(e))
var v *Alloc
if escaping {
- v = emitNew(fn, typ, e.Lbrace, "complit")
+ v = emitNew(fn, typ, e.Lbrace)
} else {
- v = emitLocal(fn, typ, e.Lbrace, "complit")
+ v = fn.addLocal(typ, e.Lbrace)
}
+ v.Comment = "complit"
var sb storebuf
b.compLit(fn, v, e, true, &sb)
sb.emit(fn)
@@ -596,8 +634,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
panic("non-constant BasicLit") // unreachable
case *ast.FuncLit:
- /* function literal */
- anon := &Function{
+ fn2 := &Function{
name: fmt.Sprintf("%s$%d", fn.Name(), 1+len(fn.AnonFuncs)),
Signature: fn.typeOf(e.Type).(*types.Signature),
pos: e.Type.Func,
@@ -606,24 +643,23 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
Pkg: fn.Pkg,
Prog: fn.Prog,
syntax: e,
- info: fn.info,
- goversion: fn.goversion,
- build: (*builder).buildFromSyntax,
topLevelOrigin: nil, // use anonIdx to lookup an anon instance's origin.
typeparams: fn.typeparams, // share the parent's type parameters.
typeargs: fn.typeargs, // share the parent's type arguments.
- subst: fn.subst, // share the parent's type substitutions.
+ info: fn.info,
+ subst: fn.subst, // share the parent's type substitutions.
}
- fn.AnonFuncs = append(fn.AnonFuncs, anon)
- // Build anon immediately, as it may cause fn's locals to escape.
- // (It is not marked 'built' until the end of the enclosing FuncDecl.)
- anon.build(b, anon)
- if anon.FreeVars == nil {
- return anon
+ fn.AnonFuncs = append(fn.AnonFuncs, fn2)
+ b.created.Add(fn2)
+ b.buildFunctionBody(fn2)
+ // fn2 is not done BUILDing. fn2.referrers can still be updated.
+ // fn2 is done BUILDing after fn.finishBody().
+ if fn2.FreeVars == nil {
+ return fn2
}
- v := &MakeClosure{Fn: anon}
+ v := &MakeClosure{Fn: fn2}
v.setType(fn.typ(tv.Type))
- for _, fv := range anon.FreeVars {
+ for _, fv := range fn2.FreeVars {
v.Bindings = append(v.Bindings, fv.outer)
fv.outer = nil
}
@@ -756,9 +792,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
case *types.Nil:
return zeroConst(fn.instanceType(e))
}
-
// Package-level func or var?
- // (obj must belong to same package or a direct import.)
if v := fn.Prog.packageLevelMember(obj); v != nil {
if g, ok := v.(*Global); ok {
return emitLoad(fn, g) // var (address)
@@ -766,12 +800,12 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
callee := v.(*Function) // (func)
if callee.typeparams.Len() > 0 {
targs := fn.subst.types(instanceArgs(fn.info, e))
- callee = callee.instance(targs, b.created)
+ callee = fn.Prog.needsInstance(callee, targs, b.created)
}
return callee
}
// Local var.
- return emitLoad(fn, fn.lookup(obj.(*types.Var), false)) // var (address)
+ return emitLoad(fn, fn.lookup(obj, false)) // var (address)
case *ast.SelectorExpr:
sel := fn.selection(e)
@@ -787,7 +821,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
case types.MethodExpr:
// (*T).f or T.f, the method f from the method-set of type T.
// The result is a "thunk".
- thunk := createThunk(fn.Prog, sel, b.created)
+ thunk := makeThunk(fn.Prog, sel, b.created)
return emitConv(fn, thunk, fn.typ(tv.Type))
case types.MethodVal:
@@ -822,7 +856,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
} else {
// non-type param interface
// Emit nil check: typeassert v.(I).
- emitTypeAssert(fn, v, rt, e.Sel.Pos())
+ emitTypeAssert(fn, v, rt, token.NoPos)
}
}
if targs := receiverTypeArgs(obj); len(targs) > 0 {
@@ -830,7 +864,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
obj = fn.Prog.canon.instantiateMethod(obj, fn.subst.types(targs), fn.Prog.ctxt)
}
c := &MakeClosure{
- Fn: createBound(fn.Prog, obj, b.created),
+ Fn: makeBound(fn.Prog, obj, b.created),
Bindings: []Value{v},
}
c.setPos(e.Sel.Pos())
@@ -960,7 +994,11 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
c.Method = obj
} else {
// "Call"-mode call.
- c.Value = fn.Prog.objectMethod(obj, b.created)
+ callee := fn.Prog.originFunc(obj)
+ if callee.typeparams.Len() > 0 {
+ callee = fn.Prog.needsInstance(callee, receiverTypeArgs(obj), b.created)
+ }
+ c.Value = callee
c.Args = append(c.Args, v)
}
return
@@ -1052,8 +1090,9 @@ func (b *builder) emitCallArgs(fn *Function, sig *types.Signature, e *ast.CallEx
} else {
// Replace a suffix of args with a slice containing it.
at := types.NewArray(vt, int64(len(varargs)))
- a := emitNew(fn, at, token.NoPos, "varargs")
+ a := emitNew(fn, at, token.NoPos)
a.setPos(e.Rparen)
+ a.Comment = "varargs"
for i, arg := range varargs {
iaddr := &IndexAddr{
X: a,
@@ -1100,7 +1139,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
// 1:1 assignment
for i, id := range spec.Names {
if !isBlankIdent(id) {
- emitLocalVar(fn, identVar(fn, id))
+ fn.addLocalForIdent(id)
}
lval := b.addr(fn, id, false) // non-escaping
b.assign(fn, lval, spec.Values[i], true, nil)
@@ -1111,7 +1150,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
// Locals are implicitly zero-initialized.
for _, id := range spec.Names {
if !isBlankIdent(id) {
- lhs := emitLocalVar(fn, identVar(fn, id))
+ lhs := fn.addLocalForIdent(id)
if fn.debugInfo() {
emitDebugRef(fn, id, lhs, true)
}
@@ -1123,7 +1162,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
tuple := b.exprN(fn, spec.Values[0])
for i, id := range spec.Names {
if !isBlankIdent(id) {
- emitLocalVar(fn, identVar(fn, id))
+ fn.addLocalForIdent(id)
lhs := b.addr(fn, id, false) // non-escaping
lhs.store(fn, emitExtract(fn, tuple, i))
}
@@ -1143,8 +1182,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
var lval lvalue = blank{}
if !isBlankIdent(lhs) {
if isDef {
- if obj, ok := fn.info.Defs[lhs.(*ast.Ident)].(*types.Var); ok {
- emitLocalVar(fn, obj)
+ if obj := fn.info.Defs[lhs.(*ast.Ident)]; obj != nil {
+ fn.addNamedLocal(obj)
isZero[i] = true
}
}
@@ -1253,7 +1292,9 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
switch t := t.(type) {
case *types.Slice:
at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts))
- array = emitNew(fn, at, e.Lbrace, "slicelit")
+ alloc := emitNew(fn, at, e.Lbrace)
+ alloc.Comment = "slicelit"
+ array = alloc
case *types.Array:
at = t
array = addr
@@ -1541,13 +1582,13 @@ func (b *builder) typeSwitchStmt(fn *Function, s *ast.TypeSwitchStmt, label *lbl
}
func (b *builder) typeCaseBody(fn *Function, cc *ast.CaseClause, x Value, done *BasicBlock) {
- if obj, ok := fn.info.Implicits[cc].(*types.Var); ok {
+ if obj := fn.info.Implicits[cc]; obj != nil {
// In a switch y := x.(type), each case clause
// implicitly declares a distinct object y.
// In a single-type case, y has that type.
// In multi-type cases, 'case nil' and default,
// y has the same type as the interface operand.
- emitStore(fn, emitLocalVar(fn, obj), x, obj.Pos())
+ emitStore(fn, fn.addNamedLocal(obj), x, obj.Pos())
}
fn.targets = &targets{
tail: fn.targets,
@@ -1696,7 +1737,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
case *ast.AssignStmt: // x := <-states[state].Chan
if comm.Tok == token.DEFINE {
- emitLocalVar(fn, identVar(fn, comm.Lhs[0].(*ast.Ident)))
+ fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
}
x := b.addr(fn, comm.Lhs[0], false) // non-escaping
v := emitExtract(fn, sel, r)
@@ -1707,7 +1748,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
if len(comm.Lhs) == 2 { // x, ok := ...
if comm.Tok == token.DEFINE {
- emitLocalVar(fn, identVar(fn, comm.Lhs[1].(*ast.Ident)))
+ fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
}
ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
ok.store(fn, emitExtract(fn, sel, 1))
@@ -1742,32 +1783,20 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
// forStmt emits to fn code for the for statement s, optionally
// labelled by label.
func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) {
- // Use forStmtGo122 instead if it applies.
- if s.Init != nil {
- if assign, ok := s.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE {
- afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0
- if afterGo122 {
- b.forStmtGo122(fn, s, label)
- return
- }
- }
- }
-
- // ...init...
- // jump loop
+ // ...init...
+ // jump loop
// loop:
- // if cond goto body else done
+ // if cond goto body else done
// body:
- // ...body...
- // jump post
- // post: (target of continue)
- // ...post...
- // jump loop
+ // ...body...
+ // jump post
+ // post: (target of continue)
+ // ...post...
+ // jump loop
// done: (target of break)
if s.Init != nil {
b.stmt(fn, s.Init)
}
-
body := fn.newBasicBlock("for.body")
done := fn.newBasicBlock("for.done") // target of 'break'
loop := body // target of back-edge
@@ -1805,188 +1834,23 @@ func (b *builder) forStmt(fn *Function, s *ast.ForStmt, label *lblock) {
fn.currentBlock = done
}
-// forStmtGo122 emits to fn code for the for statement s, optionally
-// labelled by label. s must define its variables.
-//
-// This allocates once per loop iteration. This is only correct in
-// GoVersions >= go1.22.
-func (b *builder) forStmtGo122(fn *Function, s *ast.ForStmt, label *lblock) {
- // i_outer = alloc[T]
- // *i_outer = ...init... // under objects[i] = i_outer
- // jump loop
- // loop:
- // i = phi [head: i_outer, loop: i_next]
- // ...cond... // under objects[i] = i
- // if cond goto body else done
- // body:
- // ...body... // under objects[i] = i (same as loop)
- // jump post
- // post:
- // tmp = *i
- // i_next = alloc[T]
- // *i_next = tmp
- // ...post... // under objects[i] = i_next
- // goto loop
- // done:
-
- init := s.Init.(*ast.AssignStmt)
- startingBlocks := len(fn.Blocks)
-
- pre := fn.currentBlock // current block before starting
- loop := fn.newBasicBlock("for.loop") // target of back-edge
- body := fn.newBasicBlock("for.body")
- post := fn.newBasicBlock("for.post") // target of 'continue'
- done := fn.newBasicBlock("for.done") // target of 'break'
-
- // For each of the n loop variables, we create five SSA values,
- // outer, phi, next, load, and store in pre, loop, and post.
- // There is no limit on n.
- type loopVar struct {
- obj *types.Var
- outer *Alloc
- phi *Phi
- load *UnOp
- next *Alloc
- store *Store
- }
- vars := make([]loopVar, len(init.Lhs))
- for i, lhs := range init.Lhs {
- v := identVar(fn, lhs.(*ast.Ident))
- typ := fn.typ(v.Type())
-
- fn.currentBlock = pre
- outer := emitLocal(fn, typ, v.Pos(), v.Name())
-
- fn.currentBlock = loop
- phi := &Phi{Comment: v.Name()}
- phi.pos = v.Pos()
- phi.typ = outer.Type()
- fn.emit(phi)
-
- fn.currentBlock = post
- // If next is is local, it reuses the address and zeroes the old value so
- // load before allocating next.
- load := emitLoad(fn, phi)
- next := emitLocal(fn, typ, v.Pos(), v.Name())
- store := emitStore(fn, next, load, token.NoPos)
-
- phi.Edges = []Value{outer, next} // pre edge is emitted before post edge.
-
- vars[i] = loopVar{v, outer, phi, load, next, store}
- }
-
- // ...init... under fn.objects[v] = i_outer
- fn.currentBlock = pre
- for _, v := range vars {
- fn.vars[v.obj] = v.outer
- }
- const isDef = false // assign to already-allocated outers
- b.assignStmt(fn, init.Lhs, init.Rhs, isDef)
- if label != nil {
- label._break = done
- label._continue = post
- }
- emitJump(fn, loop)
-
- // ...cond... under fn.objects[v] = i
- fn.currentBlock = loop
- for _, v := range vars {
- fn.vars[v.obj] = v.phi
- }
- if s.Cond != nil {
- b.cond(fn, s.Cond, body, done)
- } else {
- emitJump(fn, body)
- }
-
- // ...body... under fn.objects[v] = i
- fn.currentBlock = body
- fn.targets = &targets{
- tail: fn.targets,
- _break: done,
- _continue: post,
- }
- b.stmt(fn, s.Body)
- fn.targets = fn.targets.tail
- emitJump(fn, post)
-
- // ...post... under fn.objects[v] = i_next
- for _, v := range vars {
- fn.vars[v.obj] = v.next
- }
- fn.currentBlock = post
- if s.Post != nil {
- b.stmt(fn, s.Post)
- }
- emitJump(fn, loop) // back-edge
- fn.currentBlock = done
-
- // For each loop variable that does not escape,
- // (the common case), fuse its next cells into its
- // (local) outer cell as they have disjoint live ranges.
- //
- // It is sufficient to test whether i_next escapes,
- // because its Heap flag will be marked true if either
- // the cond or post expression causes i to escape
- // (because escape distributes over phi).
- var nlocals int
- for _, v := range vars {
- if !v.next.Heap {
- nlocals++
- }
- }
- if nlocals > 0 {
- replace := make(map[Value]Value, 2*nlocals)
- dead := make(map[Instruction]bool, 4*nlocals)
- for _, v := range vars {
- if !v.next.Heap {
- replace[v.next] = v.outer
- replace[v.phi] = v.outer
- dead[v.phi], dead[v.next], dead[v.load], dead[v.store] = true, true, true, true
- }
- }
-
- // Replace all uses of i_next and phi with i_outer.
- // Referrers have not been built for fn yet so only update Instruction operands.
- // We need only look within the blocks added by the loop.
- var operands []*Value // recycle storage
- for _, b := range fn.Blocks[startingBlocks:] {
- for _, instr := range b.Instrs {
- operands = instr.Operands(operands[:0])
- for _, ptr := range operands {
- k := *ptr
- if v := replace[k]; v != nil {
- *ptr = v
- }
- }
- }
- }
-
- // Remove instructions for phi, load, and store.
- // lift() will remove the unused i_next *Alloc.
- isDead := func(i Instruction) bool { return dead[i] }
- loop.Instrs = removeInstrsIf(loop.Instrs, isDead)
- post.Instrs = removeInstrsIf(post.Instrs, isDead)
- }
-}
-
// rangeIndexed emits to fn the header for an integer-indexed loop
// over array, *array or slice value x.
// The v result is defined only if tv is non-nil.
// forPos is the position of the "for" token.
func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) {
//
- // length = len(x)
- // index = -1
- // loop: (target of continue)
- // index++
- // if index < length goto body else done
+ // length = len(x)
+ // index = -1
+ // loop: (target of continue)
+ // index++
+ // if index < length goto body else done
// body:
- // k = index
- // v = x[index]
- // ...body...
- // jump loop
- // done: (target of break)
+ // k = index
+ // v = x[index]
+ // ...body...
+ // jump loop
+ // done: (target of break)
// Determine number of iterations.
var length Value
@@ -2008,7 +1872,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P
length = fn.emit(&c)
}
- index := emitLocal(fn, tInt, token.NoPos, "rangeindex")
+ index := fn.addLocal(tInt, token.NoPos)
emitStore(fn, index, intConst(-1), pos)
loop = fn.newBasicBlock("rangeindex.loop")
@@ -2071,16 +1935,16 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P
// if the respective component is not wanted.
func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.Pos) (k, v Value, loop, done *BasicBlock) {
//
- // it = range x
+ // it = range x
// loop: (target of continue)
- // okv = next it (ok, key, value)
- // ok = extract okv #0
- // if ok goto body else done
+ // okv = next it (ok, key, value)
+ // ok = extract okv #0
+ // if ok goto body else done
// body:
- // k = extract okv #1
- // v = extract okv #2
- // ...body...
- // jump loop
+ // k = extract okv #1
+ // v = extract okv #2
+ // ...body...
+ // jump loop
// done: (target of break)
//
@@ -2133,13 +1997,13 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) {
//
// loop: (target of continue)
- // ko = <-x (key, ok)
- // ok = extract ko #1
- // if ok goto body else done
+ // ko = <-x (key, ok)
+ // ok = extract ko #1
+ // if ok goto body else done
// body:
- // k = extract ko #0
- // ...body...
- // goto loop
+ // k = extract ko #0
+ // ...
+ // goto loop
// done: (target of break)
loop = fn.newBasicBlock("rangechan.loop")
@@ -2166,57 +2030,6 @@ func (b *builder) rangeChan(fn *Function, x Value, tk types.Type, pos token.Pos)
return
}
-// rangeInt emits to fn the header for a range loop with an integer operand.
-// tk is the key value's type, or nil if the k result is not wanted.
-// pos is the position of the "for" token.
-func (b *builder) rangeInt(fn *Function, x Value, tk types.Type, pos token.Pos) (k Value, loop, done *BasicBlock) {
- //
- // iter = 0
- // if 0 < x goto body else done
- // loop: (target of continue)
- // iter++
- // if iter < x goto body else done
- // body:
- // k = x
- // ...body...
- // jump loop
- // done: (target of break)
-
- if isUntyped(x.Type()) {
- x = emitConv(fn, x, tInt)
- }
-
- T := x.Type()
- iter := emitLocal(fn, T, token.NoPos, "rangeint.iter")
- // x may be unsigned. Avoid initializing x to -1.
-
- body := fn.newBasicBlock("rangeint.body")
- done = fn.newBasicBlock("rangeint.done")
- emitIf(fn, emitCompare(fn, token.LSS, zeroConst(T), x, token.NoPos), body, done)
-
- loop = fn.newBasicBlock("rangeint.loop")
- fn.currentBlock = loop
-
- incr := &BinOp{
- Op: token.ADD,
- X: emitLoad(fn, iter),
- Y: emitConv(fn, vOne, T),
- }
- incr.setType(T)
- emitStore(fn, iter, fn.emit(incr), pos)
- emitIf(fn, emitCompare(fn, token.LSS, incr, x, token.NoPos), body, done)
- fn.currentBlock = body
-
- if tk != nil {
- // Integer types (int, uint8, etc.) are named and
- // we know that k is assignable to x when tk != nil.
- // This implies tk and T are identical so no conversion is needed.
- k = emitLoad(fn, iter)
- }
-
- return
-}
-
// rangeStmt emits to fn code for the range statement s, optionally
// labelled by label.
func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
@@ -2228,26 +2041,21 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
tv = fn.typeOf(s.Value)
}
- // create locals for s.Key and s.Value.
- createVars := func() {
- // Unlike a short variable declaration, a RangeStmt
- // using := never redeclares an existing variable; it
- // always creates a new one.
+ // If iteration variables are defined (:=), this
+ // occurs once outside the loop.
+ //
+ // Unlike a short variable declaration, a RangeStmt
+ // using := never redeclares an existing variable; it
+ // always creates a new one.
+ if s.Tok == token.DEFINE {
if tk != nil {
- emitLocalVar(fn, identVar(fn, s.Key.(*ast.Ident)))
+ fn.addLocalForIdent(s.Key.(*ast.Ident))
}
if tv != nil {
- emitLocalVar(fn, identVar(fn, s.Value.(*ast.Ident)))
+ fn.addLocalForIdent(s.Value.(*ast.Ident))
}
}
- afterGo122 := versions.Compare(fn.goversion, "go1.21") > 0
- if s.Tok == token.DEFINE && !afterGo122 {
- // pre-go1.22: If iteration variables are defined (:=), this
- // occurs once outside the loop.
- createVars()
- }
-
x := b.expr(fn, s.X)
var k, v Value
@@ -2259,30 +2067,13 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
case *types.Chan:
k, loop, done = b.rangeChan(fn, x, tk, s.For)
- case *types.Map:
+ case *types.Map, *types.Basic: // string
k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For)
- case *types.Basic:
- switch {
- case rt.Info()&types.IsString != 0:
- k, v, loop, done = b.rangeIter(fn, x, tk, tv, s.For)
-
- case rt.Info()&types.IsInteger != 0:
- k, loop, done = b.rangeInt(fn, x, tk, s.For)
-
- default:
- panic("Cannot range over basic type: " + rt.String())
- }
-
default:
panic("Cannot range over: " + rt.String())
}
- if s.Tok == token.DEFINE && afterGo122 {
- // go1.22: If iteration variables are defined (:=), this occurs inside the loop.
- createVars()
- }
-
// Evaluate both LHS expressions before we update either.
var kl, vl lvalue
if tk != nil {
@@ -2506,71 +2297,73 @@ start:
}
}
-// A buildFunc is a strategy for building the SSA body for a function.
-type buildFunc = func(*builder, *Function)
-
-// iterate causes all created but unbuilt functions to be built. As
-// this may create new methods, the process is iterated until it
-// converges.
-func (b *builder) iterate() {
- for ; b.finished < b.created.Len(); b.finished++ {
- fn := b.created.At(b.finished)
- b.buildFunction(fn)
- }
-}
-
// buildFunction builds SSA code for the body of function fn. Idempotent.
func (b *builder) buildFunction(fn *Function) {
- if fn.build != nil {
+ if !fn.built {
assert(fn.parent == nil, "anonymous functions should not be built by buildFunction()")
-
- if fn.Prog.mode&LogSource != 0 {
- defer logStack("build %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
- }
- fn.build(b, fn)
+ b.buildFunctionBody(fn)
fn.done()
}
}
-// buildParamsOnly builds fn.Params from fn.Signature, but does not build fn.Body.
-func (b *builder) buildParamsOnly(fn *Function) {
- // For external (C, asm) functions or functions loaded from
- // export data, we must set fn.Params even though there is no
- // body code to reference them.
- if recv := fn.Signature.Recv(); recv != nil {
- fn.addParamVar(recv)
- }
- params := fn.Signature.Params()
- for i, n := 0, params.Len(); i < n; i++ {
- fn.addParamVar(params.At(i))
+// buildFunctionBody builds SSA code for the body of function fn.
+//
+// fn is not done building until fn.done() is called.
+func (b *builder) buildFunctionBody(fn *Function) {
+ // TODO(taking): see if this check is reachable.
+ if fn.Blocks != nil {
+ return // building already started
}
-}
-// buildFromSyntax builds fn.Body from fn.syntax, which must be non-nil.
-func (b *builder) buildFromSyntax(fn *Function) {
- var (
- recvField *ast.FieldList
- body *ast.BlockStmt
- functype *ast.FuncType
- )
- switch syntax := fn.syntax.(type) {
- case *ast.FuncDecl:
- functype = syntax.Type
- recvField = syntax.Recv
- body = syntax.Body
- if body == nil {
- b.buildParamsOnly(fn) // no body (non-Go function)
- return
+ var recvField *ast.FieldList
+ var body *ast.BlockStmt
+ var functype *ast.FuncType
+ switch n := fn.syntax.(type) {
+ case nil:
+ if fn.Params != nil {
+ return // not a Go source function. (Synthetic, or from object file.)
}
+ case *ast.FuncDecl:
+ functype = n.Type
+ recvField = n.Recv
+ body = n.Body
case *ast.FuncLit:
- functype = syntax.Type
- body = syntax.Body
- case nil:
- panic("no syntax")
+ functype = n.Type
+ body = n.Body
default:
- panic(syntax) // unexpected syntax
+ panic(n)
}
+ if body == nil {
+ // External function.
+ if fn.Params == nil {
+ // This condition ensures we add a non-empty
+ // params list once only, but we may attempt
+ // the degenerate empty case repeatedly.
+ // TODO(adonovan): opt: don't do that.
+
+ // We set Function.Params even though there is no body
+ // code to reference them. This simplifies clients.
+ if recv := fn.Signature.Recv(); recv != nil {
+ fn.addParamObj(recv)
+ }
+ params := fn.Signature.Params()
+ for i, n := 0, params.Len(); i < n; i++ {
+ fn.addParamObj(params.At(i))
+ }
+ }
+ return
+ }
+
+ // Build instantiation wrapper around generic body?
+ if fn.topLevelOrigin != nil && fn.subst == nil {
+ buildInstantiationWrapper(fn)
+ return
+ }
+
+ if fn.Prog.mode&LogSource != 0 {
+ defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
+ }
fn.startBody()
fn.createSyntacticParams(recvField, functype)
b.stmt(fn, body)
@@ -2588,17 +2381,45 @@ func (b *builder) buildFromSyntax(fn *Function) {
fn.finishBody()
}
-// addRuntimeType records t as a runtime type,
-// along with all types derivable from it using reflection.
+// buildCreated does the BUILD phase for each function created by builder that is not yet BUILT.
+// Functions are built using buildFunction.
+//
+// May add types that require runtime type information to builder.
+func (b *builder) buildCreated() {
+ for ; b.finished < b.created.Len(); b.finished++ {
+ fn := b.created.At(b.finished)
+ b.buildFunction(fn)
+ }
+}
+
+// Adds any needed runtime type information for the created functions.
//
-// Acquires prog.runtimeTypesMu.
-func addRuntimeType(prog *Program, t types.Type) {
- prog.runtimeTypesMu.Lock()
- defer prog.runtimeTypesMu.Unlock()
- forEachReachable(&prog.MethodSets, t, func(t types.Type) bool {
- prev, _ := prog.runtimeTypes.Set(t, true).(bool)
- return !prev // already seen?
- })
+// May add newly CREATEd functions that may need to be built or runtime type information.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+func (b *builder) needsRuntimeTypes() {
+ if b.created.Len() == 0 {
+ return
+ }
+ prog := b.created.At(0).Prog
+
+ var rtypes []types.Type
+ for ; b.rtypes < b.finished; b.rtypes++ {
+ fn := b.created.At(b.rtypes)
+ rtypes = append(rtypes, mayNeedRuntimeTypes(fn)...)
+ }
+
+ // Calling prog.needMethodsOf(T) on a basic type T is a no-op.
+ // Filter out the basic types to reduce acquiring prog.methodsMu.
+ rtypes = nonbasicTypes(rtypes)
+
+ for _, T := range rtypes {
+ prog.needMethodsOf(T, b.created)
+ }
+}
+
+func (b *builder) done() bool {
+ return b.rtypes >= b.created.Len()
}
// Build calls Package.Build for each package in prog.
@@ -2626,11 +2447,9 @@ func (prog *Program) Build() {
// Build builds SSA code for all functions and vars in package p.
//
-// CreatePackage must have been called for all of p's direct imports
-// (and hence its direct imports must have been error-free). It is not
-// necessary to call CreatePackage for indirect dependencies.
-// Functions will be created for all necessary methods in those
-// packages on demand.
+// Precondition: CreatePackage must have been called for all of p's
+// direct imports (and hence its direct imports must have been
+// error-free).
//
// Build is idempotent and thread-safe.
func (p *Package) Build() { p.buildOnce.Do(p.build) }
@@ -2639,39 +2458,45 @@ func (p *Package) build() {
if p.info == nil {
return // synthetic package, e.g. "testmain"
}
+
+ // Ensure we have runtime type info for all exported members.
+ // Additionally filter for just concrete types that can be runtime types.
+ //
+ // TODO(adonovan): ideally belongs in memberFromObject, but
+ // that would require package creation in topological order.
+ for name, mem := range p.Members {
+ isGround := func(m Member) bool {
+ switch m := m.(type) {
+ case *Type:
+ named, _ := m.Type().(*types.Named)
+ return named == nil || typeparams.ForNamed(named) == nil
+ case *Function:
+ return m.typeparams.Len() == 0
+ }
+ return true // *NamedConst, *Global
+ }
+ if ast.IsExported(name) && isGround(mem) {
+ p.Prog.needMethodsOf(mem.Type(), &p.created)
+ }
+ }
if p.Prog.mode&LogSource != 0 {
defer logStack("build %s", p)()
}
b := builder{created: &p.created}
- b.iterate()
-
- // We no longer need transient information: ASTs or go/types deductions.
- p.info = nil
- p.created = nil
- p.files = nil
- p.initVersion = nil
-
- if p.Prog.mode&SanityCheckFunctions != 0 {
- sanityCheckPackage(p)
- }
-}
-
-// buildPackageInit builds fn.Body for the synthetic package initializer.
-func (b *builder) buildPackageInit(fn *Function) {
- p := fn.Pkg
- fn.startBody()
+ init := p.init
+ init.startBody()
var done *BasicBlock
if p.Prog.mode&BareInits == 0 {
// Make init() skip if package is already initialized.
initguard := p.Var("init$guard")
- doinit := fn.newBasicBlock("init.start")
- done = fn.newBasicBlock("init.done")
- emitIf(fn, emitLoad(fn, initguard), done, doinit)
- fn.currentBlock = doinit
- emitStore(fn, initguard, vTrue, token.NoPos)
+ doinit := init.newBasicBlock("init.start")
+ done = init.newBasicBlock("init.done")
+ emitIf(init, emitLoad(init, initguard), done, doinit)
+ init.currentBlock = doinit
+ emitStore(init, initguard, vTrue, token.NoPos)
// Call the init() function of each package we import.
for _, pkg := range p.Pkg.Imports() {
@@ -2681,9 +2506,9 @@ func (b *builder) buildPackageInit(fn *Function) {
}
var v Call
v.Call.Value = prereq.init
- v.Call.pos = fn.pos
+ v.Call.pos = init.pos
v.setType(types.NewTuple())
- fn.emit(&v)
+ init.emit(&v)
}
}
@@ -2691,18 +2516,11 @@ func (b *builder) buildPackageInit(fn *Function) {
if len(p.info.InitOrder) > 0 && len(p.files) == 0 {
panic("no source files provided for package. cannot initialize globals")
}
-
for _, varinit := range p.info.InitOrder {
- if fn.Prog.mode&LogSource != 0 {
+ if init.Prog.mode&LogSource != 0 {
fmt.Fprintf(os.Stderr, "build global initializer %v @ %s\n",
varinit.Lhs, p.Prog.Fset.Position(varinit.Rhs.Pos()))
}
- // Initializers for global vars are evaluated in dependency
- // order, but may come from arbitrary files of the package
- // with different versions, so we transiently update
- // fn.goversion for each one. (Since init is a synthetic
- // function it has no syntax of its own that needs a version.)
- fn.goversion = p.initVersion[varinit.Rhs]
if len(varinit.Lhs) == 1 {
// 1:1 initialization: var x, y = a(), b()
var lval lvalue
@@ -2711,33 +2529,28 @@ func (b *builder) buildPackageInit(fn *Function) {
} else {
lval = blank{}
}
- b.assign(fn, lval, varinit.Rhs, true, nil)
+ b.assign(init, lval, varinit.Rhs, true, nil)
} else {
// n:1 initialization: var x, y := f()
- tuple := b.exprN(fn, varinit.Rhs)
+ tuple := b.exprN(init, varinit.Rhs)
for i, v := range varinit.Lhs {
if v.Name() == "_" {
continue
}
- emitStore(fn, p.objects[v].(*Global), emitExtract(fn, tuple, i), v.Pos())
+ emitStore(init, p.objects[v].(*Global), emitExtract(init, tuple, i), v.Pos())
}
}
}
- // The rest of the init function is synthetic:
- // no syntax, info, goversion.
- fn.info = nil
- fn.goversion = ""
-
// Call all of the declared init() functions in source order.
for _, file := range p.files {
for _, decl := range file.Decls {
if decl, ok := decl.(*ast.FuncDecl); ok {
id := decl.Name
if !isBlankIdent(id) && id.Name == "init" && decl.Recv == nil {
- declaredInit := p.objects[p.info.Defs[id]].(*Function)
+ fn := p.objects[p.info.Defs[id]].(*Function)
var v Call
- v.Call.Value = declaredInit
+ v.Call.Value = fn
v.setType(types.NewTuple())
p.init.emit(&v)
}
@@ -2747,9 +2560,35 @@ func (b *builder) buildPackageInit(fn *Function) {
// Finish up init().
if p.Prog.mode&BareInits == 0 {
- emitJump(fn, done)
- fn.currentBlock = done
+ emitJump(init, done)
+ init.currentBlock = done
+ }
+ init.emit(new(Return))
+ init.finishBody()
+ init.done()
+
+ // Build all CREATEd functions and add runtime types.
+ // These Functions include package-level functions, init functions, methods, and synthetic (including unreachable/blank ones).
+ // Builds any functions CREATEd while building this package.
+ //
+ // Initially the created functions for the package are:
+ // [init, decl0, ... , declN]
+ // Where decl0, ..., declN are declared functions in source order, but it's not significant.
+ //
+ // As these are built, more functions (function literals, wrappers, etc.) can be CREATEd.
+ // Iterate until we reach a fixed point.
+ //
+ // Wait for init() to be BUILT as that cannot be built by buildFunction().
+ //
+ for !b.done() {
+ b.buildCreated() // build any CREATEd and not BUILT function. May add runtime types.
+ b.needsRuntimeTypes() // Add all of the runtime type information. May CREATE Functions.
+ }
+
+ p.info = nil // We no longer need ASTs or go/types deductions.
+ p.created = nil // We no longer need created functions.
+
+ if p.Prog.mode&SanityCheckFunctions != 0 {
+ sanityCheckPackage(p)
}
- fn.emit(new(Return))
- fn.finishBody()
}
diff --git a/vendor/golang.org/x/tools/go/ssa/create.go b/vendor/golang.org/x/tools/go/ssa/create.go
index 653ce2e5c..1bf88c83e 100644
--- a/vendor/golang.org/x/tools/go/ssa/create.go
+++ b/vendor/golang.org/x/tools/go/ssa/create.go
@@ -15,44 +15,41 @@ import (
"os"
"sync"
+ "golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/typeparams"
- "golang.org/x/tools/internal/versions"
)
// NewProgram returns a new SSA Program.
//
// mode controls diagnostics and checking during SSA construction.
-//
-// To construct an SSA program:
-//
-// - Call NewProgram to create an empty Program.
-// - Call CreatePackage providing typed syntax for each package
-// you want to build, and call it with types but not
-// syntax for each of those package's direct dependencies.
-// - Call [Package.Build] on each syntax package you wish to build,
-// or [Program.Build] to build all of them.
-//
-// See the Example tests for simple examples.
func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
- return &Program{
+ prog := &Program{
Fset: fset,
imported: make(map[string]*Package),
packages: make(map[*types.Package]*Package),
+ thunks: make(map[selectionKey]*Function),
+ bounds: make(map[boundsKey]*Function),
mode: mode,
canon: newCanonizer(),
ctxt: typeparams.NewContext(),
+ instances: make(map[*Function]*instanceSet),
parameterized: tpWalker{seen: make(map[types.Type]bool)},
}
+
+ h := typeutil.MakeHasher() // protected by methodsMu, in effect
+ prog.methodSets.SetHasher(h)
+ prog.runtimeTypes.SetHasher(h)
+
+ return prog
}
// memberFromObject populates package pkg with a member for the
// typechecker object obj.
//
// For objects from Go source code, syntax is the associated syntax
-// tree (for funcs and vars only) and goversion defines the
-// appropriate interpretation; they will be used during the build
+// tree (for funcs and vars only); it will be used during the build
// phase.
-func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion string) {
+func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
name := obj.Name()
switch obj := obj.(type) {
case *types.Builtin:
@@ -61,11 +58,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
}
case *types.TypeName:
- if name != "_" {
- pkg.Members[name] = &Type{
- object: obj,
- pkg: pkg,
- }
+ pkg.Members[name] = &Type{
+ object: obj,
+ pkg: pkg,
}
case *types.Const:
@@ -75,9 +70,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
pkg: pkg,
}
pkg.objects[obj] = c
- if name != "_" {
- pkg.Members[name] = c
- }
+ pkg.Members[name] = c
case *types.Var:
g := &Global{
@@ -88,9 +81,7 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
pos: obj.Pos(),
}
pkg.objects[obj] = g
- if name != "_" {
- pkg.Members[name] = g
- }
+ pkg.Members[name] = g
case *types.Func:
sig := obj.Type().(*types.Signature)
@@ -98,10 +89,36 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
pkg.ninit++
name = fmt.Sprintf("init#%d", pkg.ninit)
}
- fn := createFunction(pkg.Prog, obj, name, syntax, pkg.info, goversion, &pkg.created)
- fn.Pkg = pkg
+
+ // Collect type parameters if this is a generic function/method.
+ var tparams *typeparams.TypeParamList
+ if rtparams := typeparams.RecvTypeParams(sig); rtparams.Len() > 0 {
+ tparams = rtparams
+ } else if sigparams := typeparams.ForSignature(sig); sigparams.Len() > 0 {
+ tparams = sigparams
+ }
+
+ fn := &Function{
+ name: name,
+ object: obj,
+ Signature: sig,
+ syntax: syntax,
+ pos: obj.Pos(),
+ Pkg: pkg,
+ Prog: pkg.Prog,
+ typeparams: tparams,
+ info: pkg.info,
+ }
+ pkg.created.Add(fn)
+ if syntax == nil {
+ fn.Synthetic = "loaded from gc object file"
+ }
+ if tparams.Len() > 0 {
+ fn.Prog.createInstanceSet(fn)
+ }
+
pkg.objects[obj] = fn
- if name != "_" && sig.Recv() == nil {
+ if sig.Recv() == nil {
pkg.Members[name] = fn // package-level function
}
@@ -110,79 +127,45 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
}
}
-// createFunction creates a function or method. It supports both
-// CreatePackage (with or without syntax) and the on-demand creation
-// of methods in non-created packages based on their types.Func.
-func createFunction(prog *Program, obj *types.Func, name string, syntax ast.Node, info *types.Info, goversion string, cr *creator) *Function {
- sig := obj.Type().(*types.Signature)
-
- // Collect type parameters.
- var tparams *typeparams.TypeParamList
- if rtparams := typeparams.RecvTypeParams(sig); rtparams.Len() > 0 {
- tparams = rtparams // method of generic type
- } else if sigparams := typeparams.ForSignature(sig); sigparams.Len() > 0 {
- tparams = sigparams // generic function
- }
-
- /* declared function/method (from syntax or export data) */
- fn := &Function{
- name: name,
- object: obj,
- Signature: sig,
- build: (*builder).buildFromSyntax,
- syntax: syntax,
- info: info,
- goversion: goversion,
- pos: obj.Pos(),
- Pkg: nil, // may be set by caller
- Prog: prog,
- typeparams: tparams,
- }
- if fn.syntax == nil {
- fn.Synthetic = "from type information"
- fn.build = (*builder).buildParamsOnly
- }
- if tparams.Len() > 0 {
- fn.generic = new(generic)
- }
- cr.Add(fn)
- return fn
-}
-
// membersFromDecl populates package pkg with members for each
// typechecker object (var, func, const or type) associated with the
// specified decl.
-func membersFromDecl(pkg *Package, decl ast.Decl, goversion string) {
+func membersFromDecl(pkg *Package, decl ast.Decl) {
switch decl := decl.(type) {
case *ast.GenDecl: // import, const, type or var
switch decl.Tok {
case token.CONST:
for _, spec := range decl.Specs {
for _, id := range spec.(*ast.ValueSpec).Names {
- memberFromObject(pkg, pkg.info.Defs[id], nil, "")
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], nil)
+ }
}
}
case token.VAR:
for _, spec := range decl.Specs {
- for _, rhs := range spec.(*ast.ValueSpec).Values {
- pkg.initVersion[rhs] = goversion
- }
for _, id := range spec.(*ast.ValueSpec).Names {
- memberFromObject(pkg, pkg.info.Defs[id], spec, goversion)
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], spec)
+ }
}
}
case token.TYPE:
for _, spec := range decl.Specs {
id := spec.(*ast.TypeSpec).Name
- memberFromObject(pkg, pkg.info.Defs[id], nil, "")
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], nil)
+ }
}
}
case *ast.FuncDecl:
id := decl.Name
- memberFromObject(pkg, pkg.info.Defs[id], decl, goversion)
+ if !isBlankIdent(id) {
+ memberFromObject(pkg, pkg.info.Defs[id], decl)
+ }
}
}
@@ -199,7 +182,7 @@ func (c *creator) Add(fn *Function) {
func (c *creator) At(i int) *Function { return (*c)[i] }
func (c *creator) Len() int { return len(*c) }
-// CreatePackage creates and returns an SSA Package from the
+// CreatePackage constructs and returns an SSA Package from the
// specified type-checked, error-free file ASTs, and populates its
// Members mapping.
//
@@ -207,48 +190,36 @@ func (c *creator) Len() int { return len(*c) }
// subsequent call to ImportedPackage(pkg.Path()).
//
// The real work of building SSA form for each function is not done
-// until a subsequent call to Package.Build.
-//
-// CreatePackage should not be called after building any package in
-// the program.
+// until a subsequent call to Package.Build().
func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
- // TODO(adonovan): assert that no package has yet been built.
- if pkg == nil {
- panic("nil pkg") // otherwise pkg.Scope below returns types.Universe!
- }
p := &Package{
Prog: prog,
Members: make(map[string]Member),
objects: make(map[types.Object]Member),
Pkg: pkg,
- syntax: info != nil,
- // transient values (cleared after Package.Build)
- info: info,
- files: files,
- initVersion: make(map[ast.Expr]string),
+ info: info, // transient (CREATE and BUILD phases)
+ files: files, // transient (CREATE and BUILD phases)
}
- /* synthesized package initializer */
+ // Add init() function.
p.init = &Function{
name: "init",
Signature: new(types.Signature),
Synthetic: "package initializer",
Pkg: p,
Prog: prog,
- build: (*builder).buildPackageInit,
info: p.info,
- goversion: "", // See Package.build for details.
}
p.Members[p.init.name] = p.init
p.created.Add(p.init)
+ // CREATE phase.
// Allocate all package members: vars, funcs, consts and types.
if len(files) > 0 {
// Go source package.
for _, file := range files {
- goversion := versions.Lang(versions.FileVersions(p.info, file))
for _, decl := range file.Decls {
- membersFromDecl(p, decl, goversion)
+ membersFromDecl(p, decl)
}
}
} else {
@@ -258,11 +229,11 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
scope := p.Pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
- memberFromObject(p, obj, nil, "")
+ memberFromObject(p, obj, nil)
if obj, ok := obj.(*types.TypeName); ok {
if named, ok := obj.Type().(*types.Named); ok {
for i, n := 0, named.NumMethods(); i < n; i++ {
- memberFromObject(p, named.Method(i), nil, "")
+ memberFromObject(p, named.Method(i), nil)
}
}
}
@@ -300,8 +271,8 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
// printMu serializes printing of Packages/Functions to stdout.
var printMu sync.Mutex
-// AllPackages returns a new slice containing all packages created by
-// prog.CreatePackage in in unspecified order.
+// AllPackages returns a new slice containing all packages in the
+// program prog in unspecified order.
func (prog *Program) AllPackages() []*Package {
pkgs := make([]*Package, 0, len(prog.packages))
for _, pkg := range prog.packages {
diff --git a/vendor/golang.org/x/tools/go/ssa/doc.go b/vendor/golang.org/x/tools/go/ssa/doc.go
index 56bc2fbc1..a687de45e 100644
--- a/vendor/golang.org/x/tools/go/ssa/doc.go
+++ b/vendor/golang.org/x/tools/go/ssa/doc.go
@@ -116,6 +116,9 @@
// The ssa/ssautil package provides various utilities that depend only
// on the public API of this package.
//
+// TODO(adonovan): Consider the exceptional control-flow implications
+// of defer and recover().
+//
// TODO(adonovan): write a how-to document for all the various cases
// of trying to determine corresponding elements across the four
// domains of source locations, ast.Nodes, types.Objects,
diff --git a/vendor/golang.org/x/tools/go/ssa/emit.go b/vendor/golang.org/x/tools/go/ssa/emit.go
index d77b4407a..abb617e6d 100644
--- a/vendor/golang.org/x/tools/go/ssa/emit.go
+++ b/vendor/golang.org/x/tools/go/ssa/emit.go
@@ -13,53 +13,16 @@ import (
"go/types"
)
-// emitAlloc emits to f a new Alloc instruction allocating a variable
-// of type typ.
-//
-// The caller must set Alloc.Heap=true (for an heap-allocated variable)
-// or add the Alloc to f.Locals (for a frame-allocated variable).
-//
-// During building, a variable in f.Locals may have its Heap flag
-// set when it is discovered that its address is taken.
-// These Allocs are removed from f.Locals at the end.
-//
-// The builder should generally call one of the emit{New,Local,LocalVar} wrappers instead.
-func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
- v := &Alloc{Comment: comment}
+// emitNew emits to f a new (heap Alloc) instruction allocating an
+// object of type typ. pos is the optional source location.
+func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc {
+ v := &Alloc{Heap: true}
v.setType(types.NewPointer(typ))
v.setPos(pos)
f.emit(v)
return v
}
-// emitNew emits to f a new Alloc instruction heap-allocating a
-// variable of type typ. pos is the optional source location.
-func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc {
- alloc := emitAlloc(f, typ, pos, comment)
- alloc.Heap = true
- return alloc
-}
-
-// emitLocal creates a local var for (t, pos, comment) and
-// emits an Alloc instruction for it.
-//
-// (Use this function or emitNew for synthetic variables;
-// for source-level variables, use emitLocalVar.)
-func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc {
- local := emitAlloc(f, t, pos, comment)
- f.Locals = append(f.Locals, local)
- return local
-}
-
-// emitLocalVar creates a local var for v and emits an Alloc instruction for it.
-// Subsequent calls to f.lookup(v) return it.
-// It applies the appropriate generic instantiation to the type.
-func emitLocalVar(f *Function, v *types.Var) *Alloc {
- alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name())
- f.vars[v] = alloc
- return alloc
-}
-
// emitLoad emits to f an instruction to load the address addr into a
// new temporary, and returns the value so defined.
func emitLoad(f *Function, addr Value) *UnOp {
@@ -185,7 +148,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
// Precondition: neither argument is a named type.
func isValuePreserving(ut_src, ut_dst types.Type) bool {
// Identical underlying types?
- if types.IdenticalIgnoreTags(ut_dst, ut_src) {
+ if structTypesIdentical(ut_dst, ut_src) {
return true
}
@@ -243,13 +206,6 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
val = emitConv(f, val, types.Default(ut_src))
}
- // Record the types of operands to MakeInterface, if
- // non-parameterized, as they are the set of runtime types.
- t := val.Type()
- if f.typeparams.Len() == 0 || !f.Prog.parameterized.isParameterized(t) {
- addRuntimeType(f.Prog, t)
- }
-
mi := &MakeInterface{X: val}
mi.setType(typ)
return f.emit(mi)
@@ -581,6 +537,48 @@ func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.
return v
}
+// emitSliceToArray emits to f code to convert a slice value to an array value.
+//
+// Precondition: all types in type set of typ are arrays and convertible to all
+// types in the type set of val.Type().
+func emitSliceToArray(f *Function, val Value, typ types.Type) Value {
+ // Emit the following:
+ // if val == nil && len(typ) == 0 {
+ // ptr = &[0]T{}
+ // } else {
+ // ptr = SliceToArrayPointer(val)
+ // }
+ // v = *ptr
+
+ ptype := types.NewPointer(typ)
+ p := &SliceToArrayPointer{X: val}
+ p.setType(ptype)
+ ptr := f.emit(p)
+
+ nilb := f.newBasicBlock("slicetoarray.nil")
+ nonnilb := f.newBasicBlock("slicetoarray.nonnil")
+ done := f.newBasicBlock("slicetoarray.done")
+
+ cond := emitCompare(f, token.EQL, ptr, zeroConst(ptype), token.NoPos)
+ emitIf(f, cond, nilb, nonnilb)
+ f.currentBlock = nilb
+
+ zero := f.addLocal(typ, token.NoPos)
+ emitJump(f, done)
+ f.currentBlock = nonnilb
+
+ emitJump(f, done)
+ f.currentBlock = done
+
+ phi := &Phi{Edges: []Value{zero, ptr}, Comment: "slicetoarray"}
+ phi.pos = val.Pos()
+ phi.setType(typ)
+ x := f.emit(phi)
+ unOp := &UnOp{Op: token.MUL, X: x}
+ unOp.setType(typ)
+ return f.emit(unOp)
+}
+
// createRecoverBlock emits to f a block of code to return after a
// recovered panic, and sets f.Recover to it.
//
diff --git a/vendor/golang.org/x/tools/go/ssa/func.go b/vendor/golang.org/x/tools/go/ssa/func.go
index 65ed491ba..38c3e31ba 100644
--- a/vendor/golang.org/x/tools/go/ssa/func.go
+++ b/vendor/golang.org/x/tools/go/ssa/func.go
@@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
"go/ast"
+ "go/token"
"go/types"
"io"
"os"
@@ -107,40 +108,52 @@ type lblock struct {
// labelledBlock returns the branch target associated with the
// specified label, creating it if needed.
func (f *Function) labelledBlock(label *ast.Ident) *lblock {
- obj := f.objectOf(label).(*types.Label)
+ obj := f.objectOf(label)
lb := f.lblocks[obj]
if lb == nil {
lb = &lblock{_goto: f.newBasicBlock(label.Name)}
if f.lblocks == nil {
- f.lblocks = make(map[*types.Label]*lblock)
+ f.lblocks = make(map[types.Object]*lblock)
}
f.lblocks[obj] = lb
}
return lb
}
-// addParamVar adds a parameter to f.Params.
-func (f *Function) addParamVar(v *types.Var) *Parameter {
- name := v.Name()
- if name == "" {
- name = fmt.Sprintf("arg%d", len(f.Params))
- }
- param := &Parameter{
+// addParam adds a (non-escaping) parameter to f.Params of the
+// specified name, type and source position.
+func (f *Function) addParam(name string, typ types.Type, pos token.Pos) *Parameter {
+ v := &Parameter{
name: name,
- object: v,
- typ: f.typ(v.Type()),
+ typ: typ,
+ pos: pos,
parent: f,
}
- f.Params = append(f.Params, param)
+ f.Params = append(f.Params, v)
+ return v
+}
+
+func (f *Function) addParamObj(obj types.Object) *Parameter {
+ name := obj.Name()
+ if name == "" {
+ name = fmt.Sprintf("arg%d", len(f.Params))
+ }
+ param := f.addParam(name, f.typ(obj.Type()), obj.Pos())
+ param.object = obj
return param
}
// addSpilledParam declares a parameter that is pre-spilled to the
// stack; the function body will load/store the spilled location.
// Subsequent lifting will eliminate spills where possible.
-func (f *Function) addSpilledParam(obj *types.Var) {
- param := f.addParamVar(obj)
- spill := emitLocalVar(f, obj)
+func (f *Function) addSpilledParam(obj types.Object) {
+ param := f.addParamObj(obj)
+ spill := &Alloc{Comment: obj.Name()}
+ spill.setType(types.NewPointer(param.Type()))
+ spill.setPos(obj.Pos())
+ f.objects[obj] = spill
+ f.Locals = append(f.Locals, spill)
+ f.emit(spill)
f.emit(&Store{Addr: spill, Val: param})
}
@@ -148,7 +161,7 @@ func (f *Function) addSpilledParam(obj *types.Var) {
// Precondition: f.Type() already set.
func (f *Function) startBody() {
f.currentBlock = f.newBasicBlock("entry")
- f.vars = make(map[*types.Var]Value) // needed for some synthetics, e.g. init
+ f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init
}
// createSyntacticParams populates f.Params and generates code (spills
@@ -164,11 +177,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
if recv != nil {
for _, field := range recv.List {
for _, n := range field.Names {
- f.addSpilledParam(identVar(f, n))
+ f.addSpilledParam(f.info.Defs[n])
}
// Anonymous receiver? No need to spill.
if field.Names == nil {
- f.addParamVar(f.Signature.Recv())
+ f.addParamObj(f.Signature.Recv())
}
}
}
@@ -178,11 +191,11 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
n := len(f.Params) // 1 if has recv, 0 otherwise
for _, field := range functype.Params.List {
for _, n := range field.Names {
- f.addSpilledParam(identVar(f, n))
+ f.addSpilledParam(f.info.Defs[n])
}
// Anonymous parameter? No need to spill.
if field.Names == nil {
- f.addParamVar(f.Signature.Params().At(len(f.Params) - n))
+ f.addParamObj(f.Signature.Params().At(len(f.Params) - n))
}
}
}
@@ -192,8 +205,7 @@ func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.Func
for _, field := range functype.Results.List {
// Implicit "var" decl of locals for named results.
for _, n := range field.Names {
- namedResult := emitLocalVar(f, identVar(f, n))
- f.namedResults = append(f.namedResults, namedResult)
+ f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
}
}
}
@@ -238,14 +250,49 @@ func buildReferrers(f *Function) {
}
}
+// mayNeedRuntimeTypes returns all of the types in the body of fn that might need runtime types.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
+func mayNeedRuntimeTypes(fn *Function) []types.Type {
+ // Collect all types that may need rtypes, i.e. those that flow into an interface.
+ var ts []types.Type
+ for _, bb := range fn.Blocks {
+ for _, instr := range bb.Instrs {
+ if mi, ok := instr.(*MakeInterface); ok {
+ ts = append(ts, mi.X.Type())
+ }
+ }
+ }
+
+ // Types that contain a parameterized type are considered to not be runtime types.
+ if fn.typeparams.Len() == 0 {
+ return ts // No potentially parameterized types.
+ }
+ // Filter parameterized types, in place.
+ fn.Prog.methodsMu.Lock()
+ defer fn.Prog.methodsMu.Unlock()
+ filtered := ts[:0]
+ for _, t := range ts {
+ if !fn.Prog.parameterized.isParameterized(t) {
+ filtered = append(filtered, t)
+ }
+ }
+ return filtered
+}
+
// finishBody() finalizes the contents of the function after SSA code generation of its body.
//
// The function is not done being built until done() is called.
func (f *Function) finishBody() {
- f.vars = nil
+ f.objects = nil
f.currentBlock = nil
f.lblocks = nil
+ // Don't pin the AST in memory (except in debug mode).
+ if n := f.syntax; n != nil && !f.debugInfo() {
+ f.syntax = extentNode{n.Pos(), n.End()}
+ }
+
// Remove from f.Locals any Allocs that escape to the heap.
j := 0
for _, l := range f.Locals {
@@ -273,15 +320,15 @@ func (f *Function) finishBody() {
lift(f)
}
- // clear remaining builder state
+ // clear remaining stateful variables
f.namedResults = nil // (used by lifting)
+ f.info = nil
f.subst = nil
numberRegisters(f) // uses f.namedRegisters
}
-// done marks the building of f's SSA body complete,
-// along with any nested functions, and optionally prints them.
+// After this, function is done with BUILD phase.
func (f *Function) done() {
assert(f.parent == nil, "done called on an anonymous function")
@@ -291,7 +338,7 @@ func (f *Function) done() {
visit(anon) // anon is done building before f.
}
- f.build = nil // function is built
+ f.built = true // function is done with BUILD phase
if f.Prog.mode&PrintFunctions != 0 {
printMu.Lock()
@@ -329,6 +376,7 @@ func (f *Function) removeNilBlocks() {
// size of the instruction stream, and causes Functions to depend upon
// the ASTs, potentially keeping them live in memory for longer.
func (pkg *Package) SetDebugMode(debug bool) {
+ // TODO(adonovan): do we want ast.File granularity?
pkg.debug = debug
}
@@ -339,25 +387,40 @@ func (f *Function) debugInfo() bool {
return p != nil && p.debug
}
+// addNamedLocal creates a local variable, adds it to function f and
+// returns it. Its name and type are taken from obj. Subsequent
+// calls to f.lookup(obj) will return the same local.
+func (f *Function) addNamedLocal(obj types.Object) *Alloc {
+ l := f.addLocal(obj.Type(), obj.Pos())
+ l.Comment = obj.Name()
+ f.objects[obj] = l
+ return l
+}
+
+func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc {
+ return f.addNamedLocal(f.info.Defs[id])
+}
+
+// addLocal creates an anonymous local variable of type typ, adds it
+// to function f and returns it. pos is the optional source location.
+func (f *Function) addLocal(typ types.Type, pos token.Pos) *Alloc {
+ typ = f.typ(typ)
+ v := &Alloc{}
+ v.setType(types.NewPointer(typ))
+ v.setPos(pos)
+ f.Locals = append(f.Locals, v)
+ f.emit(v)
+ return v
+}
+
// lookup returns the address of the named variable identified by obj
// that is local to function f or one of its enclosing functions.
// If escaping, the reference comes from a potentially escaping pointer
// expression and the referent must be heap-allocated.
-// We assume the referent is a *Alloc or *Phi.
-// (The only Phis at this stage are those created directly by go1.22 "for" loops.)
-func (f *Function) lookup(obj *types.Var, escaping bool) Value {
- if v, ok := f.vars[obj]; ok {
- if escaping {
- switch v := v.(type) {
- case *Alloc:
- v.Heap = true
- case *Phi:
- for _, edge := range v.Edges {
- if alloc, ok := edge.(*Alloc); ok {
- alloc.Heap = true
- }
- }
- }
+func (f *Function) lookup(obj types.Object, escaping bool) Value {
+ if v, ok := f.objects[obj]; ok {
+ if alloc, ok := v.(*Alloc); ok && escaping {
+ alloc.Heap = true
}
return v // function-local var (address)
}
@@ -375,7 +438,7 @@ func (f *Function) lookup(obj *types.Var, escaping bool) Value {
outer: outer,
parent: f,
}
- f.vars[obj] = v
+ f.objects[obj] = v
f.FreeVars = append(f.FreeVars, v)
return v
}
@@ -473,7 +536,7 @@ func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *ty
func (fn *Function) declaredPackage() *Package {
switch {
case fn.Pkg != nil:
- return fn.Pkg // non-generic function (does that follow??)
+ return fn.Pkg // non-generic function
case fn.topLevelOrigin != nil:
return fn.topLevelOrigin.Pkg // instance of a named generic function
case fn.parent != nil:
@@ -626,11 +689,17 @@ func (prog *Program) NewFunction(name string, sig *types.Signature, provenance s
return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
}
-// Syntax returns the function's syntax (*ast.Func{Decl,Lit)
-// if it was produced from syntax.
-func (f *Function) Syntax() ast.Node { return f.syntax }
+type extentNode [2]token.Pos
-// identVar returns the variable defined by id.
-func identVar(fn *Function, id *ast.Ident) *types.Var {
- return fn.info.Defs[id].(*types.Var)
-}
+func (n extentNode) Pos() token.Pos { return n[0] }
+func (n extentNode) End() token.Pos { return n[1] }
+
+// Syntax returns an ast.Node whose Pos/End methods provide the
+// lexical extent of the function if it was defined by Go source code
+// (f.Synthetic==""), or nil otherwise.
+//
+// If f was built with debug information (see Package.SetDebugRef),
+// the result is the *ast.FuncDecl or *ast.FuncLit that declared the
+// function. Otherwise, it is an opaque Node providing only position
+// information; this avoids pinning the AST in memory.
+func (f *Function) Syntax() ast.Node { return f.syntax }
diff --git a/vendor/golang.org/x/tools/go/ssa/identical.go b/vendor/golang.org/x/tools/go/ssa/identical.go
new file mode 100644
index 000000000..e8026967b
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/ssa/identical.go
@@ -0,0 +1,12 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.8
+// +build go1.8
+
+package ssa
+
+import "go/types"
+
+var structTypesIdentical = types.IdenticalIgnoreTags
diff --git a/vendor/golang.org/x/tools/go/ssa/identical_17.go b/vendor/golang.org/x/tools/go/ssa/identical_17.go
new file mode 100644
index 000000000..575aa5dfc
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/ssa/identical_17.go
@@ -0,0 +1,12 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !go1.8
+// +build !go1.8
+
+package ssa
+
+import "go/types"
+
+var structTypesIdentical = types.Identical
diff --git a/vendor/golang.org/x/tools/go/ssa/instantiate.go b/vendor/golang.org/x/tools/go/ssa/instantiate.go
index 370284ab7..38249dea2 100644
--- a/vendor/golang.org/x/tools/go/ssa/instantiate.go
+++ b/vendor/golang.org/x/tools/go/ssa/instantiate.go
@@ -6,59 +6,129 @@ package ssa
import (
"fmt"
+ "go/ast"
"go/types"
- "sync"
"golang.org/x/tools/internal/typeparams"
)
-// A generic records information about a generic origin function,
-// including a cache of existing instantiations.
-type generic struct {
- instancesMu sync.Mutex
- instances map[*typeList]*Function // canonical type arguments to an instance.
+// _Instances returns all of the instances generated by runtime types for this function in an unspecified order.
+//
+// Thread-safe.
+//
+// This is an experimental interface! It may change without warning.
+func (prog *Program) _Instances(fn *Function) []*Function {
+ if fn.typeparams.Len() == 0 || len(fn.typeargs) > 0 {
+ return nil
+ }
+
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+ return prog.instances[fn].list()
+}
+
+// A set of instantiations of a generic function fn.
+type instanceSet struct {
+ fn *Function // fn.typeparams.Len() > 0 and len(fn.typeargs) == 0.
+ instances map[*typeList]*Function // canonical type arguments to an instance.
+ syntax *ast.FuncDecl // fn.syntax copy for instantiating after fn is done. nil on synthetic packages.
+ info *types.Info // fn.pkg.info copy for building after fn is done.. nil on synthetic packages.
+
+ // TODO(taking): Consider ways to allow for clearing syntax and info when done building.
+ // May require a public API change as MethodValue can request these be built after prog.Build() is done.
+}
+
+func (insts *instanceSet) list() []*Function {
+ if insts == nil {
+ return nil
+ }
+
+ fns := make([]*Function, 0, len(insts.instances))
+ for _, fn := range insts.instances {
+ fns = append(fns, fn)
+ }
+ return fns
}
-// instance returns a Function that is the instantiation of generic
-// origin function fn with the type arguments targs.
+// createInstanceSet adds a new instanceSet for a generic function fn if one does not exist.
//
-// Any created instance is added to cr.
+// Precondition: fn is a package level declaration (function or method).
//
-// Acquires fn.generic.instancesMu.
-func (fn *Function) instance(targs []types.Type, cr *creator) *Function {
- key := fn.Prog.canon.List(targs)
-
- gen := fn.generic
-
- gen.instancesMu.Lock()
- defer gen.instancesMu.Unlock()
- inst, ok := gen.instances[key]
- if !ok {
- inst = createInstance(fn, targs, cr)
- if gen.instances == nil {
- gen.instances = make(map[*typeList]*Function)
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu)
+func (prog *Program) createInstanceSet(fn *Function) {
+ assert(fn.typeparams.Len() > 0 && len(fn.typeargs) == 0, "Can only create instance sets for generic functions")
+
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ syntax, _ := fn.syntax.(*ast.FuncDecl)
+ assert((syntax == nil) == (fn.syntax == nil), "fn.syntax is either nil or a *ast.FuncDecl")
+
+ if _, ok := prog.instances[fn]; !ok {
+ prog.instances[fn] = &instanceSet{
+ fn: fn,
+ syntax: syntax,
+ info: fn.info,
}
- gen.instances[key] = inst
}
- return inst
}
-// createInstance returns the instantiation of generic function fn using targs.
-// If the instantiation is created, this is added to cr.
+// needsInstance returns a Function that is the instantiation of fn with the type arguments targs.
//
-// Requires fn.generic.instancesMu.
-func createInstance(fn *Function, targs []types.Type, cr *creator) *Function {
+// Any CREATEd instance is added to cr.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodMu)
+func (prog *Program) needsInstance(fn *Function, targs []types.Type, cr *creator) *Function {
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ return prog.lookupOrCreateInstance(fn, targs, cr)
+}
+
+// lookupOrCreateInstance returns a Function that is the instantiation of fn with the type arguments targs.
+//
+// Any CREATEd instance is added to cr.
+//
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodMu)
+func (prog *Program) lookupOrCreateInstance(fn *Function, targs []types.Type, cr *creator) *Function {
+ return prog.instances[fn].lookupOrCreate(targs, &prog.parameterized, cr)
+}
+
+// lookupOrCreate returns the instantiation of insts.fn using targs.
+// If the instantiation is created, this is added to cr.
+func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWalker, cr *creator) *Function {
+ if insts.instances == nil {
+ insts.instances = make(map[*typeList]*Function)
+ }
+
+ fn := insts.fn
prog := fn.Prog
- // Compute signature.
+ // canonicalize on a tuple of targs. Sig is not unique.
+ //
+ // func A[T any]() {
+ // var x T
+ // fmt.Println("%T", x)
+ // }
+ key := prog.canon.List(targs)
+ if inst, ok := insts.instances[key]; ok {
+ return inst
+ }
+
+ // CREATE instance/instantiation wrapper
+ var syntax ast.Node
+ if insts.syntax != nil {
+ syntax = insts.syntax
+ }
+
var sig *types.Signature
var obj *types.Func
if recv := fn.Signature.Recv(); recv != nil {
// method
- obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt)
+ m := fn.object.(*types.Func)
+ obj = prog.canon.instantiateMethod(m, targs, prog.ctxt)
sig = obj.Type().(*types.Signature)
} else {
- // function
instSig, err := typeparams.Instantiate(prog.ctxt, fn.Signature, targs, false)
if err != nil {
panic(err)
@@ -67,48 +137,41 @@ func createInstance(fn *Function, targs []types.Type, cr *creator) *Function {
if !ok {
panic("Instantiate of a Signature returned a non-signature")
}
- obj = fn.object // instantiation does not exist yet
+ obj = fn.object.(*types.Func) // instantiation does not exist yet
sig = prog.canon.Type(instance).(*types.Signature)
}
- // Choose strategy (instance or wrapper).
- var (
- synthetic string
- subst *subster
- build buildFunc
- )
- if prog.mode&InstantiateGenerics != 0 && !prog.parameterized.anyParameterized(targs) {
+ var synthetic string
+ var subst *subster
+
+ concrete := !parameterized.anyParameterized(targs)
+
+ if prog.mode&InstantiateGenerics != 0 && concrete {
synthetic = fmt.Sprintf("instance of %s", fn.Name())
- if fn.syntax != nil {
- scope := typeparams.OriginMethod(obj).Scope()
- subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false)
- build = (*builder).buildFromSyntax
- } else {
- build = (*builder).buildParamsOnly
- }
+ scope := typeparams.OriginMethod(obj).Scope()
+ subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false)
} else {
synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
- build = (*builder).buildInstantiationWrapper
}
- /* generic instance or instantiation wrapper */
+ name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique
instance := &Function{
- name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique
+ name: name,
object: obj,
Signature: sig,
Synthetic: synthetic,
- syntax: fn.syntax, // \
- info: fn.info, // } empty for non-created packages
- goversion: fn.goversion, // /
- build: build,
+ syntax: syntax,
topLevelOrigin: fn,
pos: obj.Pos(),
Pkg: nil,
Prog: fn.Prog,
typeparams: fn.typeparams, // share with origin
typeargs: targs,
+ info: insts.info, // on synthetic packages info is nil.
subst: subst,
}
+
cr.Add(instance)
+ insts.instances[key] = instance
return instance
}
diff --git a/vendor/golang.org/x/tools/go/ssa/lift.go b/vendor/golang.org/x/tools/go/ssa/lift.go
index da49fe9f1..dbd8790c6 100644
--- a/vendor/golang.org/x/tools/go/ssa/lift.go
+++ b/vendor/golang.org/x/tools/go/ssa/lift.go
@@ -103,14 +103,9 @@ func buildDomFrontier(fn *Function) domFrontier {
}
func removeInstr(refs []Instruction, instr Instruction) []Instruction {
- return removeInstrsIf(refs, func(i Instruction) bool { return i == instr })
-}
-
-func removeInstrsIf(refs []Instruction, p func(Instruction) bool) []Instruction {
- // TODO(taking): replace with go1.22 slices.DeleteFunc.
i := 0
for _, ref := range refs {
- if p(ref) {
+ if ref == instr {
continue
}
refs[i] = ref
diff --git a/vendor/golang.org/x/tools/go/ssa/methods.go b/vendor/golang.org/x/tools/go/ssa/methods.go
index 03ef62521..294498371 100644
--- a/vendor/golang.org/x/tools/go/ssa/methods.go
+++ b/vendor/golang.org/x/tools/go/ssa/methods.go
@@ -10,124 +10,54 @@ import (
"fmt"
"go/types"
- "golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/typeparams"
)
// MethodValue returns the Function implementing method sel, building
-// wrapper methods on demand. It returns nil if sel denotes an
-// interface or generic method.
+// wrapper methods on demand. It returns nil if sel denotes an
+// abstract (interface or parameterized) method.
//
// Precondition: sel.Kind() == MethodVal.
//
// Thread-safe.
//
-// Acquires prog.methodsMu.
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
func (prog *Program) MethodValue(sel *types.Selection) *Function {
if sel.Kind() != types.MethodVal {
panic(fmt.Sprintf("MethodValue(%s) kind != MethodVal", sel))
}
T := sel.Recv()
if types.IsInterface(T) {
- return nil // interface method or type parameter
+ return nil // abstract method (interface, possibly type param)
}
-
- if prog.parameterized.isParameterized(T) {
- return nil // generic method
- }
-
if prog.mode&LogSource != 0 {
defer logStack("MethodValue %s %v", T, sel)()
}
- var cr creator
+ var m *Function
+ b := builder{created: &creator{}}
- m := func() *Function {
- prog.methodsMu.Lock()
- defer prog.methodsMu.Unlock()
-
- // Get or create SSA method set.
- mset, ok := prog.methodSets.At(T).(*methodSet)
- if !ok {
- mset = &methodSet{mapping: make(map[string]*Function)}
- prog.methodSets.Set(T, mset)
- }
-
- // Get or create SSA method.
- id := sel.Obj().Id()
- fn, ok := mset.mapping[id]
- if !ok {
- obj := sel.Obj().(*types.Func)
- _, ptrObj := deptr(recvType(obj))
- _, ptrRecv := deptr(T)
- needsPromotion := len(sel.Index()) > 1
- needsIndirection := !ptrObj && ptrRecv
- if needsPromotion || needsIndirection {
- fn = createWrapper(prog, toSelection(sel), &cr)
- } else {
- fn = prog.objectMethod(obj, &cr)
- }
- if fn.Signature.Recv() == nil {
- panic(fn)
- }
- mset.mapping[id] = fn
- }
-
- return fn
- }()
-
- b := builder{created: &cr}
- b.iterate()
-
- return m
-}
-
-// objectMethod returns the Function for a given method symbol.
-// The symbol may be an instance of a generic function. It need not
-// belong to an existing SSA package created by a call to
-// prog.CreatePackage.
-//
-// objectMethod panics if the function is not a method.
-//
-// Acquires prog.objectMethodsMu.
-func (prog *Program) objectMethod(obj *types.Func, cr *creator) *Function {
- sig := obj.Type().(*types.Signature)
- if sig.Recv() == nil {
- panic("not a method: " + obj.String())
+ prog.methodsMu.Lock()
+ // Checks whether a type param is reachable from T.
+ // This is an expensive check. May need to be optimized later.
+ if !prog.parameterized.isParameterized(T) {
+ m = prog.addMethod(prog.createMethodSet(T), sel, b.created)
}
+ prog.methodsMu.Unlock()
- // Belongs to a created package?
- if fn := prog.FuncValue(obj); fn != nil {
- return fn
+ if m == nil {
+ return nil // abstract method (generic)
}
-
- // Instantiation of generic?
- if originObj := typeparams.OriginMethod(obj); originObj != obj {
- origin := prog.objectMethod(originObj, cr)
- assert(origin.typeparams.Len() > 0, "origin is not generic")
- targs := receiverTypeArgs(obj)
- return origin.instance(targs, cr)
- }
-
- // Consult/update cache of methods created from types.Func.
- prog.objectMethodsMu.Lock()
- defer prog.objectMethodsMu.Unlock()
- fn, ok := prog.objectMethods[obj]
- if !ok {
- fn = createFunction(prog, obj, obj.Name(), nil, nil, "", cr)
- fn.Synthetic = "from type information (on demand)"
-
- if prog.objectMethods == nil {
- prog.objectMethods = make(map[*types.Func]*Function)
- }
- prog.objectMethods[obj] = fn
+ for !b.done() {
+ b.buildCreated()
+ b.needsRuntimeTypes()
}
- return fn
+ return m
}
// LookupMethod returns the implementation of the method of type T
// identified by (pkg, name). It returns nil if the method exists but
-// is an interface method or generic method, and panics if T has no such method.
+// is abstract, and panics if T has no such method.
func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string) *Function {
sel := prog.MethodSets.MethodSet(T).Lookup(pkg, name)
if sel == nil {
@@ -138,136 +68,208 @@ func (prog *Program) LookupMethod(T types.Type, pkg *types.Package, name string)
// methodSet contains the (concrete) methods of a concrete type (non-interface, non-parameterized).
type methodSet struct {
- mapping map[string]*Function // populated lazily
+ mapping map[string]*Function // populated lazily
+ complete bool // mapping contains all methods
}
-// RuntimeTypes returns a new unordered slice containing all types in
-// the program for which a runtime type is required.
-//
-// A runtime type is required for any non-parameterized, non-interface
-// type that is converted to an interface, or for any type (including
-// interface types) derivable from one through reflection.
-//
-// The methods of such types may be reachable through reflection or
-// interface calls even if they are never called directly.
+// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized.
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func (prog *Program) createMethodSet(T types.Type) *methodSet {
+ if prog.mode&SanityCheckFunctions != 0 {
+ if types.IsInterface(T) || prog.parameterized.isParameterized(T) {
+ panic("type is interface or parameterized")
+ }
+ }
+ mset, ok := prog.methodSets.At(T).(*methodSet)
+ if !ok {
+ mset = &methodSet{mapping: make(map[string]*Function)}
+ prog.methodSets.Set(T, mset)
+ }
+ return mset
+}
+
+// Adds any created functions to cr.
+// Precondition: T is a concrete type, e.g. !isInterface(T) and not parameterized.
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func (prog *Program) addMethod(mset *methodSet, sel *types.Selection, cr *creator) *Function {
+ if sel.Kind() == types.MethodExpr {
+ panic(sel)
+ }
+ id := sel.Obj().Id()
+ fn := mset.mapping[id]
+ if fn == nil {
+ sel := toSelection(sel)
+ obj := sel.obj.(*types.Func)
+
+ _, ptrObj := deptr(recvType(obj))
+ _, ptrRecv := deptr(sel.recv)
+
+ needsPromotion := len(sel.index) > 1
+ needsIndirection := !ptrObj && ptrRecv
+ if needsPromotion || needsIndirection {
+ fn = makeWrapper(prog, sel, cr)
+ } else {
+ fn = prog.originFunc(obj)
+ if fn.typeparams.Len() > 0 { // instantiate
+ targs := receiverTypeArgs(obj)
+ fn = prog.lookupOrCreateInstance(fn, targs, cr)
+ }
+ }
+ if fn.Signature.Recv() == nil {
+ panic(fn) // missing receiver
+ }
+ mset.mapping[id] = fn
+ }
+ return fn
+}
+
+// RuntimeTypes returns a new unordered slice containing all
+// concrete types in the program for which a complete (non-empty)
+// method set is required at run-time.
//
// Thread-safe.
//
-// Acquires prog.runtimeTypesMu.
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
func (prog *Program) RuntimeTypes() []types.Type {
- prog.runtimeTypesMu.Lock()
- defer prog.runtimeTypesMu.Unlock()
- return prog.runtimeTypes.Keys()
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ var res []types.Type
+ prog.methodSets.Iterate(func(T types.Type, v interface{}) {
+ if v.(*methodSet).complete {
+ res = append(res, T)
+ }
+ })
+ return res
+}
+
+// declaredFunc returns the concrete function/method denoted by obj.
+// Panic ensues if there is none.
+func (prog *Program) declaredFunc(obj *types.Func) *Function {
+ if v := prog.packageLevelMember(obj); v != nil {
+ return v.(*Function)
+ }
+ panic("no concrete method: " + obj.String())
}
-// forEachReachable calls f for type T and each type reachable from
-// its type through reflection.
+// needMethodsOf ensures that runtime type information (including the
+// complete method set) is available for the specified type T and all
+// its subcomponents.
+//
+// needMethodsOf must be called for at least every type that is an
+// operand of some MakeInterface instruction, and for the type of
+// every exported package member.
+//
+// Adds any created functions to cr.
+//
+// Precondition: T is not a method signature (*Signature with Recv()!=nil).
+// Precondition: T is not parameterized.
+//
+// Thread-safe. (Called via Package.build from multiple builder goroutines.)
//
-// The function f must use memoization to break cycles and
-// return false when the type has already been visited.
+// TODO(adonovan): make this faster. It accounts for 20% of SSA build time.
//
-// TODO(adonovan): publish in typeutil and share with go/callgraph/rta.
-func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types.Type) bool) {
- var visit func(T types.Type, skip bool)
- visit = func(T types.Type, skip bool) {
- if !skip {
- if !f(T) {
- return
+// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+func (prog *Program) needMethodsOf(T types.Type, cr *creator) {
+ prog.methodsMu.Lock()
+ prog.needMethods(T, false, cr)
+ prog.methodsMu.Unlock()
+}
+
+// Precondition: T is not a method signature (*Signature with Recv()!=nil).
+// Precondition: T is not parameterized.
+// Recursive case: skip => don't create methods for T.
+//
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func (prog *Program) needMethods(T types.Type, skip bool, cr *creator) {
+ // Each package maintains its own set of types it has visited.
+ if prevSkip, ok := prog.runtimeTypes.At(T).(bool); ok {
+ // needMethods(T) was previously called
+ if !prevSkip || skip {
+ return // already seen, with same or false 'skip' value
+ }
+ }
+ prog.runtimeTypes.Set(T, skip)
+
+ tmset := prog.MethodSets.MethodSet(T)
+
+ if !skip && !types.IsInterface(T) && tmset.Len() > 0 {
+ // Create methods of T.
+ mset := prog.createMethodSet(T)
+ if !mset.complete {
+ mset.complete = true
+ n := tmset.Len()
+ for i := 0; i < n; i++ {
+ prog.addMethod(mset, tmset.At(i), cr)
}
}
+ }
- // Recursion over signatures of each method.
- tmset := msets.MethodSet(T)
- for i := 0; i < tmset.Len(); i++ {
- sig := tmset.At(i).Type().(*types.Signature)
- // It is tempting to call visit(sig, false)
- // but, as noted in golang.org/cl/65450043,
- // the Signature.Recv field is ignored by
- // types.Identical and typeutil.Map, which
- // is confusing at best.
- //
- // More importantly, the true signature rtype
- // reachable from a method using reflection
- // has no receiver but an extra ordinary parameter.
- // For the Read method of io.Reader we want:
- // func(Reader, []byte) (int, error)
- // but here sig is:
- // func([]byte) (int, error)
- // with .Recv = Reader (though it is hard to
- // notice because it doesn't affect Signature.String
- // or types.Identical).
- //
- // TODO(adonovan): construct and visit the correct
- // non-method signature with an extra parameter
- // (though since unnamed func types have no methods
- // there is essentially no actual demand for this).
- //
- // TODO(adonovan): document whether or not it is
- // safe to skip non-exported methods (as RTA does).
- visit(sig.Params(), true) // skip the Tuple
- visit(sig.Results(), true) // skip the Tuple
- }
+ // Recursion over signatures of each method.
+ for i := 0; i < tmset.Len(); i++ {
+ sig := tmset.At(i).Type().(*types.Signature)
+ prog.needMethods(sig.Params(), false, cr)
+ prog.needMethods(sig.Results(), false, cr)
+ }
- switch T := T.(type) {
- case *types.Basic:
- // nop
+ switch t := T.(type) {
+ case *types.Basic:
+ // nop
- case *types.Interface:
- // nop---handled by recursion over method set.
+ case *types.Interface:
+ // nop---handled by recursion over method set.
- case *types.Pointer:
- visit(T.Elem(), false)
+ case *types.Pointer:
+ prog.needMethods(t.Elem(), false, cr)
- case *types.Slice:
- visit(T.Elem(), false)
+ case *types.Slice:
+ prog.needMethods(t.Elem(), false, cr)
- case *types.Chan:
- visit(T.Elem(), false)
+ case *types.Chan:
+ prog.needMethods(t.Elem(), false, cr)
- case *types.Map:
- visit(T.Key(), false)
- visit(T.Elem(), false)
+ case *types.Map:
+ prog.needMethods(t.Key(), false, cr)
+ prog.needMethods(t.Elem(), false, cr)
- case *types.Signature:
- if T.Recv() != nil {
- panic(fmt.Sprintf("Signature %s has Recv %s", T, T.Recv()))
- }
- visit(T.Params(), true) // skip the Tuple
- visit(T.Results(), true) // skip the Tuple
-
- case *types.Named:
- // A pointer-to-named type can be derived from a named
- // type via reflection. It may have methods too.
- visit(types.NewPointer(T), false)
-
- // Consider 'type T struct{S}' where S has methods.
- // Reflection provides no way to get from T to struct{S},
- // only to S, so the method set of struct{S} is unwanted,
- // so set 'skip' flag during recursion.
- visit(T.Underlying(), true) // skip the unnamed type
-
- case *types.Array:
- visit(T.Elem(), false)
-
- case *types.Struct:
- for i, n := 0, T.NumFields(); i < n; i++ {
- // TODO(adonovan): document whether or not
- // it is safe to skip non-exported fields.
- visit(T.Field(i).Type(), false)
- }
+ case *types.Signature:
+ if t.Recv() != nil {
+ panic(fmt.Sprintf("Signature %s has Recv %s", t, t.Recv()))
+ }
+ prog.needMethods(t.Params(), false, cr)
+ prog.needMethods(t.Results(), false, cr)
+
+ case *types.Named:
+ // A pointer-to-named type can be derived from a named
+ // type via reflection. It may have methods too.
+ prog.needMethods(types.NewPointer(T), false, cr)
+
+ // Consider 'type T struct{S}' where S has methods.
+ // Reflection provides no way to get from T to struct{S},
+ // only to S, so the method set of struct{S} is unwanted,
+ // so set 'skip' flag during recursion.
+ prog.needMethods(t.Underlying(), true, cr)
+
+ case *types.Array:
+ prog.needMethods(t.Elem(), false, cr)
+
+ case *types.Struct:
+ for i, n := 0, t.NumFields(); i < n; i++ {
+ prog.needMethods(t.Field(i).Type(), false, cr)
+ }
- case *types.Tuple:
- for i, n := 0, T.Len(); i < n; i++ {
- visit(T.At(i).Type(), false)
- }
+ case *types.Tuple:
+ for i, n := 0, t.Len(); i < n; i++ {
+ prog.needMethods(t.At(i).Type(), false, cr)
+ }
- case *typeparams.TypeParam, *typeparams.Union:
- // forEachReachable must not be called on parameterized types.
- panic(T)
+ case *typeparams.TypeParam:
+ panic(T) // type parameters are always abstract.
- default:
- panic(T)
- }
+ case *typeparams.Union:
+ // nop
+
+ default:
+ panic(T)
}
- visit(T, false)
}
diff --git a/vendor/golang.org/x/tools/go/ssa/parameterized.go b/vendor/golang.org/x/tools/go/ssa/parameterized.go
index 656417ac8..b90ee0e86 100644
--- a/vendor/golang.org/x/tools/go/ssa/parameterized.go
+++ b/vendor/golang.org/x/tools/go/ssa/parameterized.go
@@ -6,7 +6,6 @@ package ssa
import (
"go/types"
- "sync"
"golang.org/x/tools/internal/typeparams"
)
@@ -15,24 +14,11 @@ import (
//
// NOTE: Adapted from go/types/infer.go. If that is exported in a future release remove this copy.
type tpWalker struct {
- mu sync.Mutex
seen map[types.Type]bool
}
-// isParameterized reports whether t recursively contains a type parameter.
-// Thread-safe.
-func (w *tpWalker) isParameterized(t types.Type) bool {
- // TODO(adonovan): profile. If this operation is expensive,
- // handle the most common but shallow cases such as T, pkg.T,
- // *T without consulting the cache under the lock.
-
- w.mu.Lock()
- defer w.mu.Unlock()
- return w.isParameterizedLocked(t)
-}
-
-// Requires w.mu.
-func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
+// isParameterized returns true when typ reaches any type parameter.
+func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
// NOTE: Adapted from go/types/infer.go. Try to keep in sync.
// detect cycles
@@ -49,25 +35,25 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
break
case *types.Array:
- return w.isParameterizedLocked(t.Elem())
+ return w.isParameterized(t.Elem())
case *types.Slice:
- return w.isParameterizedLocked(t.Elem())
+ return w.isParameterized(t.Elem())
case *types.Struct:
for i, n := 0, t.NumFields(); i < n; i++ {
- if w.isParameterizedLocked(t.Field(i).Type()) {
+ if w.isParameterized(t.Field(i).Type()) {
return true
}
}
case *types.Pointer:
- return w.isParameterizedLocked(t.Elem())
+ return w.isParameterized(t.Elem())
case *types.Tuple:
n := t.Len()
for i := 0; i < n; i++ {
- if w.isParameterizedLocked(t.At(i).Type()) {
+ if w.isParameterized(t.At(i).Type()) {
return true
}
}
@@ -80,11 +66,11 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
// Similarly, the receiver of a method may declare (rather than
// use) type parameters, we don't care about those either.
// Thus, we only need to look at the input and result parameters.
- return w.isParameterizedLocked(t.Params()) || w.isParameterizedLocked(t.Results())
+ return w.isParameterized(t.Params()) || w.isParameterized(t.Results())
case *types.Interface:
for i, n := 0, t.NumMethods(); i < n; i++ {
- if w.isParameterizedLocked(t.Method(i).Type()) {
+ if w.isParameterized(t.Method(i).Type()) {
return true
}
}
@@ -93,16 +79,16 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
panic(err)
}
for _, term := range terms {
- if w.isParameterizedLocked(term.Type()) {
+ if w.isParameterized(term.Type()) {
return true
}
}
case *types.Map:
- return w.isParameterizedLocked(t.Key()) || w.isParameterizedLocked(t.Elem())
+ return w.isParameterized(t.Key()) || w.isParameterized(t.Elem())
case *types.Chan:
- return w.isParameterizedLocked(t.Elem())
+ return w.isParameterized(t.Elem())
case *types.Named:
args := typeparams.NamedTypeArgs(t)
@@ -111,11 +97,11 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
return true
}
for i, n := 0, args.Len(); i < n; i++ {
- if w.isParameterizedLocked(args.At(i)) {
+ if w.isParameterized(args.At(i)) {
return true
}
}
- return w.isParameterizedLocked(t.Underlying()) // recurse for types local to parameterized functions
+ return w.isParameterized(t.Underlying()) // recurse for types local to parameterized functions
case *typeparams.TypeParam:
return true
@@ -127,13 +113,9 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
return false
}
-// anyParameterized reports whether any element of ts is parameterized.
-// Thread-safe.
func (w *tpWalker) anyParameterized(ts []types.Type) bool {
- w.mu.Lock()
- defer w.mu.Unlock()
for _, t := range ts {
- if w.isParameterizedLocked(t) {
+ if w.isParameterized(t) {
return true
}
}
diff --git a/vendor/golang.org/x/tools/go/ssa/sanity.go b/vendor/golang.org/x/tools/go/ssa/sanity.go
index 28ec131f8..886be0532 100644
--- a/vendor/golang.org/x/tools/go/ssa/sanity.go
+++ b/vendor/golang.org/x/tools/go/ssa/sanity.go
@@ -422,8 +422,7 @@ func (s *sanity) checkFunction(fn *Function) bool {
// shared across packages, or duplicated as weak symbols in a
// separate-compilation model), and error.Error.
if fn.Pkg == nil {
- if strings.HasPrefix(fn.Synthetic, "from type information (on demand)") ||
- strings.HasPrefix(fn.Synthetic, "wrapper ") ||
+ if strings.HasPrefix(fn.Synthetic, "wrapper ") ||
strings.HasPrefix(fn.Synthetic, "bound ") ||
strings.HasPrefix(fn.Synthetic, "thunk ") ||
strings.HasSuffix(fn.name, "Error") ||
diff --git a/vendor/golang.org/x/tools/go/ssa/source.go b/vendor/golang.org/x/tools/go/ssa/source.go
index 6700305bd..9c900e3aa 100644
--- a/vendor/golang.org/x/tools/go/ssa/source.go
+++ b/vendor/golang.org/x/tools/go/ssa/source.go
@@ -172,19 +172,16 @@ func (f *Function) ValueForExpr(e ast.Expr) (value Value, isAddr bool) {
// --- Lookup functions for source-level named entities (types.Objects) ---
// Package returns the SSA Package corresponding to the specified
-// type-checker package. It returns nil if no such Package was
-// created by a prior call to prog.CreatePackage.
-func (prog *Program) Package(pkg *types.Package) *Package {
- return prog.packages[pkg]
+// type-checker package object.
+// It returns nil if no such SSA package has been created.
+func (prog *Program) Package(obj *types.Package) *Package {
+ return prog.packages[obj]
}
-// packageLevelMember returns the package-level member corresponding
-// to the specified symbol, which may be a package-level const
-// (*NamedConst), var (*Global) or func/method (*Function) of some
-// package in prog.
-//
-// It returns nil if the object belongs to a package that has not been
-// created by prog.CreatePackage.
+// packageLevelMember returns the package-level member corresponding to
+// the specified named object, which may be a package-level const
+// (*NamedConst), var (*Global) or func (*Function) of some package in
+// prog. It returns nil if the object is not found.
func (prog *Program) packageLevelMember(obj types.Object) Member {
if pkg, ok := prog.packages[obj.Pkg()]; ok {
return pkg.objects[obj]
@@ -192,16 +189,24 @@ func (prog *Program) packageLevelMember(obj types.Object) Member {
return nil
}
-// FuncValue returns the SSA function or (non-interface) method
-// denoted by the specified func symbol. It returns nil id the symbol
-// denotes an interface method, or belongs to a package that was not
-// created by prog.CreatePackage.
+// originFunc returns the package-level generic function that is the
+// origin of obj. If returns nil if the generic function is not found.
+func (prog *Program) originFunc(obj *types.Func) *Function {
+ return prog.declaredFunc(typeparams.OriginMethod(obj))
+}
+
+// FuncValue returns the concrete Function denoted by the source-level
+// named function obj, or nil if obj denotes an interface method.
+//
+// TODO(adonovan): check the invariant that obj.Type() matches the
+// result's Signature, both in the params/results and in the receiver.
func (prog *Program) FuncValue(obj *types.Func) *Function {
fn, _ := prog.packageLevelMember(obj).(*Function)
return fn
}
-// ConstValue returns the SSA constant denoted by the specified const symbol.
+// ConstValue returns the SSA Value denoted by the source-level named
+// constant obj.
func (prog *Program) ConstValue(obj *types.Const) *Const {
// TODO(adonovan): opt: share (don't reallocate)
// Consts for const objects and constant ast.Exprs.
@@ -218,7 +223,7 @@ func (prog *Program) ConstValue(obj *types.Const) *Const {
}
// VarValue returns the SSA Value that corresponds to a specific
-// identifier denoting the specified var symbol.
+// identifier denoting the source-level named variable obj.
//
// VarValue returns nil if a local variable was not found, perhaps
// because its package was not built, the debug information was not
diff --git a/vendor/golang.org/x/tools/go/ssa/ssa.go b/vendor/golang.org/x/tools/go/ssa/ssa.go
index 58a641a1f..bd42f2e0a 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssa.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssa.go
@@ -23,25 +23,20 @@ import (
type Program struct {
Fset *token.FileSet // position information for the files of this Program
imported map[string]*Package // all importable Packages, keyed by import path
- packages map[*types.Package]*Package // all created Packages
+ packages map[*types.Package]*Package // all loaded Packages, keyed by object
mode BuilderMode // set of mode bits for SSA construction
MethodSets typeutil.MethodSetCache // cache of type-checker's method-sets
canon *canonizer // type canonicalization map
ctxt *typeparams.Context // cache for type checking instantiations
- methodsMu sync.Mutex
- methodSets typeutil.Map // maps type to its concrete *methodSet
-
- parameterized tpWalker // memoization of whether a type refers to type parameters
-
- runtimeTypesMu sync.Mutex
- runtimeTypes typeutil.Map // set of runtime types (from MakeInterface)
-
- // objectMethods is a memoization of objectMethod
- // to avoid creation of duplicate methods from type information.
- objectMethodsMu sync.Mutex
- objectMethods map[*types.Func]*Function
+ methodsMu sync.Mutex // guards the following maps:
+ methodSets typeutil.Map // maps type to its concrete methodSet
+ runtimeTypes typeutil.Map // types for which rtypes are needed
+ bounds map[boundsKey]*Function // bounds for curried x.Method closures
+ thunks map[selectionKey]*Function // thunks for T.Method expressions
+ instances map[*Function]*instanceSet // instances of generic functions
+ parameterized tpWalker // determines whether a type reaches a type parameter.
}
// A Package is a single analyzed Go package containing Members for
@@ -56,19 +51,17 @@ type Package struct {
Prog *Program // the owning program
Pkg *types.Package // the corresponding go/types.Package
Members map[string]Member // all package members keyed by name (incl. init and init#%d)
- objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function (values but not types)
+ objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function.
init *Function // Func("init"); the package's init function
debug bool // include full debug info in this package
- syntax bool // package was loaded from syntax
// The following fields are set transiently, then cleared
// after building.
- buildOnce sync.Once // ensures package building occurs once
- ninit int32 // number of init functions
- info *types.Info // package type information
- files []*ast.File // package ASTs
- created creator // members created as a result of building this package (includes declared functions, wrappers)
- initVersion map[ast.Expr]string // goversion to use for each global var init expr
+ buildOnce sync.Once // ensures package building occurs once
+ ninit int32 // number of init functions
+ info *types.Info // package type information
+ files []*ast.File // package ASTs
+ created creator // members created as a result of building this package (includes declared functions, wrappers)
}
// A Member is a member of a Go package, implemented by *NamedConst,
@@ -303,8 +296,8 @@ type Node interface {
//
// A generic function is a function or method that has uninstantiated type
// parameters (TypeParams() != nil). Consider a hypothetical generic
-// method, (*Map[K,V]).Get. It may be instantiated with all
-// non-parameterized types as (*Map[string,int]).Get or with
+// method, (*Map[K,V]).Get. It may be instantiated with all ground
+// (non-parameterized) types as (*Map[string,int]).Get or with
// parameterized types as (*Map[string,U]).Get, where U is a type parameter.
// In both instantiations, Origin() refers to the instantiated generic
// method, (*Map[K,V]).Get, TypeParams() refers to the parameters [K,V] of
@@ -312,45 +305,39 @@ type Node interface {
// respectively, and is nil in the generic method.
type Function struct {
name string
- object *types.Func // symbol for declared function (nil for FuncLit or synthetic init)
- method *selection // info about provenance of synthetic methods; thunk => non-nil
+ object types.Object // a declared *types.Func or one of its wrappers
+ method *selection // info about provenance of synthetic methods; thunk => non-nil
Signature *types.Signature
pos token.Pos
- // source information
- Synthetic string // provenance of synthetic function; "" for true source functions
- syntax ast.Node // *ast.Func{Decl,Lit}, if from syntax (incl. generic instances)
- info *types.Info // type annotations (iff syntax != nil)
- goversion string // Go version of syntax (NB: init is special)
-
- build buildFunc // algorithm to build function body (nil => built)
- parent *Function // enclosing function if anon; nil if global
- Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
- Prog *Program // enclosing program
-
- // These fields are populated only when the function body is built:
-
+ Synthetic string // provenance of synthetic function; "" for true source functions
+ syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode
+ parent *Function // enclosing function if anon; nil if global
+ Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
+ Prog *Program // enclosing program
Params []*Parameter // function parameters; for methods, includes receiver
FreeVars []*FreeVar // free variables whose values must be supplied by closure
- Locals []*Alloc // frame-allocated variables of this function
+ Locals []*Alloc // local variables of this function
Blocks []*BasicBlock // basic blocks of the function; nil => external
Recover *BasicBlock // optional; control transfers here after recovered panic
AnonFuncs []*Function // anonymous functions directly beneath this one
referrers []Instruction // referring instructions (iff Parent() != nil)
+ built bool // function has completed both CREATE and BUILD phase.
anonIdx int32 // position of a nested function in parent's AnonFuncs. fn.Parent()!=nil => fn.Parent().AnonFunc[fn.anonIdx] == fn.
typeparams *typeparams.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function
typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function
topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil.
- generic *generic // instances of this function, if generic
- // The following fields are cleared after building.
+ // The following fields are set transiently during building,
+ // then cleared.
currentBlock *BasicBlock // where to emit code
- vars map[*types.Var]Value // addresses of local variables
+ objects map[types.Object]Value // addresses of local variables
namedResults []*Alloc // tuple of named results
targets *targets // linked stack of branch targets
- lblocks map[*types.Label]*lblock // labelled blocks
- subst *subster // type parameter substitutions (if non-nil)
+ lblocks map[types.Object]*lblock // labelled blocks
+ info *types.Info // *types.Info to build from. nil for wrappers.
+ subst *subster // non-nil => expand generic body using this type substitution of ground types
}
// BasicBlock represents an SSA basic block.
@@ -415,8 +402,9 @@ type FreeVar struct {
// A Parameter represents an input parameter of a function.
type Parameter struct {
name string
- object *types.Var // non-nil
+ object types.Object // a *types.Var; nil for non-source locals
typ types.Type
+ pos token.Pos
parent *Function
referrers []Instruction
}
@@ -494,12 +482,15 @@ type Builtin struct {
// type of the allocated variable is actually
// Type().Underlying().(*types.Pointer).Elem().
//
-// If Heap is false, Alloc zero-initializes the same local variable in
-// the call frame and returns its address; in this case the Alloc must
-// be present in Function.Locals. We call this a "local" alloc.
+// If Heap is false, Alloc allocates space in the function's
+// activation record (frame); we refer to an Alloc(Heap=false) as a
+// "local" alloc. Each local Alloc returns the same address each time
+// it is executed within the same activation; the space is
+// re-initialized to zero.
//
-// If Heap is true, Alloc allocates a new zero-initialized variable
-// each time the instruction is executed. We call this a "new" alloc.
+// If Heap is true, Alloc allocates space in the heap; we
+// refer to an Alloc(Heap=true) as a "new" alloc. Each new Alloc
+// returns a different address each time it is executed.
//
// When Alloc is applied to a channel, map or slice type, it returns
// the address of an uninitialized (nil) reference of that kind; store
@@ -1077,12 +1068,11 @@ type Next struct {
// Type() reflects the actual type of the result, possibly a
// 2-types.Tuple; AssertedType is the asserted type.
//
-// Depending on the TypeAssert's purpose, Pos may return:
-// - the ast.CallExpr.Lparen of an explicit T(e) conversion;
-// - the ast.TypeAssertExpr.Lparen of an explicit e.(T) operation;
-// - the ast.CaseClause.Case of a case of a type-switch statement;
-// - the Ident(m).NamePos of an interface method value i.m
-// (for which TypeAssert may be used to effect the nil check).
+// Pos() returns the ast.CallExpr.Lparen if the instruction arose from
+// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
+// instruction arose from an explicit e.(T) operation; or the
+// ast.CaseClause.Case if the instruction arose from a case of a
+// type-switch statement.
//
// Example printed form:
//
@@ -1400,7 +1390,7 @@ type anInstruction struct {
// represents a dynamically dispatched call to an interface method.
// In this mode, Value is the interface value and Method is the
// interface's abstract method. The interface value may be a type
-// parameter. Note: an interface method may be shared by multiple
+// parameter. Note: an abstract method may be shared by multiple
// interfaces due to embedding; Value.Type() provides the specific
// interface used for this call.
//
@@ -1418,7 +1408,7 @@ type anInstruction struct {
// the last element of Args is a slice.
type CallCommon struct {
Value Value // receiver (invoke mode) or func value (call mode)
- Method *types.Func // interface method (invoke mode)
+ Method *types.Func // abstract method (invoke mode)
Args []Value // actual parameters (in static method call, includes receiver)
pos token.Pos // position of CallExpr.Lparen, iff explicit in source
}
@@ -1517,19 +1507,14 @@ func (v *Global) String() string { return v.RelString(nil)
func (v *Global) Package() *Package { return v.Pkg }
func (v *Global) RelString(from *types.Package) string { return relString(v, from) }
-func (v *Function) Name() string { return v.name }
-func (v *Function) Type() types.Type { return v.Signature }
-func (v *Function) Pos() token.Pos { return v.pos }
-func (v *Function) Token() token.Token { return token.FUNC }
-func (v *Function) Object() types.Object {
- if v.object != nil {
- return types.Object(v.object)
- }
- return nil
-}
-func (v *Function) String() string { return v.RelString(nil) }
-func (v *Function) Package() *Package { return v.Pkg }
-func (v *Function) Parent() *Function { return v.parent }
+func (v *Function) Name() string { return v.name }
+func (v *Function) Type() types.Type { return v.Signature }
+func (v *Function) Pos() token.Pos { return v.pos }
+func (v *Function) Token() token.Token { return token.FUNC }
+func (v *Function) Object() types.Object { return v.object }
+func (v *Function) String() string { return v.RelString(nil) }
+func (v *Function) Package() *Package { return v.Pkg }
+func (v *Function) Parent() *Function { return v.parent }
func (v *Function) Referrers() *[]Instruction {
if v.parent != nil {
return &v.referrers
@@ -1577,7 +1562,7 @@ func (v *Parameter) Type() types.Type { return v.typ }
func (v *Parameter) Name() string { return v.name }
func (v *Parameter) Object() types.Object { return v.object }
func (v *Parameter) Referrers() *[]Instruction { return &v.referrers }
-func (v *Parameter) Pos() token.Pos { return v.object.Pos() }
+func (v *Parameter) Pos() token.Pos { return v.pos }
func (v *Parameter) Parent() *Function { return v.parent }
func (v *Alloc) Type() types.Type { return v.typ }
diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go
index fb62c2bd4..96d69a20a 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go
@@ -15,7 +15,6 @@ import (
"golang.org/x/tools/go/packages"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/internal/typeparams"
- "golang.org/x/tools/internal/versions"
)
// Packages creates an SSA program for a set of packages.
@@ -36,24 +35,6 @@ import (
//
// The mode parameter controls diagnostics and checking during SSA construction.
func Packages(initial []*packages.Package, mode ssa.BuilderMode) (*ssa.Program, []*ssa.Package) {
- // TODO(adonovan): opt: this calls CreatePackage far more than
- // necessary: for all dependencies, not just the (non-initial)
- // direct dependencies of the initial packages.
- //
- // But can it reasonably be changed without breaking the
- // spirit and/or letter of the law above? Clients may notice
- // if we call CreatePackage less, as methods like
- // Program.FuncValue will return nil. Or must we provide a new
- // function (and perhaps deprecate this one)? Is it worth it?
- //
- // Tim King makes the interesting point that it would be
- // possible to entirely alleviate the client from the burden
- // of calling CreatePackage for non-syntax packages, if we
- // were to treat vars and funcs lazily in the same way we now
- // treat methods. (In essence, try to move away from the
- // notion of ssa.Packages, and make the Program answer
- // all reasonable questions about any types.Object.)
-
return doPackages(initial, mode, false)
}
@@ -166,7 +147,6 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil
Selections: make(map[*ast.SelectorExpr]*types.Selection),
}
typeparams.InitInstanceInfo(info)
- versions.InitFileVersions(info)
if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil {
return nil, nil, err
}
@@ -188,25 +168,6 @@ func BuildPackage(tc *types.Config, fset *token.FileSet, pkg *types.Package, fil
}
createAll(pkg.Imports())
- // TODO(adonovan): we could replace createAll with just:
- //
- // // Create SSA packages for all imports.
- // for _, p := range pkg.Imports() {
- // prog.CreatePackage(p, nil, nil, true)
- // }
- //
- // (with minor changes to changes to ../builder_test.go as
- // shown in CL 511715 PS 10.) But this would strictly violate
- // the letter of the doc comment above, which says "all
- // dependencies created".
- //
- // Tim makes the good point with some extra work we could
- // remove the need for any CreatePackage calls except the
- // ones with syntax (i.e. primary packages). Of course
- // You wouldn't have ssa.Packages and Members for as
- // many things but no-one really uses that anyway.
- // I wish I had done this from the outset.
-
// Create and build the primary package.
ssapkg := prog.CreatePackage(pkg, files, info, false)
ssapkg.Build()
diff --git a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
index 3cdd34622..5f27050b0 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
@@ -4,15 +4,7 @@
package ssautil // import "golang.org/x/tools/go/ssa/ssautil"
-import (
- "go/ast"
- "go/types"
-
- "golang.org/x/tools/go/ssa"
- "golang.org/x/tools/internal/typeparams"
-
- _ "unsafe" // for linkname hack
-)
+import "golang.org/x/tools/go/ssa"
// This file defines utilities for visiting the SSA representation of
// a Program.
@@ -26,113 +18,50 @@ import (
// synthetic wrappers.
//
// Precondition: all packages are built.
-//
-// TODO(adonovan): this function is underspecified. It doesn't
-// actually work like a linker, which computes reachability from main
-// using something like go/callgraph/cha (without materializing the
-// call graph). In fact, it treats all public functions and all
-// methods of public non-parameterized types as roots, even though
-// they may be unreachable--but only in packages created from syntax.
-//
-// I think we should deprecate AllFunctions function in favor of two
-// clearly defined ones:
-//
-// 1. The first would efficiently compute CHA reachability from a set
-// of main packages, making it suitable for a whole-program
-// analysis context with InstantiateGenerics, in conjunction with
-// Program.Build.
-//
-// 2. The second would return only the set of functions corresponding
-// to source Func{Decl,Lit} syntax, like SrcFunctions in
-// go/analysis/passes/buildssa; this is suitable for
-// package-at-a-time (or handful of packages) context.
-// ssa.Package could easily expose it as a field.
-//
-// We could add them unexported for now and use them via the linkname hack.
func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool {
- seen := make(map[*ssa.Function]bool)
-
- var function func(fn *ssa.Function)
- function = func(fn *ssa.Function) {
- if !seen[fn] {
- seen[fn] = true
- var buf [10]*ssa.Value // avoid alloc in common case
- for _, b := range fn.Blocks {
- for _, instr := range b.Instrs {
- for _, op := range instr.Operands(buf[:0]) {
- if fn, ok := (*op).(*ssa.Function); ok {
- function(fn)
- }
- }
- }
- }
- }
+ visit := visitor{
+ prog: prog,
+ seen: make(map[*ssa.Function]bool),
}
+ visit.program()
+ return visit.seen
+}
- // TODO(adonovan): opt: provide a way to share a builder
- // across a sequence of MethodValue calls.
+type visitor struct {
+ prog *ssa.Program
+ seen map[*ssa.Function]bool
+}
- methodsOf := func(T types.Type) {
- if !types.IsInterface(T) {
- mset := prog.MethodSets.MethodSet(T)
- for i := 0; i < mset.Len(); i++ {
- function(prog.MethodValue(mset.At(i)))
+func (visit *visitor) program() {
+ for _, pkg := range visit.prog.AllPackages() {
+ for _, mem := range pkg.Members {
+ if fn, ok := mem.(*ssa.Function); ok {
+ visit.function(fn)
}
}
}
-
- // Historically, Program.RuntimeTypes used to include the type
- // of any exported member of a package loaded from syntax that
- // has a non-parameterized type, plus all types
- // reachable from that type using reflection, even though
- // these runtime types may not be required for them.
- //
- // Rather than break existing programs that rely on
- // AllFunctions visiting extra methods that are unreferenced
- // by IR and unreachable via reflection, we moved the logic
- // here, unprincipled though it is.
- // (See doc comment for better ideas.)
- //
- // Nonetheless, after the move, we no longer visit every
- // method of any type recursively reachable from T, only the
- // methods of T and *T themselves, and we only apply this to
- // named types T, and not to the type of every exported
- // package member.
- exportedTypeHack := func(t *ssa.Type) {
- if isSyntactic(t.Package()) &&
- ast.IsExported(t.Name()) &&
- !types.IsInterface(t.Type()) {
- // Consider only named types.
- // (Ignore aliases and unsafe.Pointer.)
- if named, ok := t.Type().(*types.Named); ok {
- if typeparams.ForNamed(named) == nil {
- methodsOf(named) // T
- methodsOf(types.NewPointer(named)) // *T
- }
- }
+ for _, T := range visit.prog.RuntimeTypes() {
+ mset := visit.prog.MethodSets.MethodSet(T)
+ for i, n := 0, mset.Len(); i < n; i++ {
+ visit.function(visit.prog.MethodValue(mset.At(i)))
}
}
+}
- for _, pkg := range prog.AllPackages() {
- for _, mem := range pkg.Members {
- switch mem := mem.(type) {
- case *ssa.Function:
- // Visit all package-level declared functions.
- function(mem)
-
- case *ssa.Type:
- exportedTypeHack(mem)
+func (visit *visitor) function(fn *ssa.Function) {
+ if !visit.seen[fn] {
+ visit.seen[fn] = true
+ var buf [10]*ssa.Value // avoid alloc in common case
+ for _, b := range fn.Blocks {
+ for _, instr := range b.Instrs {
+ for _, op := range instr.Operands(buf[:0]) {
+ if fn, ok := (*op).(*ssa.Function); ok {
+ visit.function(fn)
+ }
+ }
}
}
}
-
- // Visit all methods of types for which runtime types were
- // materialized, as they are reachable through reflection.
- for _, T := range prog.RuntimeTypes() {
- methodsOf(T)
- }
-
- return seen
}
// MainPackages returns the subset of the specified packages
@@ -147,12 +76,3 @@ func MainPackages(pkgs []*ssa.Package) []*ssa.Package {
}
return mains
}
-
-// TODO(adonovan): propose a principled API for this. One possibility
-// is a new field, Package.SrcFunctions []*Function, which would
-// contain the list of SrcFunctions described in point 2 of the
-// AllFunctions doc comment, or nil if the package is not from syntax.
-// But perhaps overloading nil vs empty slice is too subtle.
-//
-//go:linkname isSyntactic golang.org/x/tools/go/ssa.isSyntactic
-func isSyntactic(pkg *ssa.Package) bool
diff --git a/vendor/golang.org/x/tools/go/ssa/util.go b/vendor/golang.org/x/tools/go/ssa/util.go
index 63fbbc128..68cc971b3 100644
--- a/vendor/golang.org/x/tools/go/ssa/util.go
+++ b/vendor/golang.org/x/tools/go/ssa/util.go
@@ -180,6 +180,24 @@ func makeLen(T types.Type) *Builtin {
}
}
+// nonbasicTypes returns a list containing all of the types T in ts that are non-basic.
+func nonbasicTypes(ts []types.Type) []types.Type {
+ if len(ts) == 0 {
+ return nil
+ }
+ added := make(map[types.Type]bool) // additionally filter duplicates
+ var filtered []types.Type
+ for _, T := range ts {
+ if !isBasic(T) {
+ if !added[T] {
+ added[T] = true
+ filtered = append(filtered, T)
+ }
+ }
+ }
+ return filtered
+}
+
// receiverTypeArgs returns the type arguments to a function's receiver.
// Returns an empty list if obj does not have a receiver or its receiver does not have type arguments.
func receiverTypeArgs(obj *types.Func) []types.Type {
@@ -366,16 +384,3 @@ func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctx
obj, _, _ := types.LookupFieldOrMethod(rep, true, m.Pkg(), m.Name())
return obj.(*types.Func)
}
-
-// Exposed to ssautil using the linkname hack.
-func isSyntactic(pkg *Package) bool { return pkg.syntax }
-
-// mapValues returns a new unordered array of map values.
-func mapValues[K comparable, V any](m map[K]V) []V {
- vals := make([]V, 0, len(m))
- for _, fn := range m {
- vals = append(vals, fn)
- }
- return vals
-
-}
diff --git a/vendor/golang.org/x/tools/go/ssa/wrappers.go b/vendor/golang.org/x/tools/go/ssa/wrappers.go
index 7c7ee4099..123ea6858 100644
--- a/vendor/golang.org/x/tools/go/ssa/wrappers.go
+++ b/vendor/golang.org/x/tools/go/ssa/wrappers.go
@@ -28,7 +28,7 @@ import (
// -- wrappers -----------------------------------------------------------
-// createWrapper returns a synthetic method that delegates to the
+// makeWrapper returns a synthetic method that delegates to the
// declared method denoted by meth.Obj(), first performing any
// necessary pointer indirections or field selections implied by meth.
//
@@ -40,17 +40,21 @@ import (
// - optional implicit field selections
// - meth.Obj() may denote a concrete or an interface method
// - the result may be a thunk or a wrapper.
-func createWrapper(prog *Program, sel *selection, cr *creator) *Function {
+//
+// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
+func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
obj := sel.obj.(*types.Func) // the declared function
sig := sel.typ.(*types.Signature) // type of this wrapper
var recv *types.Var // wrapper's receiver or thunk's params[0]
name := obj.Name()
var description string
+ var start int // first regular param
if sel.kind == types.MethodExpr {
name += "$thunk"
description = "thunk"
recv = sig.Params().At(0)
+ start = 1
} else {
description = "wrapper"
recv = sig.Recv()
@@ -58,9 +62,8 @@ func createWrapper(prog *Program, sel *selection, cr *creator) *Function {
description = fmt.Sprintf("%s for %s", description, sel.obj)
if prog.mode&LogSource != 0 {
- defer logStack("create %s to (%s)", description, recv.Type())()
+ defer logStack("make %s to (%s)", description, recv.Type())()
}
- /* method wrapper */
fn := &Function{
name: name,
method: sel,
@@ -69,53 +72,35 @@ func createWrapper(prog *Program, sel *selection, cr *creator) *Function {
Synthetic: description,
Prog: prog,
pos: obj.Pos(),
- // wrappers have no syntax
- build: (*builder).buildWrapper,
- syntax: nil,
- info: nil,
- goversion: "",
+ info: nil, // info is not set on wrappers.
}
cr.Add(fn)
- return fn
-}
-
-// buildWrapper builds fn.Body for a method wrapper.
-func (b *builder) buildWrapper(fn *Function) {
- var recv *types.Var // wrapper's receiver or thunk's params[0]
- var start int // first regular param
- if fn.method.kind == types.MethodExpr {
- recv = fn.Signature.Params().At(0)
- start = 1
- } else {
- recv = fn.Signature.Recv()
- }
-
fn.startBody()
fn.addSpilledParam(recv)
createParams(fn, start)
- indices := fn.method.index
+ indices := sel.index
var v Value = fn.Locals[0] // spilled receiver
- srdt, ptrRecv := deptr(fn.method.recv)
+ srdt, ptrRecv := deptr(sel.recv)
if ptrRecv {
v = emitLoad(fn, v)
// For simple indirection wrappers, perform an informative nil-check:
// "value method (T).f called using nil *T pointer"
- _, ptrObj := deptr(recvType(fn.object))
+ _, ptrObj := deptr(recvType(obj))
if len(indices) == 1 && !ptrObj {
var c Call
c.Call.Value = &Builtin{
name: "ssa:wrapnilchk",
sig: types.NewSignature(nil,
- types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)),
- types.NewTuple(anonVar(fn.method.recv)), false),
+ types.NewTuple(anonVar(sel.recv), anonVar(tString), anonVar(tString)),
+ types.NewTuple(anonVar(sel.recv)), false),
}
c.Call.Args = []Value{
v,
stringConst(srdt.String()),
- stringConst(fn.method.obj.Name()),
+ stringConst(sel.obj.Name()),
}
c.setType(v.Type())
v = fn.emit(&c)
@@ -137,14 +122,18 @@ func (b *builder) buildWrapper(fn *Function) {
// address of implicit C field.
var c Call
- if r := recvType(fn.object); !types.IsInterface(r) { // concrete method
+ if r := recvType(obj); !types.IsInterface(r) { // concrete method
if _, ptrObj := deptr(r); !ptrObj {
v = emitLoad(fn, v)
}
- c.Call.Value = fn.Prog.objectMethod(fn.object, b.created)
+ callee := prog.originFunc(obj)
+ if callee.typeparams.Len() > 0 {
+ callee = prog.lookupOrCreateInstance(callee, receiverTypeArgs(obj), cr)
+ }
+ c.Call.Value = callee
c.Call.Args = append(c.Call.Args, v)
} else {
- c.Call.Method = fn.object
+ c.Call.Method = obj
c.Call.Value = emitLoad(fn, v) // interface (possibly a typeparam)
}
for _, arg := range fn.Params[1:] {
@@ -152,6 +141,8 @@ func (b *builder) buildWrapper(fn *Function) {
}
emitTailCall(fn, &c)
fn.finishBody()
+ fn.done()
+ return fn
}
// createParams creates parameters for wrapper method fn based on its
@@ -160,13 +151,13 @@ func (b *builder) buildWrapper(fn *Function) {
func createParams(fn *Function, start int) {
tparams := fn.Signature.Params()
for i, n := start, tparams.Len(); i < n; i++ {
- fn.addParamVar(tparams.At(i))
+ fn.addParamObj(tparams.At(i))
}
}
// -- bounds -----------------------------------------------------------
-// createBound returns a bound method wrapper (or "bound"), a synthetic
+// makeBound returns a bound method wrapper (or "bound"), a synthetic
// function that delegates to a concrete or interface method denoted
// by obj. The resulting function has no receiver, but has one free
// variable which will be used as the method's receiver in the
@@ -185,57 +176,66 @@ func createParams(fn *Function, start int) {
//
// f := func() { return t.meth() }
//
-// Unlike createWrapper, createBound need perform no indirection or field
+// Unlike makeWrapper, makeBound need perform no indirection or field
// selections because that can be done before the closure is
// constructed.
-func createBound(prog *Program, obj *types.Func, cr *creator) *Function {
- description := fmt.Sprintf("bound method wrapper for %s", obj)
- if prog.mode&LogSource != 0 {
- defer logStack("%s", description)()
- }
- /* bound method wrapper */
- fn := &Function{
- name: obj.Name() + "$bound",
- object: obj,
- Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
- Synthetic: description,
- Prog: prog,
- pos: obj.Pos(),
- // wrappers have no syntax
- build: (*builder).buildBound,
- syntax: nil,
- info: nil,
- goversion: "",
- }
- fn.FreeVars = []*FreeVar{{name: "recv", typ: recvType(obj), parent: fn}} // (cyclic)
- cr.Add(fn)
- return fn
-}
-
-// buildBound builds fn.Body for a bound method closure.
-func (b *builder) buildBound(fn *Function) {
- fn.startBody()
- createParams(fn, 0)
- var c Call
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
+func makeBound(prog *Program, obj *types.Func, cr *creator) *Function {
+ targs := receiverTypeArgs(obj)
+ key := boundsKey{obj, prog.canon.List(targs)}
+
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+ fn, ok := prog.bounds[key]
+ if !ok {
+ description := fmt.Sprintf("bound method wrapper for %s", obj)
+ if prog.mode&LogSource != 0 {
+ defer logStack("%s", description)()
+ }
+ fn = &Function{
+ name: obj.Name() + "$bound",
+ object: obj,
+ Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
+ Synthetic: description,
+ Prog: prog,
+ pos: obj.Pos(),
+ info: nil, // info is not set on wrappers.
+ }
+ cr.Add(fn)
+
+ fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn}
+ fn.FreeVars = []*FreeVar{fv}
+ fn.startBody()
+ createParams(fn, 0)
+ var c Call
+
+ if !types.IsInterface(recvType(obj)) { // concrete
+ callee := prog.originFunc(obj)
+ if callee.typeparams.Len() > 0 {
+ callee = prog.lookupOrCreateInstance(callee, targs, cr)
+ }
+ c.Call.Value = callee
+ c.Call.Args = []Value{fv}
+ } else {
+ c.Call.Method = obj
+ c.Call.Value = fv // interface (possibly a typeparam)
+ }
+ for _, arg := range fn.Params {
+ c.Call.Args = append(c.Call.Args, arg)
+ }
+ emitTailCall(fn, &c)
+ fn.finishBody()
+ fn.done()
- recv := fn.FreeVars[0]
- if !types.IsInterface(recvType(fn.object)) { // concrete
- c.Call.Value = fn.Prog.objectMethod(fn.object, b.created)
- c.Call.Args = []Value{recv}
- } else {
- c.Call.Method = fn.object
- c.Call.Value = recv // interface (possibly a typeparam)
- }
- for _, arg := range fn.Params {
- c.Call.Args = append(c.Call.Args, arg)
+ prog.bounds[key] = fn
}
- emitTailCall(fn, &c)
- fn.finishBody()
+ return fn
}
// -- thunks -----------------------------------------------------------
-// createThunk returns a thunk, a synthetic function that delegates to a
+// makeThunk returns a thunk, a synthetic function that delegates to a
// concrete or interface method denoted by sel.obj. The resulting
// function has no receiver, but has an additional (first) regular
// parameter.
@@ -251,16 +251,38 @@ func (b *builder) buildBound(fn *Function) {
// f is a synthetic wrapper defined as if by:
//
// f := func(t T) { return t.meth() }
-func createThunk(prog *Program, sel *selection, cr *creator) *Function {
+//
+// TODO(adonovan): opt: currently the stub is created even when used
+// directly in a function call: C.f(i, 0). This is less efficient
+// than inlining the stub.
+//
+// EXCLUSIVE_LOCKS_ACQUIRED(meth.Prog.methodsMu)
+func makeThunk(prog *Program, sel *selection, cr *creator) *Function {
if sel.kind != types.MethodExpr {
panic(sel)
}
- fn := createWrapper(prog, sel, cr)
- if fn.Signature.Recv() != nil {
- panic(fn) // unexpected receiver
+ // Canonicalize sel.recv to avoid constructing duplicate thunks.
+ canonRecv := prog.canon.Type(sel.recv)
+ key := selectionKey{
+ kind: sel.kind,
+ recv: canonRecv,
+ obj: sel.obj,
+ index: fmt.Sprint(sel.index),
+ indirect: sel.indirect,
}
+ prog.methodsMu.Lock()
+ defer prog.methodsMu.Unlock()
+
+ fn, ok := prog.thunks[key]
+ if !ok {
+ fn = makeWrapper(prog, sel, cr)
+ if fn.Signature.Recv() != nil {
+ panic(fn) // unexpected receiver
+ }
+ prog.thunks[key] = fn
+ }
return fn
}
@@ -268,6 +290,21 @@ func changeRecv(s *types.Signature, recv *types.Var) *types.Signature {
return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic())
}
+// selectionKey is like types.Selection but a usable map key.
+type selectionKey struct {
+ kind types.SelectionKind
+ recv types.Type // canonicalized via Program.canon
+ obj types.Object
+ index string
+ indirect bool
+}
+
+// boundsKey is a unique for the object and a type instantiation.
+type boundsKey struct {
+ obj types.Object // t.meth
+ inst *typeList // canonical type instantiation list.
+}
+
// A local version of *types.Selection.
// Needed for some additional control, such as creating a MethodExpr for an instantiation.
type selection struct {
@@ -292,16 +329,16 @@ func toSelection(sel *types.Selection) *selection {
// -- instantiations --------------------------------------------------
-// buildInstantiationWrapper builds the body of an instantiation
+// buildInstantiationWrapper creates a body for an instantiation
// wrapper fn. The body calls the original generic function,
// bracketed by ChangeType conversions on its arguments and results.
-func (b *builder) buildInstantiationWrapper(fn *Function) {
+func buildInstantiationWrapper(fn *Function) {
orig := fn.topLevelOrigin
sig := fn.Signature
fn.startBody()
if sig.Recv() != nil {
- fn.addParamVar(sig.Recv())
+ fn.addParamObj(sig.Recv())
}
createParams(fn, 0)
diff --git a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
index e742ecc46..fa5834baf 100644
--- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
+++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
@@ -26,10 +26,13 @@ package objectpath
import (
"fmt"
"go/types"
+ "sort"
"strconv"
"strings"
+ _ "unsafe"
"golang.org/x/tools/internal/typeparams"
+ "golang.org/x/tools/internal/typesinternal"
)
// A Path is an opaque name that identifies a types.Object
@@ -120,7 +123,20 @@ func For(obj types.Object) (Path, error) {
// An Encoder amortizes the cost of encoding the paths of multiple objects.
// The zero value of an Encoder is ready to use.
type Encoder struct {
- scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
+ scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
+ namedMethodsMemo map[*types.Named][]*types.Func // memoization of namedMethods()
+ skipMethodSorting bool
+}
+
+// Expose back doors so that gopls can avoid method sorting, which can dominate
+// analysis on certain repositories.
+//
+// TODO(golang/go#61443): remove this.
+func init() {
+ typesinternal.SkipEncoderMethodSorting = func(enc interface{}) {
+ enc.(*Encoder).skipMethodSorting = true
+ }
+ typesinternal.ObjectpathObject = object
}
// For returns the path to an object relative to its package,
@@ -312,18 +328,31 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
// Inspect declared methods of defined types.
if T, ok := o.Type().(*types.Named); ok {
path = append(path, opType)
- // The method index here is always with respect
- // to the underlying go/types data structures,
- // which ultimately derives from source order
- // and must be preserved by export data.
- for i := 0; i < T.NumMethods(); i++ {
- m := T.Method(i)
- path2 := appendOpArg(path, opMethod, i)
- if m == obj {
- return Path(path2), nil // found declared method
+ if !enc.skipMethodSorting {
+ // Note that method index here is always with respect
+ // to canonical ordering of methods, regardless of how
+ // they appear in the underlying type.
+ for i, m := range enc.namedMethods(T) {
+ path2 := appendOpArg(path, opMethod, i)
+ if m == obj {
+ return Path(path2), nil // found declared method
+ }
+ if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
+ return Path(r), nil
+ }
}
- if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
- return Path(r), nil
+ } else {
+ // This branch must match the logic in the branch above, using go/types
+ // APIs without sorting.
+ for i := 0; i < T.NumMethods(); i++ {
+ m := T.Method(i)
+ path2 := appendOpArg(path, opMethod, i)
+ if m == obj {
+ return Path(path2), nil // found declared method
+ }
+ if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
+ return Path(r), nil
+ }
}
}
}
@@ -419,13 +448,22 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
path = append(path, name...)
path = append(path, opType)
- // Method indices are w.r.t. the go/types data structures,
- // ultimately deriving from source order,
- // which is preserved by export data.
- for i := 0; i < named.NumMethods(); i++ {
- if named.Method(i) == meth {
- path = appendOpArg(path, opMethod, i)
- return Path(path), true
+ if !enc.skipMethodSorting {
+ for i, m := range enc.namedMethods(named) {
+ if m == meth {
+ path = appendOpArg(path, opMethod, i)
+ return Path(path), true
+ }
+ }
+ } else {
+ // This branch must match the logic of the branch above, using go/types
+ // APIs without sorting.
+ for i := 0; i < named.NumMethods(); i++ {
+ m := named.Method(i)
+ if m == meth {
+ path = appendOpArg(path, opMethod, i)
+ return Path(path), true
+ }
}
}
@@ -538,7 +576,12 @@ func findTypeParam(obj types.Object, list *typeparams.TypeParamList, path []byte
// Object returns the object denoted by path p within the package pkg.
func Object(pkg *types.Package, p Path) (types.Object, error) {
- pathstr := string(p)
+ return object(pkg, string(p), false)
+}
+
+// Note: the skipMethodSorting parameter must match the value of
+// Encoder.skipMethodSorting used during encoding.
+func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.Object, error) {
if pathstr == "" {
return nil, fmt.Errorf("empty path")
}
@@ -704,7 +747,12 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
if index >= t.NumMethods() {
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
}
- obj = t.Method(index)
+ if skipMethodSorting {
+ obj = t.Method(index)
+ } else {
+ methods := namedMethods(t) // (unmemoized)
+ obj = methods[index] // Id-ordered
+ }
default:
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
@@ -731,6 +779,33 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
return obj, nil // success
}
+// namedMethods returns the methods of a Named type in ascending Id order.
+func namedMethods(named *types.Named) []*types.Func {
+ methods := make([]*types.Func, named.NumMethods())
+ for i := range methods {
+ methods[i] = named.Method(i)
+ }
+ sort.Slice(methods, func(i, j int) bool {
+ return methods[i].Id() < methods[j].Id()
+ })
+ return methods
+}
+
+// namedMethods is a memoization of the namedMethods function. Callers must not modify the result.
+func (enc *Encoder) namedMethods(named *types.Named) []*types.Func {
+ m := enc.namedMethodsMemo
+ if m == nil {
+ m = make(map[*types.Named][]*types.Func)
+ enc.namedMethodsMemo = m
+ }
+ methods, ok := m[named]
+ if !ok {
+ methods = namedMethods(named) // allocates and sorts
+ m[named] = methods
+ }
+ return methods
+}
+
// scopeObjects is a memoization of scope objects.
// Callers must not modify the result.
func (enc *Encoder) scopeObjects(scope *types.Scope) []types.Object {
diff --git a/vendor/golang.org/x/tools/internal/diff/unified.go b/vendor/golang.org/x/tools/internal/diff/unified.go
index cfbda6102..1308503f7 100644
--- a/vendor/golang.org/x/tools/internal/diff/unified.go
+++ b/vendor/golang.org/x/tools/internal/diff/unified.go
@@ -10,16 +10,12 @@ import (
"strings"
)
-// DefaultContextLines is the number of unchanged lines of surrounding
-// context displayed by Unified. Use ToUnified to specify a different value.
-const DefaultContextLines = 3
-
// Unified returns a unified diff of the old and new strings.
// The old and new labels are the names of the old and new files.
// If the strings are equal, it returns the empty string.
func Unified(oldLabel, newLabel, old, new string) string {
edits := Strings(old, new)
- unified, err := ToUnified(oldLabel, newLabel, old, edits, DefaultContextLines)
+ unified, err := ToUnified(oldLabel, newLabel, old, edits)
if err != nil {
// Can't happen: edits are consistent.
log.Fatalf("internal error in diff.Unified: %v", err)
@@ -27,12 +23,11 @@ func Unified(oldLabel, newLabel, old, new string) string {
return unified
}
-// ToUnified applies the edits to content and returns a unified diff,
-// with contextLines lines of (unchanged) context around each diff hunk.
+// ToUnified applies the edits to content and returns a unified diff.
// The old and new labels are the names of the content and result files.
// It returns an error if the edits are inconsistent; see ApplyEdits.
-func ToUnified(oldLabel, newLabel, content string, edits []Edit, contextLines int) (string, error) {
- u, err := toUnified(oldLabel, newLabel, content, edits, contextLines)
+func ToUnified(oldLabel, newLabel, content string, edits []Edit) (string, error) {
+ u, err := toUnified(oldLabel, newLabel, content, edits)
if err != nil {
return "", err
}
@@ -98,10 +93,14 @@ func (k opKind) String() string {
}
}
+const (
+ edge = 3
+ gap = edge * 2
+)
+
// toUnified takes a file contents and a sequence of edits, and calculates
// a unified diff that represents those edits.
-func toUnified(fromName, toName string, content string, edits []Edit, contextLines int) (unified, error) {
- gap := contextLines * 2
+func toUnified(fromName, toName string, content string, edits []Edit) (unified, error) {
u := unified{
from: fromName,
to: toName,
@@ -137,7 +136,7 @@ func toUnified(fromName, toName string, content string, edits []Edit, contextLin
//need to start a new hunk
if h != nil {
// add the edge to the previous hunk
- addEqualLines(h, lines, last, last+contextLines)
+ addEqualLines(h, lines, last, last+edge)
u.hunks = append(u.hunks, h)
}
toLine += start - last
@@ -146,7 +145,7 @@ func toUnified(fromName, toName string, content string, edits []Edit, contextLin
toLine: toLine + 1,
}
// add the edge to the new hunk
- delta := addEqualLines(h, lines, start-contextLines, start)
+ delta := addEqualLines(h, lines, start-edge, start)
h.fromLine -= delta
h.toLine -= delta
}
@@ -164,7 +163,7 @@ func toUnified(fromName, toName string, content string, edits []Edit, contextLin
}
if h != nil {
// add the edge to the final hunk
- addEqualLines(h, lines, last, last+contextLines)
+ addEqualLines(h, lines, last, last+edge)
u.hunks = append(u.hunks, h)
}
return u, nil
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
new file mode 100644
index 000000000..c40c7e931
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
@@ -0,0 +1,196 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fastwalk provides a faster version of [filepath.Walk] for file system
+// scanning tools.
+package fastwalk
+
+import (
+ "errors"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sync"
+)
+
+// ErrTraverseLink is used as a return value from WalkFuncs to indicate that the
+// symlink named in the call may be traversed.
+var ErrTraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory")
+
+// ErrSkipFiles is a used as a return value from WalkFuncs to indicate that the
+// callback should not be called for any other files in the current directory.
+// Child directories will still be traversed.
+var ErrSkipFiles = errors.New("fastwalk: skip remaining files in directory")
+
+// Walk is a faster implementation of [filepath.Walk].
+//
+// [filepath.Walk]'s design necessarily calls [os.Lstat] on each file,
+// even if the caller needs less info.
+// Many tools need only the type of each file.
+// On some platforms, this information is provided directly by the readdir
+// system call, avoiding the need to stat each file individually.
+// fastwalk_unix.go contains a fork of the syscall routines.
+//
+// See golang.org/issue/16399.
+//
+// Walk walks the file tree rooted at root, calling walkFn for
+// each file or directory in the tree, including root.
+//
+// If Walk returns [filepath.SkipDir], the directory is skipped.
+//
+// Unlike [filepath.Walk]:
+// - file stat calls must be done by the user.
+// The only provided metadata is the file type, which does not include
+// any permission bits.
+// - multiple goroutines stat the filesystem concurrently. The provided
+// walkFn must be safe for concurrent use.
+// - Walk can follow symlinks if walkFn returns the TraverseLink
+// sentinel error. It is the walkFn's responsibility to prevent
+// Walk from going into symlink cycles.
+func Walk(root string, walkFn func(path string, typ os.FileMode) error) error {
+ // TODO(bradfitz): make numWorkers configurable? We used a
+ // minimum of 4 to give the kernel more info about multiple
+ // things we want, in hopes its I/O scheduling can take
+ // advantage of that. Hopefully most are in cache. Maybe 4 is
+ // even too low of a minimum. Profile more.
+ numWorkers := 4
+ if n := runtime.NumCPU(); n > numWorkers {
+ numWorkers = n
+ }
+
+ // Make sure to wait for all workers to finish, otherwise
+ // walkFn could still be called after returning. This Wait call
+ // runs after close(e.donec) below.
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ w := &walker{
+ fn: walkFn,
+ enqueuec: make(chan walkItem, numWorkers), // buffered for performance
+ workc: make(chan walkItem, numWorkers), // buffered for performance
+ donec: make(chan struct{}),
+
+ // buffered for correctness & not leaking goroutines:
+ resc: make(chan error, numWorkers),
+ }
+ defer close(w.donec)
+
+ for i := 0; i < numWorkers; i++ {
+ wg.Add(1)
+ go w.doWork(&wg)
+ }
+ todo := []walkItem{{dir: root}}
+ out := 0
+ for {
+ workc := w.workc
+ var workItem walkItem
+ if len(todo) == 0 {
+ workc = nil
+ } else {
+ workItem = todo[len(todo)-1]
+ }
+ select {
+ case workc <- workItem:
+ todo = todo[:len(todo)-1]
+ out++
+ case it := <-w.enqueuec:
+ todo = append(todo, it)
+ case err := <-w.resc:
+ out--
+ if err != nil {
+ return err
+ }
+ if out == 0 && len(todo) == 0 {
+ // It's safe to quit here, as long as the buffered
+ // enqueue channel isn't also readable, which might
+ // happen if the worker sends both another unit of
+ // work and its result before the other select was
+ // scheduled and both w.resc and w.enqueuec were
+ // readable.
+ select {
+ case it := <-w.enqueuec:
+ todo = append(todo, it)
+ default:
+ return nil
+ }
+ }
+ }
+ }
+}
+
+// doWork reads directories as instructed (via workc) and runs the
+// user's callback function.
+func (w *walker) doWork(wg *sync.WaitGroup) {
+ defer wg.Done()
+ for {
+ select {
+ case <-w.donec:
+ return
+ case it := <-w.workc:
+ select {
+ case <-w.donec:
+ return
+ case w.resc <- w.walk(it.dir, !it.callbackDone):
+ }
+ }
+ }
+}
+
+type walker struct {
+ fn func(path string, typ os.FileMode) error
+
+ donec chan struct{} // closed on fastWalk's return
+ workc chan walkItem // to workers
+ enqueuec chan walkItem // from workers
+ resc chan error // from workers
+}
+
+type walkItem struct {
+ dir string
+ callbackDone bool // callback already called; don't do it again
+}
+
+func (w *walker) enqueue(it walkItem) {
+ select {
+ case w.enqueuec <- it:
+ case <-w.donec:
+ }
+}
+
+func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error {
+ joined := dirName + string(os.PathSeparator) + baseName
+ if typ == os.ModeDir {
+ w.enqueue(walkItem{dir: joined})
+ return nil
+ }
+
+ err := w.fn(joined, typ)
+ if typ == os.ModeSymlink {
+ if err == ErrTraverseLink {
+ // Set callbackDone so we don't call it twice for both the
+ // symlink-as-symlink and the symlink-as-directory later:
+ w.enqueue(walkItem{dir: joined, callbackDone: true})
+ return nil
+ }
+ if err == filepath.SkipDir {
+ // Permit SkipDir on symlinks too.
+ return nil
+ }
+ }
+ return err
+}
+
+func (w *walker) walk(root string, runUserCallback bool) error {
+ if runUserCallback {
+ err := w.fn(root, os.ModeDir)
+ if err == filepath.SkipDir {
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ }
+
+ return readDir(root, w.onDirEnt)
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go
new file mode 100644
index 000000000..0ca55e0d5
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go
@@ -0,0 +1,119 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin && cgo
+// +build darwin,cgo
+
+package fastwalk
+
+/*
+#include <dirent.h>
+
+// fastwalk_readdir_r wraps readdir_r so that we don't have to pass a dirent**
+// result pointer which triggers CGO's "Go pointer to Go pointer" check unless
+// we allocat the result dirent* with malloc.
+//
+// fastwalk_readdir_r returns 0 on success, -1 upon reaching the end of the
+// directory, or a positive error number to indicate failure.
+static int fastwalk_readdir_r(DIR *fd, struct dirent *entry) {
+ struct dirent *result;
+ int ret = readdir_r(fd, entry, &result);
+ if (ret == 0 && result == NULL) {
+ ret = -1; // EOF
+ }
+ return ret;
+}
+*/
+import "C"
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
+ fd, err := openDir(dirName)
+ if err != nil {
+ return &os.PathError{Op: "opendir", Path: dirName, Err: err}
+ }
+ defer C.closedir(fd)
+
+ skipFiles := false
+ var dirent syscall.Dirent
+ for {
+ ret := int(C.fastwalk_readdir_r(fd, (*C.struct_dirent)(unsafe.Pointer(&dirent))))
+ if ret != 0 {
+ if ret == -1 {
+ break // EOF
+ }
+ if ret == int(syscall.EINTR) {
+ continue
+ }
+ return &os.PathError{Op: "readdir", Path: dirName, Err: syscall.Errno(ret)}
+ }
+ if dirent.Ino == 0 {
+ continue
+ }
+ typ := dtToType(dirent.Type)
+ if skipFiles && typ.IsRegular() {
+ continue
+ }
+ name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:]
+ name = name[:dirent.Namlen]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ if err := fn(dirName, string(name), typ); err != nil {
+ if err != ErrSkipFiles {
+ return err
+ }
+ skipFiles = true
+ }
+ }
+
+ return nil
+}
+
+func dtToType(typ uint8) os.FileMode {
+ switch typ {
+ case syscall.DT_BLK:
+ return os.ModeDevice
+ case syscall.DT_CHR:
+ return os.ModeDevice | os.ModeCharDevice
+ case syscall.DT_DIR:
+ return os.ModeDir
+ case syscall.DT_FIFO:
+ return os.ModeNamedPipe
+ case syscall.DT_LNK:
+ return os.ModeSymlink
+ case syscall.DT_REG:
+ return 0
+ case syscall.DT_SOCK:
+ return os.ModeSocket
+ }
+ return ^os.FileMode(0)
+}
+
+// openDir wraps opendir(3) and handles any EINTR errors. The returned *DIR
+// needs to be closed with closedir(3).
+func openDir(path string) (*C.DIR, error) {
+ name, err := syscall.BytePtrFromString(path)
+ if err != nil {
+ return nil, err
+ }
+ for {
+ fd, err := C.opendir((*C.char)(unsafe.Pointer(name)))
+ if err != syscall.EINTR {
+ return fd, err
+ }
+ }
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go
new file mode 100644
index 000000000..d58595dbd
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build freebsd || openbsd || netbsd
+// +build freebsd openbsd netbsd
+
+package fastwalk
+
+import "syscall"
+
+func direntInode(dirent *syscall.Dirent) uint64 {
+ return uint64(dirent.Fileno)
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go
new file mode 100644
index 000000000..d3922890b
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (linux || (darwin && !cgo)) && !appengine
+// +build linux darwin,!cgo
+// +build !appengine
+
+package fastwalk
+
+import "syscall"
+
+func direntInode(dirent *syscall.Dirent) uint64 {
+ return dirent.Ino
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go
new file mode 100644
index 000000000..38a4db6af
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go
@@ -0,0 +1,14 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && !cgo) || freebsd || openbsd || netbsd
+// +build darwin,!cgo freebsd openbsd netbsd
+
+package fastwalk
+
+import "syscall"
+
+func direntNamlen(dirent *syscall.Dirent) uint64 {
+ return uint64(dirent.Namlen)
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go
new file mode 100644
index 000000000..c82e57df8
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux && !appengine
+// +build linux,!appengine
+
+package fastwalk
+
+import (
+ "bytes"
+ "syscall"
+ "unsafe"
+)
+
+func direntNamlen(dirent *syscall.Dirent) uint64 {
+ const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name))
+ nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
+ const nameBufLen = uint16(len(nameBuf))
+ limit := dirent.Reclen - fixedHdr
+ if limit > nameBufLen {
+ limit = nameBufLen
+ }
+ nameLen := bytes.IndexByte(nameBuf[:limit], 0)
+ if nameLen < 0 {
+ panic("failed to find terminating 0 byte in dirent")
+ }
+ return uint64(nameLen)
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
new file mode 100644
index 000000000..27e860243
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
@@ -0,0 +1,41 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build appengine || (!linux && !darwin && !freebsd && !openbsd && !netbsd)
+// +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd
+
+package fastwalk
+
+import (
+ "os"
+)
+
+// readDir calls fn for each directory entry in dirName.
+// It does not descend into directories or follow symlinks.
+// If fn returns a non-nil error, readDir returns with that error
+// immediately.
+func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
+ fis, err := os.ReadDir(dirName)
+ if err != nil {
+ return err
+ }
+ skipFiles := false
+ for _, fi := range fis {
+ info, err := fi.Info()
+ if err != nil {
+ return err
+ }
+ if info.Mode().IsRegular() && skipFiles {
+ continue
+ }
+ if err := fn(dirName, fi.Name(), info.Mode()&os.ModeType); err != nil {
+ if err == ErrSkipFiles {
+ skipFiles = true
+ continue
+ }
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go
new file mode 100644
index 000000000..f12f1a734
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go
@@ -0,0 +1,153 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (linux || freebsd || openbsd || netbsd || (darwin && !cgo)) && !appengine
+// +build linux freebsd openbsd netbsd darwin,!cgo
+// +build !appengine
+
+package fastwalk
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+const blockSize = 8 << 10
+
+// unknownFileMode is a sentinel (and bogus) os.FileMode
+// value used to represent a syscall.DT_UNKNOWN Dirent.Type.
+const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice
+
+func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error {
+ fd, err := open(dirName, 0, 0)
+ if err != nil {
+ return &os.PathError{Op: "open", Path: dirName, Err: err}
+ }
+ defer syscall.Close(fd)
+
+ // The buffer must be at least a block long.
+ buf := make([]byte, blockSize) // stack-allocated; doesn't escape
+ bufp := 0 // starting read position in buf
+ nbuf := 0 // end valid data in buf
+ skipFiles := false
+ for {
+ if bufp >= nbuf {
+ bufp = 0
+ nbuf, err = readDirent(fd, buf)
+ if err != nil {
+ return os.NewSyscallError("readdirent", err)
+ }
+ if nbuf <= 0 {
+ return nil
+ }
+ }
+ consumed, name, typ := parseDirEnt(buf[bufp:nbuf])
+ bufp += consumed
+ if name == "" || name == "." || name == ".." {
+ continue
+ }
+ // Fallback for filesystems (like old XFS) that don't
+ // support Dirent.Type and have DT_UNKNOWN (0) there
+ // instead.
+ if typ == unknownFileMode {
+ fi, err := os.Lstat(dirName + "/" + name)
+ if err != nil {
+ // It got deleted in the meantime.
+ if os.IsNotExist(err) {
+ continue
+ }
+ return err
+ }
+ typ = fi.Mode() & os.ModeType
+ }
+ if skipFiles && typ.IsRegular() {
+ continue
+ }
+ if err := fn(dirName, name, typ); err != nil {
+ if err == ErrSkipFiles {
+ skipFiles = true
+ continue
+ }
+ return err
+ }
+ }
+}
+
+func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) {
+ // golang.org/issue/37269
+ dirent := &syscall.Dirent{}
+ copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(dirent))[:], buf)
+ if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v {
+ panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v))
+ }
+ if len(buf) < int(dirent.Reclen) {
+ panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen))
+ }
+ consumed = int(dirent.Reclen)
+ if direntInode(dirent) == 0 { // File absent in directory.
+ return
+ }
+ switch dirent.Type {
+ case syscall.DT_REG:
+ typ = 0
+ case syscall.DT_DIR:
+ typ = os.ModeDir
+ case syscall.DT_LNK:
+ typ = os.ModeSymlink
+ case syscall.DT_BLK:
+ typ = os.ModeDevice
+ case syscall.DT_FIFO:
+ typ = os.ModeNamedPipe
+ case syscall.DT_SOCK:
+ typ = os.ModeSocket
+ case syscall.DT_UNKNOWN:
+ typ = unknownFileMode
+ default:
+ // Skip weird things.
+ // It's probably a DT_WHT (http://lwn.net/Articles/325369/)
+ // or something. Revisit if/when this package is moved outside
+ // of goimports. goimports only cares about regular files,
+ // symlinks, and directories.
+ return
+ }
+
+ nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
+ nameLen := direntNamlen(dirent)
+
+ // Special cases for common things:
+ if nameLen == 1 && nameBuf[0] == '.' {
+ name = "."
+ } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' {
+ name = ".."
+ } else {
+ name = string(nameBuf[:nameLen])
+ }
+ return
+}
+
+// According to https://golang.org/doc/go1.14#runtime
+// A consequence of the implementation of preemption is that on Unix systems, including Linux and macOS
+// systems, programs built with Go 1.14 will receive more signals than programs built with earlier releases.
+//
+// This causes syscall.Open and syscall.ReadDirent sometimes fail with EINTR errors.
+// We need to retry in this case.
+func open(path string, mode int, perm uint32) (fd int, err error) {
+ for {
+ fd, err := syscall.Open(path, mode, perm)
+ if err != syscall.EINTR {
+ return fd, err
+ }
+ }
+}
+
+func readDirent(fd int, buf []byte) (n int, err error) {
+ for {
+ nbuf, err := syscall.ReadDirent(fd, buf)
+ if err != syscall.EINTR {
+ return nbuf, err
+ }
+ }
+}
diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go
index 55312522d..53cf66da0 100644
--- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go
+++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go
@@ -13,7 +13,6 @@ import (
"io"
"log"
"os"
- "os/exec"
"reflect"
"regexp"
"runtime"
@@ -22,6 +21,8 @@ import (
"sync"
"time"
+ exec "golang.org/x/sys/execabs"
+
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/event/keys"
"golang.org/x/tools/internal/event/label"
@@ -84,7 +85,6 @@ func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stde
// RunRaw runs the invocation, serializing requests only if they fight over
// go.mod changes.
-// Postcondition: both error results have same nilness.
func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
ctx, done := event.Start(ctx, "gocommand.Runner.RunRaw", invLabels(inv)...)
defer done()
@@ -95,24 +95,23 @@ func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer
stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv)
// If we encounter a load concurrency error, we need to retry serially.
- if friendlyErr != nil && modConcurrencyError.MatchString(friendlyErr.Error()) {
- event.Error(ctx, "Load concurrency error, will retry serially", err)
-
- // Run serially by calling runPiped.
- stdout.Reset()
- stderr.Reset()
- friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
+ if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) {
+ return stdout, stderr, friendlyErr, err
}
+ event.Error(ctx, "Load concurrency error, will retry serially", err)
+ // Run serially by calling runPiped.
+ stdout.Reset()
+ stderr.Reset()
+ friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr)
return stdout, stderr, friendlyErr, err
}
-// Postcondition: both error results have same nilness.
func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) {
// Wait for 1 worker to become available.
select {
case <-ctx.Done():
- return nil, nil, ctx.Err(), ctx.Err()
+ return nil, nil, nil, ctx.Err()
case runner.inFlight <- struct{}{}:
defer func() { <-runner.inFlight }()
}
@@ -122,7 +121,6 @@ func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes
return stdout, stderr, friendlyErr, err
}
-// Postcondition: both error results have same nilness.
func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) {
// Make sure the runner is always initialized.
runner.initialize()
@@ -131,7 +129,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
// runPiped commands.
select {
case <-ctx.Done():
- return ctx.Err(), ctx.Err()
+ return nil, ctx.Err()
case runner.serialized <- struct{}{}:
defer func() { <-runner.serialized }()
}
@@ -141,7 +139,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
for i := 0; i < maxInFlight; i++ {
select {
case <-ctx.Done():
- return ctx.Err(), ctx.Err()
+ return nil, ctx.Err()
case runner.inFlight <- struct{}{}:
// Make sure we always "return" any workers we took.
defer func() { <-runner.inFlight }()
@@ -174,7 +172,6 @@ type Invocation struct {
Logf func(format string, args ...interface{})
}
-// Postcondition: both error results have same nilness.
func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) {
rawError = i.run(ctx, stdout, stderr)
if rawError != nil {
diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
index 52f74e643..452e342c5 100644
--- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
+++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
@@ -9,12 +9,13 @@ package gopathwalk
import (
"bufio"
"bytes"
- "io/fs"
"log"
"os"
"path/filepath"
"strings"
"time"
+
+ "golang.org/x/tools/internal/fastwalk"
)
// Options controls the behavior of a Walk call.
@@ -44,18 +45,21 @@ type Root struct {
}
// Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages.
-// For each package found, add will be called with the absolute
+// For each package found, add will be called (concurrently) with the absolute
// paths of the containing source directory and the package directory.
+// add will be called concurrently.
func Walk(roots []Root, add func(root Root, dir string), opts Options) {
WalkSkip(roots, add, func(Root, string) bool { return false }, opts)
}
// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages.
-// For each package found, add will be called with the absolute
+// For each package found, add will be called (concurrently) with the absolute
// paths of the containing source directory and the package directory.
-// For each directory that will be scanned, skip will be called
+// For each directory that will be scanned, skip will be called (concurrently)
// with the absolute paths of the containing source directory and the directory.
// If skip returns false on a directory it will be processed.
+// add will be called concurrently.
+// skip will be called concurrently.
func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) {
for _, root := range roots {
walkDir(root, add, skip, opts)
@@ -74,25 +78,14 @@ func walkDir(root Root, add func(Root, string), skip func(root Root, dir string)
if opts.Logf != nil {
opts.Logf("scanning %s", root.Path)
}
-
w := &walker{
- root: root,
- add: add,
- skip: skip,
- opts: opts,
- added: make(map[string]bool),
+ root: root,
+ add: add,
+ skip: skip,
+ opts: opts,
}
w.init()
-
- // Add a trailing path separator to cause filepath.WalkDir to traverse symlinks.
- path := root.Path
- if len(path) == 0 {
- path = "." + string(filepath.Separator)
- } else if !os.IsPathSeparator(path[len(path)-1]) {
- path = path + string(filepath.Separator)
- }
-
- if err := filepath.WalkDir(path, w.walk); err != nil {
+ if err := fastwalk.Walk(root.Path, w.walk); err != nil {
logf := opts.Logf
if logf == nil {
logf = log.Printf
@@ -112,10 +105,7 @@ type walker struct {
skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true.
opts Options // Options passed to Walk by the user.
- pathSymlinks []os.FileInfo
- ignoredDirs []string
-
- added map[string]bool
+ ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files.
}
// init initializes the walker based on its Options
@@ -131,9 +121,13 @@ func (w *walker) init() {
for _, p := range ignoredPaths {
full := filepath.Join(w.root.Path, p)
- w.ignoredDirs = append(w.ignoredDirs, full)
- if w.opts.Logf != nil {
- w.opts.Logf("Directory added to ignore list: %s", full)
+ if fi, err := os.Stat(full); err == nil {
+ w.ignoredDirs = append(w.ignoredDirs, fi)
+ if w.opts.Logf != nil {
+ w.opts.Logf("Directory added to ignore list: %s", full)
+ }
+ } else if w.opts.Logf != nil {
+ w.opts.Logf("Error statting ignored directory: %v", err)
}
}
}
@@ -168,9 +162,9 @@ func (w *walker) getIgnoredDirs(path string) []string {
}
// shouldSkipDir reports whether the file should be skipped or not.
-func (w *walker) shouldSkipDir(dir string) bool {
+func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool {
for _, ignoredDir := range w.ignoredDirs {
- if dir == ignoredDir {
+ if os.SameFile(fi, ignoredDir) {
return true
}
}
@@ -182,150 +176,85 @@ func (w *walker) shouldSkipDir(dir string) bool {
}
// walk walks through the given path.
-//
-// Errors are logged if w.opts.Logf is non-nil, but otherwise ignored:
-// walk returns only nil or fs.SkipDir.
-func (w *walker) walk(path string, d fs.DirEntry, err error) error {
- if err != nil {
- // We have no way to report errors back through Walk or WalkSkip,
- // so just log and ignore them.
- if w.opts.Logf != nil {
- w.opts.Logf("%v", err)
- }
- if d == nil {
- // Nothing more to do: the error prevents us from knowing
- // what path even represents.
- return nil
- }
- }
-
- if d.Type().IsRegular() {
- if !strings.HasSuffix(path, ".go") {
- return nil
- }
-
+func (w *walker) walk(path string, typ os.FileMode) error {
+ if typ.IsRegular() {
dir := filepath.Dir(path)
if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) {
// Doesn't make sense to have regular files
// directly in your $GOPATH/src or $GOROOT/src.
+ return fastwalk.ErrSkipFiles
+ }
+ if !strings.HasSuffix(path, ".go") {
return nil
}
- if !w.added[dir] {
- w.add(w.root, dir)
- w.added[dir] = true
- }
- return nil
+ w.add(w.root, dir)
+ return fastwalk.ErrSkipFiles
}
-
- if d.IsDir() {
+ if typ == os.ModeDir {
base := filepath.Base(path)
if base == "" || base[0] == '.' || base[0] == '_' ||
base == "testdata" ||
(w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") ||
(!w.opts.ModulesEnabled && base == "node_modules") {
- return fs.SkipDir
+ return filepath.SkipDir
}
- if w.shouldSkipDir(path) {
- return fs.SkipDir
+ fi, err := os.Lstat(path)
+ if err == nil && w.shouldSkipDir(fi, path) {
+ return filepath.SkipDir
}
return nil
}
-
- if d.Type()&os.ModeSymlink != 0 {
- // TODO(bcmills): 'go list all' itself ignores symlinks within GOROOT/src
- // and GOPATH/src. Do we really need to traverse them here? If so, why?
-
- fi, err := os.Stat(path)
- if err != nil || !fi.IsDir() {
- // Not a directory. Just walk the file (or broken link) and be done.
- return w.walk(path, fs.FileInfoToDirEntry(fi), err)
+ if typ == os.ModeSymlink {
+ base := filepath.Base(path)
+ if strings.HasPrefix(base, ".#") {
+ // Emacs noise.
+ return nil
}
-
- // Avoid walking symlink cycles: if we have already followed a symlink to
- // this directory as a parent of itself, don't follow it again.
- //
- // This doesn't catch the first time through a cycle, but it also minimizes
- // the number of extra stat calls we make if we *don't* encounter a cycle.
- // Since we don't actually expect to encounter symlink cycles in practice,
- // this seems like the right tradeoff.
- for _, parent := range w.pathSymlinks {
- if os.SameFile(fi, parent) {
- return nil
- }
+ if w.shouldTraverse(path) {
+ return fastwalk.ErrTraverseLink
}
+ }
+ return nil
+}
- w.pathSymlinks = append(w.pathSymlinks, fi)
- defer func() {
- w.pathSymlinks = w.pathSymlinks[:len(w.pathSymlinks)-1]
- }()
-
- // On some platforms the OS (or the Go os package) sometimes fails to
- // resolve directory symlinks before a trailing slash
- // (even though POSIX requires it to do so).
- //
- // On macOS that failure may be caused by a known libc/kernel bug;
- // see https://go.dev/issue/59586.
- //
- // On Windows before Go 1.21, it may be caused by a bug in
- // os.Lstat (fixed in https://go.dev/cl/463177).
- //
- // Since we need to handle this explicitly on broken platforms anyway,
- // it is simplest to just always do that and not rely on POSIX pathname
- // resolution to walk the directory (such as by calling WalkDir with
- // a trailing slash appended to the path).
- //
- // Instead, we make a sequence of walk calls — directly and through
- // recursive calls to filepath.WalkDir — simulating what WalkDir would do
- // if the symlink were a regular directory.
-
- // First we call walk on the path as a directory
- // (instead of a symlink).
- err = w.walk(path, fs.FileInfoToDirEntry(fi), nil)
- if err == fs.SkipDir {
- return nil
- } else if err != nil {
- // This should be impossible, but handle it anyway in case
- // walk is changed to return other errors.
- return err
+// shouldTraverse reports whether the symlink fi, found in dir,
+// should be followed. It makes sure symlinks were never visited
+// before to avoid symlink loops.
+func (w *walker) shouldTraverse(path string) bool {
+ ts, err := os.Stat(path)
+ if err != nil {
+ logf := w.opts.Logf
+ if logf == nil {
+ logf = log.Printf
}
-
- // Now read the directory and walk its entries.
- ents, err := os.ReadDir(path)
+ logf("%v", err)
+ return false
+ }
+ if !ts.IsDir() {
+ return false
+ }
+ if w.shouldSkipDir(ts, filepath.Dir(path)) {
+ return false
+ }
+ // Check for symlink loops by statting each directory component
+ // and seeing if any are the same file as ts.
+ for {
+ parent := filepath.Dir(path)
+ if parent == path {
+ // Made it to the root without seeing a cycle.
+ // Use this symlink.
+ return true
+ }
+ parentInfo, err := os.Stat(parent)
if err != nil {
- // Report the ReadDir error, as filepath.WalkDir would do.
- err = w.walk(path, fs.FileInfoToDirEntry(fi), err)
- if err == fs.SkipDir {
- return nil
- } else if err != nil {
- return err // Again, should be impossible.
- }
- // Fall through and iterate over whatever entries we did manage to get.
+ return false
}
-
- for _, d := range ents {
- nextPath := filepath.Join(path, d.Name())
- if d.IsDir() {
- // We want to walk the whole directory tree rooted at nextPath,
- // not just the single entry for the directory.
- err := filepath.WalkDir(nextPath, w.walk)
- if err != nil && w.opts.Logf != nil {
- w.opts.Logf("%v", err)
- }
- } else {
- err := w.walk(nextPath, d, nil)
- if err == fs.SkipDir {
- // Skip the rest of the entries in the parent directory of nextPath
- // (that is, path itself).
- break
- } else if err != nil {
- return err // Again, should be impossible.
- }
- }
+ if os.SameFile(ts, parentInfo) {
+ // Cycle. Don't traverse.
+ return false
}
- return nil
+ path = parent
}
- // Not a file, regular directory, or symlink; skip.
- return nil
}
diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
index 44719de17..d9950b1f0 100644
--- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
+++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go
@@ -5,6 +5,10 @@
// Package packagesinternal exposes internal-only fields from go/packages.
package packagesinternal
+import (
+ "golang.org/x/tools/internal/gocommand"
+)
+
var GetForTest = func(p interface{}) string { return "" }
var GetDepsErrors = func(p interface{}) []*PackageError { return nil }
@@ -14,6 +18,10 @@ type PackageError struct {
Err string // the error itself
}
+var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil }
+
+var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {}
+
var TypecheckCgo int
var DepsErrors int // must be set as a LoadMode to call GetDepsErrors
var ForTest int // must be set as a LoadMode to call GetForTest
diff --git a/vendor/golang.org/x/tools/internal/testenv/testenv.go b/vendor/golang.org/x/tools/internal/testenv/testenv.go
index 511da9d7e..4d29ebe7f 100644
--- a/vendor/golang.org/x/tools/internal/testenv/testenv.go
+++ b/vendor/golang.org/x/tools/internal/testenv/testenv.go
@@ -11,7 +11,6 @@ import (
"fmt"
"go/build"
"os"
- "os/exec"
"path/filepath"
"runtime"
"runtime/debug"
@@ -22,6 +21,8 @@ import (
"golang.org/x/mod/modfile"
"golang.org/x/tools/internal/goroot"
+
+ exec "golang.org/x/sys/execabs"
)
// packageMainIsDevel reports whether the module containing package main
@@ -446,32 +447,3 @@ func NeedsLocalXTools(t testing.TB) {
t.Skipf("skipping test: %s module path is %q, not %q", modFilePath, modulePath, want)
}
}
-
-// NeedsGoExperiment skips t if the current process environment does not
-// have a GOEXPERIMENT flag set.
-func NeedsGoExperiment(t testing.TB, flag string) {
- t.Helper()
-
- goexp := os.Getenv("GOEXPERIMENT")
- set := false
- for _, f := range strings.Split(goexp, ",") {
- if f == "" {
- continue
- }
- if f == "none" {
- // GOEXPERIMENT=none disables all experiment flags.
- set = false
- break
- }
- val := true
- if strings.HasPrefix(f, "no") {
- f, val = f[2:], false
- }
- if f == flag {
- set = val
- }
- }
- if !set {
- t.Skipf("skipping test: flag %q is not set in GOEXPERIMENT=%q", flag, goexp)
- }
-}
diff --git a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go b/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go
new file mode 100644
index 000000000..5e96e8955
--- /dev/null
+++ b/vendor/golang.org/x/tools/internal/typesinternal/objectpath.go
@@ -0,0 +1,24 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typesinternal
+
+import "go/types"
+
+// This file contains back doors that allow gopls to avoid method sorting when
+// using the objectpath package.
+//
+// This is performance-critical in certain repositories, but changing the
+// behavior of the objectpath package is still being discussed in
+// golang/go#61443. If we decide to remove the sorting in objectpath we can
+// simply delete these back doors. Otherwise, we should add a new API to
+// objectpath that allows controlling the sorting.
+
+// SkipEncoderMethodSorting marks enc (which must be an *objectpath.Encoder) as
+// not requiring sorted methods.
+var SkipEncoderMethodSorting func(enc interface{})
+
+// ObjectpathObject is like objectpath.Object, but allows suppressing method
+// sorting.
+var ObjectpathObject func(pkg *types.Package, p string, skipMethodSorting bool) (types.Object, error)
diff --git a/vendor/golang.org/x/tools/internal/versions/gover.go b/vendor/golang.org/x/tools/internal/versions/gover.go
deleted file mode 100644
index bbabcd22e..000000000
--- a/vendor/golang.org/x/tools/internal/versions/gover.go
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This is a fork of internal/gover for use by x/tools until
-// go1.21 and earlier are no longer supported by x/tools.
-
-package versions
-
-import "strings"
-
-// A gover is a parsed Go gover: major[.Minor[.Patch]][kind[pre]]
-// The numbers are the original decimal strings to avoid integer overflows
-// and since there is very little actual math. (Probably overflow doesn't matter in practice,
-// but at the time this code was written, there was an existing test that used
-// go1.99999999999, which does not fit in an int on 32-bit platforms.
-// The "big decimal" representation avoids the problem entirely.)
-type gover struct {
- major string // decimal
- minor string // decimal or ""
- patch string // decimal or ""
- kind string // "", "alpha", "beta", "rc"
- pre string // decimal or ""
-}
-
-// compare returns -1, 0, or +1 depending on whether
-// x < y, x == y, or x > y, interpreted as toolchain versions.
-// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21".
-// Malformed versions compare less than well-formed versions and equal to each other.
-// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0".
-func compare(x, y string) int {
- vx := parse(x)
- vy := parse(y)
-
- if c := cmpInt(vx.major, vy.major); c != 0 {
- return c
- }
- if c := cmpInt(vx.minor, vy.minor); c != 0 {
- return c
- }
- if c := cmpInt(vx.patch, vy.patch); c != 0 {
- return c
- }
- if c := strings.Compare(vx.kind, vy.kind); c != 0 { // "" < alpha < beta < rc
- return c
- }
- if c := cmpInt(vx.pre, vy.pre); c != 0 {
- return c
- }
- return 0
-}
-
-// lang returns the Go language version. For example, lang("1.2.3") == "1.2".
-func lang(x string) string {
- v := parse(x)
- if v.minor == "" || v.major == "1" && v.minor == "0" {
- return v.major
- }
- return v.major + "." + v.minor
-}
-
-// isValid reports whether the version x is valid.
-func isValid(x string) bool {
- return parse(x) != gover{}
-}
-
-// parse parses the Go version string x into a version.
-// It returns the zero version if x is malformed.
-func parse(x string) gover {
- var v gover
-
- // Parse major version.
- var ok bool
- v.major, x, ok = cutInt(x)
- if !ok {
- return gover{}
- }
- if x == "" {
- // Interpret "1" as "1.0.0".
- v.minor = "0"
- v.patch = "0"
- return v
- }
-
- // Parse . before minor version.
- if x[0] != '.' {
- return gover{}
- }
-
- // Parse minor version.
- v.minor, x, ok = cutInt(x[1:])
- if !ok {
- return gover{}
- }
- if x == "" {
- // Patch missing is same as "0" for older versions.
- // Starting in Go 1.21, patch missing is different from explicit .0.
- if cmpInt(v.minor, "21") < 0 {
- v.patch = "0"
- }
- return v
- }
-
- // Parse patch if present.
- if x[0] == '.' {
- v.patch, x, ok = cutInt(x[1:])
- if !ok || x != "" {
- // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != "").
- // Allowing them would be a bit confusing because we already have:
- // 1.21 < 1.21rc1
- // But a prerelease of a patch would have the opposite effect:
- // 1.21.3rc1 < 1.21.3
- // We've never needed them before, so let's not start now.
- return gover{}
- }
- return v
- }
-
- // Parse prerelease.
- i := 0
- for i < len(x) && (x[i] < '0' || '9' < x[i]) {
- if x[i] < 'a' || 'z' < x[i] {
- return gover{}
- }
- i++
- }
- if i == 0 {
- return gover{}
- }
- v.kind, x = x[:i], x[i:]
- if x == "" {
- return v
- }
- v.pre, x, ok = cutInt(x)
- if !ok || x != "" {
- return gover{}
- }
-
- return v
-}
-
-// cutInt scans the leading decimal number at the start of x to an integer
-// and returns that value and the rest of the string.
-func cutInt(x string) (n, rest string, ok bool) {
- i := 0
- for i < len(x) && '0' <= x[i] && x[i] <= '9' {
- i++
- }
- if i == 0 || x[0] == '0' && i != 1 { // no digits or unnecessary leading zero
- return "", "", false
- }
- return x[:i], x[i:], true
-}
-
-// cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers.
-// (Copied from golang.org/x/mod/semver's compareInt.)
-func cmpInt(x, y string) int {
- if x == y {
- return 0
- }
- if len(x) < len(y) {
- return -1
- }
- if len(x) > len(y) {
- return +1
- }
- if x < y {
- return -1
- } else {
- return +1
- }
-}
diff --git a/vendor/golang.org/x/tools/internal/versions/types.go b/vendor/golang.org/x/tools/internal/versions/types.go
deleted file mode 100644
index 562eef21f..000000000
--- a/vendor/golang.org/x/tools/internal/versions/types.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package versions
-
-import (
- "go/types"
-)
-
-// GoVersion returns the Go version of the type package.
-// It returns zero if no version can be determined.
-func GoVersion(pkg *types.Package) string {
- // TODO(taking): x/tools can call GoVersion() [from 1.21] after 1.25.
- if pkg, ok := any(pkg).(interface{ GoVersion() string }); ok {
- return pkg.GoVersion()
- }
- return ""
-}
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go121.go b/vendor/golang.org/x/tools/internal/versions/types_go121.go
deleted file mode 100644
index a7b79207a..000000000
--- a/vendor/golang.org/x/tools/internal/versions/types_go121.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.22
-// +build !go1.22
-
-package versions
-
-import (
- "go/ast"
- "go/types"
-)
-
-// FileVersions always reports the a file's Go version as the
-// zero version at this Go version.
-func FileVersions(info *types.Info, file *ast.File) string { return "" }
-
-// InitFileVersions is a noop at this Go version.
-func InitFileVersions(*types.Info) {}
diff --git a/vendor/golang.org/x/tools/internal/versions/types_go122.go b/vendor/golang.org/x/tools/internal/versions/types_go122.go
deleted file mode 100644
index 7b9ba89a8..000000000
--- a/vendor/golang.org/x/tools/internal/versions/types_go122.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.22
-// +build go1.22
-
-package versions
-
-import (
- "go/ast"
- "go/types"
-)
-
-// FileVersions maps a file to the file's semantic Go version.
-// The reported version is the zero version if a version cannot be determined.
-func FileVersions(info *types.Info, file *ast.File) string {
- return info.FileVersions[file]
-}
-
-// InitFileVersions initializes info to record Go versions for Go files.
-func InitFileVersions(info *types.Info) {
- info.FileVersions = make(map[*ast.File]string)
-}
diff --git a/vendor/golang.org/x/tools/internal/versions/versions_go121.go b/vendor/golang.org/x/tools/internal/versions/versions_go121.go
deleted file mode 100644
index cf4a7d036..000000000
--- a/vendor/golang.org/x/tools/internal/versions/versions_go121.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.22
-// +build !go1.22
-
-package versions
-
-// Lang returns the Go language version for version x.
-// If x is not a valid version, Lang returns the empty string.
-// For example:
-//
-// Lang("go1.21rc2") = "go1.21"
-// Lang("go1.21.2") = "go1.21"
-// Lang("go1.21") = "go1.21"
-// Lang("go1") = "go1"
-// Lang("bad") = ""
-// Lang("1.21") = ""
-func Lang(x string) string {
- v := lang(stripGo(x))
- if v == "" {
- return ""
- }
- return x[:2+len(v)] // "go"+v without allocation
-}
-
-// Compare returns -1, 0, or +1 depending on whether
-// x < y, x == y, or x > y, interpreted as Go versions.
-// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21".
-// Invalid versions, including the empty string, compare less than
-// valid versions and equal to each other.
-// The language version "go1.21" compares less than the
-// release candidate and eventual releases "go1.21rc1" and "go1.21.0".
-// Custom toolchain suffixes are ignored during comparison:
-// "go1.21.0" and "go1.21.0-bigcorp" are equal.
-func Compare(x, y string) int { return compare(stripGo(x), stripGo(y)) }
-
-// IsValid reports whether the version x is valid.
-func IsValid(x string) bool { return isValid(stripGo(x)) }
-
-// stripGo converts from a "go1.21" version to a "1.21" version.
-// If v does not start with "go", stripGo returns the empty string (a known invalid version).
-func stripGo(v string) string {
- if len(v) < 2 || v[:2] != "go" {
- return ""
- }
- return v[2:]
-}
diff --git a/vendor/golang.org/x/tools/internal/versions/versions_go122.go b/vendor/golang.org/x/tools/internal/versions/versions_go122.go
deleted file mode 100644
index c1c1814b2..000000000
--- a/vendor/golang.org/x/tools/internal/versions/versions_go122.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build go1.22
-// +build go1.22
-
-package versions
-
-import (
- "go/version"
-)
-
-// Lang returns the Go language version for version x.
-// If x is not a valid version, Lang returns the empty string.
-// For example:
-//
-// Lang("go1.21rc2") = "go1.21"
-// Lang("go1.21.2") = "go1.21"
-// Lang("go1.21") = "go1.21"
-// Lang("go1") = "go1"
-// Lang("bad") = ""
-// Lang("1.21") = ""
-func Lang(x string) string { return version.Lang(x) }
-
-// Compare returns -1, 0, or +1 depending on whether
-// x < y, x == y, or x > y, interpreted as Go versions.
-// The versions x and y must begin with a "go" prefix: "go1.21" not "1.21".
-// Invalid versions, including the empty string, compare less than
-// valid versions and equal to each other.
-// The language version "go1.21" compares less than the
-// release candidate and eventual releases "go1.21rc1" and "go1.21.0".
-// Custom toolchain suffixes are ignored during comparison:
-// "go1.21.0" and "go1.21.0-bigcorp" are equal.
-func Compare(x, y string) int { return version.Compare(x, y) }
-
-// IsValid reports whether the version x is valid.
-func IsValid(x string) bool { return version.IsValid(x) }
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8d66f2853..11af7396b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -830,7 +830,7 @@ golang.org/x/exp/slices
# golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833
## explicit; go 1.18
golang.org/x/exp/typeparams
-# golang.org/x/mod v0.14.0
+# golang.org/x/mod v0.13.0
## explicit; go 1.18
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -868,6 +868,7 @@ golang.org/x/sync/semaphore
# golang.org/x/sys v0.15.0
## explicit; go 1.18
golang.org/x/sys/cpu
+golang.org/x/sys/execabs
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/text v0.14.0
@@ -882,7 +883,7 @@ golang.org/x/text/width
# golang.org/x/time v0.5.0
## explicit; go 1.18
golang.org/x/time/rate
-# golang.org/x/tools v0.16.0
+# golang.org/x/tools v0.14.0
## explicit; go 1.18
golang.org/x/tools/go/analysis
golang.org/x/tools/go/analysis/analysistest
@@ -955,6 +956,7 @@ golang.org/x/tools/internal/event/core
golang.org/x/tools/internal/event/keys
golang.org/x/tools/internal/event/label
golang.org/x/tools/internal/event/tag
+golang.org/x/tools/internal/fastwalk
golang.org/x/tools/internal/gcimporter
golang.org/x/tools/internal/gocommand
golang.org/x/tools/internal/gopathwalk
@@ -967,7 +969,6 @@ golang.org/x/tools/internal/testenv
golang.org/x/tools/internal/tokeninternal
golang.org/x/tools/internal/typeparams
golang.org/x/tools/internal/typesinternal
-golang.org/x/tools/internal/versions
golang.org/x/tools/txtar
# golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
## explicit; go 1.17