aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>2023-11-10 10:15:22 +0000
committerTaras Madan <tarasmadan@google.com>2023-11-10 11:16:54 +0000
commit910357f994885a9e8af8a28ee2bc3d87d40b9d89 (patch)
tree052b0649702064ad80885d7c4bd50606ab8777dc
parent4a320846d42d41c1f68bf0bdc5944dca9718b8b8 (diff)
mod: do: bump golang.org/x/tools from 0.14.0 to 0.15.0
Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.14.0 to 0.15.0. - [Release notes](https://github.com/golang/tools/releases) - [Commits](https://github.com/golang/tools/compare/v0.14.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/tools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
-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/tools/go/analysis/internal/checker/checker.go4
-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/loopclosure.go17
-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/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/packagesdriver/sizes.go15
-rw-r--r--vendor/golang.org/x/tools/go/packages/golist.go74
-rw-r--r--vendor/golang.org/x/tools/go/packages/golist_overlay.go492
-rw-r--r--vendor/golang.org/x/tools/go/packages/packages.go169
-rw-r--r--vendor/golang.org/x/tools/go/ssa/builder.go793
-rw-r--r--vendor/golang.org/x/tools/go/ssa/create.go170
-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/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.go65
-rw-r--r--vendor/golang.org/x/tools/go/ssa/ssa.go129
-rw-r--r--vendor/golang.org/x/tools/go/ssa/ssautil/load.go38
-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/versions_go122.go21
-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.go24
-rw-r--r--vendor/golang.org/x/tools/internal/gopathwalk/walk.go121
-rw-r--r--vendor/golang.org/x/tools/internal/testenv/testenv.go29
-rw-r--r--vendor/golang.org/x/tools/internal/typesinternal/objectpath.go24
-rw-r--r--vendor/modules.txt5
64 files changed, 1722 insertions, 2847 deletions
diff --git a/go.mod b/go.mod
index baf491998..74f4a47c7 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.14.0
- golang.org/x/tools v0.14.0
+ golang.org/x/tools v0.15.0
google.golang.org/api v0.150.0
google.golang.org/appengine/v2 v2.0.5
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b
@@ -202,7 +202,7 @@ require (
golang.org/x/crypto v0.15.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.13.0 // indirect
+ golang.org/x/mod v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
diff --git a/go.sum b/go.sum
index 4a3b89675..9593fa122 100644
--- a/go.sum
+++ b/go.sum
@@ -729,8 +729,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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
-golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -963,8 +963,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.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
-golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
+golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
+golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
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 e0869fa38..35fd1f534 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,7 +555,6 @@ 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{
@@ -679,14 +678,15 @@ 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
+// 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
// 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 strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") ||
- strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) ||
+ return ns == "." || strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, `.\`) ||
+ 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/tools/go/analysis/internal/checker/checker.go b/vendor/golang.org/x/tools/go/analysis/internal/checker/checker.go
index 33ca77a06..8efb89f6b 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
@@ -485,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)
+ xdiff, err := diff.ToUnified(oldlabel, xlabel, old, xedits, diff.DefaultContextLines)
if err != nil {
return err
}
- ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits)
+ ydiff, err := diff.ToUnified(oldlabel, ylabel, old, yedits, diff.DefaultContextLines)
if err != nil {
return err
}
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 10489bea1..3bfd50122 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,6 +18,7 @@ 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"
)
@@ -77,7 +78,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 := analysisutil.Unparen(e).(*ast.IndexExpr); ok {
+ if idx, ok := astutil.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 b40e081ec..931f9ca75 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,18 +52,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
if !ok {
continue
}
- 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":
+ fn := typeutil.StaticCallee(pass.TypesInfo, call)
+ if analysisutil.IsFunctionNamed(fn, "sync/atomic", "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 01683e45a..aff6d25b3 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,6 +18,7 @@ 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"
@@ -42,31 +43,20 @@ 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)
- 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":
-
+ fn := typeutil.StaticCallee(pass.TypesInfo, call)
+ if analysisutil.IsFunctionNamed(fn, "sync/atomic", funcNames...) {
// For all the listed functions, the expression to check is always the first function argument.
- check64BitAlignment(pass, sel.Sel.Name, call.Args[0])
+ check64BitAlignment(pass, fn.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 4219f087b..564329774 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,6 +14,7 @@ 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"
)
@@ -83,7 +84,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) || hasSideEffects(info, exprs[j]) {
+ if j == len(exprs) || analysisutil.HasSideEffects(info, exprs[j]) {
if i < j {
sets = append(sets, exprs[i:j])
}
@@ -162,46 +163,13 @@ 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 = unparen(e)
+ e = astutil.Unparen(e)
if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
seen[b] = true
exprs = append(exprs, op.split(b.Y, seen)...)
@@ -213,14 +181,3 @@ 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 881b8fd67..f077ea282 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,15 +26,13 @@ var Analyzer = &analysis.Analyzer{
}
// SSA provides SSA-form intermediate representation for all the
-// non-blank source functions in the current package.
+// 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
@@ -51,20 +49,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
prog := ssa.NewProgram(pass.Fset, mode)
- // 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())
- }
- }
+ // Create SSA packages for direct imports.
+ for _, p := range pass.Pkg.Imports() {
+ prog.CreatePackage(p, nil, nil, true)
}
- createAll(pass.Pkg.Imports())
// Create and build the primary package.
ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false)
@@ -76,16 +64,6 @@ 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 98d9a777a..4e8643975 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,6 +19,7 @@ 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
@@ -64,7 +65,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 := analysisutil.Unparen(call.Fun).(*ast.SelectorExpr); ok {
+ if sel, ok := astutil.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 ec7727de7..2eeb0a330 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,6 +16,7 @@ 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"
)
@@ -223,7 +224,7 @@ func (path typePath) String() string {
}
func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
- x = analysisutil.Unparen(x) // ignore parens on rhs
+ x = astutil.Unparen(x) // ignore parens on rhs
if _, ok := x.(*ast.CompositeLit); ok {
return nil
@@ -233,7 +234,7 @@ func lockPathRhs(pass *analysis.Pass, x ast.Expr) typePath {
return nil
}
if star, ok := x.(*ast.StarExpr); ok {
- if _, ok := analysisutil.Unparen(star.X).(*ast.CallExpr); ok {
+ if _, ok := astutil.Unparen(star.X).(*ast.CallExpr); ok {
// A call may return a pointer to a zero value.
return nil
}
@@ -319,9 +320,7 @@ 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 named, ok := typ.(*types.Named); ok &&
- named.Obj().Name() == "noCopy" &&
- named.Obj().Pkg().Path() == "sync" {
+ if analysisutil.IsNamedType(typ, "sync", "noCopy") {
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 3a1818764..1a83bddbc 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,11 +46,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
call := n.(*ast.CallExpr)
- 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]) {
+ fn, _ := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
+ if analysisutil.IsFunctionNamed(fn, "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 ed2a122f2..5e8e80a6a 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,7 +7,6 @@ package defers
import (
_ "embed"
"go/ast"
- "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -36,8 +35,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
checkDeferCall := func(node ast.Node) bool {
switch v := node.(type) {
case *ast.CallExpr:
- fn, ok := typeutil.Callee(pass.TypesInfo, v).(*types.Func)
- if ok && fn.Name() == "Since" && fn.Pkg().Path() == "time" {
+ if analysisutil.IsFunctionNamed(typeutil.StaticCallee(pass.TypesInfo, v), "time", "Since") {
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 2fcbdfafb..7f62ad4c8 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,15 +51,12 @@ 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 fn == nil {
- return // not a static call
+ if !analysisutil.IsFunctionNamed(fn, "errors", "As") {
+ return
}
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)
}
@@ -69,9 +66,6 @@ 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 61c3b764f..c6b6c81b4 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 || !isNamedType(ptr.Elem(), "net/http", "Response") {
+ if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !analysisutil.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 isNamedType(typ, "net/http", "Client") {
+ if analysisutil.IsNamedType(typ, "net/http", "Client") {
return true // method on http.Client.
}
ptr, ok := typ.(*types.Pointer)
- return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
+ return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
}
// restOfBlock, given a traversal stack, finds the innermost containing
@@ -171,13 +171,3 @@ 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 a8d84034d..c0060753f 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,17 +55,6 @@ 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) {
@@ -118,3 +107,46 @@ 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/loopclosure.go b/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
index 5620c35fa..fbcdc223d 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
@@ -359,20 +359,5 @@ func isMethodCall(info *types.Info, expr ast.Expr, pkgPath, typeName, method str
if ptr, ok := recv.Type().(*types.Pointer); ok {
rtype = ptr.Elem()
}
- 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
+ return analysisutil.IsNamedType(rtype, pkgPath, typeName)
}
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 d1ca0748e..c4999f7a9 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,11 +38,15 @@ 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{}) {
- pass.Report(analysis.Diagnostic{
- Pos: pos,
- Category: category,
- Message: fmt.Sprintf(format, args...),
- })
+ // 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...),
+ })
+ }
}
// 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 b2b8c67c7..070654f01 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,15 +511,10 @@ func isFormatter(typ types.Type) bool {
sig := fn.Type().(*types.Signature)
return sig.Params().Len() == 2 &&
sig.Results().Len() == 0 &&
- isNamed(sig.Params().At(0).Type(), "fmt", "State") &&
+ analysisutil.IsNamedType(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 27677139e..6789d7357 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,11 +49,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
}
case *ast.CallExpr:
- 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])) {
+ fn, _ := typeutil.Callee(pass.TypesInfo, n).(*types.Func)
+ if analysisutil.IsFunctionNamed(fn, "reflect", "DeepEqual") && (isReflectValue(pass, n.Args[0]) || isReflectValue(pass, n.Args[1])) {
pass.ReportRangef(n, "avoid using reflect.DeepEqual with reflect.Value")
}
}
@@ -68,11 +65,7 @@ func isReflectValue(pass *analysis.Pass, e ast.Expr) bool {
return false
}
// See if the type is 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" {
+ if !analysisutil.IsNamedType(tv.Type, "reflect", "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 92c1da8ef..a1323c3e6 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 isNamed(t, "log/slog", "Attr")
+ return analysisutil.IsNamedType(t, "log/slog", "Attr")
}
// shortName returns a name for the function that is shorter than FullName.
@@ -232,12 +232,3 @@ 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 1fe206b0f..6c151a02c 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,12 +47,7 @@ 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 fn == nil {
- return
- }
-
- fnName := fn.FullName()
- if fnName != "sort.Slice" && fnName != "sort.SliceStable" && fnName != "sort.SliceIsSorted" {
+ if !analysisutil.IsFunctionNamed(fn, "sort", "Slice", "SliceStable", "SliceIsSorted") {
return
}
@@ -131,7 +126,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", fnName, typ.String()),
+ Message: fmt.Sprintf("%s's argument must be a slice; is called with %s", fn.FullName(), typ.String()),
SuggestedFixes: fixes,
})
})
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 9589a46a5..d0b0ebb10 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,13 +257,7 @@ func isTestingType(typ types.Type, testingType string) bool {
if !ok {
return false
}
- 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
+ return analysisutil.IsNamedType(ptr.Elem(), "testing", 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 c45b9fa54..eb84502bd 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,29 +88,16 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
func isTimeDotFormat(f *types.Func) bool {
- if f.Name() != "Format" || f.Pkg().Path() != "time" {
- return false
- }
- sig, ok := f.Type().(*types.Signature)
- if !ok {
+ if f.Name() != "Format" || f.Pkg() == nil || f.Pkg().Path() != "time" {
return false
}
// Verify that the receiver is time.Time.
- recv := sig.Recv()
- if recv == nil {
- return false
- }
- named, ok := recv.Type().(*types.Named)
- return ok && named.Obj().Name() == "Time"
+ recv := f.Type().(*types.Signature).Recv()
+ return recv != nil && analysisutil.IsNamedType(recv.Type(), "time", "Time")
}
func isTimeDotParse(f *types.Func) bool {
- 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
+ return analysisutil.IsFunctionNamed(f, "time", "Parse")
}
// 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 e43ac2078..32e71ef97 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,6 +15,7 @@ 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"
)
@@ -68,7 +69,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 := analysisutil.Unparen(x).(type) {
+ switch x := astutil.Unparen(x).(type) {
case *ast.SelectorExpr:
// "(6) Conversion of a reflect.SliceHeader or
// reflect.StringHeader Data field to or from Pointer."
@@ -104,8 +105,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
}
switch sel.Sel.Name {
case "Pointer", "UnsafeAddr":
- t, ok := info.Types[sel.X].Type.(*types.Named)
- if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
+ if analysisutil.IsNamedType(info.Types[sel.X].Type, "reflect", "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 := analysisutil.Unparen(x).(type) {
+ switch x := astutil.Unparen(x).(type) {
case *ast.CallExpr:
// Base case: initial conversion from unsafe.Pointer to uintptr.
return len(x.Args) == 1 &&
@@ -153,13 +153,5 @@ 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 {
- 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
+ return analysisutil.IsNamedType(t, "reflect", "SliceHeader", "StringHeader")
}
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 cb487a217..7f79b4a75 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,6 +24,7 @@ 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"
)
@@ -82,7 +83,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
(*ast.ExprStmt)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
- call, ok := analysisutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
+ call, ok := astutil.Unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
if !ok {
return // not a call statement
}
@@ -92,7 +93,6 @@ 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 9da5692af..4f2c40456 100644
--- a/vendor/golang.org/x/tools/go/analysis/validate.go
+++ b/vendor/golang.org/x/tools/go/analysis/validate.go
@@ -19,6 +19,8 @@ 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/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
index 0454cdd78..333676b7c 100644
--- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
+++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
@@ -13,16 +13,17 @@ 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 {
- 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.
+ 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.
// TODO(matloob): Is this a problem in practice?
inv.Verb = "env"
inv.Args = []string{"GOARCH"}
@@ -32,8 +33,12 @@ func GetSizesForArgsGolist(ctx context.Context, inv gocommand.Invocation, gocmdR
}
goarch = strings.TrimSpace(envout.String())
compiler = "gc"
- } else {
+ } else if friendlyErr != nil {
return "", "", friendlyErr
+ } else {
+ // This should be unreachable, but be defensive
+ // in case RunRaw's error results are inconsistent.
+ return "", "", rawErr
}
} else {
fields := strings.Fields(stdout.String())
diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go
index 1f1eade0a..c1292b30f 100644
--- a/vendor/golang.org/x/tools/go/packages/golist.go
+++ b/vendor/golang.org/x/tools/go/packages/golist.go
@@ -208,62 +208,6 @@ 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
@@ -271,24 +215,6 @@ 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 9576b472f..d823c474a 100644
--- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go
+++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go
@@ -6,314 +6,11 @@ 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) {
@@ -384,192 +81,3 @@ 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 ece0e7c60..6cbd3de83 100644
--- a/vendor/golang.org/x/tools/go/packages/packages.go
+++ b/vendor/golang.org/x/tools/go/packages/packages.go
@@ -258,31 +258,52 @@ 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) {
- l := newLoader(cfg)
- response, err := defaultDriver(&l.Config, patterns...)
+ ld := newLoader(cfg)
+ response, external, err := defaultDriver(&ld.Config, patterns...)
if err != nil {
return nil, err
}
- l.sizes = types.SizesFor(response.Compiler, response.Arch)
- return l.refine(response)
+
+ 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)
}
// 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.
-func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
- driver := findExternalDriver(cfg)
- if driver == nil {
- driver = goListDriver
- }
- response, err := driver(cfg, patterns...)
- if err != nil {
- return response, err
- } else if response.NotHandled {
- return goListDriver(cfg, patterns...)
+// 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)
}
- return response, nil
+
+ response, err := goListDriver(cfg, patterns...)
+ return response, false, err
}
// A Package describes a loaded Go package.
@@ -553,7 +574,7 @@ type loaderPackage struct {
type loader struct {
pkgs map[string]*loaderPackage
Config
- sizes types.Sizes
+ sizes types.Sizes // non-nil if needed by mode
parseCache map[string]*parseValue
parseCacheMu sync.Mutex
exportMu sync.Mutex // enforces mutual exclusion of exportdata operations
@@ -678,39 +699,38 @@ func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
}
}
- // 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 {
+ 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
lpkg.Imports = make(map[string]*Package, len(stubs))
for importPath, ipkg := range stubs {
var importErr error
@@ -734,40 +754,39 @@ 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
- return lpkg.needsrc
- }
+ // 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
+ }
+ }
- 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
+ // 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
}
- } else {
+
// For each initial package, create its import DAG.
for _, lpkg := range initial {
visit(lpkg)
}
- }
- 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
- }
+
+ } 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
}
}
+
// 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 {
@@ -1042,7 +1061,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial,
Error: appendError,
- Sizes: ld.sizes,
+ Sizes: ld.sizes, // may be nil
}
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 0e49537d0..b64c50b43 100644
--- a/vendor/golang.org/x/tools/go/ssa/builder.go
+++ b/vendor/golang.org/x/tools/go/ssa/builder.go
@@ -4,106 +4,73 @@
package ssa
-// This file implements the BUILD phase of SSA construction.
+// This file defines the builder, which builds SSA-form IR for function bodies.
//
-// 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.
+// 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.
//
-// 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.
+// 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.)
//
-// TODO(adonovan): indeed, building functions is now embarrassingly parallel.
-// Audit for concurrency then benchmark using more goroutines.
+// 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.
//
-// State:
+// 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.
//
-// 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.
+// 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.
//
-// 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.
+// 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.)
//
-// Locks:
+// Runtime types
//
-// 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.
+// 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.
//
-// Synthetics:
+// 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.)
//
-// 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.
+// Function literals
//
-// Runtime types:
+// 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.)
//
-// 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".
+// The Function.build fields determines the algorithm for building the
+// function body. It is cleared to mark that building is complete.
import (
"fmt"
@@ -150,7 +117,6 @@ 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
@@ -323,10 +289,8 @@ 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: alloc,
+ X: emitNew(fn, at, pos, "makeslice"),
High: n,
}
v.setPos(pos)
@@ -363,9 +327,7 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
}
case "new":
- alloc := emitNew(fn, mustDeref(typ), pos)
- alloc.Comment = "new"
- return alloc
+ return emitNew(fn, mustDeref(typ), pos, "new")
case "len", "cap":
// Special case: len or cap of an array or *array is
@@ -419,7 +381,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
if isBlankIdent(e) {
return blank{}
}
- obj := fn.objectOf(e)
+ obj := fn.objectOf(e).(*types.Var)
var v Value
if g := fn.Prog.packageLevelMember(obj); g != nil {
v = g.(*Global) // var (address)
@@ -432,11 +394,10 @@ 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)
+ v = emitNew(fn, typ, e.Lbrace, "complit")
} else {
- v = fn.addLocal(typ, e.Lbrace)
+ v = emitLocal(fn, typ, e.Lbrace, "complit")
}
- v.Comment = "complit"
var sb storebuf
b.compLit(fn, v, e, true, &sb)
sb.emit(fn)
@@ -634,7 +595,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
panic("non-constant BasicLit") // unreachable
case *ast.FuncLit:
- fn2 := &Function{
+ /* function literal */
+ anon := &Function{
name: fmt.Sprintf("%s$%d", fn.Name(), 1+len(fn.AnonFuncs)),
Signature: fn.typeOf(e.Type).(*types.Signature),
pos: e.Type.Func,
@@ -643,23 +605,24 @@ 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.
- info: fn.info,
- subst: fn.subst, // share the parent's type substitutions.
+ subst: fn.subst, // share the parent's type substitutions.
}
- 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
+ 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
}
- v := &MakeClosure{Fn: fn2}
+ v := &MakeClosure{Fn: anon}
v.setType(fn.typ(tv.Type))
- for _, fv := range fn2.FreeVars {
+ for _, fv := range anon.FreeVars {
v.Bindings = append(v.Bindings, fv.outer)
fv.outer = nil
}
@@ -792,7 +755,9 @@ 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)
@@ -800,12 +765,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 = fn.Prog.needsInstance(callee, targs, b.created)
+ callee = callee.instance(targs, b.created)
}
return callee
}
// Local var.
- return emitLoad(fn, fn.lookup(obj, false)) // var (address)
+ return emitLoad(fn, fn.lookup(obj.(*types.Var), false)) // var (address)
case *ast.SelectorExpr:
sel := fn.selection(e)
@@ -821,7 +786,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 := makeThunk(fn.Prog, sel, b.created)
+ thunk := createThunk(fn.Prog, sel, b.created)
return emitConv(fn, thunk, fn.typ(tv.Type))
case types.MethodVal:
@@ -856,7 +821,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, token.NoPos)
+ emitTypeAssert(fn, v, rt, e.Sel.Pos())
}
}
if targs := receiverTypeArgs(obj); len(targs) > 0 {
@@ -864,7 +829,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: makeBound(fn.Prog, obj, b.created),
+ Fn: createBound(fn.Prog, obj, b.created),
Bindings: []Value{v},
}
c.setPos(e.Sel.Pos())
@@ -994,11 +959,7 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
c.Method = obj
} else {
// "Call"-mode call.
- callee := fn.Prog.originFunc(obj)
- if callee.typeparams.Len() > 0 {
- callee = fn.Prog.needsInstance(callee, receiverTypeArgs(obj), b.created)
- }
- c.Value = callee
+ c.Value = fn.Prog.objectMethod(obj, b.created)
c.Args = append(c.Args, v)
}
return
@@ -1090,9 +1051,8 @@ 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)
+ a := emitNew(fn, at, token.NoPos, "varargs")
a.setPos(e.Rparen)
- a.Comment = "varargs"
for i, arg := range varargs {
iaddr := &IndexAddr{
X: a,
@@ -1139,7 +1099,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
// 1:1 assignment
for i, id := range spec.Names {
if !isBlankIdent(id) {
- fn.addLocalForIdent(id)
+ emitLocalVar(fn, identVar(fn, id))
}
lval := b.addr(fn, id, false) // non-escaping
b.assign(fn, lval, spec.Values[i], true, nil)
@@ -1150,7 +1110,7 @@ func (b *builder) localValueSpec(fn *Function, spec *ast.ValueSpec) {
// Locals are implicitly zero-initialized.
for _, id := range spec.Names {
if !isBlankIdent(id) {
- lhs := fn.addLocalForIdent(id)
+ lhs := emitLocalVar(fn, identVar(fn, id))
if fn.debugInfo() {
emitDebugRef(fn, id, lhs, true)
}
@@ -1162,7 +1122,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) {
- fn.addLocalForIdent(id)
+ emitLocalVar(fn, identVar(fn, id))
lhs := b.addr(fn, id, false) // non-escaping
lhs.store(fn, emitExtract(fn, tuple, i))
}
@@ -1182,8 +1142,8 @@ func (b *builder) assignStmt(fn *Function, lhss, rhss []ast.Expr, isDef bool) {
var lval lvalue = blank{}
if !isBlankIdent(lhs) {
if isDef {
- if obj := fn.info.Defs[lhs.(*ast.Ident)]; obj != nil {
- fn.addNamedLocal(obj)
+ if obj, ok := fn.info.Defs[lhs.(*ast.Ident)].(*types.Var); ok {
+ emitLocalVar(fn, obj)
isZero[i] = true
}
}
@@ -1292,9 +1252,7 @@ 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))
- alloc := emitNew(fn, at, e.Lbrace)
- alloc.Comment = "slicelit"
- array = alloc
+ array = emitNew(fn, at, e.Lbrace, "slicelit")
case *types.Array:
at = t
array = addr
@@ -1582,13 +1540,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 := fn.info.Implicits[cc]; obj != nil {
+ if obj, ok := fn.info.Implicits[cc].(*types.Var); ok {
// 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, fn.addNamedLocal(obj), x, obj.Pos())
+ emitStore(fn, emitLocalVar(fn, obj), x, obj.Pos())
}
fn.targets = &targets{
tail: fn.targets,
@@ -1737,7 +1695,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
case *ast.AssignStmt: // x := <-states[state].Chan
if comm.Tok == token.DEFINE {
- fn.addLocalForIdent(comm.Lhs[0].(*ast.Ident))
+ emitLocalVar(fn, identVar(fn, comm.Lhs[0].(*ast.Ident)))
}
x := b.addr(fn, comm.Lhs[0], false) // non-escaping
v := emitExtract(fn, sel, r)
@@ -1748,7 +1706,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
if len(comm.Lhs) == 2 { // x, ok := ...
if comm.Tok == token.DEFINE {
- fn.addLocalForIdent(comm.Lhs[1].(*ast.Ident))
+ emitLocalVar(fn, identVar(fn, comm.Lhs[1].(*ast.Ident)))
}
ok := b.addr(fn, comm.Lhs[1], false) // non-escaping
ok.store(fn, emitExtract(fn, sel, 1))
@@ -1783,20 +1741,33 @@ 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) {
- // ...init...
- // jump loop
+ // Use forStmtGo122 instead if it applies.
+ if s.Init != nil {
+ if assign, ok := s.Init.(*ast.AssignStmt); ok && assign.Tok == token.DEFINE {
+ major, minor := parseGoVersion(fn.goversion)
+ afterGo122 := major >= 1 && minor >= 22
+ if afterGo122 {
+ b.forStmtGo122(fn, s, label)
+ return
+ }
+ }
+ }
+
+ // ...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
@@ -1834,23 +1805,142 @@ 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)
+
+ 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 three SSA values,
+ // outer[i], phi[i], and next[i] in pre, loop, and post.
+ // There is no limit on n.
+ lhss := init.Lhs
+ vars := make([]*types.Var, len(lhss))
+ outers := make([]Value, len(vars))
+ phis := make([]Value, len(vars))
+ nexts := make([]Value, len(vars))
+ for i, lhs := range lhss {
+ 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.
+ // Load before the Alloc.
+ load := emitLoad(fn, phi)
+ next := emitLocal(fn, typ, v.Pos(), v.Name())
+ emitStore(fn, next, load, token.NoPos)
+
+ phi.Edges = []Value{outer, next} // pre edge is emitted before post edge.
+
+ vars[i] = v
+ outers[i] = outer
+ phis[i] = phi
+ nexts[i] = next
+ }
+
+ varsCurrentlyReferTo := func(vals []Value) {
+ for i, v := range vars {
+ fn.vars[v] = vals[i]
+ }
+ }
+
+ // ...init... under fn.objects[v] = i_outer
+ fn.currentBlock = pre
+ varsCurrentlyReferTo(outers)
+ const isDef = false // assign to already-allocated outers
+ b.assignStmt(fn, lhss, init.Rhs, isDef)
+ if label != nil {
+ label._break = done
+ label._continue = post
+ }
+ emitJump(fn, loop)
+
+ // ...cond... under fn.objects[v] = i
+ fn.currentBlock = loop
+ varsCurrentlyReferTo(phis)
+ 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
+ varsCurrentlyReferTo(nexts)
+ fn.currentBlock = post
+ if s.Post != nil {
+ b.stmt(fn, s.Post)
+ }
+ emitJump(fn, loop) // back-edge
+ fn.currentBlock = done
+
+ // TODO(taking): Optimizations for when local variables can be fused.
+ // Principled approach is: hoist i_next, fuse i_outer and i_next, eliminate redundant phi, and ssa-lifting.
+ // Unclear if we want to do any of this in general or only for range/for-loops with new lifetimes.
+}
+
// 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
@@ -1872,7 +1962,7 @@ func (b *builder) rangeIndexed(fn *Function, x Value, tv types.Type, pos token.P
length = fn.emit(&c)
}
- index := fn.addLocal(tInt, token.NoPos)
+ index := emitLocal(fn, tInt, token.NoPos, "rangeindex")
emitStore(fn, index, intConst(-1), pos)
loop = fn.newBasicBlock("rangeindex.loop")
@@ -1935,16 +2025,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)
//
@@ -1997,13 +2087,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
- // ...
- // goto loop
+ // k = extract ko #0
+ // ...body...
+ // goto loop
// done: (target of break)
loop = fn.newBasicBlock("rangechan.loop")
@@ -2030,6 +2120,57 @@ 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) {
@@ -2041,21 +2182,28 @@ func (b *builder) rangeStmt(fn *Function, s *ast.RangeStmt, label *lblock) {
tv = fn.typeOf(s.Value)
}
- // 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 {
+ // 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 tk != nil {
- fn.addLocalForIdent(s.Key.(*ast.Ident))
+ emitLocalVar(fn, identVar(fn, s.Key.(*ast.Ident)))
}
if tv != nil {
- fn.addLocalForIdent(s.Value.(*ast.Ident))
+ emitLocalVar(fn, identVar(fn, s.Value.(*ast.Ident)))
}
}
+ major, minor := parseGoVersion(fn.goversion)
+ afterGo122 := major >= 1 && minor >= 22
+
+ 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
@@ -2067,13 +2215,30 @@ 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, *types.Basic: // string
+ case *types.Map:
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 {
@@ -2297,73 +2462,71 @@ 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.built {
+ if fn.build != nil {
assert(fn.parent == nil, "anonymous functions should not be built by buildFunction()")
- b.buildFunctionBody(fn)
+
+ if fn.Prog.mode&LogSource != 0 {
+ defer logStack("build %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
+ }
+ fn.build(b, fn)
fn.done()
}
}
-// 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
+// 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))
+ }
+}
- 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.)
- }
+// 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 = n.Type
- recvField = n.Recv
- body = n.Body
+ functype = syntax.Type
+ recvField = syntax.Recv
+ body = syntax.Body
+ if body == nil {
+ b.buildParamsOnly(fn) // no body (non-Go function)
+ return
+ }
case *ast.FuncLit:
- functype = n.Type
- body = n.Body
+ functype = syntax.Type
+ body = syntax.Body
+ case nil:
+ panic("no syntax")
default:
- 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
+ panic(syntax) // unexpected syntax
}
- // 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)
@@ -2381,45 +2544,17 @@ func (b *builder) buildFunctionBody(fn *Function) {
fn.finishBody()
}
-// 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.
-//
-// May add newly CREATEd functions that may need to be built or runtime type information.
+// addRuntimeType records t as a runtime type,
+// along with all types derivable from it using reflection.
//
-// 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()
+// 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?
+ })
}
// Build calls Package.Build for each package in prog.
@@ -2447,9 +2582,11 @@ func (prog *Program) Build() {
// Build builds SSA code for all functions and vars in package p.
//
-// Precondition: CreatePackage must have been called for all of p's
-// direct imports (and hence its direct imports must have been
-// error-free).
+// 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.
//
// Build is idempotent and thread-safe.
func (p *Package) Build() { p.buildOnce.Do(p.build) }
@@ -2458,45 +2595,39 @@ 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}
- init := p.init
- init.startBody()
+ 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()
var done *BasicBlock
if p.Prog.mode&BareInits == 0 {
// Make init() skip if package is already initialized.
initguard := p.Var("init$guard")
- 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)
+ 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)
// Call the init() function of each package we import.
for _, pkg := range p.Pkg.Imports() {
@@ -2506,9 +2637,9 @@ func (p *Package) build() {
}
var v Call
v.Call.Value = prereq.init
- v.Call.pos = init.pos
+ v.Call.pos = fn.pos
v.setType(types.NewTuple())
- init.emit(&v)
+ fn.emit(&v)
}
}
@@ -2516,11 +2647,18 @@ func (p *Package) build() {
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 init.Prog.mode&LogSource != 0 {
+ if fn.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
@@ -2529,28 +2667,33 @@ func (p *Package) build() {
} else {
lval = blank{}
}
- b.assign(init, lval, varinit.Rhs, true, nil)
+ b.assign(fn, lval, varinit.Rhs, true, nil)
} else {
// n:1 initialization: var x, y := f()
- tuple := b.exprN(init, varinit.Rhs)
+ tuple := b.exprN(fn, varinit.Rhs)
for i, v := range varinit.Lhs {
if v.Name() == "_" {
continue
}
- emitStore(init, p.objects[v].(*Global), emitExtract(init, tuple, i), v.Pos())
+ emitStore(fn, p.objects[v].(*Global), emitExtract(fn, 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 {
- fn := p.objects[p.info.Defs[id]].(*Function)
+ declaredInit := p.objects[p.info.Defs[id]].(*Function)
var v Call
- v.Call.Value = fn
+ v.Call.Value = declaredInit
v.setType(types.NewTuple())
p.init.emit(&v)
}
@@ -2560,35 +2703,9 @@ func (p *Package) build() {
// Finish up init().
if p.Prog.mode&BareInits == 0 {
- 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)
+ emitJump(fn, done)
+ fn.currentBlock = done
}
+ 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 1bf88c83e..eaaf4695e 100644
--- a/vendor/golang.org/x/tools/go/ssa/create.go
+++ b/vendor/golang.org/x/tools/go/ssa/create.go
@@ -15,41 +15,43 @@ import (
"os"
"sync"
- "golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/typeparams"
)
// 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 {
- prog := &Program{
+ return &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); it will be used during the build
+// tree (for funcs and vars only) and goversion defines the
+// appropriate interpretation; they will be used during the build
// phase.
-func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
+func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion string) {
name := obj.Name()
switch obj := obj.(type) {
case *types.Builtin:
@@ -58,9 +60,11 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
}
case *types.TypeName:
- pkg.Members[name] = &Type{
- object: obj,
- pkg: pkg,
+ if name != "_" {
+ pkg.Members[name] = &Type{
+ object: obj,
+ pkg: pkg,
+ }
}
case *types.Const:
@@ -70,7 +74,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
pkg: pkg,
}
pkg.objects[obj] = c
- pkg.Members[name] = c
+ if name != "_" {
+ pkg.Members[name] = c
+ }
case *types.Var:
g := &Global{
@@ -81,7 +87,9 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
pos: obj.Pos(),
}
pkg.objects[obj] = g
- pkg.Members[name] = g
+ if name != "_" {
+ pkg.Members[name] = g
+ }
case *types.Func:
sig := obj.Type().(*types.Signature)
@@ -89,36 +97,10 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
pkg.ninit++
name = fmt.Sprintf("init#%d", pkg.ninit)
}
-
- // 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)
- }
-
+ fn := createFunction(pkg.Prog, obj, name, syntax, pkg.info, goversion, &pkg.created)
+ fn.Pkg = pkg
pkg.objects[obj] = fn
- if sig.Recv() == nil {
+ if name != "_" && sig.Recv() == nil {
pkg.Members[name] = fn // package-level function
}
@@ -127,45 +109,79 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
}
}
+// 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) {
+func membersFromDecl(pkg *Package, decl ast.Decl, goversion string) {
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 {
- if !isBlankIdent(id) {
- memberFromObject(pkg, pkg.info.Defs[id], nil)
- }
+ 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 {
- if !isBlankIdent(id) {
- memberFromObject(pkg, pkg.info.Defs[id], spec)
- }
+ memberFromObject(pkg, pkg.info.Defs[id], spec, goversion)
}
}
case token.TYPE:
for _, spec := range decl.Specs {
id := spec.(*ast.TypeSpec).Name
- if !isBlankIdent(id) {
- memberFromObject(pkg, pkg.info.Defs[id], nil)
- }
+ memberFromObject(pkg, pkg.info.Defs[id], nil, "")
}
}
case *ast.FuncDecl:
id := decl.Name
- if !isBlankIdent(id) {
- memberFromObject(pkg, pkg.info.Defs[id], decl)
- }
+ memberFromObject(pkg, pkg.info.Defs[id], decl, goversion)
}
}
@@ -182,7 +198,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 constructs and returns an SSA Package from the
+// CreatePackage creates and returns an SSA Package from the
// specified type-checked, error-free file ASTs, and populates its
// Members mapping.
//
@@ -190,36 +206,48 @@ 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().
+// until a subsequent call to Package.Build.
+//
+// CreatePackage should not be called after building any package in
+// the program.
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,
- info: info, // transient (CREATE and BUILD phases)
- files: files, // transient (CREATE and BUILD phases)
+ syntax: info != nil,
+ // transient values (cleared after Package.Build)
+ info: info,
+ files: files,
+ initVersion: make(map[ast.Expr]string),
}
- // Add init() function.
+ /* synthesized package initializer */
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 := goversionOf(p, file)
for _, decl := range file.Decls {
- membersFromDecl(p, decl)
+ membersFromDecl(p, decl, goversion)
}
}
} else {
@@ -229,11 +257,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, "")
}
}
}
@@ -271,8 +299,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 in the
-// program prog in unspecified order.
+// AllPackages returns a new slice containing all packages created by
+// prog.CreatePackage in 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 a687de45e..56bc2fbc1 100644
--- a/vendor/golang.org/x/tools/go/ssa/doc.go
+++ b/vendor/golang.org/x/tools/go/ssa/doc.go
@@ -116,9 +116,6 @@
// 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 abb617e6d..d77b4407a 100644
--- a/vendor/golang.org/x/tools/go/ssa/emit.go
+++ b/vendor/golang.org/x/tools/go/ssa/emit.go
@@ -13,16 +13,53 @@ import (
"go/types"
)
-// 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}
+// 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}
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 {
@@ -148,7 +185,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 structTypesIdentical(ut_dst, ut_src) {
+ if types.IdenticalIgnoreTags(ut_dst, ut_src) {
return true
}
@@ -206,6 +243,13 @@ 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)
@@ -537,48 +581,6 @@ 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 38c3e31ba..65ed491ba 100644
--- a/vendor/golang.org/x/tools/go/ssa/func.go
+++ b/vendor/golang.org/x/tools/go/ssa/func.go
@@ -10,7 +10,6 @@ import (
"bytes"
"fmt"
"go/ast"
- "go/token"
"go/types"
"io"
"os"
@@ -108,52 +107,40 @@ 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)
+ obj := f.objectOf(label).(*types.Label)
lb := f.lblocks[obj]
if lb == nil {
lb = &lblock{_goto: f.newBasicBlock(label.Name)}
if f.lblocks == nil {
- f.lblocks = make(map[types.Object]*lblock)
+ f.lblocks = make(map[*types.Label]*lblock)
}
f.lblocks[obj] = lb
}
return lb
}
-// 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,
- typ: typ,
- pos: pos,
- parent: f,
- }
- f.Params = append(f.Params, v)
- return v
-}
-
-func (f *Function) addParamObj(obj types.Object) *Parameter {
- name := obj.Name()
+// 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 := f.addParam(name, f.typ(obj.Type()), obj.Pos())
- param.object = obj
+ param := &Parameter{
+ name: name,
+ object: v,
+ typ: f.typ(v.Type()),
+ parent: f,
+ }
+ f.Params = append(f.Params, param)
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.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)
+func (f *Function) addSpilledParam(obj *types.Var) {
+ param := f.addParamVar(obj)
+ spill := emitLocalVar(f, obj)
f.emit(&Store{Addr: spill, Val: param})
}
@@ -161,7 +148,7 @@ func (f *Function) addSpilledParam(obj types.Object) {
// Precondition: f.Type() already set.
func (f *Function) startBody() {
f.currentBlock = f.newBasicBlock("entry")
- f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init
+ f.vars = make(map[*types.Var]Value) // needed for some synthetics, e.g. init
}
// createSyntacticParams populates f.Params and generates code (spills
@@ -177,11 +164,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(f.info.Defs[n])
+ f.addSpilledParam(identVar(f, n))
}
// Anonymous receiver? No need to spill.
if field.Names == nil {
- f.addParamObj(f.Signature.Recv())
+ f.addParamVar(f.Signature.Recv())
}
}
}
@@ -191,11 +178,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(f.info.Defs[n])
+ f.addSpilledParam(identVar(f, n))
}
// Anonymous parameter? No need to spill.
if field.Names == nil {
- f.addParamObj(f.Signature.Params().At(len(f.Params) - n))
+ f.addParamVar(f.Signature.Params().At(len(f.Params) - n))
}
}
}
@@ -205,7 +192,8 @@ 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 {
- f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
+ namedResult := emitLocalVar(f, identVar(f, n))
+ f.namedResults = append(f.namedResults, namedResult)
}
}
}
@@ -250,49 +238,14 @@ 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.objects = nil
+ f.vars = 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 {
@@ -320,15 +273,15 @@ func (f *Function) finishBody() {
lift(f)
}
- // clear remaining stateful variables
+ // clear remaining builder state
f.namedResults = nil // (used by lifting)
- f.info = nil
f.subst = nil
numberRegisters(f) // uses f.namedRegisters
}
-// After this, function is done with BUILD phase.
+// done marks the building of f's SSA body complete,
+// along with any nested functions, and optionally prints them.
func (f *Function) done() {
assert(f.parent == nil, "done called on an anonymous function")
@@ -338,7 +291,7 @@ func (f *Function) done() {
visit(anon) // anon is done building before f.
}
- f.built = true // function is done with BUILD phase
+ f.build = nil // function is built
if f.Prog.mode&PrintFunctions != 0 {
printMu.Lock()
@@ -376,7 +329,6 @@ 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
}
@@ -387,40 +339,25 @@ 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.
-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
+// 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
+ }
+ }
+ }
}
return v // function-local var (address)
}
@@ -438,7 +375,7 @@ func (f *Function) lookup(obj types.Object, escaping bool) Value {
outer: outer,
parent: f,
}
- f.objects[obj] = v
+ f.vars[obj] = v
f.FreeVars = append(f.FreeVars, v)
return v
}
@@ -536,7 +473,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
+ return fn.Pkg // non-generic function (does that follow??)
case fn.topLevelOrigin != nil:
return fn.topLevelOrigin.Pkg // instance of a named generic function
case fn.parent != nil:
@@ -689,17 +626,11 @@ func (prog *Program) NewFunction(name string, sig *types.Signature, provenance s
return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance}
}
-type extentNode [2]token.Pos
-
-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.
+// 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 }
+
+// identVar returns the variable defined by id.
+func identVar(fn *Function, id *ast.Ident) *types.Var {
+ return fn.info.Defs[id].(*types.Var)
+}
diff --git a/vendor/golang.org/x/tools/go/ssa/identical.go b/vendor/golang.org/x/tools/go/ssa/identical.go
deleted file mode 100644
index e8026967b..000000000
--- a/vendor/golang.org/x/tools/go/ssa/identical.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
deleted file mode 100644
index 575aa5dfc..000000000
--- a/vendor/golang.org/x/tools/go/ssa/identical_17.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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 38249dea2..370284ab7 100644
--- a/vendor/golang.org/x/tools/go/ssa/instantiate.go
+++ b/vendor/golang.org/x/tools/go/ssa/instantiate.go
@@ -6,129 +6,59 @@ package ssa
import (
"fmt"
- "go/ast"
"go/types"
+ "sync"
"golang.org/x/tools/internal/typeparams"
)
-// _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
+// 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.
}
-// createInstanceSet adds a new instanceSet for a generic function fn if one does not exist.
+// instance returns a Function that is the instantiation of generic
+// origin function fn with the type arguments targs.
//
-// Precondition: fn is a package level declaration (function or method).
+// Any created instance is added to cr.
//
-// 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,
+// 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)
}
+ gen.instances[key] = inst
}
+ return inst
}
-// needsInstance returns a Function that is the instantiation of fn with the type arguments targs.
-//
-// 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.
+// createInstance returns the instantiation of generic function 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
+//
+// Requires fn.generic.instancesMu.
+func createInstance(fn *Function, targs []types.Type, cr *creator) *Function {
prog := fn.Prog
- // 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
- }
-
+ // Compute signature.
var sig *types.Signature
var obj *types.Func
if recv := fn.Signature.Recv(); recv != nil {
// method
- m := fn.object.(*types.Func)
- obj = prog.canon.instantiateMethod(m, targs, prog.ctxt)
+ obj = prog.canon.instantiateMethod(fn.object, 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)
@@ -137,41 +67,48 @@ func (insts *instanceSet) lookupOrCreate(targs []types.Type, parameterized *tpWa
if !ok {
panic("Instantiate of a Signature returned a non-signature")
}
- obj = fn.object.(*types.Func) // instantiation does not exist yet
+ obj = fn.object // instantiation does not exist yet
sig = prog.canon.Type(instance).(*types.Signature)
}
- var synthetic string
- var subst *subster
-
- concrete := !parameterized.anyParameterized(targs)
-
- if prog.mode&InstantiateGenerics != 0 && concrete {
+ // Choose strategy (instance or wrapper).
+ var (
+ synthetic string
+ subst *subster
+ build buildFunc
+ )
+ if prog.mode&InstantiateGenerics != 0 && !prog.parameterized.anyParameterized(targs) {
synthetic = fmt.Sprintf("instance of %s", fn.Name())
- scope := typeparams.OriginMethod(obj).Scope()
- subst = makeSubster(prog.ctxt, scope, fn.typeparams, targs, false)
+ 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
+ }
} else {
synthetic = fmt.Sprintf("instantiation wrapper of %s", fn.Name())
+ build = (*builder).buildInstantiationWrapper
}
- name := fmt.Sprintf("%s%s", fn.Name(), targs) // may not be unique
+ /* generic instance or instantiation wrapper */
instance := &Function{
- name: name,
+ name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique
object: obj,
Signature: sig,
Synthetic: synthetic,
- syntax: syntax,
+ syntax: fn.syntax, // \
+ info: fn.info, // } empty for non-created packages
+ goversion: fn.goversion, // /
+ build: build,
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/methods.go b/vendor/golang.org/x/tools/go/ssa/methods.go
index 294498371..03ef62521 100644
--- a/vendor/golang.org/x/tools/go/ssa/methods.go
+++ b/vendor/golang.org/x/tools/go/ssa/methods.go
@@ -10,54 +10,124 @@ 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
-// abstract (interface or parameterized) method.
+// wrapper methods on demand. It returns nil if sel denotes an
+// interface or generic method.
//
// Precondition: sel.Kind() == MethodVal.
//
// Thread-safe.
//
-// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+// Acquires 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 // abstract method (interface, possibly type param)
+ return nil // interface method or type parameter
}
+
+ if prog.parameterized.isParameterized(T) {
+ return nil // generic method
+ }
+
if prog.mode&LogSource != 0 {
defer logStack("MethodValue %s %v", T, sel)()
}
- var m *Function
- b := builder{created: &creator{}}
+ var cr creator
- 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)
+ 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.Unlock()
- if m == nil {
- return nil // abstract method (generic)
+ // Belongs to a created package?
+ if fn := prog.FuncValue(obj); fn != nil {
+ return fn
}
- for !b.done() {
- b.buildCreated()
- b.needsRuntimeTypes()
+
+ // 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)
}
- return m
+
+ // 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
+ }
+ return fn
}
// LookupMethod returns the implementation of the method of type T
// identified by (pkg, name). It returns nil if the method exists but
-// is abstract, and panics if T has no such method.
+// is an interface method or generic method, 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 {
@@ -68,208 +138,136 @@ 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
- complete bool // mapping contains all methods
-}
-
-// 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
+ mapping map[string]*Function // populated lazily
}
-// 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.
+// 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.
//
// Thread-safe.
//
-// EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
+// Acquires prog.runtimeTypesMu.
func (prog *Program) RuntimeTypes() []types.Type {
- 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())
+ prog.runtimeTypesMu.Lock()
+ defer prog.runtimeTypesMu.Unlock()
+ return prog.runtimeTypes.Keys()
}
-// 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.)
+// forEachReachable calls f for type T and each type reachable from
+// its type through reflection.
//
-// TODO(adonovan): make this faster. It accounts for 20% of SSA build time.
+// The function f must use memoization to break cycles and
+// return false when the type has already been visited.
//
-// 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)
+// 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
}
}
- }
-
- // 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
+ // 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
+ }
- case *types.Interface:
- // nop---handled by recursion over method set.
+ switch T := T.(type) {
+ case *types.Basic:
+ // nop
- case *types.Pointer:
- prog.needMethods(t.Elem(), false, cr)
+ case *types.Interface:
+ // nop---handled by recursion over method set.
- case *types.Slice:
- prog.needMethods(t.Elem(), false, cr)
+ case *types.Pointer:
+ visit(T.Elem(), false)
- case *types.Chan:
- prog.needMethods(t.Elem(), false, cr)
+ case *types.Slice:
+ visit(T.Elem(), false)
- case *types.Map:
- prog.needMethods(t.Key(), false, cr)
- prog.needMethods(t.Elem(), false, cr)
+ case *types.Chan:
+ visit(T.Elem(), 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.Map:
+ visit(T.Key(), false)
+ visit(T.Elem(), false)
- case *types.Tuple:
- for i, n := 0, t.Len(); i < n; i++ {
- prog.needMethods(t.At(i).Type(), 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 *typeparams.TypeParam:
- panic(T) // type parameters are always abstract.
+ case *types.Tuple:
+ for i, n := 0, T.Len(); i < n; i++ {
+ visit(T.At(i).Type(), false)
+ }
- case *typeparams.Union:
- // nop
+ case *typeparams.TypeParam, *typeparams.Union:
+ // forEachReachable must not be called on parameterized types.
+ panic(T)
- default:
- panic(T)
+ 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 b90ee0e86..656417ac8 100644
--- a/vendor/golang.org/x/tools/go/ssa/parameterized.go
+++ b/vendor/golang.org/x/tools/go/ssa/parameterized.go
@@ -6,6 +6,7 @@ package ssa
import (
"go/types"
+ "sync"
"golang.org/x/tools/internal/typeparams"
)
@@ -14,11 +15,24 @@ 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 returns true when typ reaches any type parameter.
-func (w *tpWalker) isParameterized(typ types.Type) (res 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) {
// NOTE: Adapted from go/types/infer.go. Try to keep in sync.
// detect cycles
@@ -35,25 +49,25 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
break
case *types.Array:
- return w.isParameterized(t.Elem())
+ return w.isParameterizedLocked(t.Elem())
case *types.Slice:
- return w.isParameterized(t.Elem())
+ return w.isParameterizedLocked(t.Elem())
case *types.Struct:
for i, n := 0, t.NumFields(); i < n; i++ {
- if w.isParameterized(t.Field(i).Type()) {
+ if w.isParameterizedLocked(t.Field(i).Type()) {
return true
}
}
case *types.Pointer:
- return w.isParameterized(t.Elem())
+ return w.isParameterizedLocked(t.Elem())
case *types.Tuple:
n := t.Len()
for i := 0; i < n; i++ {
- if w.isParameterized(t.At(i).Type()) {
+ if w.isParameterizedLocked(t.At(i).Type()) {
return true
}
}
@@ -66,11 +80,11 @@ func (w *tpWalker) isParameterized(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.isParameterized(t.Params()) || w.isParameterized(t.Results())
+ return w.isParameterizedLocked(t.Params()) || w.isParameterizedLocked(t.Results())
case *types.Interface:
for i, n := 0, t.NumMethods(); i < n; i++ {
- if w.isParameterized(t.Method(i).Type()) {
+ if w.isParameterizedLocked(t.Method(i).Type()) {
return true
}
}
@@ -79,16 +93,16 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
panic(err)
}
for _, term := range terms {
- if w.isParameterized(term.Type()) {
+ if w.isParameterizedLocked(term.Type()) {
return true
}
}
case *types.Map:
- return w.isParameterized(t.Key()) || w.isParameterized(t.Elem())
+ return w.isParameterizedLocked(t.Key()) || w.isParameterizedLocked(t.Elem())
case *types.Chan:
- return w.isParameterized(t.Elem())
+ return w.isParameterizedLocked(t.Elem())
case *types.Named:
args := typeparams.NamedTypeArgs(t)
@@ -97,11 +111,11 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
return true
}
for i, n := 0, args.Len(); i < n; i++ {
- if w.isParameterized(args.At(i)) {
+ if w.isParameterizedLocked(args.At(i)) {
return true
}
}
- return w.isParameterized(t.Underlying()) // recurse for types local to parameterized functions
+ return w.isParameterizedLocked(t.Underlying()) // recurse for types local to parameterized functions
case *typeparams.TypeParam:
return true
@@ -113,9 +127,13 @@ func (w *tpWalker) isParameterized(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.isParameterized(t) {
+ if w.isParameterizedLocked(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 886be0532..28ec131f8 100644
--- a/vendor/golang.org/x/tools/go/ssa/sanity.go
+++ b/vendor/golang.org/x/tools/go/ssa/sanity.go
@@ -422,7 +422,8 @@ 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, "wrapper ") ||
+ if strings.HasPrefix(fn.Synthetic, "from type information (on demand)") ||
+ 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 9c900e3aa..7b1eb8527 100644
--- a/vendor/golang.org/x/tools/go/ssa/source.go
+++ b/vendor/golang.org/x/tools/go/ssa/source.go
@@ -11,6 +11,7 @@ package ssa
// the originating syntax, as specified.
import (
+ "fmt"
"go/ast"
"go/token"
"go/types"
@@ -131,6 +132,31 @@ func findNamedFunc(pkg *Package, pos token.Pos) *Function {
return nil
}
+// goversionOf returns the goversion of a node in the package
+// where the node is either a function declaration or the initial
+// value of a package level variable declaration.
+func goversionOf(p *Package, file *ast.File) string {
+ if p.info == nil {
+ return ""
+ }
+
+ // TODO(taking): Update to the following when internal/versions available:
+ // return versions.Lang(versions.FileVersions(p.info, file))
+ return fileVersions(file)
+}
+
+// TODO(taking): Remove when internal/versions is available.
+var fileVersions = func(file *ast.File) string { return "" }
+
+// parses a goXX.YY version or returns a negative version on an error.
+// TODO(taking): Switch to a permanent solution when internal/versions is submitted.
+func parseGoVersion(x string) (major, minor int) {
+ if _, err := fmt.Sscanf(x, "go%d.%d", &major, &minor); err != nil || major < 0 || minor < 0 {
+ return -1, -1
+ }
+ return
+}
+
// ValueForExpr returns the SSA Value that corresponds to non-constant
// expression e.
//
@@ -172,16 +198,19 @@ 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 object.
-// It returns nil if no such SSA package has been created.
-func (prog *Program) Package(obj *types.Package) *Package {
- return prog.packages[obj]
+// 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]
}
-// 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.
+// 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.
func (prog *Program) packageLevelMember(obj types.Object) Member {
if pkg, ok := prog.packages[obj.Pkg()]; ok {
return pkg.objects[obj]
@@ -189,24 +218,16 @@ func (prog *Program) packageLevelMember(obj types.Object) Member {
return nil
}
-// 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.
+// 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.
func (prog *Program) FuncValue(obj *types.Func) *Function {
fn, _ := prog.packageLevelMember(obj).(*Function)
return fn
}
-// ConstValue returns the SSA Value denoted by the source-level named
-// constant obj.
+// ConstValue returns the SSA constant denoted by the specified const symbol.
func (prog *Program) ConstValue(obj *types.Const) *Const {
// TODO(adonovan): opt: share (don't reallocate)
// Consts for const objects and constant ast.Exprs.
@@ -223,7 +244,7 @@ func (prog *Program) ConstValue(obj *types.Const) *Const {
}
// VarValue returns the SSA Value that corresponds to a specific
-// identifier denoting the source-level named variable obj.
+// identifier denoting the specified var symbol.
//
// 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 bd42f2e0a..58a641a1f 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssa.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssa.go
@@ -23,20 +23,25 @@ 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 loaded Packages, keyed by object
+ packages map[*types.Package]*Package // all created Packages
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 // 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.
+ 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
}
// A Package is a single analyzed Go package containing Members for
@@ -51,17 +56,19 @@ 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.
+ objects map[types.Object]Member // mapping of package objects to members (incl. methods). Contains *NamedConst, *Global, *Function (values but not types)
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)
+ 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
}
// A Member is a member of a Go package, implemented by *NamedConst,
@@ -296,8 +303,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 ground
-// (non-parameterized) types as (*Map[string,int]).Get or with
+// method, (*Map[K,V]).Get. It may be instantiated with all
+// 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
@@ -305,39 +312,45 @@ type Node interface {
// respectively, and is nil in the generic method.
type Function struct {
name string
- object types.Object // a declared *types.Func or one of its wrappers
- method *selection // info about provenance of synthetic methods; thunk => non-nil
+ object *types.Func // symbol for declared function (nil for FuncLit or synthetic init)
+ method *selection // info about provenance of synthetic methods; thunk => non-nil
Signature *types.Signature
pos token.Pos
- 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
+ // 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:
+
Params []*Parameter // function parameters; for methods, includes receiver
FreeVars []*FreeVar // free variables whose values must be supplied by closure
- Locals []*Alloc // local variables of this function
+ Locals []*Alloc // frame-allocated 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 set transiently during building,
- // then cleared.
+ // The following fields are cleared after building.
currentBlock *BasicBlock // where to emit code
- objects map[types.Object]Value // addresses of local variables
+ vars map[*types.Var]Value // addresses of local variables
namedResults []*Alloc // tuple of named results
targets *targets // linked stack of branch targets
- 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
+ lblocks map[*types.Label]*lblock // labelled blocks
+ subst *subster // type parameter substitutions (if non-nil)
}
// BasicBlock represents an SSA basic block.
@@ -402,9 +415,8 @@ type FreeVar struct {
// A Parameter represents an input parameter of a function.
type Parameter struct {
name string
- object types.Object // a *types.Var; nil for non-source locals
+ object *types.Var // non-nil
typ types.Type
- pos token.Pos
parent *Function
referrers []Instruction
}
@@ -482,15 +494,12 @@ type Builtin struct {
// type of the allocated variable is actually
// Type().Underlying().(*types.Pointer).Elem().
//
-// 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 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 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.
+// If Heap is true, Alloc allocates a new zero-initialized variable
+// each time the instruction is executed. We call this a "new" alloc.
//
// When Alloc is applied to a channel, map or slice type, it returns
// the address of an uninitialized (nil) reference of that kind; store
@@ -1068,11 +1077,12 @@ type Next struct {
// Type() reflects the actual type of the result, possibly a
// 2-types.Tuple; AssertedType is the asserted type.
//
-// 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.
+// 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).
//
// Example printed form:
//
@@ -1390,7 +1400,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 abstract method may be shared by multiple
+// parameter. Note: an interface method may be shared by multiple
// interfaces due to embedding; Value.Type() provides the specific
// interface used for this call.
//
@@ -1408,7 +1418,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 // abstract method (invoke mode)
+ Method *types.Func // interface method (invoke mode)
Args []Value // actual parameters (in static method call, includes receiver)
pos token.Pos // position of CallExpr.Lparen, iff explicit in source
}
@@ -1507,14 +1517,19 @@ 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 { 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) 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) Referrers() *[]Instruction {
if v.parent != nil {
return &v.referrers
@@ -1562,7 +1577,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.pos }
+func (v *Parameter) Pos() token.Pos { return v.object.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 96d69a20a..67e75cb26 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssautil/load.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssautil/load.go
@@ -35,6 +35,24 @@ 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)
}
@@ -147,6 +165,7 @@ 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) // TODO(taking): Enable when internal/versions is available.
if err := types.NewChecker(tc, fset, pkg, info).Files(files); err != nil {
return nil, nil, err
}
@@ -168,6 +187,25 @@ 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 5f27050b0..3cdd34622 100644
--- a/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
+++ b/vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
@@ -4,7 +4,15 @@
package ssautil // import "golang.org/x/tools/go/ssa/ssautil"
-import "golang.org/x/tools/go/ssa"
+import (
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/ssa"
+ "golang.org/x/tools/internal/typeparams"
+
+ _ "unsafe" // for linkname hack
+)
// This file defines utilities for visiting the SSA representation of
// a Program.
@@ -18,50 +26,113 @@ import "golang.org/x/tools/go/ssa"
// 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 {
- visit := visitor{
- prog: prog,
- seen: make(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.program()
- return visit.seen
-}
-type visitor struct {
- prog *ssa.Program
- seen map[*ssa.Function]bool
-}
+ // TODO(adonovan): opt: provide a way to share a builder
+ // across a sequence of MethodValue calls.
-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)
+ 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)))
}
}
}
- 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)))
+
+ // 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
+ }
+ }
}
}
-}
-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)
- }
- }
+ 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)
}
}
}
+
+ // 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
@@ -76,3 +147,12 @@ 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 68cc971b3..63fbbc128 100644
--- a/vendor/golang.org/x/tools/go/ssa/util.go
+++ b/vendor/golang.org/x/tools/go/ssa/util.go
@@ -180,24 +180,6 @@ 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 {
@@ -384,3 +366,16 @@ 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/versions_go122.go b/vendor/golang.org/x/tools/go/ssa/versions_go122.go
new file mode 100644
index 000000000..b74165a8e
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/ssa/versions_go122.go
@@ -0,0 +1,21 @@
+// 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 ssa
+
+import (
+ "go/ast"
+)
+
+func init() {
+ fileVersions = func(file *ast.File) string {
+ if maj, min := parseGoVersion(file.GoVersion); maj >= 0 && min >= 0 {
+ return file.GoVersion
+ }
+ return ""
+ }
+}
diff --git a/vendor/golang.org/x/tools/go/ssa/wrappers.go b/vendor/golang.org/x/tools/go/ssa/wrappers.go
index 123ea6858..7c7ee4099 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 -----------------------------------------------------------
-// makeWrapper returns a synthetic method that delegates to the
+// createWrapper 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,21 +40,17 @@ import (
// - optional implicit field selections
// - meth.Obj() may denote a concrete or an interface method
// - the result may be a thunk or a wrapper.
-//
-// EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu)
-func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
+func createWrapper(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()
@@ -62,8 +58,9 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
description = fmt.Sprintf("%s for %s", description, sel.obj)
if prog.mode&LogSource != 0 {
- defer logStack("make %s to (%s)", description, recv.Type())()
+ defer logStack("create %s to (%s)", description, recv.Type())()
}
+ /* method wrapper */
fn := &Function{
name: name,
method: sel,
@@ -72,35 +69,53 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
Synthetic: description,
Prog: prog,
pos: obj.Pos(),
- info: nil, // info is not set on wrappers.
+ // wrappers have no syntax
+ build: (*builder).buildWrapper,
+ syntax: nil,
+ info: nil,
+ goversion: "",
}
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 := sel.index
+ indices := fn.method.index
var v Value = fn.Locals[0] // spilled receiver
- srdt, ptrRecv := deptr(sel.recv)
+ srdt, ptrRecv := deptr(fn.method.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(obj))
+ _, ptrObj := deptr(recvType(fn.object))
if len(indices) == 1 && !ptrObj {
var c Call
c.Call.Value = &Builtin{
name: "ssa:wrapnilchk",
sig: types.NewSignature(nil,
- types.NewTuple(anonVar(sel.recv), anonVar(tString), anonVar(tString)),
- types.NewTuple(anonVar(sel.recv)), false),
+ types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)),
+ types.NewTuple(anonVar(fn.method.recv)), false),
}
c.Call.Args = []Value{
v,
stringConst(srdt.String()),
- stringConst(sel.obj.Name()),
+ stringConst(fn.method.obj.Name()),
}
c.setType(v.Type())
v = fn.emit(&c)
@@ -122,18 +137,14 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
// address of implicit C field.
var c Call
- if r := recvType(obj); !types.IsInterface(r) { // concrete method
+ if r := recvType(fn.object); !types.IsInterface(r) { // concrete method
if _, ptrObj := deptr(r); !ptrObj {
v = emitLoad(fn, v)
}
- callee := prog.originFunc(obj)
- if callee.typeparams.Len() > 0 {
- callee = prog.lookupOrCreateInstance(callee, receiverTypeArgs(obj), cr)
- }
- c.Call.Value = callee
+ c.Call.Value = fn.Prog.objectMethod(fn.object, b.created)
c.Call.Args = append(c.Call.Args, v)
} else {
- c.Call.Method = obj
+ c.Call.Method = fn.object
c.Call.Value = emitLoad(fn, v) // interface (possibly a typeparam)
}
for _, arg := range fn.Params[1:] {
@@ -141,8 +152,6 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
}
emitTailCall(fn, &c)
fn.finishBody()
- fn.done()
- return fn
}
// createParams creates parameters for wrapper method fn based on its
@@ -151,13 +160,13 @@ func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
func createParams(fn *Function, start int) {
tparams := fn.Signature.Params()
for i, n := start, tparams.Len(); i < n; i++ {
- fn.addParamObj(tparams.At(i))
+ fn.addParamVar(tparams.At(i))
}
}
// -- bounds -----------------------------------------------------------
-// makeBound returns a bound method wrapper (or "bound"), a synthetic
+// createBound 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
@@ -176,66 +185,57 @@ func createParams(fn *Function, start int) {
//
// f := func() { return t.meth() }
//
-// Unlike makeWrapper, makeBound need perform no indirection or field
+// Unlike createWrapper, createBound need perform no indirection or field
// selections because that can be done before the closure is
// constructed.
-//
-// 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()
-
- prog.bounds[key] = fn
+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
+
+ 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)
+ }
+ emitTailCall(fn, &c)
+ fn.finishBody()
+}
+
// -- thunks -----------------------------------------------------------
-// makeThunk returns a thunk, a synthetic function that delegates to a
+// createThunk 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,38 +251,16 @@ func makeBound(prog *Program, obj *types.Func, cr *creator) *Function {
// f is a synthetic wrapper defined as if by:
//
// f := func(t T) { return t.meth() }
-//
-// 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 {
+func createThunk(prog *Program, sel *selection, cr *creator) *Function {
if sel.kind != types.MethodExpr {
panic(sel)
}
- // 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,
+ fn := createWrapper(prog, sel, cr)
+ if fn.Signature.Recv() != nil {
+ panic(fn) // unexpected receiver
}
- 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
}
@@ -290,21 +268,6 @@ 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 {
@@ -329,16 +292,16 @@ func toSelection(sel *types.Selection) *selection {
// -- instantiations --------------------------------------------------
-// buildInstantiationWrapper creates a body for an instantiation
+// buildInstantiationWrapper builds the body of an instantiation
// wrapper fn. The body calls the original generic function,
// bracketed by ChangeType conversions on its arguments and results.
-func buildInstantiationWrapper(fn *Function) {
+func (b *builder) buildInstantiationWrapper(fn *Function) {
orig := fn.topLevelOrigin
sig := fn.Signature
fn.startBody()
if sig.Recv() != nil {
- fn.addParamObj(sig.Recv())
+ fn.addParamVar(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 fa5834baf..e742ecc46 100644
--- a/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
+++ b/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
@@ -26,13 +26,10 @@ 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
@@ -123,20 +120,7 @@ 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
- 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
+ scopeMemo map[*types.Scope][]types.Object // memoization of scopeObjects
}
// For returns the path to an object relative to its package,
@@ -328,31 +312,18 @@ 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)
- 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
- }
+ // 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
}
- } 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
- }
+ if r := find(obj, m.Type(), append(path2, opType), nil); r != nil {
+ return Path(r), nil
}
}
}
@@ -448,22 +419,13 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
path = append(path, name...)
path = append(path, opType)
- 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
- }
+ // 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
}
}
@@ -576,12 +538,7 @@ 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) {
- 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) {
+ pathstr := string(p)
if pathstr == "" {
return nil, fmt.Errorf("empty path")
}
@@ -747,12 +704,7 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
if index >= t.NumMethods() {
return nil, fmt.Errorf("method index %d out of range [0-%d)", index, t.NumMethods())
}
- if skipMethodSorting {
- obj = t.Method(index)
- } else {
- methods := namedMethods(t) // (unmemoized)
- obj = methods[index] // Id-ordered
- }
+ obj = t.Method(index)
default:
return nil, fmt.Errorf("cannot apply %q to %s (got %T, want interface or named)", code, t, t)
@@ -779,33 +731,6 @@ func object(pkg *types.Package, pathstr string, skipMethodSorting bool) (types.O
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 1308503f7..cfbda6102 100644
--- a/vendor/golang.org/x/tools/internal/diff/unified.go
+++ b/vendor/golang.org/x/tools/internal/diff/unified.go
@@ -10,12 +10,16 @@ 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)
+ unified, err := ToUnified(oldLabel, newLabel, old, edits, DefaultContextLines)
if err != nil {
// Can't happen: edits are consistent.
log.Fatalf("internal error in diff.Unified: %v", err)
@@ -23,11 +27,12 @@ func Unified(oldLabel, newLabel, old, new string) string {
return unified
}
-// ToUnified applies the edits to content and returns a unified diff.
+// ToUnified applies the edits to content and returns a unified diff,
+// with contextLines lines of (unchanged) context around each diff hunk.
// 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) (string, error) {
- u, err := toUnified(oldLabel, newLabel, content, edits)
+func ToUnified(oldLabel, newLabel, content string, edits []Edit, contextLines int) (string, error) {
+ u, err := toUnified(oldLabel, newLabel, content, edits, contextLines)
if err != nil {
return "", err
}
@@ -93,14 +98,10 @@ 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) (unified, error) {
+func toUnified(fromName, toName string, content string, edits []Edit, contextLines int) (unified, error) {
+ gap := contextLines * 2
u := unified{
from: fromName,
to: toName,
@@ -136,7 +137,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified,
//need to start a new hunk
if h != nil {
// add the edge to the previous hunk
- addEqualLines(h, lines, last, last+edge)
+ addEqualLines(h, lines, last, last+contextLines)
u.hunks = append(u.hunks, h)
}
toLine += start - last
@@ -145,7 +146,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified,
toLine: toLine + 1,
}
// add the edge to the new hunk
- delta := addEqualLines(h, lines, start-edge, start)
+ delta := addEqualLines(h, lines, start-contextLines, start)
h.fromLine -= delta
h.toLine -= delta
}
@@ -163,7 +164,7 @@ func toUnified(fromName, toName string, content string, edits []Edit) (unified,
}
if h != nil {
// add the edge to the final hunk
- addEqualLines(h, lines, last, last+edge)
+ addEqualLines(h, lines, last, last+contextLines)
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
deleted file mode 100644
index c40c7e931..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// 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
deleted file mode 100644
index 0ca55e0d5..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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
deleted file mode 100644
index d58595dbd..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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
deleted file mode 100644
index d3922890b..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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
deleted file mode 100644
index 38a4db6af..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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
deleted file mode 100644
index c82e57df8..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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
deleted file mode 100644
index 27e860243..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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
deleted file mode 100644
index f12f1a734..000000000
--- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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 53cf66da0..c27b91f8c 100644
--- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go
+++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go
@@ -85,6 +85,7 @@ 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,23 +96,24 @@ 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()) {
- return stdout, stderr, friendlyErr, err
+ 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)
}
- 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, nil, ctx.Err()
+ return nil, nil, ctx.Err(), ctx.Err()
case runner.inFlight <- struct{}{}:
defer func() { <-runner.inFlight }()
}
@@ -121,6 +123,7 @@ 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()
@@ -129,7 +132,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
// runPiped commands.
select {
case <-ctx.Done():
- return nil, ctx.Err()
+ return ctx.Err(), ctx.Err()
case runner.serialized <- struct{}{}:
defer func() { <-runner.serialized }()
}
@@ -139,7 +142,7 @@ func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stde
for i := 0; i < maxInFlight; i++ {
select {
case <-ctx.Done():
- return nil, ctx.Err()
+ return ctx.Err(), ctx.Err()
case runner.inFlight <- struct{}{}:
// Make sure we always "return" any workers we took.
defer func() { <-runner.inFlight }()
@@ -172,6 +175,7 @@ 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 452e342c5..f79dd8cc3 100644
--- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
+++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
@@ -9,13 +9,12 @@ 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.
@@ -78,14 +77,25 @@ 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,
+ root: root,
+ add: add,
+ skip: skip,
+ opts: opts,
+ added: make(map[string]bool),
}
w.init()
- if err := fastwalk.Walk(root.Path, w.walk); err != nil {
+
+ // 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 {
logf := opts.Logf
if logf == nil {
logf = log.Printf
@@ -105,7 +115,9 @@ 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.
- ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files.
+ ignoredDirs []string
+
+ added map[string]bool
}
// init initializes the walker based on its Options
@@ -121,13 +133,9 @@ func (w *walker) init() {
for _, p := range ignoredPaths {
full := filepath.Join(w.root.Path, p)
- 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)
+ w.ignoredDirs = append(w.ignoredDirs, full)
+ if w.opts.Logf != nil {
+ w.opts.Logf("Directory added to ignore list: %s", full)
}
}
}
@@ -162,9 +170,9 @@ func (w *walker) getIgnoredDirs(path string) []string {
}
// shouldSkipDir reports whether the file should be skipped or not.
-func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool {
+func (w *walker) shouldSkipDir(dir string) bool {
for _, ignoredDir := range w.ignoredDirs {
- if os.SameFile(fi, ignoredDir) {
+ if dir == ignoredDir {
return true
}
}
@@ -176,20 +184,25 @@ func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool {
}
// walk walks through the given path.
-func (w *walker) walk(path string, typ os.FileMode) error {
+func (w *walker) walk(path string, d fs.DirEntry, err error) error {
+ typ := d.Type()
if typ.IsRegular() {
+ if !strings.HasSuffix(path, ".go") {
+ return nil
+ }
+
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
}
- w.add(w.root, dir)
- return fastwalk.ErrSkipFiles
+ if !w.added[dir] {
+ w.add(w.root, dir)
+ w.added[dir] = true
+ }
+ return nil
}
if typ == os.ModeDir {
base := filepath.Base(path)
@@ -199,20 +212,66 @@ func (w *walker) walk(path string, typ os.FileMode) error {
(!w.opts.ModulesEnabled && base == "node_modules") {
return filepath.SkipDir
}
- fi, err := os.Lstat(path)
- if err == nil && w.shouldSkipDir(fi, path) {
+ if w.shouldSkipDir(path) {
return filepath.SkipDir
}
return nil
}
- if typ == os.ModeSymlink {
+ if typ == os.ModeSymlink && err == nil {
+ // 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?
+
+ if os.IsPathSeparator(path[len(path)-1]) {
+ // The OS was supposed to resolve a directory symlink but didn't.
+ //
+ // On macOS this may be caused by a known libc/kernel bug;
+ // see https://go.dev/issue/59586.
+ //
+ // On Windows before Go 1.21, this may be caused by a bug in
+ // os.Lstat (fixed in https://go.dev/cl/463177).
+ //
+ // In either case, we can work around the bug by walking this level
+ // explicitly: first the symlink target itself, then its contents.
+
+ fi, err := os.Stat(path)
+ if err != nil || !fi.IsDir() {
+ return nil
+ }
+ err = w.walk(path, fs.FileInfoToDirEntry(fi), nil)
+ if err == filepath.SkipDir {
+ return nil
+ } else if err != nil {
+ return err
+ }
+
+ ents, _ := os.ReadDir(path) // ignore error if unreadable
+ for _, d := range ents {
+ nextPath := filepath.Join(path, d.Name())
+ var err error
+ if d.IsDir() {
+ err = filepath.WalkDir(nextPath, w.walk)
+ } else {
+ err = w.walk(nextPath, d, nil)
+ if err == filepath.SkipDir {
+ break
+ }
+ }
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
base := filepath.Base(path)
if strings.HasPrefix(base, ".#") {
// Emacs noise.
return nil
}
if w.shouldTraverse(path) {
- return fastwalk.ErrTraverseLink
+ // Add a trailing separator to traverse the symlink.
+ nextPath := path + string(filepath.Separator)
+ return filepath.WalkDir(nextPath, w.walk)
}
}
return nil
@@ -222,6 +281,10 @@ func (w *walker) walk(path string, typ os.FileMode) error {
// should be followed. It makes sure symlinks were never visited
// before to avoid symlink loops.
func (w *walker) shouldTraverse(path string) bool {
+ if w.shouldSkipDir(path) {
+ return false
+ }
+
ts, err := os.Stat(path)
if err != nil {
logf := w.opts.Logf
@@ -234,9 +297,7 @@ func (w *walker) shouldTraverse(path string) bool {
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 {
diff --git a/vendor/golang.org/x/tools/internal/testenv/testenv.go b/vendor/golang.org/x/tools/internal/testenv/testenv.go
index 4d29ebe7f..88de3da05 100644
--- a/vendor/golang.org/x/tools/internal/testenv/testenv.go
+++ b/vendor/golang.org/x/tools/internal/testenv/testenv.go
@@ -447,3 +447,32 @@ 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
deleted file mode 100644
index 5e96e8955..000000000
--- a/vendor/golang.org/x/tools/internal/typesinternal/objectpath.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.
-
-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/modules.txt b/vendor/modules.txt
index 99fcd08bb..f99471400 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -808,7 +808,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.13.0
+# golang.org/x/mod v0.14.0
## explicit; go 1.18
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -861,7 +861,7 @@ golang.org/x/text/width
# golang.org/x/time v0.3.0
## explicit
golang.org/x/time/rate
-# golang.org/x/tools v0.14.0
+# golang.org/x/tools v0.15.0
## explicit; go 1.18
golang.org/x/tools/go/analysis
golang.org/x/tools/go/analysis/analysistest
@@ -933,7 +933,6 @@ 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