aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/load/pkg.go
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2020-04-08 17:39:57 -0400
committerFilippo Valsorda <filippo@golang.org>2020-04-08 17:48:41 -0400
commite067ce5225300a87ae6fe3c48e73102f6fa9368d (patch)
tree3b9335e0023a30f50c3261545019a2f9bb1bab97 /src/cmd/go/internal/load/pkg.go
parent79284c28734bf854f44106835b5578ead75eb547 (diff)
parent9baafabac9a84813a336f068862207d2bb06d255 (diff)
downloadgo-e067ce5225300a87ae6fe3c48e73102f6fa9368d.tar.gz
go-e067ce5225300a87ae6fe3c48e73102f6fa9368d.zip
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: I2dcec316fd08d91db4183fb9d3b9afde65cc248f
Diffstat (limited to 'src/cmd/go/internal/load/pkg.go')
-rw-r--r--src/cmd/go/internal/load/pkg.go278
1 files changed, 169 insertions, 109 deletions
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index b7ba884da6..4bfc291fe0 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"go/build"
+ "go/scanner"
"go/token"
"io/ioutil"
"os"
@@ -186,20 +187,17 @@ type PackageInternal struct {
Gccgoflags []string // -gccgoflags for this package
}
+// A NoGoError indicates that no Go files for the package were applicable to the
+// build for that package.
+//
+// That may be because there were no files whatsoever, or because all files were
+// excluded, or because all non-excluded files were test sources.
type NoGoError struct {
Package *Package
}
func (e *NoGoError) Error() string {
- // Count files beginning with _ and ., which we will pretend don't exist at all.
- dummy := 0
- for _, name := range e.Package.IgnoredGoFiles {
- if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
- dummy++
- }
- }
-
- if len(e.Package.IgnoredGoFiles) > dummy {
+ if len(e.Package.constraintIgnoredGoFiles()) > 0 {
// Go files exist, but they were ignored due to build constraints.
return "build constraints exclude all Go files in " + e.Package.Dir
}
@@ -212,6 +210,23 @@ func (e *NoGoError) Error() string {
return "no Go files in " + e.Package.Dir
}
+// rewordError returns a version of err with trivial layers removed and
+// (possibly-wrapped) instances of build.NoGoError replaced with load.NoGoError,
+// which more clearly distinguishes sub-cases.
+func (p *Package) rewordError(err error) error {
+ if mErr, ok := err.(*search.MatchError); ok && mErr.Match.IsLiteral() {
+ err = mErr.Err
+ }
+ var noGo *build.NoGoError
+ if errors.As(err, &noGo) {
+ if p.Dir == "" && noGo.Dir != "" {
+ p.Dir = noGo.Dir
+ }
+ err = &NoGoError{Package: p}
+ }
+ return err
+}
+
// Resolve returns the resolved version of imports,
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
// The imports in p.TestImports and p.XTestImports are not recursively
@@ -309,19 +324,16 @@ func (p *Package) copyBuild(pp *build.Package) {
// A PackageError describes an error loading information about a package.
type PackageError struct {
- ImportStack []string // shortest path from package named on command line to this one
- Pos string // position of error
- Err error // the error itself
- IsImportCycle bool // the error is an import cycle
- Hard bool // whether the error is soft or hard; soft errors are ignored in some places
+ ImportStack []string // shortest path from package named on command line to this one
+ Pos string // position of error
+ Err error // the error itself
+ IsImportCycle bool // the error is an import cycle
+ Hard bool // whether the error is soft or hard; soft errors are ignored in some places
+ alwaysPrintStack bool // whether to always print the ImportStack
}
func (p *PackageError) Error() string {
- // Import cycles deserve special treatment.
- if p.IsImportCycle {
- return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
- }
- if p.Pos != "" {
+ if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
// Omit import stack. The full path to the file where the error
// is the most important thing.
return p.Pos + ": " + p.Err.Error()
@@ -333,17 +345,18 @@ func (p *PackageError) Error() string {
// last path on the stack, we don't omit the path. An error like
// "package A imports B: error loading C caused by B" would not be clearer
// if "imports B" were omitted.
- stack := p.ImportStack
- var ierr ImportPathError
- if len(stack) > 0 && errors.As(p.Err, &ierr) && ierr.ImportPath() == stack[len(stack)-1] {
- stack = stack[:len(stack)-1]
- }
- if len(stack) == 0 {
+ if len(p.ImportStack) == 0 {
return p.Err.Error()
}
- return "package " + strings.Join(stack, "\n\timports ") + ": " + p.Err.Error()
+ var optpos string
+ if p.Pos != "" {
+ optpos = "\n\t" + p.Pos
+ }
+ return "package " + strings.Join(p.ImportStack, "\n\timports ") + optpos + ": " + p.Err.Error()
}
+func (p *PackageError) Unwrap() error { return p.Err }
+
// PackageError implements MarshalJSON so that Err is marshaled as a string
// and non-essential fields are omitted.
func (p *PackageError) MarshalJSON() ([]byte, error) {
@@ -541,9 +554,6 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
panic("LoadImport called with empty package path")
}
- stk.Push(path)
- defer stk.Pop()
-
var parentPath, parentRoot string
parentIsStd := false
if parent != nil {
@@ -556,6 +566,11 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
pre.preloadImports(bp.Imports, bp)
}
if bp == nil {
+ if importErr, ok := err.(ImportPathError); !ok || importErr.ImportPath() != path {
+ // Only add path to the error's import stack if it's not already present on the error.
+ stk.Push(path)
+ defer stk.Pop()
+ }
return &Package{
PackagePublic: PackagePublic{
ImportPath: path,
@@ -570,7 +585,9 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
importPath := bp.ImportPath
p := packageCache[importPath]
if p != nil {
+ stk.Push(path)
p = reusePackage(p, stk)
+ stk.Pop()
} else {
p = new(Package)
p.Internal.Local = build.IsLocalImport(path)
@@ -580,17 +597,21 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
// Load package.
// loadPackageData may return bp != nil even if an error occurs,
// in order to return partial information.
- p.load(stk, bp, err)
- if p.Error != nil && p.Error.Pos == "" {
+ p.load(path, stk, bp, err)
+ // Add position information unless this is a NoGoError or an ImportCycle error.
+ // Import cycles deserve special treatment.
+ var g *build.NoGoError
+ if p.Error != nil && p.Error.Pos == "" && !errors.As(err, &g) && !p.Error.IsImportCycle {
p = setErrorPos(p, importPos)
}
if !cfg.ModulesEnabled && path != cleanImport(path) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: fmt.Errorf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)),
+ Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
}
p.Incomplete = true
+ setErrorPos(p, importPos)
}
}
@@ -599,7 +620,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
return setErrorPos(perr, importPos)
}
if mode&ResolveImport != 0 {
- if perr := disallowVendor(srcDir, path, p, stk); perr != p {
+ if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p {
return setErrorPos(perr, importPos)
}
}
@@ -676,6 +697,11 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
// we create from the full directory to the package.
// Otherwise it is the usual import path.
// For vendored imports, it is the expanded form.
+ //
+ // Note that when modules are enabled, local import paths are normally
+ // canonicalized by modload.ImportPaths before now. However, if there's an
+ // error resolving a local path, it will be returned untransformed
+ // so that 'go list -e' reports something useful.
importKey := importSpec{
path: path,
parentPath: parentPath,
@@ -1232,7 +1258,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
// as if it were generated into the testing directory tree
// (it's actually in a temporary directory outside any Go tree).
// This cleans up a former kludge in passing functionality to the testing package.
- if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
+ if str.HasPathPrefix(p.ImportPath, "testing/internal") && importerPath == "testmain" {
return p
}
@@ -1248,11 +1274,10 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
return p
}
- // The stack includes p.ImportPath.
- // If that's the only thing on the stack, we started
+ // importerPath is empty: we started
// with a name given on the command line, not an
// import. Anything listed on the command line is fine.
- if len(*stk) == 1 {
+ if importerPath == "" {
return p
}
@@ -1301,8 +1326,9 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
// Internal is present, and srcDir is outside parent's tree. Not allowed.
perr := *p
perr.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"),
+ alwaysPrintStack: true,
+ ImportStack: stk.Copy(),
+ Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"),
}
perr.Incomplete = true
return &perr
@@ -1330,16 +1356,15 @@ func findInternal(path string) (index int, ok bool) {
// disallowVendor checks that srcDir is allowed to import p as path.
// If the import is allowed, disallowVendor returns the original package p.
// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *Package {
- // The stack includes p.ImportPath.
- // If that's the only thing on the stack, we started
+func disallowVendor(srcDir string, path string, importerPath string, p *Package, stk *ImportStack) *Package {
+ // If the importerPath is empty, we started
// with a name given on the command line, not an
// import. Anything listed on the command line is fine.
- if len(*stk) == 1 {
+ if importerPath == "" {
return p
}
- if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
+ if perr := disallowVendorVisibility(srcDir, p, importerPath, stk); perr != p {
return perr
}
@@ -1362,12 +1387,12 @@ func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *P
// is not subject to the rules, only subdirectories of vendor.
// This allows people to have packages and commands named vendor,
// for maximal compatibility with existing source trees.
-func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package {
- // The stack includes p.ImportPath.
- // If that's the only thing on the stack, we started
+func disallowVendorVisibility(srcDir string, p *Package, importerPath string, stk *ImportStack) *Package {
+ // The stack does not include p.ImportPath.
+ // If there's nothing on the stack, we started
// with a name given on the command line, not an
// import. Anything listed on the command line is fine.
- if len(*stk) == 1 {
+ if importerPath == "" {
return p
}
@@ -1511,7 +1536,8 @@ func (p *Package) DefaultExecName() string {
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
-func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
+// stk contains the import stack, not including path itself.
+func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err error) {
p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to.
@@ -1520,17 +1546,35 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.Internal.LocalPrefix = dirToImportPath(p.Dir)
}
- if err != nil {
- if _, ok := err.(*build.NoGoError); ok {
- err = &NoGoError{Package: p}
+ // setError sets p.Error if it hasn't already been set. We may proceed
+ // after encountering some errors so that 'go list -e' has more complete
+ // output. If there's more than one error, we should report the first.
+ setError := func(err error) {
+ if p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.Copy(),
+ Err: err,
+ }
}
+ }
+
+ if err != nil {
p.Incomplete = true
- err = base.ExpandScanner(err)
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: err,
+ // Report path in error stack unless err is an ImportPathError with path already set.
+ pushed := false
+ if e, ok := err.(ImportPathError); !ok || e.ImportPath() != path {
+ stk.Push(path)
+ pushed = true // Remember to pop after setError.
}
- return
+ setError(base.ExpandScanner(p.rewordError(err)))
+ if pushed {
+ stk.Pop()
+ }
+ if _, isScanErr := err.(scanner.ErrorList); !isScanErr {
+ return
+ }
+ // Fall through if there was an error parsing a file. 'go list -e' should
+ // still report imports and other metadata.
}
useBindir := p.Name == "main"
@@ -1546,7 +1590,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
if InstallTargetDir(p) == StalePath {
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
- p.Error = &PackageError{Err: e}
+ setError(e)
return
}
elem := p.DefaultExecName()
@@ -1585,7 +1629,10 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.Target = ""
} else {
p.Target = p.Internal.Build.PkgObj
- if cfg.BuildLinkshared {
+ if cfg.BuildLinkshared && p.Target != "" {
+ // TODO(bcmills): The reliance on p.Target implies that -linkshared does
+ // not work for any package that lacks a Target — such as a non-main
+ // package in module mode. We should probably fix that.
shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
shlib, err := ioutil.ReadFile(shlibnamefile)
if err != nil && !os.IsNotExist(err) {
@@ -1649,6 +1696,23 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
}
}
+ // Check for case-insensitive collisions of import paths.
+ fold := str.ToFold(p.ImportPath)
+ if other := foldPath[fold]; other == "" {
+ foldPath[fold] = p.ImportPath
+ } else if other != p.ImportPath {
+ setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other))
+ return
+ }
+
+ if !SafeArg(p.ImportPath) {
+ setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath))
+ return
+ }
+
+ stk.Push(path)
+ defer stk.Pop()
+
// Check for case-insensitive collision of input files.
// To avoid problems on case-insensitive files, we reject any package
// where two different input files have equal names under a case-insensitive
@@ -1656,10 +1720,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
inputs := p.AllFiles()
f1, f2 := str.FoldDup(inputs)
if f1 != "" {
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2),
- }
+ setError(fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2))
return
}
@@ -1672,25 +1733,12 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// so we shouldn't see any _cgo_ files anyway, but just be safe.
for _, file := range inputs {
if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: fmt.Errorf("invalid input file name %q", file),
- }
+ setError(fmt.Errorf("invalid input file name %q", file))
return
}
}
if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: fmt.Errorf("invalid input directory name %q", name),
- }
- return
- }
- if !SafeArg(p.ImportPath) {
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath),
- }
+ setError(fmt.Errorf("invalid input directory name %q", name))
return
}
@@ -1735,13 +1783,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// code; see issue #16050).
}
- setError := func(err error) {
- p.Error = &PackageError{
- ImportStack: stk.Copy(),
- Err: err,
- }
- }
-
// The gc toolchain only permits C source files with cgo or SWIG.
if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
setError(fmt.Errorf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
@@ -1763,15 +1804,6 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
return
}
- // Check for case-insensitive collisions of import paths.
- fold := str.ToFold(p.ImportPath)
- if other := foldPath[fold]; other == "" {
- foldPath[fold] = p.ImportPath
- } else if other != p.ImportPath {
- setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other))
- return
- }
-
if cfg.ModulesEnabled && p.Error == nil {
mainPath := p.ImportPath
if p.Internal.CmdlineFiles {
@@ -1874,7 +1906,9 @@ func externalLinkingForced(p *Package) bool {
// Some targets must use external linking even inside GOROOT.
switch cfg.BuildContext.GOOS {
case "android":
- return true
+ if cfg.BuildContext.GOARCH != "arm64" {
+ return true
+ }
case "darwin":
switch cfg.BuildContext.GOARCH {
case "arm", "arm64":
@@ -1935,13 +1969,22 @@ func (p *Package) InternalXGoFiles() []string {
// using absolute paths. "Possibly relevant" means that files are not excluded
// due to build tags, but files with names beginning with . or _ are still excluded.
func (p *Package) InternalAllGoFiles() []string {
- var extra []string
+ return p.mkAbs(str.StringList(p.constraintIgnoredGoFiles(), p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
+}
+
+// constraintIgnoredGoFiles returns the list of Go files ignored for reasons
+// other than having a name beginning with '.' or '_'.
+func (p *Package) constraintIgnoredGoFiles() []string {
+ if len(p.IgnoredGoFiles) == 0 {
+ return nil
+ }
+ files := make([]string, 0, len(p.IgnoredGoFiles))
for _, f := range p.IgnoredGoFiles {
- if f != "" && f[0] != '.' || f[0] != '_' {
- extra = append(extra, f)
+ if f != "" && f[0] != '.' && f[0] != '_' {
+ files = append(files, f)
}
}
- return p.mkAbs(str.StringList(extra, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
+ return files
}
// usesSwig reports whether the package needs to run SWIG.
@@ -2035,7 +2078,7 @@ func Packages(args []string) []*Package {
var pkgs []*Package
for _, pkg := range PackagesAndErrors(args) {
if pkg.Error != nil {
- base.Errorf("can't load package: %s", pkg.Error)
+ base.Errorf("%v", pkg.Error)
continue
}
pkgs = append(pkgs, pkg)
@@ -2075,13 +2118,13 @@ func PackagesAndErrors(patterns []string) []*Package {
for _, m := range matches {
for _, pkg := range m.Pkgs {
if pkg == "" {
- panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern))
+ panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern()))
}
p := loadImport(pre, pkg, base.Cwd, nil, &stk, nil, 0)
- p.Match = append(p.Match, m.Pattern)
+ p.Match = append(p.Match, m.Pattern())
p.Internal.CmdlinePkg = true
- if m.Literal {
- // Note: do not set = m.Literal unconditionally
+ if m.IsLiteral() {
+ // Note: do not set = m.IsLiteral unconditionally
// because maybe we'll see p matching both
// a literal and also a non-literal pattern.
p.Internal.CmdlinePkgLiteral = true
@@ -2092,6 +2135,25 @@ func PackagesAndErrors(patterns []string) []*Package {
seenPkg[p] = true
pkgs = append(pkgs, p)
}
+
+ if len(m.Errs) > 0 {
+ // In addition to any packages that were actually resolved from the
+ // pattern, there was some error in resolving the pattern itself.
+ // Report it as a synthetic package.
+ p := new(Package)
+ p.ImportPath = m.Pattern()
+ p.Error = &PackageError{
+ ImportStack: nil, // The error arose from a pattern, not an import.
+ Err: p.rewordError(m.Errs[0]),
+ }
+ p.Incomplete = true
+ p.Match = append(p.Match, m.Pattern())
+ p.Internal.CmdlinePkg = true
+ if m.IsLiteral() {
+ p.Internal.CmdlinePkgLiteral = true
+ }
+ pkgs = append(pkgs, p)
+ }
}
// Now that CmdlinePkg is set correctly,
@@ -2127,7 +2189,7 @@ func PackagesForBuild(args []string) []*Package {
printed := map[*PackageError]bool{}
for _, pkg := range pkgs {
if pkg.Error != nil {
- base.Errorf("can't load package: %s", pkg.Error)
+ base.Errorf("%v", pkg.Error)
printed[pkg.Error] = true
}
for _, err := range pkg.DepsErrors {
@@ -2137,7 +2199,7 @@ func PackagesForBuild(args []string) []*Package {
// Only print each once.
if !printed[err] {
printed[err] = true
- base.Errorf("%s", err)
+ base.Errorf("%v", err)
}
}
}
@@ -2229,9 +2291,7 @@ func GoFilesPackage(gofiles []string) *Package {
pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
- stk.Push("main")
- pkg.load(&stk, bp, err)
- stk.Pop()
+ pkg.load("command-line-arguments", &stk, bp, err)
pkg.Internal.LocalPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""