Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions src/cmd/go/internal/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -936,11 +936,23 @@ func collectDeps(p *load.Package) {
func collectDepsErrors(p *load.Package) {
depsErrors := make(map[*load.PackageError]bool)

for _, p := range p.Internal.Imports {
if p.Error != nil {
depsErrors[p.Error] = true
for _, dep := range p.Internal.Imports {
if dep.Error != nil {
// The cached Package for dep may be shared by multiple importers.
// Clone the error and, if Pos refers to the importer side,
// replace it with p's own import position (#78183).
depErr := new(dep.Error)
if depErr.IsImporterPos() && p.Internal.Build != nil {
if pos := p.Internal.Build.ImportPos[dep.ImportPath]; len(pos) > 0 {
p0 := pos[0]
p0.Filename = base.ShortPath(p0.Filename)
depErr.Pos = p0.String()
}
}
depsErrors[&depErr] = true
}
for _, q := range p.DepsErrors {

for _, q := range dep.DepsErrors {
depsErrors[q] = true
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/cmd/go/internal/load/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
top, ok := stk.Top()
if ok && path != top.Pkg {
p.Error.setPos(importPos)
p.Error.setImporterPos(importPos)
}
}

Expand Down Expand Up @@ -457,6 +458,7 @@ type PackageError struct {
Err error // the error itself
IsImportCycle bool // the error is an import cycle
alwaysPrintStack bool // whether to always print the ImportStack
importerPos bool // Pos refers to the importer, not the imported package
}

func (p *PackageError) Error() string {
Expand Down Expand Up @@ -509,6 +511,18 @@ func (p *PackageError) setPos(posList []token.Position) {
pos := posList[0]
pos.Filename = base.ShortPath(pos.Filename)
p.Pos = pos.String()
p.importerPos = true
}

func (p *PackageError) setImporterPos(posList []token.Position) {
p.setPos(posList)
p.importerPos = true
}

// IsImporterPos reports whether Pos refers to the import statement
// in the importing package, not to the imported package's source.
func (p *PackageError) IsImporterPos() bool {
return p.importerPos
}

// ImportPathError is a type of error that prevents a package from being loaded
Expand Down Expand Up @@ -781,17 +795,20 @@ func loadImport(loaderstate *modload.State, ctx context.Context, opts PackageOpt
}
p.Incomplete = true
p.Error.setPos(importPos)
p.Error.setImporterPos(importPos)
}
}

// Checked on every import because the rules depend on the code doing the importing.
if perr := disallowInternal(loaderstate, ctx, srcDir, parent, parentPath, p, stk); perr != nil {
perr.setPos(importPos)
perr.setImporterPos(importPos)
return p, perr
}
if mode&ResolveImport != 0 {
if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != nil {
perr.setPos(importPos)
perr.setImporterPos(importPos)
return p, perr
}
}
Expand All @@ -802,6 +819,7 @@ func loadImport(loaderstate *modload.State, ctx context.Context, opts PackageOpt
Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
}
perr.setPos(importPos)
perr.setImporterPos(importPos)
return p, perr
}

Expand All @@ -817,6 +835,7 @@ func loadImport(loaderstate *modload.State, ctx context.Context, opts PackageOpt
Err: err,
}
perr.setPos(importPos)
perr.setImporterPos(importPos)
return p, perr
}

Expand Down Expand Up @@ -1802,6 +1821,7 @@ func (p *Package) load(loaderstate *modload.State, ctx context.Context, opts Pac
top, ok := stk.Top()
if ok && path != top.Pkg && len(importPos) > 0 {
p.Error.setPos(importPos)
p.Error.setImporterPos(importPos)
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/cmd/go/testdata/script/golist_missingimport.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Test that go list reports correct Pos for each import of a missing package.
# When two different packages import the same missing package, each should
# report the position of its own import statement, not reuse the first one.
# See issue #78183.

env GOWORK=off

go list -e -f '{{range .DepsErrors}}package {{$.ImportPath}}: error at {{.Pos}}: {{.Err}}{{end}}' ./...

stdout 'package example.com/test/p: error at p/p.go:3:8: no required module'
stdout 'package example.com/test/q: error at q/q.go:3:8: no required module'

-- go.mod --
module example.com/test

go 1.22

-- p/p.go --
package p

import _ "example.com/missing"

-- q/q.go --
package q

import _ "example.com/missing"