internal/gcimporter: API for shallow export data
This change adds an internal API for marshalling and
unmarshalling a types.Package to "shallow" export data,
which does not index packages other than the main one.
The import function accepts a function that loads symbols
on demand (e.g. by recursively reading export data for
indirect dependencies).
The CL includes a test that the entire standard
library can be type-checked using shallow data.
Also:
- break dependency on go/ast.
- narrow the name and type of qualifiedObject.
- add (test) dependency on errgroup, and tidy go.mod.
Change-Id: I92d31efd343cf5dd6fca6d7b918a23749e2d1e83
Reviewed-on: https://go-review.googlesource.com/c/tools/+/447737
Run-TryBot: Alan Donovan <adonovan@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/gcimporter/iimport.go b/internal/gcimporter/iimport.go
index 6e4c066..a1c4696 100644
--- a/internal/gcimporter/iimport.go
+++ b/internal/gcimporter/iimport.go
@@ -85,7 +85,7 @@
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
- pkgs, err := iimportCommon(fset, imports, data, false, path)
+ pkgs, err := iimportCommon(fset, imports, data, false, path, nil)
if err != nil {
return 0, nil, err
}
@@ -94,10 +94,10 @@
// IImportBundle imports a set of packages from the serialized package bundle.
func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) {
- return iimportCommon(fset, imports, data, true, "")
+ return iimportCommon(fset, imports, data, true, "", nil)
}
-func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
+func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) {
const currentVersion = iexportVersionCurrent
version := int64(-1)
if !debug {
@@ -147,6 +147,7 @@
p := iimporter{
version: int(version),
ipath: path,
+ insert: insert,
stringData: stringData,
stringCache: make(map[uint64]string),
@@ -187,11 +188,18 @@
} else if pkg.Name() != pkgName {
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
}
+ if i == 0 && !bundle {
+ p.localpkg = pkg
+ }
p.pkgCache[pkgPathOff] = pkg
+ // Read index for package.
nameIndex := make(map[string]uint64)
- for nSyms := r.uint64(); nSyms > 0; nSyms-- {
+ nSyms := r.uint64()
+ // In shallow mode we don't expect an index for other packages.
+ assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil)
+ for ; nSyms > 0; nSyms-- {
name := p.stringAt(r.uint64())
nameIndex[name] = r.uint64()
}
@@ -267,6 +275,9 @@
version int
ipath string
+ localpkg *types.Package
+ insert func(pkg *types.Package, name string) // "shallow" mode only
+
stringData []byte
stringCache map[uint64]string
pkgCache map[uint64]*types.Package
@@ -310,6 +321,13 @@
off, ok := p.pkgIndex[pkg][name]
if !ok {
+ // In "shallow" mode, call back to the application to
+ // find the object and insert it into the package scope.
+ if p.insert != nil {
+ assert(pkg != p.localpkg)
+ p.insert(pkg, name) // "can't fail"
+ return
+ }
errorf("%v.%v not in index", pkg, name)
}