mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-13 23:17:09 +08:00
vendor: github.com/moby/buildkit v0.21.0-rc1
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
This commit is contained in:
27
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
27
vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go
generated
vendored
@ -106,24 +106,18 @@ func Find(importPath, srcDir string) (filename, path string) {
|
||||
// additional trailing data beyond the end of the export data.
|
||||
func NewReader(r io.Reader) (io.Reader, error) {
|
||||
buf := bufio.NewReader(r)
|
||||
_, size, err := gcimporter.FindExportData(buf)
|
||||
size, err := gcimporter.FindExportData(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if size >= 0 {
|
||||
// We were given an archive and found the __.PKGDEF in it.
|
||||
// This tells us the size of the export data, and we don't
|
||||
// need to return the entire file.
|
||||
return &io.LimitedReader{
|
||||
R: buf,
|
||||
N: size,
|
||||
}, nil
|
||||
} else {
|
||||
// We were given an object file. As such, we don't know how large
|
||||
// the export data is and must return the entire file.
|
||||
return buf, nil
|
||||
}
|
||||
// We were given an archive and found the __.PKGDEF in it.
|
||||
// This tells us the size of the export data, and we don't
|
||||
// need to return the entire file.
|
||||
return &io.LimitedReader{
|
||||
R: buf,
|
||||
N: size,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// readAll works the same way as io.ReadAll, but avoids allocations and copies
|
||||
@ -199,10 +193,7 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package,
|
||||
return pkg, err
|
||||
|
||||
default:
|
||||
l := len(data)
|
||||
if l > 10 {
|
||||
l = 10
|
||||
}
|
||||
l := min(len(data), 10)
|
||||
return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), path)
|
||||
}
|
||||
}
|
||||
|
9
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
9
vendor/golang.org/x/tools/go/packages/external.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -89,7 +90,7 @@ func findExternalDriver(cfg *Config) driver {
|
||||
const toolPrefix = "GOPACKAGESDRIVER="
|
||||
tool := ""
|
||||
for _, env := range cfg.Env {
|
||||
if val := strings.TrimPrefix(env, toolPrefix); val != env {
|
||||
if val, ok := strings.CutPrefix(env, toolPrefix); ok {
|
||||
tool = val
|
||||
}
|
||||
}
|
||||
@ -131,7 +132,7 @@ func findExternalDriver(cfg *Config) driver {
|
||||
// command.
|
||||
//
|
||||
// (See similar trick in Invocation.run in ../../internal/gocommand/invoke.go)
|
||||
cmd.Env = append(slicesClip(cfg.Env), "PWD="+cfg.Dir)
|
||||
cmd.Env = append(slices.Clip(cfg.Env), "PWD="+cfg.Dir)
|
||||
cmd.Stdin = bytes.NewReader(req)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = stderr
|
||||
@ -150,7 +151,3 @@ func findExternalDriver(cfg *Config) driver {
|
||||
return &response, nil
|
||||
}
|
||||
}
|
||||
|
||||
// slicesClip removes unused capacity from the slice, returning s[:len(s):len(s)].
|
||||
// TODO(adonovan): use go1.21 slices.Clip.
|
||||
func slicesClip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] }
|
||||
|
10
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
10
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
@ -322,6 +322,7 @@ type jsonPackage struct {
|
||||
ImportPath string
|
||||
Dir string
|
||||
Name string
|
||||
Target string
|
||||
Export string
|
||||
GoFiles []string
|
||||
CompiledGoFiles []string
|
||||
@ -505,13 +506,15 @@ func (state *golistState) createDriverResponse(words ...string) (*DriverResponse
|
||||
pkg := &Package{
|
||||
Name: p.Name,
|
||||
ID: p.ImportPath,
|
||||
Dir: p.Dir,
|
||||
Target: p.Target,
|
||||
GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles),
|
||||
CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles),
|
||||
OtherFiles: absJoin(p.Dir, otherFiles(p)...),
|
||||
EmbedFiles: absJoin(p.Dir, p.EmbedFiles),
|
||||
EmbedPatterns: absJoin(p.Dir, p.EmbedPatterns),
|
||||
IgnoredFiles: absJoin(p.Dir, p.IgnoredGoFiles, p.IgnoredOtherFiles),
|
||||
forTest: p.ForTest,
|
||||
ForTest: p.ForTest,
|
||||
depsErrors: p.DepsErrors,
|
||||
Module: p.Module,
|
||||
}
|
||||
@ -795,7 +798,7 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
||||
// Request Dir in the unlikely case Export is not absolute.
|
||||
addFields("Dir", "Export")
|
||||
}
|
||||
if cfg.Mode&needInternalForTest != 0 {
|
||||
if cfg.Mode&NeedForTest != 0 {
|
||||
addFields("ForTest")
|
||||
}
|
||||
if cfg.Mode&needInternalDepsErrors != 0 {
|
||||
@ -810,6 +813,9 @@ func jsonFlag(cfg *Config, goVersion int) string {
|
||||
if cfg.Mode&NeedEmbedPatterns != 0 {
|
||||
addFields("EmbedPatterns")
|
||||
}
|
||||
if cfg.Mode&NeedTarget != 0 {
|
||||
addFields("Target")
|
||||
}
|
||||
return "-json=" + strings.Join(fields, ",")
|
||||
}
|
||||
|
||||
|
2
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
2
vendor/golang.org/x/tools/go/packages/loadmode_string.go
generated
vendored
@ -23,9 +23,11 @@ var modes = [...]struct {
|
||||
{NeedSyntax, "NeedSyntax"},
|
||||
{NeedTypesInfo, "NeedTypesInfo"},
|
||||
{NeedTypesSizes, "NeedTypesSizes"},
|
||||
{NeedForTest, "NeedForTest"},
|
||||
{NeedModule, "NeedModule"},
|
||||
{NeedEmbedFiles, "NeedEmbedFiles"},
|
||||
{NeedEmbedPatterns, "NeedEmbedPatterns"},
|
||||
{NeedTarget, "NeedTarget"},
|
||||
}
|
||||
|
||||
func (mode LoadMode) String() string {
|
||||
|
77
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
77
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
@ -43,19 +43,33 @@ import (
|
||||
// ID and Errors (if present) will always be filled.
|
||||
// [Load] may return more information than requested.
|
||||
//
|
||||
// The Mode flag is a union of several bits named NeedName,
|
||||
// NeedFiles, and so on, each of which determines whether
|
||||
// a given field of Package (Name, Files, etc) should be
|
||||
// populated.
|
||||
//
|
||||
// For convenience, we provide named constants for the most
|
||||
// common combinations of Need flags:
|
||||
//
|
||||
// [LoadFiles] lists of files in each package
|
||||
// [LoadImports] ... plus imports
|
||||
// [LoadTypes] ... plus type information
|
||||
// [LoadSyntax] ... plus type-annotated syntax
|
||||
// [LoadAllSyntax] ... for all dependencies
|
||||
//
|
||||
// Unfortunately there are a number of open bugs related to
|
||||
// interactions among the LoadMode bits:
|
||||
// - https://github.com/golang/go/issues/56633
|
||||
// - https://github.com/golang/go/issues/56677
|
||||
// - https://github.com/golang/go/issues/58726
|
||||
// - https://github.com/golang/go/issues/63517
|
||||
// - https://go.dev/issue/56633
|
||||
// - https://go.dev/issue/56677
|
||||
// - https://go.dev/issue/58726
|
||||
// - https://go.dev/issue/63517
|
||||
type LoadMode int
|
||||
|
||||
const (
|
||||
// NeedName adds Name and PkgPath.
|
||||
NeedName LoadMode = 1 << iota
|
||||
|
||||
// NeedFiles adds GoFiles, OtherFiles, and IgnoredFiles
|
||||
// NeedFiles adds Dir, GoFiles, OtherFiles, and IgnoredFiles
|
||||
NeedFiles
|
||||
|
||||
// NeedCompiledGoFiles adds CompiledGoFiles.
|
||||
@ -86,9 +100,10 @@ const (
|
||||
// needInternalDepsErrors adds the internal deps errors field for use by gopls.
|
||||
needInternalDepsErrors
|
||||
|
||||
// needInternalForTest adds the internal forTest field.
|
||||
// NeedForTest adds ForTest.
|
||||
//
|
||||
// Tests must also be set on the context for this field to be populated.
|
||||
needInternalForTest
|
||||
NeedForTest
|
||||
|
||||
// typecheckCgo enables full support for type checking cgo. Requires Go 1.15+.
|
||||
// Modifies CompiledGoFiles and Types, and has no effect on its own.
|
||||
@ -103,41 +118,31 @@ const (
|
||||
// NeedEmbedPatterns adds EmbedPatterns.
|
||||
NeedEmbedPatterns
|
||||
|
||||
// NeedTarget adds Target.
|
||||
NeedTarget
|
||||
|
||||
// Be sure to update loadmode_string.go when adding new items!
|
||||
)
|
||||
|
||||
const (
|
||||
// LoadFiles loads the name and file names for the initial packages.
|
||||
//
|
||||
// Deprecated: LoadFiles exists for historical compatibility
|
||||
// and should not be used. Please directly specify the needed fields using the Need values.
|
||||
LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles
|
||||
|
||||
// LoadImports loads the name, file names, and import mapping for the initial packages.
|
||||
//
|
||||
// Deprecated: LoadImports exists for historical compatibility
|
||||
// and should not be used. Please directly specify the needed fields using the Need values.
|
||||
LoadImports = LoadFiles | NeedImports
|
||||
|
||||
// LoadTypes loads exported type information for the initial packages.
|
||||
//
|
||||
// Deprecated: LoadTypes exists for historical compatibility
|
||||
// and should not be used. Please directly specify the needed fields using the Need values.
|
||||
LoadTypes = LoadImports | NeedTypes | NeedTypesSizes
|
||||
|
||||
// LoadSyntax loads typed syntax for the initial packages.
|
||||
//
|
||||
// Deprecated: LoadSyntax exists for historical compatibility
|
||||
// and should not be used. Please directly specify the needed fields using the Need values.
|
||||
LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo
|
||||
|
||||
// LoadAllSyntax loads typed syntax for the initial packages and all dependencies.
|
||||
//
|
||||
// Deprecated: LoadAllSyntax exists for historical compatibility
|
||||
// and should not be used. Please directly specify the needed fields using the Need values.
|
||||
LoadAllSyntax = LoadSyntax | NeedDeps
|
||||
|
||||
// Deprecated: NeedExportsFile is a historical misspelling of NeedExportFile.
|
||||
//
|
||||
//go:fix inline
|
||||
NeedExportsFile = NeedExportFile
|
||||
)
|
||||
|
||||
@ -158,7 +163,7 @@ type Config struct {
|
||||
// If the user provides a logger, debug logging is enabled.
|
||||
// If the GOPACKAGESDEBUG environment variable is set to true,
|
||||
// but the logger is nil, default to log.Printf.
|
||||
Logf func(format string, args ...interface{})
|
||||
Logf func(format string, args ...any)
|
||||
|
||||
// Dir is the directory in which to run the build system's query tool
|
||||
// that provides information about the packages.
|
||||
@ -434,6 +439,12 @@ type Package struct {
|
||||
// PkgPath is the package path as used by the go/types package.
|
||||
PkgPath string
|
||||
|
||||
// Dir is the directory associated with the package, if it exists.
|
||||
//
|
||||
// For packages listed by the go command, this is the directory containing
|
||||
// the package files.
|
||||
Dir string
|
||||
|
||||
// Errors contains any errors encountered querying the metadata
|
||||
// of the package, or while parsing or type-checking its files.
|
||||
Errors []Error
|
||||
@ -473,6 +484,10 @@ type Package struct {
|
||||
// information for the package as provided by the build system.
|
||||
ExportFile string
|
||||
|
||||
// Target is the absolute install path of the .a file, for libraries,
|
||||
// and of the executable file, for binaries.
|
||||
Target string
|
||||
|
||||
// Imports maps import paths appearing in the package's Go source files
|
||||
// to corresponding loaded Packages.
|
||||
Imports map[string]*Package
|
||||
@ -521,8 +536,8 @@ type Package struct {
|
||||
|
||||
// -- internal --
|
||||
|
||||
// forTest is the package under test, if any.
|
||||
forTest string
|
||||
// ForTest is the package under test, if any.
|
||||
ForTest string
|
||||
|
||||
// depsErrors is the DepsErrors field from the go list response, if any.
|
||||
depsErrors []*packagesinternal.PackageError
|
||||
@ -551,21 +566,17 @@ type ModuleError struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
packagesinternal.GetForTest = func(p interface{}) string {
|
||||
return p.(*Package).forTest
|
||||
}
|
||||
packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError {
|
||||
packagesinternal.GetDepsErrors = func(p any) []*packagesinternal.PackageError {
|
||||
return p.(*Package).depsErrors
|
||||
}
|
||||
packagesinternal.SetModFile = func(config interface{}, value string) {
|
||||
packagesinternal.SetModFile = func(config any, value string) {
|
||||
config.(*Config).modFile = value
|
||||
}
|
||||
packagesinternal.SetModFlag = func(config interface{}, value string) {
|
||||
packagesinternal.SetModFlag = func(config any, value string) {
|
||||
config.(*Config).modFlag = value
|
||||
}
|
||||
packagesinternal.TypecheckCgo = int(typecheckCgo)
|
||||
packagesinternal.DepsErrors = int(needInternalDepsErrors)
|
||||
packagesinternal.ForTest = int(needInternalForTest)
|
||||
}
|
||||
|
||||
// An Error describes a problem with a package's metadata, syntax, or types.
|
||||
@ -730,7 +741,7 @@ func newLoader(cfg *Config) *loader {
|
||||
if debug {
|
||||
ld.Config.Logf = log.Printf
|
||||
} else {
|
||||
ld.Config.Logf = func(format string, args ...interface{}) {}
|
||||
ld.Config.Logf = func(format string, args ...any) {}
|
||||
}
|
||||
}
|
||||
if ld.Config.Mode == 0 {
|
||||
|
83
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
83
vendor/golang.org/x/tools/go/types/typeutil/callee.go
generated
vendored
@ -7,45 +7,23 @@ package typeutil
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
_ "unsafe" // for linkname
|
||||
)
|
||||
|
||||
// Callee returns the named target of a function call, if any:
|
||||
// a function, method, builtin, or variable.
|
||||
//
|
||||
// Functions and methods may potentially have type parameters.
|
||||
//
|
||||
// Note: for calls of instantiated functions and methods, Callee returns
|
||||
// the corresponding generic function or method on the generic type.
|
||||
func Callee(info *types.Info, call *ast.CallExpr) types.Object {
|
||||
fun := ast.Unparen(call.Fun)
|
||||
|
||||
// Look through type instantiation if necessary.
|
||||
isInstance := false
|
||||
switch fun.(type) {
|
||||
case *ast.IndexExpr, *ast.IndexListExpr:
|
||||
// When extracting the callee from an *IndexExpr, we need to check that
|
||||
// it is a *types.Func and not a *types.Var.
|
||||
// Example: Don't match a slice m within the expression `m[0]()`.
|
||||
isInstance = true
|
||||
fun, _, _, _ = typeparams.UnpackIndexExpr(fun)
|
||||
}
|
||||
|
||||
var obj types.Object
|
||||
switch fun := fun.(type) {
|
||||
case *ast.Ident:
|
||||
obj = info.Uses[fun] // type, var, builtin, or declared func
|
||||
case *ast.SelectorExpr:
|
||||
if sel, ok := info.Selections[fun]; ok {
|
||||
obj = sel.Obj() // method or field
|
||||
} else {
|
||||
obj = info.Uses[fun.Sel] // qualified identifier?
|
||||
}
|
||||
obj := info.Uses[usedIdent(info, call.Fun)]
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := obj.(*types.TypeName); ok {
|
||||
return nil // T(x) is a conversion, not a call
|
||||
}
|
||||
// A Func is required to match instantiations.
|
||||
if _, ok := obj.(*types.Func); isInstance && !ok {
|
||||
return nil // Was not a Func.
|
||||
return nil
|
||||
}
|
||||
return obj
|
||||
}
|
||||
@ -56,13 +34,52 @@ func Callee(info *types.Info, call *ast.CallExpr) types.Object {
|
||||
// Note: for calls of instantiated functions and methods, StaticCallee returns
|
||||
// the corresponding generic function or method on the generic type.
|
||||
func StaticCallee(info *types.Info, call *ast.CallExpr) *types.Func {
|
||||
if f, ok := Callee(info, call).(*types.Func); ok && !interfaceMethod(f) {
|
||||
return f
|
||||
obj := info.Uses[usedIdent(info, call.Fun)]
|
||||
fn, _ := obj.(*types.Func)
|
||||
if fn == nil || interfaceMethod(fn) {
|
||||
return nil
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
// usedIdent is the implementation of [internal/typesinternal.UsedIdent].
|
||||
// It returns the identifier associated with e.
|
||||
// See typesinternal.UsedIdent for a fuller description.
|
||||
// This function should live in typesinternal, but cannot because it would
|
||||
// create an import cycle.
|
||||
//
|
||||
//go:linkname usedIdent
|
||||
func usedIdent(info *types.Info, e ast.Expr) *ast.Ident {
|
||||
if info.Types == nil || info.Uses == nil {
|
||||
panic("one of info.Types or info.Uses is nil; both must be populated")
|
||||
}
|
||||
// Look through type instantiation if necessary.
|
||||
switch d := ast.Unparen(e).(type) {
|
||||
case *ast.IndexExpr:
|
||||
if info.Types[d.Index].IsType() {
|
||||
e = d.X
|
||||
}
|
||||
case *ast.IndexListExpr:
|
||||
e = d.X
|
||||
}
|
||||
|
||||
switch e := ast.Unparen(e).(type) {
|
||||
// info.Uses always has the object we want, even for selector expressions.
|
||||
// We don't need info.Selections.
|
||||
// See go/types/recording.go:recordSelection.
|
||||
case *ast.Ident:
|
||||
return e
|
||||
case *ast.SelectorExpr:
|
||||
return e.Sel
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// interfaceMethod reports whether its argument is a method of an interface.
|
||||
// This function should live in typesinternal, but cannot because it would create an import cycle.
|
||||
//
|
||||
//go:linkname interfaceMethod
|
||||
func interfaceMethod(f *types.Func) bool {
|
||||
recv := f.Type().(*types.Signature).Recv()
|
||||
recv := f.Signature().Recv()
|
||||
return recv != nil && types.IsInterface(recv.Type())
|
||||
}
|
||||
|
250
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
250
vendor/golang.org/x/tools/go/types/typeutil/map.go
generated
vendored
@ -2,30 +2,35 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package typeutil defines various utilities for types, such as Map,
|
||||
// a mapping from types.Type to any values.
|
||||
package typeutil // import "golang.org/x/tools/go/types/typeutil"
|
||||
// Package typeutil defines various utilities for types, such as [Map],
|
||||
// a hash table that maps [types.Type] to any value.
|
||||
package typeutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"reflect"
|
||||
"hash/maphash"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
// Map is a hash-table-based mapping from types (types.Type) to
|
||||
// arbitrary any values. The concrete types that implement
|
||||
// arbitrary values. The concrete types that implement
|
||||
// the Type interface are pointers. Since they are not canonicalized,
|
||||
// == cannot be used to check for equivalence, and thus we cannot
|
||||
// simply use a Go map.
|
||||
//
|
||||
// Just as with map[K]V, a nil *Map is a valid empty map.
|
||||
//
|
||||
// Not thread-safe.
|
||||
// Read-only map operations ([Map.At], [Map.Len], and so on) may
|
||||
// safely be called concurrently.
|
||||
//
|
||||
// TODO(adonovan): deprecate in favor of https://go.dev/issues/69420
|
||||
// and 69559, if the latter proposals for a generic hash-map type and
|
||||
// a types.Hash function are accepted.
|
||||
type Map struct {
|
||||
hasher Hasher // shared by many Maps
|
||||
table map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
|
||||
length int // number of map entries
|
||||
}
|
||||
@ -36,35 +41,17 @@ type entry struct {
|
||||
value any
|
||||
}
|
||||
|
||||
// SetHasher sets the hasher used by Map.
|
||||
// SetHasher has no effect.
|
||||
//
|
||||
// All Hashers are functionally equivalent but contain internal state
|
||||
// used to cache the results of hashing previously seen types.
|
||||
//
|
||||
// A single Hasher created by MakeHasher() may be shared among many
|
||||
// Maps. This is recommended if the instances have many keys in
|
||||
// common, as it will amortize the cost of hash computation.
|
||||
//
|
||||
// A Hasher may grow without bound as new types are seen. Even when a
|
||||
// type is deleted from the map, the Hasher never shrinks, since other
|
||||
// types in the map may reference the deleted type indirectly.
|
||||
//
|
||||
// Hashers are not thread-safe, and read-only operations such as
|
||||
// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
|
||||
// read-lock) is require around all Map operations if a shared
|
||||
// hasher is accessed from multiple threads.
|
||||
//
|
||||
// If SetHasher is not called, the Map will create a private hasher at
|
||||
// the first call to Insert.
|
||||
func (m *Map) SetHasher(hasher Hasher) {
|
||||
m.hasher = hasher
|
||||
}
|
||||
// It is a relic of an optimization that is no longer profitable. Do
|
||||
// not use [Hasher], [MakeHasher], or [SetHasher] in new code.
|
||||
func (m *Map) SetHasher(Hasher) {}
|
||||
|
||||
// Delete removes the entry with the given key, if any.
|
||||
// It returns true if the entry was found.
|
||||
func (m *Map) Delete(key types.Type) bool {
|
||||
if m != nil && m.table != nil {
|
||||
hash := m.hasher.Hash(key)
|
||||
hash := hash(key)
|
||||
bucket := m.table[hash]
|
||||
for i, e := range bucket {
|
||||
if e.key != nil && types.Identical(key, e.key) {
|
||||
@ -83,7 +70,7 @@ func (m *Map) Delete(key types.Type) bool {
|
||||
// The result is nil if the entry is not present.
|
||||
func (m *Map) At(key types.Type) any {
|
||||
if m != nil && m.table != nil {
|
||||
for _, e := range m.table[m.hasher.Hash(key)] {
|
||||
for _, e := range m.table[hash(key)] {
|
||||
if e.key != nil && types.Identical(key, e.key) {
|
||||
return e.value
|
||||
}
|
||||
@ -96,7 +83,7 @@ func (m *Map) At(key types.Type) any {
|
||||
// and returns the previous entry, if any.
|
||||
func (m *Map) Set(key types.Type, value any) (prev any) {
|
||||
if m.table != nil {
|
||||
hash := m.hasher.Hash(key)
|
||||
hash := hash(key)
|
||||
bucket := m.table[hash]
|
||||
var hole *entry
|
||||
for i, e := range bucket {
|
||||
@ -115,10 +102,7 @@ func (m *Map) Set(key types.Type, value any) (prev any) {
|
||||
m.table[hash] = append(bucket, entry{key, value})
|
||||
}
|
||||
} else {
|
||||
if m.hasher.memo == nil {
|
||||
m.hasher = MakeHasher()
|
||||
}
|
||||
hash := m.hasher.Hash(key)
|
||||
hash := hash(key)
|
||||
m.table = map[uint32][]entry{hash: {entry{key, value}}}
|
||||
}
|
||||
|
||||
@ -195,53 +179,35 @@ func (m *Map) KeysString() string {
|
||||
return m.toString(false)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Hasher
|
||||
// -- Hasher --
|
||||
|
||||
// A Hasher maps each type to its hash value.
|
||||
// For efficiency, a hasher uses memoization; thus its memory
|
||||
// footprint grows monotonically over time.
|
||||
// Hashers are not thread-safe.
|
||||
// Hashers have reference semantics.
|
||||
// Call MakeHasher to create a Hasher.
|
||||
type Hasher struct {
|
||||
memo map[types.Type]uint32
|
||||
|
||||
// ptrMap records pointer identity.
|
||||
ptrMap map[any]uint32
|
||||
|
||||
// sigTParams holds type parameters from the signature being hashed.
|
||||
// Signatures are considered identical modulo renaming of type parameters, so
|
||||
// within the scope of a signature type the identity of the signature's type
|
||||
// parameters is just their index.
|
||||
//
|
||||
// Since the language does not currently support referring to uninstantiated
|
||||
// generic types or functions, and instantiated signatures do not have type
|
||||
// parameter lists, we should never encounter a second non-empty type
|
||||
// parameter list when hashing a generic signature.
|
||||
sigTParams *types.TypeParamList
|
||||
// hash returns the hash of type t.
|
||||
// TODO(adonovan): replace by types.Hash when Go proposal #69420 is accepted.
|
||||
func hash(t types.Type) uint32 {
|
||||
return theHasher.Hash(t)
|
||||
}
|
||||
|
||||
// MakeHasher returns a new Hasher instance.
|
||||
func MakeHasher() Hasher {
|
||||
return Hasher{
|
||||
memo: make(map[types.Type]uint32),
|
||||
ptrMap: make(map[any]uint32),
|
||||
sigTParams: nil,
|
||||
}
|
||||
}
|
||||
// A Hasher provides a [Hasher.Hash] method to map a type to its hash value.
|
||||
// Hashers are stateless, and all are equivalent.
|
||||
type Hasher struct{}
|
||||
|
||||
var theHasher Hasher
|
||||
|
||||
// MakeHasher returns Hasher{}.
|
||||
// Hashers are stateless; all are equivalent.
|
||||
func MakeHasher() Hasher { return theHasher }
|
||||
|
||||
// Hash computes a hash value for the given type t such that
|
||||
// Identical(t, t') => Hash(t) == Hash(t').
|
||||
func (h Hasher) Hash(t types.Type) uint32 {
|
||||
hash, ok := h.memo[t]
|
||||
if !ok {
|
||||
hash = h.hashFor(t)
|
||||
h.memo[t] = hash
|
||||
}
|
||||
return hash
|
||||
return hasher{inGenericSig: false}.hash(t)
|
||||
}
|
||||
|
||||
// hasher holds the state of a single Hash traversal: whether we are
|
||||
// inside the signature of a generic function; this is used to
|
||||
// optimize [hasher.hashTypeParam].
|
||||
type hasher struct{ inGenericSig bool }
|
||||
|
||||
// hashString computes the Fowler–Noll–Vo hash of s.
|
||||
func hashString(s string) uint32 {
|
||||
var h uint32
|
||||
@ -252,21 +218,21 @@ func hashString(s string) uint32 {
|
||||
return h
|
||||
}
|
||||
|
||||
// hashFor computes the hash of t.
|
||||
func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
// hash computes the hash of t.
|
||||
func (h hasher) hash(t types.Type) uint32 {
|
||||
// See Identical for rationale.
|
||||
switch t := t.(type) {
|
||||
case *types.Basic:
|
||||
return uint32(t.Kind())
|
||||
|
||||
case *types.Alias:
|
||||
return h.Hash(types.Unalias(t))
|
||||
return h.hash(types.Unalias(t))
|
||||
|
||||
case *types.Array:
|
||||
return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
|
||||
return 9043 + 2*uint32(t.Len()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Slice:
|
||||
return 9049 + 2*h.Hash(t.Elem())
|
||||
return 9049 + 2*h.hash(t.Elem())
|
||||
|
||||
case *types.Struct:
|
||||
var hash uint32 = 9059
|
||||
@ -277,12 +243,12 @@ func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
}
|
||||
hash += hashString(t.Tag(i))
|
||||
hash += hashString(f.Name()) // (ignore f.Pkg)
|
||||
hash += h.Hash(f.Type())
|
||||
hash += h.hash(f.Type())
|
||||
}
|
||||
return hash
|
||||
|
||||
case *types.Pointer:
|
||||
return 9067 + 2*h.Hash(t.Elem())
|
||||
return 9067 + 2*h.hash(t.Elem())
|
||||
|
||||
case *types.Signature:
|
||||
var hash uint32 = 9091
|
||||
@ -290,33 +256,14 @@ func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
hash *= 8863
|
||||
}
|
||||
|
||||
// Use a separate hasher for types inside of the signature, where type
|
||||
// parameter identity is modified to be (index, constraint). We must use a
|
||||
// new memo for this hasher as type identity may be affected by this
|
||||
// masking. For example, in func[T any](*T), the identity of *T depends on
|
||||
// whether we are mapping the argument in isolation, or recursively as part
|
||||
// of hashing the signature.
|
||||
//
|
||||
// We should never encounter a generic signature while hashing another
|
||||
// generic signature, but defensively set sigTParams only if h.mask is
|
||||
// unset.
|
||||
tparams := t.TypeParams()
|
||||
if h.sigTParams == nil && tparams.Len() != 0 {
|
||||
h = Hasher{
|
||||
// There may be something more efficient than discarding the existing
|
||||
// memo, but it would require detecting whether types are 'tainted' by
|
||||
// references to type parameters.
|
||||
memo: make(map[types.Type]uint32),
|
||||
// Re-using ptrMap ensures that pointer identity is preserved in this
|
||||
// hasher.
|
||||
ptrMap: h.ptrMap,
|
||||
sigTParams: tparams,
|
||||
}
|
||||
}
|
||||
if n := tparams.Len(); n > 0 {
|
||||
h.inGenericSig = true // affects constraints, params, and results
|
||||
|
||||
for i := 0; i < tparams.Len(); i++ {
|
||||
tparam := tparams.At(i)
|
||||
hash += 7 * h.Hash(tparam.Constraint())
|
||||
for i := range n {
|
||||
tparam := tparams.At(i)
|
||||
hash += 7 * h.hash(tparam.Constraint())
|
||||
}
|
||||
}
|
||||
|
||||
return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())
|
||||
@ -350,17 +297,17 @@ func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
return hash
|
||||
|
||||
case *types.Map:
|
||||
return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())
|
||||
return 9109 + 2*h.hash(t.Key()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Chan:
|
||||
return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())
|
||||
return 9127 + 2*uint32(t.Dir()) + 3*h.hash(t.Elem())
|
||||
|
||||
case *types.Named:
|
||||
hash := h.hashPtr(t.Obj())
|
||||
hash := h.hashTypeName(t.Obj())
|
||||
targs := t.TypeArgs()
|
||||
for i := 0; i < targs.Len(); i++ {
|
||||
targ := targs.At(i)
|
||||
hash += 2 * h.Hash(targ)
|
||||
hash += 2 * h.hash(targ)
|
||||
}
|
||||
return hash
|
||||
|
||||
@ -374,17 +321,17 @@ func (h Hasher) hashFor(t types.Type) uint32 {
|
||||
panic(fmt.Sprintf("%T: %v", t, t))
|
||||
}
|
||||
|
||||
func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
|
||||
func (h hasher) hashTuple(tuple *types.Tuple) uint32 {
|
||||
// See go/types.identicalTypes for rationale.
|
||||
n := tuple.Len()
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := 0; i < n; i++ {
|
||||
hash += 3 * h.Hash(tuple.At(i).Type())
|
||||
for i := range n {
|
||||
hash += 3 * h.hash(tuple.At(i).Type())
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
func (h Hasher) hashUnion(t *types.Union) uint32 {
|
||||
func (h hasher) hashUnion(t *types.Union) uint32 {
|
||||
// Hash type restrictions.
|
||||
terms, err := typeparams.UnionTermSet(t)
|
||||
// if err != nil t has invalid type restrictions. Fall back on a non-zero
|
||||
@ -395,11 +342,11 @@ func (h Hasher) hashUnion(t *types.Union) uint32 {
|
||||
return h.hashTermSet(terms)
|
||||
}
|
||||
|
||||
func (h Hasher) hashTermSet(terms []*types.Term) uint32 {
|
||||
func (h hasher) hashTermSet(terms []*types.Term) uint32 {
|
||||
hash := 9157 + 2*uint32(len(terms))
|
||||
for _, term := range terms {
|
||||
// term order is not significant.
|
||||
termHash := h.Hash(term.Type())
|
||||
termHash := h.hash(term.Type())
|
||||
if term.Tilde() {
|
||||
termHash *= 9161
|
||||
}
|
||||
@ -408,36 +355,47 @@ func (h Hasher) hashTermSet(terms []*types.Term) uint32 {
|
||||
return hash
|
||||
}
|
||||
|
||||
// hashTypeParam returns a hash of the type parameter t, with a hash value
|
||||
// depending on whether t is contained in h.sigTParams.
|
||||
//
|
||||
// If h.sigTParams is set and contains t, then we are in the process of hashing
|
||||
// a signature, and the hash value of t must depend only on t's index and
|
||||
// constraint: signatures are considered identical modulo type parameter
|
||||
// renaming. To avoid infinite recursion, we only hash the type parameter
|
||||
// index, and rely on types.Identical to handle signatures where constraints
|
||||
// are not identical.
|
||||
//
|
||||
// Otherwise the hash of t depends only on t's pointer identity.
|
||||
func (h Hasher) hashTypeParam(t *types.TypeParam) uint32 {
|
||||
if h.sigTParams != nil {
|
||||
i := t.Index()
|
||||
if i >= 0 && i < h.sigTParams.Len() && t == h.sigTParams.At(i) {
|
||||
return 9173 + 3*uint32(i)
|
||||
}
|
||||
// hashTypeParam returns the hash of a type parameter.
|
||||
func (h hasher) hashTypeParam(t *types.TypeParam) uint32 {
|
||||
// Within the signature of a generic function, TypeParams are
|
||||
// identical if they have the same index and constraint, so we
|
||||
// hash them based on index.
|
||||
//
|
||||
// When we are outside a generic function, free TypeParams are
|
||||
// identical iff they are the same object, so we can use a
|
||||
// more discriminating hash consistent with object identity.
|
||||
// This optimization saves [Map] about 4% when hashing all the
|
||||
// types.Info.Types in the forward closure of net/http.
|
||||
if !h.inGenericSig {
|
||||
// Optimization: outside a generic function signature,
|
||||
// use a more discrimating hash consistent with object identity.
|
||||
return h.hashTypeName(t.Obj())
|
||||
}
|
||||
return h.hashPtr(t.Obj())
|
||||
return 9173 + 3*uint32(t.Index())
|
||||
}
|
||||
|
||||
// hashPtr hashes the pointer identity of ptr. It uses h.ptrMap to ensure that
|
||||
// pointers values are not dependent on the GC.
|
||||
func (h Hasher) hashPtr(ptr any) uint32 {
|
||||
if hash, ok := h.ptrMap[ptr]; ok {
|
||||
return hash
|
||||
var theSeed = maphash.MakeSeed()
|
||||
|
||||
// hashTypeName hashes the pointer of tname.
|
||||
func (hasher) hashTypeName(tname *types.TypeName) uint32 {
|
||||
// Since types.Identical uses == to compare TypeNames,
|
||||
// the Hash function uses maphash.Comparable.
|
||||
// TODO(adonovan): or will, when it becomes available in go1.24.
|
||||
// In the meantime we use the pointer's numeric value.
|
||||
//
|
||||
// hash := maphash.Comparable(theSeed, tname)
|
||||
//
|
||||
// (Another approach would be to hash the name and package
|
||||
// path, and whether or not it is a package-level typename. It
|
||||
// is rare for a package to define multiple local types with
|
||||
// the same name.)
|
||||
ptr := uintptr(unsafe.Pointer(tname))
|
||||
if unsafe.Sizeof(ptr) == 8 {
|
||||
hash := uint64(ptr)
|
||||
return uint32(hash ^ (hash >> 32))
|
||||
} else {
|
||||
return uint32(ptr)
|
||||
}
|
||||
hash := uint32(reflect.ValueOf(ptr).Pointer())
|
||||
h.ptrMap[ptr] = hash
|
||||
return hash
|
||||
}
|
||||
|
||||
// shallowHash computes a hash of t without looking at any of its
|
||||
@ -454,7 +412,7 @@ func (h Hasher) hashPtr(ptr any) uint32 {
|
||||
// include m itself; there is no mention of the named type X that
|
||||
// might help us break the cycle.
|
||||
// (See comment in go/types.identical, case *Interface, for more.)
|
||||
func (h Hasher) shallowHash(t types.Type) uint32 {
|
||||
func (h hasher) shallowHash(t types.Type) uint32 {
|
||||
// t is the type of an interface method (Signature),
|
||||
// its params or results (Tuples), or their immediate
|
||||
// elements (mostly Slice, Pointer, Basic, Named),
|
||||
@ -475,7 +433,7 @@ func (h Hasher) shallowHash(t types.Type) uint32 {
|
||||
case *types.Tuple:
|
||||
n := t.Len()
|
||||
hash := 9137 + 2*uint32(n)
|
||||
for i := 0; i < n; i++ {
|
||||
for i := range n {
|
||||
hash += 53471161 * h.shallowHash(t.At(i).Type())
|
||||
}
|
||||
return hash
|
||||
@ -508,10 +466,10 @@ func (h Hasher) shallowHash(t types.Type) uint32 {
|
||||
return 9127
|
||||
|
||||
case *types.Named:
|
||||
return h.hashPtr(t.Obj())
|
||||
return h.hashTypeName(t.Obj())
|
||||
|
||||
case *types.TypeParam:
|
||||
return h.hashPtr(t.Obj())
|
||||
return h.hashTypeParam(t)
|
||||
}
|
||||
panic(fmt.Sprintf("shallowHash: %T: %v", t, t))
|
||||
}
|
||||
|
Reference in New Issue
Block a user