Go version
go version go1.21.6 linux/amd64
Output of go env
in your module/workspace:
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/austin/.cache/go-build'
GOENV='/home/austin/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/austin/r/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/austin/r/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/austin/sdk/go1.21.6'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/austin/sdk/go1.21.6/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.6'
GCCGO='/usr/bin/gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/tmp/m/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2463259172=/tmp/go-build -gno-record-gcc-switches'
What did you do?
go install golang.org/x/exp/cmd/txtar@latest
mkdir m
cd m
txtar -x <<EOF
-- go.mod --
module m
-- a/a.go --
package a
import _ "x"
-- b/b.go --
package b
import _ "x"
EOF
go list -deps -json ./a ./b
What did you see happen?
Here's the full output:
a/a.go:3:8: package x is not in std (/home/austin/sdk/go1.21.6/src/x)
{
"ImportPath": "x",
"DepOnly": true,
"Incomplete": true,
"Stale": true,
"StaleReason": "build ID mismatch",
"Error": {
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
}
{
"Dir": "/tmp/m/a",
"ImportPath": "m/a",
"Name": "a",
"Root": "/tmp/m",
"Module": {
"Path": "m",
"Main": true,
"Dir": "/tmp/m",
"GoMod": "/tmp/m/go.mod",
"GoVersion": "1.16"
},
"Match": [
"./a"
],
"Incomplete": true,
"Stale": true,
"StaleReason": "stale dependency: x",
"GoFiles": [
"a.go"
],
"Imports": [
"x"
],
"Deps": [
"x"
],
"DepsErrors": [
{
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
]
}
{
"Dir": "/tmp/m/b",
"ImportPath": "m/b",
"Name": "b",
"Root": "/tmp/m",
"Module": {
"Path": "m",
"Main": true,
"Dir": "/tmp/m",
"GoMod": "/tmp/m/go.mod",
"GoVersion": "1.16"
},
"Match": [
"./b"
],
"Incomplete": true,
"Stale": true,
"StaleReason": "stale dependency: x",
"GoFiles": [
"b.go"
],
"Imports": [
"x"
],
"Deps": [
"x"
],
"DepsErrors": [
{
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
]
}
And just the bits I found surprising:
a/a.go:3:8: package x is not in std (/home/austin/sdk/go1.21.6/src/x)
{
"ImportPath": "x",
...
"Error": {
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
}
{
"ImportPath": "m/a",
...
"DepsErrors": [
{
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
]
}
{
"ImportPath": "m/b",
...
"DepsErrors": [
{
"ImportStack": [
"m/a"
],
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
]
}
Notably:
- Only the error in a is reported in the text output, not the bad import in b.
- The errors are reported as DepsErrors on packages a and b, rather than just Errors
- The error directly attributed to "package" x reports a position in package a (of the import of x)
- We see the same error in package b, attributed to the import line in a, even though a and b have no relationship
What did you expect to see?
I expected go list
to report errors on packages a and b attributed to the bad import statements. That is, one error on package a at a/a.go:3 and another on package b at b/b.go:3. Something like:
a/a.go:3:8: package x is not in std (/home/austin/sdk/go1.21.6/src/x)
b/b.go:3:8: package x is not in std (/home/austin/sdk/go1.21.6/src/x)
{
"ImportPath": "m/a",
...
"Error": {
"ImportStack": null,
"Pos": "a/a.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
}
{
"ImportPath": "m/b",
...
"Error": {
"ImportStack": null,
"Pos": "b/b.go:3:8",
"Err": "package x is not in std (/home/austin/sdk/go1.21.6/src/x)"
}
}
I'm not sure whether I expected it to report a package for "x" at all. If it did, that would presumably also need an error. The "x" package it currently reports is pretty weird because it's missing so many fields (like Dir). If it didn't report a package "x", it would probably have to omit "x" from the Imports
and Deps
lists, which I think would be fine.
3条答案
按热度按时间ut6juiuv1#
我花了相当长的时间来弄清楚为什么会这样。显然,cmd/go将这个错误对象表示为一个附加到包x的单个错误对象,因此只能给它附加一行号(而"a"恰好赢了)。
在
modload
层,modload.(*loader).resolveMissingImports
调用modload.queryImport("x")
,它返回一个modload.ImportMissingError
,resolveMissingImports
将它保存到 x 的modload.loadPkg.err
字段中。这个错误是最终变成珍珠的沙粒之一,报告在包 "x" 上,并作为 "a" 和 "b" 上的 deps 错误由go list
报告。包 "x" 的modload.loadPkg
最终存储在modload.loaded.pkgCache
中。在
load
层,load.PackagesAndErrors
->load.loadImport(..., "./a", ...)
-> ... ->load.loadImport(..., "x", ...)
。这调用load.loadPackageData
->modload.Lookup(..., "x")
,它从load.loaded.pkgCache
获取 "x" 的load.loadPkg
并返回err
字段。load.loadImport
将此错误传递给load.(*Package).load
->load.setLoadPackageDataError
,它通过importPos
堆栈找到 "x" 的导入位置,并将modload.ImportMissingError
用load.PackageError
Package 。在这个例子中,由于我们首先通过 "a" 来到 "x",所以setLoadPackageDataError
将load.PackageError.Pos
字段设置为 "a" 的导入,尽管PackageError
本身附加到 x 的load.Package
对象上。后来,我们看到
load.loadImport(..., "./b", ...)
-> ... ->load.loadImport(..., "x", ...)
,它在load.Package
中找到 "x" 的load.Package
,因此不会进入load.(*Package).load
,所以 "a" 中的位仍然附加到 "x" 的load.Package
上。这一切都足够复杂,以至于我不确定应该在哪里更改错误如何附加到包。如果我们不想在
go list
输出中表示 "x",那么我认为modload
层应该将modload.ImportMissingError
附加到 "a" 和 "b" 的modload.loadPkg
上,而不是为 "x" 创建一个完全独立的loadPkg
。然后我认为剩下的部分就会“正常工作”。t2a7ltrp2#
在
modload.(*loader).resolveMissingImports
之前,我错过了一个步骤。在modload.loadFromRoots
期间,modload.(*loader).pkg
和modload.(*loader).load
一起遍历导入图。最终,pkg
被调用来构造一个 "x" 的loadPkg
并调用load
。load
调用importFromModules
,在该函数的末尾有一个if mg != nil
检查,实际上构造并返回了 "x" 的ImportMissingError
。这是resolveMissingImports
最终选择的ImportMissingError
。d4so4syb3#
这可能是#26909的重复。