Skip to content

Commit 5a61de3

Browse files
author
Bryan C. Mills
committed
cmd/go: rationalize errors in internal/load and internal/modload
This change is a non-minimal fix for #32917, but incidentally fixes several other bugs and makes the error messages much more ergonomic. Updates #32917 Updates #27122 Updates #28459 Updates #29280 Updates #30590 Updates #37214 Updates #36173 Updates #36587 Fixes #36008 Fixes #30992 Change-Id: Iedb26d2e0963697c130df5d0f72e7f83ec2dcf06 Reviewed-on: https://go-review.googlesource.com/c/go/+/185345 Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
1 parent d11e1f9 commit 5a61de3

25 files changed

+470
-180
lines changed

src/cmd/go/internal/clean/clean.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func clean(p *load.Package) {
232232
cleaned[p] = true
233233

234234
if p.Dir == "" {
235-
base.Errorf("can't load package: %v", p.Error)
235+
base.Errorf("%v", p.Error)
236236
return
237237
}
238238
dirs, err := ioutil.ReadDir(p.Dir)

src/cmd/go/internal/fmtcmd/fmt.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
package fmtcmd
77

88
import (
9+
"errors"
910
"fmt"
1011
"os"
1112
"path/filepath"
1213
"runtime"
13-
"strings"
1414
"sync"
1515

1616
"cmd/go/internal/base"
@@ -72,11 +72,12 @@ func runFmt(cmd *base.Command, args []string) {
7272
continue
7373
}
7474
if pkg.Error != nil {
75-
if strings.HasPrefix(pkg.Error.Err.Error(), "build constraints exclude all Go files") {
75+
var nogo *load.NoGoError
76+
if errors.As(pkg.Error, &nogo) && len(pkg.InternalAllGoFiles()) > 0 {
7677
// Skip this error, as we will format
7778
// all files regardless.
7879
} else {
79-
base.Errorf("can't load package: %s", pkg.Error)
80+
base.Errorf("%v", pkg.Error)
8081
continue
8182
}
8283
}

src/cmd/go/internal/list/list.go

+1
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ func runList(cmd *base.Command, args []string) {
451451
pkgs = load.PackagesAndErrors(args)
452452
} else {
453453
pkgs = load.Packages(args)
454+
base.ExitIfErrors()
454455
}
455456

456457
if cache.Default() == nil {

src/cmd/go/internal/load/pkg.go

+63-28
Original file line numberDiff line numberDiff line change
@@ -187,20 +187,17 @@ type PackageInternal struct {
187187
Gccgoflags []string // -gccgoflags for this package
188188
}
189189

190+
// A NoGoError indicates that no Go files for the package were applicable to the
191+
// build for that package.
192+
//
193+
// That may be because there were no files whatsoever, or because all files were
194+
// excluded, or because all non-excluded files were test sources.
190195
type NoGoError struct {
191196
Package *Package
192197
}
193198

194199
func (e *NoGoError) Error() string {
195-
// Count files beginning with _ and ., which we will pretend don't exist at all.
196-
dummy := 0
197-
for _, name := range e.Package.IgnoredGoFiles {
198-
if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
199-
dummy++
200-
}
201-
}
202-
203-
if len(e.Package.IgnoredGoFiles) > dummy {
200+
if len(e.Package.constraintIgnoredGoFiles()) > 0 {
204201
// Go files exist, but they were ignored due to build constraints.
205202
return "build constraints exclude all Go files in " + e.Package.Dir
206203
}
@@ -213,6 +210,23 @@ func (e *NoGoError) Error() string {
213210
return "no Go files in " + e.Package.Dir
214211
}
215212

213+
// rewordError returns a version of err with trivial layers removed and
214+
// (possibly-wrapped) instances of build.NoGoError replaced with load.NoGoError,
215+
// which more clearly distinguishes sub-cases.
216+
func (p *Package) rewordError(err error) error {
217+
if mErr, ok := err.(*search.MatchError); ok && mErr.Match.IsLiteral() {
218+
err = mErr.Err
219+
}
220+
var noGo *build.NoGoError
221+
if errors.As(err, &noGo) {
222+
if p.Dir == "" && noGo.Dir != "" {
223+
p.Dir = noGo.Dir
224+
}
225+
err = &NoGoError{Package: p}
226+
}
227+
return err
228+
}
229+
216230
// Resolve returns the resolved version of imports,
217231
// which should be p.TestImports or p.XTestImports, NOT p.Imports.
218232
// The imports in p.TestImports and p.XTestImports are not recursively
@@ -313,10 +327,7 @@ type PackageError struct {
313327

314328
func (p *PackageError) Error() string {
315329
// Import cycles deserve special treatment.
316-
if p.IsImportCycle {
317-
return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
318-
}
319-
if p.Pos != "" {
330+
if p.Pos != "" && !p.IsImportCycle {
320331
// Omit import stack. The full path to the file where the error
321332
// is the most important thing.
322333
return p.Pos + ": " + p.Err.Error()
@@ -339,6 +350,8 @@ func (p *PackageError) Error() string {
339350
return "package " + strings.Join(stack, "\n\timports ") + ": " + p.Err.Error()
340351
}
341352

353+
func (p *PackageError) Unwrap() error { return p.Err }
354+
342355
// PackageError implements MarshalJSON so that Err is marshaled as a string
343356
// and non-essential fields are omitted.
344357
func (p *PackageError) MarshalJSON() ([]byte, error) {
@@ -583,9 +596,10 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
583596
if !cfg.ModulesEnabled && path != cleanImport(path) {
584597
p.Error = &PackageError{
585598
ImportStack: stk.Copy(),
586-
Err: fmt.Errorf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)),
599+
Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
587600
}
588601
p.Incomplete = true
602+
setErrorPos(p, importPos)
589603
}
590604
}
591605

@@ -1533,12 +1547,8 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
15331547
}
15341548

15351549
if err != nil {
1536-
if _, ok := err.(*build.NoGoError); ok {
1537-
err = &NoGoError{Package: p}
1538-
}
15391550
p.Incomplete = true
1540-
1541-
setError(base.ExpandScanner(err))
1551+
setError(base.ExpandScanner(p.rewordError(err)))
15421552
if _, isScanErr := err.(scanner.ErrorList); !isScanErr {
15431553
return
15441554
}
@@ -1934,13 +1944,22 @@ func (p *Package) InternalXGoFiles() []string {
19341944
// using absolute paths. "Possibly relevant" means that files are not excluded
19351945
// due to build tags, but files with names beginning with . or _ are still excluded.
19361946
func (p *Package) InternalAllGoFiles() []string {
1937-
var extra []string
1947+
return p.mkAbs(str.StringList(p.constraintIgnoredGoFiles(), p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
1948+
}
1949+
1950+
// constraintIgnoredGoFiles returns the list of Go files ignored for reasons
1951+
// other than having a name beginning with '.' or '_'.
1952+
func (p *Package) constraintIgnoredGoFiles() []string {
1953+
if len(p.IgnoredGoFiles) == 0 {
1954+
return nil
1955+
}
1956+
files := make([]string, 0, len(p.IgnoredGoFiles))
19381957
for _, f := range p.IgnoredGoFiles {
1939-
if f != "" && f[0] != '.' || f[0] != '_' {
1940-
extra = append(extra, f)
1958+
if f != "" && f[0] != '.' && f[0] != '_' {
1959+
files = append(files, f)
19411960
}
19421961
}
1943-
return p.mkAbs(str.StringList(extra, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
1962+
return files
19441963
}
19451964

19461965
// usesSwig reports whether the package needs to run SWIG.
@@ -2034,7 +2053,7 @@ func Packages(args []string) []*Package {
20342053
var pkgs []*Package
20352054
for _, pkg := range PackagesAndErrors(args) {
20362055
if pkg.Error != nil {
2037-
base.Errorf("can't load package: %s", pkg.Error)
2056+
base.Errorf("%v", pkg.Error)
20382057
continue
20392058
}
20402059
pkgs = append(pkgs, pkg)
@@ -2092,8 +2111,24 @@ func PackagesAndErrors(patterns []string) []*Package {
20922111
pkgs = append(pkgs, p)
20932112
}
20942113

2095-
// TODO: if len(m.Pkgs) == 0 && len(m.Errs) > 0, should we add a *Package
2096-
// with a non-nil Error field?
2114+
if len(m.Errs) > 0 {
2115+
// In addition to any packages that were actually resolved from the
2116+
// pattern, there was some error in resolving the pattern itself.
2117+
// Report it as a synthetic package.
2118+
p := new(Package)
2119+
p.ImportPath = m.Pattern()
2120+
p.Error = &PackageError{
2121+
ImportStack: nil, // The error arose from a pattern, not an import.
2122+
Err: p.rewordError(m.Errs[0]),
2123+
}
2124+
p.Incomplete = true
2125+
p.Match = append(p.Match, m.Pattern())
2126+
p.Internal.CmdlinePkg = true
2127+
if m.IsLiteral() {
2128+
p.Internal.CmdlinePkgLiteral = true
2129+
}
2130+
pkgs = append(pkgs, p)
2131+
}
20972132
}
20982133

20992134
// Now that CmdlinePkg is set correctly,
@@ -2129,7 +2164,7 @@ func PackagesForBuild(args []string) []*Package {
21292164
printed := map[*PackageError]bool{}
21302165
for _, pkg := range pkgs {
21312166
if pkg.Error != nil {
2132-
base.Errorf("can't load package: %s", pkg.Error)
2167+
base.Errorf("%v", pkg.Error)
21332168
printed[pkg.Error] = true
21342169
}
21352170
for _, err := range pkg.DepsErrors {
@@ -2139,7 +2174,7 @@ func PackagesForBuild(args []string) []*Package {
21392174
// Only print each once.
21402175
if !printed[err] {
21412176
printed[err] = true
2142-
base.Errorf("%s", err)
2177+
base.Errorf("%v", err)
21432178
}
21442179
}
21452180
}

src/cmd/go/internal/modload/import.go

-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,6 @@ func Import(path string) (m module.Version, dir string, err error) {
132132
}
133133
dir := filepath.Join(cfg.GOROOT, "src", path)
134134
return module.Version{}, dir, nil
135-
} else if pathIsStd && path == cfg.GOROOTsrc {
136-
return module.Version{}, dir, errors.New("directory should not directly contain source files")
137135
}
138136

139137
// -mod=vendor is special.

0 commit comments

Comments
 (0)