Initialize module and dependencies

This commit is contained in:
dwrz
2026-01-04 20:57:40 +00:00
commit a3b390c008
514 changed files with 310495 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains the remaining vestiges of
// $GOROOT/src/go/internal/gcimporter/bimport.go.
package gcimporter
import (
"fmt"
"go/token"
"go/types"
"sync"
)
func errorf(format string, args ...any) {
panic(fmt.Sprintf(format, args...))
}
const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
// Synthesize a token.Pos
type fakeFileSet struct {
fset *token.FileSet
files map[string]*fileInfo
}
type fileInfo struct {
file *token.File
lastline int
}
const maxlines = 64 * 1024
func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
_ = column // TODO(mdempsky): Make use of column.
// Since we don't know the set of needed file positions, we reserve maxlines
// positions per file. We delay calling token.File.SetLines until all
// positions have been calculated (by way of fakeFileSet.setLines), so that
// we can avoid setting unnecessary lines. See also golang/go#46586.
f := s.files[file]
if f == nil {
f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)}
s.files[file] = f
}
if line > maxlines {
line = 1
}
if line > f.lastline {
f.lastline = line
}
// Return a fake position assuming that f.file consists only of newlines.
return token.Pos(f.file.Base() + line - 1)
}
func (s *fakeFileSet) setLines() {
fakeLinesOnce.Do(func() {
fakeLines = make([]int, maxlines)
for i := range fakeLines {
fakeLines[i] = i
}
})
for _, f := range s.files {
f.file.SetLines(fakeLines[:f.lastline])
}
}
var (
fakeLines []int
fakeLinesOnce sync.Once
)
func chanDir(d int) types.ChanDir {
// tag values must match the constants in cmd/compile/internal/gc/go.go
switch d {
case 1 /* Crecv */ :
return types.RecvOnly
case 2 /* Csend */ :
return types.SendOnly
case 3 /* Cboth */ :
return types.SendRecv
default:
errorf("unexpected channel dir %d", d)
return 0
}
}

View File

@@ -0,0 +1,421 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file should be kept in sync with $GOROOT/src/internal/exportdata/exportdata.go.
// This file also additionally implements FindExportData for gcexportdata.NewReader.
package gcimporter
import (
"bufio"
"bytes"
"errors"
"fmt"
"go/build"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
)
// FindExportData positions the reader r at the beginning of the
// export data section of an underlying cmd/compile created archive
// file by reading from it. The reader must be positioned at the
// start of the file before calling this function.
// This returns the length of the export data in bytes.
//
// This function is needed by [gcexportdata.Read], which must
// accept inputs produced by the last two releases of cmd/compile,
// plus tip.
func FindExportData(r *bufio.Reader) (size int64, err error) {
arsize, err := FindPackageDefinition(r)
if err != nil {
return
}
size = int64(arsize)
objapi, headers, err := ReadObjectHeaders(r)
if err != nil {
return
}
size -= int64(len(objapi))
for _, h := range headers {
size -= int64(len(h))
}
// Check for the binary export data section header "$$B\n".
// TODO(taking): Unify with ReadExportDataHeader so that it stops at the 'u' instead of reading
line, err := r.ReadSlice('\n')
if err != nil {
return
}
hdr := string(line)
if hdr != "$$B\n" {
err = fmt.Errorf("unknown export data header: %q", hdr)
return
}
size -= int64(len(hdr))
// For files with a binary export data header "$$B\n",
// these are always terminated by an end-of-section marker "\n$$\n".
// So the last bytes must always be this constant.
//
// The end-of-section marker is not a part of the export data itself.
// Do not include these in size.
//
// It would be nice to have sanity check that the final bytes after
// the export data are indeed the end-of-section marker. The split
// of gcexportdata.NewReader and gcexportdata.Read make checking this
// ugly so gcimporter gives up enforcing this. The compiler and go/types
// importer do enforce this, which seems good enough.
const endofsection = "\n$$\n"
size -= int64(len(endofsection))
if size < 0 {
err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", arsize, size)
return
}
return
}
// ReadUnified reads the contents of the unified export data from a reader r
// that contains the contents of a GC-created archive file.
//
// On success, the reader will be positioned after the end-of-section marker "\n$$\n".
//
// Supported GC-created archive files have 4 layers of nesting:
// - An archive file containing a package definition file.
// - The package definition file contains headers followed by a data section.
// Headers are lines (≤ 4kb) that do not start with "$$".
// - The data section starts with "$$B\n" followed by export data followed
// by an end of section marker "\n$$\n". (The section start "$$\n" is no
// longer supported.)
// - The export data starts with a format byte ('u') followed by the <data> in
// the given format. (See ReadExportDataHeader for older formats.)
//
// Putting this together, the bytes in a GC-created archive files are expected
// to look like the following.
// See cmd/internal/archive for more details on ar file headers.
//
// | <!arch>\n | ar file signature
// | __.PKGDEF...size...\n | ar header for __.PKGDEF including size.
// | go object <...>\n | objabi header
// | <optional headers>\n | other headers such as build id
// | $$B\n | binary format marker
// | u<data>\n | unified export <data>
// | $$\n | end-of-section marker
// | [optional padding] | padding byte (0x0A) if size is odd
// | [ar file header] | other ar files
// | [ar file data] |
func ReadUnified(r *bufio.Reader) (data []byte, err error) {
// We historically guaranteed headers at the default buffer size (4096) work.
// This ensures we can use ReadSlice throughout.
const minBufferSize = 4096
r = bufio.NewReaderSize(r, minBufferSize)
size, err := FindPackageDefinition(r)
if err != nil {
return
}
n := size
objapi, headers, err := ReadObjectHeaders(r)
if err != nil {
return
}
n -= len(objapi)
for _, h := range headers {
n -= len(h)
}
hdrlen, err := ReadExportDataHeader(r)
if err != nil {
return
}
n -= hdrlen
// size also includes the end of section marker. Remove that many bytes from the end.
const marker = "\n$$\n"
n -= len(marker)
if n < 0 {
err = fmt.Errorf("invalid size (%d) in the archive file: %d bytes remain without section headers (recompile package)", size, n)
return
}
// Read n bytes from buf.
data = make([]byte, n)
_, err = io.ReadFull(r, data)
if err != nil {
return
}
// Check for marker at the end.
var suffix [len(marker)]byte
_, err = io.ReadFull(r, suffix[:])
if err != nil {
return
}
if s := string(suffix[:]); s != marker {
err = fmt.Errorf("read %q instead of end-of-section marker (%q)", s, marker)
return
}
return
}
// FindPackageDefinition positions the reader r at the beginning of a package
// definition file ("__.PKGDEF") within a GC-created archive by reading
// from it, and returns the size of the package definition file in the archive.
//
// The reader must be positioned at the start of the archive file before calling
// this function, and "__.PKGDEF" is assumed to be the first file in the archive.
//
// See cmd/internal/archive for details on the archive format.
func FindPackageDefinition(r *bufio.Reader) (size int, err error) {
// Uses ReadSlice to limit risk of malformed inputs.
// Read first line to make sure this is an object file.
line, err := r.ReadSlice('\n')
if err != nil {
err = fmt.Errorf("can't find export data (%v)", err)
return
}
// Is the first line an archive file signature?
if string(line) != "!<arch>\n" {
err = fmt.Errorf("not the start of an archive file (%q)", line)
return
}
// package export block should be first
size = readArchiveHeader(r, "__.PKGDEF")
if size <= 0 {
err = fmt.Errorf("not a package file")
return
}
return
}
// ReadObjectHeaders reads object headers from the reader. Object headers are
// lines that do not start with an end-of-section marker "$$". The first header
// is the objabi header. On success, the reader will be positioned at the beginning
// of the end-of-section marker.
//
// It returns an error if any header does not fit in r.Size() bytes.
func ReadObjectHeaders(r *bufio.Reader) (objapi string, headers []string, err error) {
// line is a temporary buffer for headers.
// Use bounded reads (ReadSlice, Peek) to limit risk of malformed inputs.
var line []byte
// objapi header should be the first line
if line, err = r.ReadSlice('\n'); err != nil {
err = fmt.Errorf("can't find export data (%v)", err)
return
}
objapi = string(line)
// objapi header begins with "go object ".
if !strings.HasPrefix(objapi, "go object ") {
err = fmt.Errorf("not a go object file: %s", objapi)
return
}
// process remaining object header lines
for {
// check for an end of section marker "$$"
line, err = r.Peek(2)
if err != nil {
return
}
if string(line) == "$$" {
return // stop
}
// read next header
line, err = r.ReadSlice('\n')
if err != nil {
return
}
headers = append(headers, string(line))
}
}
// ReadExportDataHeader reads the export data header and format from r.
// It returns the number of bytes read, or an error if the format is no longer
// supported or it failed to read.
//
// The only currently supported format is binary export data in the
// unified export format.
func ReadExportDataHeader(r *bufio.Reader) (n int, err error) {
// Read export data header.
line, err := r.ReadSlice('\n')
if err != nil {
return
}
hdr := string(line)
switch hdr {
case "$$\n":
err = fmt.Errorf("old textual export format no longer supported (recompile package)")
return
case "$$B\n":
var format byte
format, err = r.ReadByte()
if err != nil {
return
}
// The unified export format starts with a 'u'.
switch format {
case 'u':
default:
// Older no longer supported export formats include:
// indexed export format which started with an 'i'; and
// the older binary export format which started with a 'c',
// 'd', or 'v' (from "version").
err = fmt.Errorf("binary export format %q is no longer supported (recompile package)", format)
return
}
default:
err = fmt.Errorf("unknown export data header: %q", hdr)
return
}
n = len(hdr) + 1 // + 1 is for 'u'
return
}
// FindPkg returns the filename and unique package id for an import
// path based on package information provided by build.Import (using
// the build.Default build.Context). A relative srcDir is interpreted
// relative to the current working directory.
//
// FindPkg is only used in tests within x/tools.
func FindPkg(path, srcDir string) (filename, id string, err error) {
// TODO(taking): Move internal/exportdata.FindPkg into its own file,
// and then this copy into a _test package.
if path == "" {
return "", "", errors.New("path is empty")
}
var noext string
switch {
default:
// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
// Don't require the source files to be present.
if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
srcDir = abs
}
var bp *build.Package
bp, err = build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
if bp.PkgObj == "" {
if bp.Goroot && bp.Dir != "" {
filename, err = lookupGorootExport(bp.Dir)
if err == nil {
_, err = os.Stat(filename)
}
if err == nil {
return filename, bp.ImportPath, nil
}
}
goto notfound
} else {
noext = strings.TrimSuffix(bp.PkgObj, ".a")
}
id = bp.ImportPath
case build.IsLocalImport(path):
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
noext = filepath.Join(srcDir, path)
id = noext
case filepath.IsAbs(path):
// for completeness only - go/build.Import
// does not support absolute imports
// "/x" -> "/x.ext", "/x"
noext = path
id = path
}
if false { // for debugging
if path != id {
fmt.Printf("%s -> %s\n", path, id)
}
}
// try extensions
for _, ext := range pkgExts {
filename = noext + ext
f, statErr := os.Stat(filename)
if statErr == nil && !f.IsDir() {
return filename, id, nil
}
if err == nil {
err = statErr
}
}
notfound:
if err == nil {
return "", path, fmt.Errorf("can't find import: %q", path)
}
return "", path, fmt.Errorf("can't find import: %q: %w", path, err)
}
var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
var exportMap sync.Map // package dir → func() (string, error)
// lookupGorootExport returns the location of the export data
// (normally found in the build cache, but located in GOROOT/pkg
// in prior Go releases) for the package located in pkgDir.
//
// (We use the package's directory instead of its import path
// mainly to simplify handling of the packages in src/vendor
// and cmd/vendor.)
//
// lookupGorootExport is only used in tests within x/tools.
func lookupGorootExport(pkgDir string) (string, error) {
f, ok := exportMap.Load(pkgDir)
if !ok {
var (
listOnce sync.Once
exportPath string
err error
)
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, error) {
listOnce.Do(func() {
cmd := exec.Command(filepath.Join(build.Default.GOROOT, "bin", "go"), "list", "-export", "-f", "{{.Export}}", pkgDir)
cmd.Dir = build.Default.GOROOT
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
var output []byte
output, err = cmd.Output()
if err != nil {
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
err = errors.New(string(ee.Stderr))
}
return
}
exports := strings.Split(string(bytes.TrimSpace(output)), "\n")
if len(exports) != 1 {
err = fmt.Errorf("go list reported %d exports; expected 1", len(exports))
return
}
exportPath = exports[0]
})
return exportPath, err
})
}
return f.(func() (string, error))()
}

View File

@@ -0,0 +1,108 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file is a reduced copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go.
// Package gcimporter provides various functions for reading
// gc-generated object files that can be used to implement the
// Importer interface defined by the Go 1.5 standard library package.
//
// The encoding is deterministic: if the encoder is applied twice to
// the same types.Package data structure, both encodings are equal.
// This property may be important to avoid spurious changes in
// applications such as build systems.
//
// However, the encoder is not necessarily idempotent. Importing an
// exported package may yield a types.Package that, while it
// represents the same set of Go types as the original, may differ in
// the details of its internal representation. Because of these
// differences, re-encoding the imported package may yield a
// different, but equally valid, encoding of the package.
package gcimporter // import "golang.org/x/tools/internal/gcimporter"
import (
"bufio"
"fmt"
"go/token"
"go/types"
"io"
"os"
)
const (
// Enable debug during development: it adds some additional checks, and
// prevents errors from being recovered.
debug = false
// If trace is set, debugging output is printed to std out.
trace = false
)
// Import imports a gc-generated package given its import path and srcDir, adds
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
//
// Import is only used in tests.
func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
var rc io.ReadCloser
var id string
if lookup != nil {
// With custom lookup specified, assume that caller has
// converted path to a canonical import path for use in the map.
if path == "unsafe" {
return types.Unsafe, nil
}
id = path
// No need to re-import if the package was imported completely before.
if pkg = packages[id]; pkg != nil && pkg.Complete() {
return
}
f, err := lookup(path)
if err != nil {
return nil, err
}
rc = f
} else {
var filename string
filename, id, err = FindPkg(path, srcDir)
if filename == "" {
if path == "unsafe" {
return types.Unsafe, nil
}
return nil, err
}
// no need to re-import if the package was imported completely before
if pkg = packages[id]; pkg != nil && pkg.Complete() {
return
}
// open file
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
// add file name to error
err = fmt.Errorf("%s: %v", filename, err)
}
}()
rc = f
}
defer rc.Close()
buf := bufio.NewReader(rc)
data, err := ReadUnified(buf)
if err != nil {
err = fmt.Errorf("import %q: %v", path, err)
return
}
// unified: emitted by cmd/compile since go1.20.
_, pkg, err = UImportData(fset, packages, data, id)
return
}

1603
vendor/golang.org/x/tools/internal/gcimporter/iexport.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1120
vendor/golang.org/x/tools/internal/gcimporter/iimport.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
// Copyright 2024 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 gcimporter
import (
"go/types"
"sync"
)
// predecl is a cache for the predeclared types in types.Universe.
//
// Cache a distinct result based on the runtime value of any.
// The pointer value of the any type varies based on GODEBUG settings.
var predeclMu sync.Mutex
var predecl map[types.Type][]types.Type
func predeclared() []types.Type {
anyt := types.Universe.Lookup("any").Type()
predeclMu.Lock()
defer predeclMu.Unlock()
if pre, ok := predecl[anyt]; ok {
return pre
}
if predecl == nil {
predecl = make(map[types.Type][]types.Type)
}
decls := []types.Type{ // basic types
types.Typ[types.Bool],
types.Typ[types.Int],
types.Typ[types.Int8],
types.Typ[types.Int16],
types.Typ[types.Int32],
types.Typ[types.Int64],
types.Typ[types.Uint],
types.Typ[types.Uint8],
types.Typ[types.Uint16],
types.Typ[types.Uint32],
types.Typ[types.Uint64],
types.Typ[types.Uintptr],
types.Typ[types.Float32],
types.Typ[types.Float64],
types.Typ[types.Complex64],
types.Typ[types.Complex128],
types.Typ[types.String],
// basic type aliases
types.Universe.Lookup("byte").Type(),
types.Universe.Lookup("rune").Type(),
// error
types.Universe.Lookup("error").Type(),
// untyped types
types.Typ[types.UntypedBool],
types.Typ[types.UntypedInt],
types.Typ[types.UntypedRune],
types.Typ[types.UntypedFloat],
types.Typ[types.UntypedComplex],
types.Typ[types.UntypedString],
types.Typ[types.UntypedNil],
// package unsafe
types.Typ[types.UnsafePointer],
// invalid type
types.Typ[types.Invalid], // only appears in packages with errors
// used internally by gc; never used by this package or in .a files
anyType{},
// comparable
types.Universe.Lookup("comparable").Type(),
// any
anyt,
}
predecl[anyt] = decls
return decls
}
type anyType struct{}
func (t anyType) Underlying() types.Type { return t }
func (t anyType) String() string { return "any" }

View File

@@ -0,0 +1,30 @@
// Copyright 2024 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 gcimporter
import (
"bufio"
"io"
"strconv"
"strings"
)
// Copy of $GOROOT/src/cmd/internal/archive.ReadHeader.
func readArchiveHeader(b *bufio.Reader, name string) int {
// architecture-independent object file output
const HeaderSize = 60
var buf [HeaderSize]byte
if _, err := io.ReadFull(b, buf[:]); err != nil {
return -1
}
aname := strings.Trim(string(buf[0:16]), " ")
if !strings.HasPrefix(aname, name) {
return -1
}
asize := strings.Trim(string(buf[48:58]), " ")
i, _ := strconv.Atoi(asize)
return i
}

View File

@@ -0,0 +1,761 @@
// Copyright 2021 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.
// Derived from go/internal/gcimporter/ureader.go
package gcimporter
import (
"fmt"
"go/token"
"go/types"
"sort"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/pkgbits"
"golang.org/x/tools/internal/typesinternal"
)
// A pkgReader holds the shared state for reading a unified IR package
// description.
type pkgReader struct {
pkgbits.PkgDecoder
fake fakeFileSet
ctxt *types.Context
imports map[string]*types.Package // previously imported packages, indexed by path
aliases bool // create types.Alias nodes
// lazily initialized arrays corresponding to the unified IR
// PosBase, Pkg, and Type sections, respectively.
posBases []string // position bases (i.e., file names)
pkgs []*types.Package
typs []types.Type
// laterFns holds functions that need to be invoked at the end of
// import reading.
laterFns []func()
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
laterFors map[types.Type]int
// ifaces holds a list of constructed Interfaces, which need to have
// Complete called after importing is done.
ifaces []*types.Interface
}
// later adds a function to be invoked at the end of import reading.
func (pr *pkgReader) later(fn func()) {
pr.laterFns = append(pr.laterFns, fn)
}
// See cmd/compile/internal/noder.derivedInfo.
type derivedInfo struct {
idx pkgbits.Index
}
// See cmd/compile/internal/noder.typeInfo.
type typeInfo struct {
idx pkgbits.Index
derived bool
}
func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
if !debug {
defer func() {
if x := recover(); x != nil {
err = fmt.Errorf("internal error in importing %q (%v); please report an issue", path, x)
}
}()
}
s := string(data)
input := pkgbits.NewPkgDecoder(path, s)
pkg = readUnifiedPackage(fset, nil, imports, input)
return
}
// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing.
func (pr *pkgReader) laterFor(t types.Type, fn func()) {
if pr.laterFors == nil {
pr.laterFors = make(map[types.Type]int)
}
pr.laterFors[t] = len(pr.laterFns)
pr.laterFns = append(pr.laterFns, fn)
}
// readUnifiedPackage reads a package description from the given
// unified IR export data decoder.
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
pr := pkgReader{
PkgDecoder: input,
fake: fakeFileSet{
fset: fset,
files: make(map[string]*fileInfo),
},
ctxt: ctxt,
imports: imports,
aliases: aliases.Enabled(),
posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
typs: make([]types.Type, input.NumElems(pkgbits.RelocType)),
}
defer pr.fake.setLines()
r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
pkg := r.pkg()
if r.Version().Has(pkgbits.HasInit) {
r.Bool()
}
for i, n := 0, r.Len(); i < n; i++ {
// As if r.obj(), but avoiding the Scope.Lookup call,
// to avoid eager loading of imports.
r.Sync(pkgbits.SyncObject)
if r.Version().Has(pkgbits.DerivedFuncInstance) {
assert(!r.Bool())
}
r.p.objIdx(r.Reloc(pkgbits.RelocObj))
assert(r.Len() == 0)
}
r.Sync(pkgbits.SyncEOF)
for _, fn := range pr.laterFns {
fn()
}
for _, iface := range pr.ifaces {
iface.Complete()
}
// Imports() of pkg are all of the transitive packages that were loaded.
var imps []*types.Package
for _, imp := range pr.pkgs {
if imp != nil && imp != pkg {
imps = append(imps, imp)
}
}
sort.Sort(byPath(imps))
pkg.SetImports(imps)
pkg.MarkComplete()
return pkg
}
// A reader holds the state for reading a single unified IR element
// within a package.
type reader struct {
pkgbits.Decoder
p *pkgReader
dict *readerDict
}
// A readerDict holds the state for type parameters that parameterize
// the current unified IR element.
type readerDict struct {
// bounds is a slice of typeInfos corresponding to the underlying
// bounds of the element's type parameters.
bounds []typeInfo
// tparams is a slice of the constructed TypeParams for the element.
tparams []*types.TypeParam
// derived is a slice of types derived from tparams, which may be
// instantiated while reading the current element.
derived []derivedInfo
derivedTypes []types.Type // lazily instantiated from derived
}
func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
return &reader{
Decoder: pr.NewDecoder(k, idx, marker),
p: pr,
}
}
func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
return &reader{
Decoder: pr.TempDecoder(k, idx, marker),
p: pr,
}
}
func (pr *pkgReader) retireReader(r *reader) {
pr.RetireDecoder(&r.Decoder)
}
// @@@ Positions
func (r *reader) pos() token.Pos {
r.Sync(pkgbits.SyncPos)
if !r.Bool() {
return token.NoPos
}
// TODO(mdempsky): Delta encoding.
posBase := r.posBase()
line := r.Uint()
col := r.Uint()
return r.p.fake.pos(posBase, int(line), int(col))
}
func (r *reader) posBase() string {
return r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))
}
func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
if b := pr.posBases[idx]; b != "" {
return b
}
var filename string
{
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
// Within types2, position bases have a lot more details (e.g.,
// keeping track of where //line directives appeared exactly).
//
// For go/types, we just track the file name.
filename = r.String()
if r.Bool() { // file base
// Was: "b = token.NewTrimmedFileBase(filename, true)"
} else { // line base
pos := r.pos()
line := r.Uint()
col := r.Uint()
// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
_, _, _ = pos, line, col
}
pr.retireReader(r)
}
b := filename
pr.posBases[idx] = b
return b
}
// @@@ Packages
func (r *reader) pkg() *types.Package {
r.Sync(pkgbits.SyncPkg)
return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg))
}
func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package {
// TODO(mdempsky): Consider using some non-nil pointer to indicate
// the universe scope, so we don't need to keep re-reading it.
if pkg := pr.pkgs[idx]; pkg != nil {
return pkg
}
pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg()
pr.pkgs[idx] = pkg
return pkg
}
func (r *reader) doPkg() *types.Package {
path := r.String()
switch path {
// cmd/compile emits path="main" for main packages because
// that's the linker symbol prefix it used; but we need
// the package's path as it would be reported by go list,
// hence "main" below.
// See test at go/packages.TestMainPackagePathInModeTypes.
case "", "main":
path = r.p.PkgPath()
case "builtin":
return nil // universe
case "unsafe":
return types.Unsafe
}
if pkg := r.p.imports[path]; pkg != nil {
return pkg
}
name := r.String()
pkg := types.NewPackage(path, name)
r.p.imports[path] = pkg
return pkg
}
// @@@ Types
func (r *reader) typ() types.Type {
return r.p.typIdx(r.typInfo(), r.dict)
}
func (r *reader) typInfo() typeInfo {
r.Sync(pkgbits.SyncType)
if r.Bool() {
return typeInfo{idx: pkgbits.Index(r.Len()), derived: true}
}
return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false}
}
func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type {
idx := info.idx
var where *types.Type
if info.derived {
where = &dict.derivedTypes[idx]
idx = dict.derived[idx].idx
} else {
where = &pr.typs[idx]
}
if typ := *where; typ != nil {
return typ
}
var typ types.Type
{
r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx)
r.dict = dict
typ = r.doTyp()
assert(typ != nil)
pr.retireReader(r)
}
// See comment in pkgReader.typIdx explaining how this happens.
if prev := *where; prev != nil {
return prev
}
*where = typ
return typ
}
func (r *reader) doTyp() (res types.Type) {
switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {
default:
errorf("unhandled type tag: %v", tag)
panic("unreachable")
case pkgbits.TypeBasic:
return types.Typ[r.Len()]
case pkgbits.TypeNamed:
obj, targs := r.obj()
name := obj.(*types.TypeName)
if len(targs) != 0 {
t, _ := types.Instantiate(r.p.ctxt, name.Type(), targs, false)
return t
}
return name.Type()
case pkgbits.TypeTypeParam:
return r.dict.tparams[r.Len()]
case pkgbits.TypeArray:
len := int64(r.Uint64())
return types.NewArray(r.typ(), len)
case pkgbits.TypeChan:
dir := types.ChanDir(r.Len())
return types.NewChan(dir, r.typ())
case pkgbits.TypeMap:
return types.NewMap(r.typ(), r.typ())
case pkgbits.TypePointer:
return types.NewPointer(r.typ())
case pkgbits.TypeSignature:
return r.signature(nil, nil, nil)
case pkgbits.TypeSlice:
return types.NewSlice(r.typ())
case pkgbits.TypeStruct:
return r.structType()
case pkgbits.TypeInterface:
return r.interfaceType()
case pkgbits.TypeUnion:
return r.unionType()
}
}
func (r *reader) structType() *types.Struct {
fields := make([]*types.Var, r.Len())
var tags []string
for i := range fields {
pos := r.pos()
pkg, name := r.selector()
ftyp := r.typ()
tag := r.String()
embedded := r.Bool()
fields[i] = types.NewField(pos, pkg, name, ftyp, embedded)
if tag != "" {
for len(tags) < i {
tags = append(tags, "")
}
tags = append(tags, tag)
}
}
return types.NewStruct(fields, tags)
}
func (r *reader) unionType() *types.Union {
terms := make([]*types.Term, r.Len())
for i := range terms {
terms[i] = types.NewTerm(r.Bool(), r.typ())
}
return types.NewUnion(terms)
}
func (r *reader) interfaceType() *types.Interface {
methods := make([]*types.Func, r.Len())
embeddeds := make([]types.Type, r.Len())
implicit := len(methods) == 0 && len(embeddeds) == 1 && r.Bool()
for i := range methods {
pos := r.pos()
pkg, name := r.selector()
mtyp := r.signature(nil, nil, nil)
methods[i] = types.NewFunc(pos, pkg, name, mtyp)
}
for i := range embeddeds {
embeddeds[i] = r.typ()
}
iface := types.NewInterfaceType(methods, embeddeds)
if implicit {
iface.MarkImplicit()
}
// We need to call iface.Complete(), but if there are any embedded
// defined types, then we may not have set their underlying
// interface type yet. So we need to defer calling Complete until
// after we've called SetUnderlying everywhere.
//
// TODO(mdempsky): After CL 424876 lands, it should be safe to call
// iface.Complete() immediately.
r.p.ifaces = append(r.p.ifaces, iface)
return iface
}
func (r *reader) signature(recv *types.Var, rtparams, tparams []*types.TypeParam) *types.Signature {
r.Sync(pkgbits.SyncSignature)
params := r.params()
results := r.params()
variadic := r.Bool()
return types.NewSignatureType(recv, rtparams, tparams, params, results, variadic)
}
func (r *reader) params() *types.Tuple {
r.Sync(pkgbits.SyncParams)
params := make([]*types.Var, r.Len())
for i := range params {
params[i] = r.param()
}
return types.NewTuple(params...)
}
func (r *reader) param() *types.Var {
r.Sync(pkgbits.SyncParam)
pos := r.pos()
pkg, name := r.localIdent()
typ := r.typ()
return types.NewParam(pos, pkg, name, typ)
}
// @@@ Objects
func (r *reader) obj() (types.Object, []types.Type) {
r.Sync(pkgbits.SyncObject)
if r.Version().Has(pkgbits.DerivedFuncInstance) {
assert(!r.Bool())
}
pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj))
obj := pkgScope(pkg).Lookup(name)
targs := make([]types.Type, r.Len())
for i := range targs {
targs[i] = r.typ()
}
return obj, targs
}
func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
var objPkg *types.Package
var objName string
var tag pkgbits.CodeObj
{
rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
objPkg, objName = rname.qualifiedIdent()
assert(objName != "")
tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
pr.retireReader(rname)
}
if tag == pkgbits.ObjStub {
assert(objPkg == nil || objPkg == types.Unsafe)
return objPkg, objName
}
// Ignore local types promoted to global scope (#55110).
if _, suffix := splitVargenSuffix(objName); suffix != "" {
return objPkg, objName
}
if objPkg.Scope().Lookup(objName) == nil {
dict := pr.objDictIdx(idx)
r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1)
r.dict = dict
declare := func(obj types.Object) {
objPkg.Scope().Insert(obj)
}
switch tag {
default:
panic("weird")
case pkgbits.ObjAlias:
pos := r.pos()
var tparams []*types.TypeParam
if r.Version().Has(pkgbits.AliasTypeParamNames) {
tparams = r.typeParamNames()
}
typ := r.typ()
declare(aliases.NewAlias(r.p.aliases, pos, objPkg, objName, typ, tparams))
case pkgbits.ObjConst:
pos := r.pos()
typ := r.typ()
val := r.Value()
declare(types.NewConst(pos, objPkg, objName, typ, val))
case pkgbits.ObjFunc:
pos := r.pos()
tparams := r.typeParamNames()
sig := r.signature(nil, nil, tparams)
declare(types.NewFunc(pos, objPkg, objName, sig))
case pkgbits.ObjType:
pos := r.pos()
obj := types.NewTypeName(pos, objPkg, objName, nil)
named := types.NewNamed(obj, nil, nil)
declare(obj)
named.SetTypeParams(r.typeParamNames())
setUnderlying := func(underlying types.Type) {
// If the underlying type is an interface, we need to
// duplicate its methods so we can replace the receiver
// parameter's type (#49906).
if iface, ok := types.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
methods := make([]*types.Func, iface.NumExplicitMethods())
for i := range methods {
fn := iface.ExplicitMethod(i)
sig := fn.Type().(*types.Signature)
recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
typesinternal.SetVarKind(recv, typesinternal.RecvVar)
methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignatureType(recv, nil, nil, sig.Params(), sig.Results(), sig.Variadic()))
}
embeds := make([]types.Type, iface.NumEmbeddeds())
for i := range embeds {
embeds[i] = iface.EmbeddedType(i)
}
newIface := types.NewInterfaceType(methods, embeds)
r.p.ifaces = append(r.p.ifaces, newIface)
underlying = newIface
}
named.SetUnderlying(underlying)
}
// Since go.dev/cl/455279, we can assume rhs.Underlying() will
// always be non-nil. However, to temporarily support users of
// older snapshot releases, we continue to fallback to the old
// behavior for now.
//
// TODO(mdempsky): Remove fallback code and simplify after
// allowing time for snapshot users to upgrade.
rhs := r.typ()
if underlying := rhs.Underlying(); underlying != nil {
setUnderlying(underlying)
} else {
pk := r.p
pk.laterFor(named, func() {
// First be sure that the rhs is initialized, if it needs to be initialized.
delete(pk.laterFors, named) // prevent cycles
if i, ok := pk.laterFors[rhs]; ok {
f := pk.laterFns[i]
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
f() // initialize RHS
}
setUnderlying(rhs.Underlying())
})
}
for i, n := 0, r.Len(); i < n; i++ {
named.AddMethod(r.method())
}
case pkgbits.ObjVar:
pos := r.pos()
typ := r.typ()
v := types.NewVar(pos, objPkg, objName, typ)
typesinternal.SetVarKind(v, typesinternal.PackageVar)
declare(v)
}
}
return objPkg, objName
}
func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
var dict readerDict
{
r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
if implicits := r.Len(); implicits != 0 {
errorf("unexpected object with %v implicit type parameter(s)", implicits)
}
dict.bounds = make([]typeInfo, r.Len())
for i := range dict.bounds {
dict.bounds[i] = r.typInfo()
}
dict.derived = make([]derivedInfo, r.Len())
dict.derivedTypes = make([]types.Type, len(dict.derived))
for i := range dict.derived {
dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.RelocType)}
if r.Version().Has(pkgbits.DerivedInfoNeeded) {
assert(!r.Bool())
}
}
pr.retireReader(r)
}
// function references follow, but reader doesn't need those
return &dict
}
func (r *reader) typeParamNames() []*types.TypeParam {
r.Sync(pkgbits.SyncTypeParamNames)
// Note: This code assumes it only processes objects without
// implement type parameters. This is currently fine, because
// reader is only used to read in exported declarations, which are
// always package scoped.
if len(r.dict.bounds) == 0 {
return nil
}
// Careful: Type parameter lists may have cycles. To allow for this,
// we construct the type parameter list in two passes: first we
// create all the TypeNames and TypeParams, then we construct and
// set the bound type.
r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
for i := range r.dict.bounds {
pos := r.pos()
pkg, name := r.localIdent()
tname := types.NewTypeName(pos, pkg, name, nil)
r.dict.tparams[i] = types.NewTypeParam(tname, nil)
}
typs := make([]types.Type, len(r.dict.bounds))
for i, bound := range r.dict.bounds {
typs[i] = r.p.typIdx(bound, r.dict)
}
// TODO(mdempsky): This is subtle, elaborate further.
//
// We have to save tparams outside of the closure, because
// typeParamNames() can be called multiple times with the same
// dictionary instance.
//
// Also, this needs to happen later to make sure SetUnderlying has
// been called.
//
// TODO(mdempsky): Is it safe to have a single "later" slice or do
// we need to have multiple passes? See comments on CL 386002 and
// go.dev/issue/52104.
tparams := r.dict.tparams
r.p.later(func() {
for i, typ := range typs {
tparams[i].SetConstraint(typ)
}
})
return r.dict.tparams
}
func (r *reader) method() *types.Func {
r.Sync(pkgbits.SyncMethod)
pos := r.pos()
pkg, name := r.selector()
rparams := r.typeParamNames()
sig := r.signature(r.param(), rparams, nil)
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
return types.NewFunc(pos, pkg, name, sig)
}
func (r *reader) qualifiedIdent() (*types.Package, string) { return r.ident(pkgbits.SyncSym) }
func (r *reader) localIdent() (*types.Package, string) { return r.ident(pkgbits.SyncLocalIdent) }
func (r *reader) selector() (*types.Package, string) { return r.ident(pkgbits.SyncSelector) }
func (r *reader) ident(marker pkgbits.SyncMarker) (*types.Package, string) {
r.Sync(marker)
return r.pkg(), r.String()
}
// pkgScope returns pkg.Scope().
// If pkg is nil, it returns types.Universe instead.
//
// TODO(mdempsky): Remove after x/tools can depend on Go 1.19.
func pkgScope(pkg *types.Package) *types.Scope {
if pkg != nil {
return pkg.Scope()
}
return types.Universe
}
// See cmd/compile/internal/types.SplitVargenSuffix.
func splitVargenSuffix(name string) (base, suffix string) {
i := len(name)
for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
i--
}
const dot = "·"
if i >= len(dot) && name[i-len(dot):i] == dot {
i -= len(dot)
return name[:i], name[i:]
}
return name, ""
}