mirror of
https://github.com/golang/go
synced 2024-11-17 19:44:43 -07:00
modload: provide a clearer error for standard library packages from newer releases
An older version of go compiling a main module that references a standard library package from a newer release (e.g. net/netip added in go 1.18) currently produces a confusing error message. This changes adds a new error message including go version diagnostics. Fixes #48966 Change-Id: I1e8319dafcf1f67d1b1ca869fe84190c3b3f3c3e Reviewed-on: https://go-review.googlesource.com/c/go/+/432075 Auto-Submit: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
9be09916d9
commit
40c7e94cc5
@ -41,6 +41,10 @@ type ImportMissingError struct {
|
||||
// modules.
|
||||
isStd bool
|
||||
|
||||
// importerGoVersion is the version the module containing the import error
|
||||
// specified. It is only set when isStd is true.
|
||||
importerGoVersion string
|
||||
|
||||
// replaced the highest replaced version of the module where the replacement
|
||||
// contains the package. replaced is only set if the replacement is unused.
|
||||
replaced module.Version
|
||||
@ -53,7 +57,11 @@ type ImportMissingError struct {
|
||||
func (e *ImportMissingError) Error() string {
|
||||
if e.Module.Path == "" {
|
||||
if e.isStd {
|
||||
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
|
||||
msg := fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
|
||||
if e.importerGoVersion != "" {
|
||||
msg += fmt.Sprintf("\nnote: imported by a module that requires go %s", e.importerGoVersion)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
if e.QueryErr != nil && e.QueryErr != ErrNoModRoot {
|
||||
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
|
||||
|
@ -984,7 +984,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||
if ld.GoVersion == "" {
|
||||
ld.GoVersion = MainModules.GoVersion()
|
||||
|
||||
if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 {
|
||||
if ld.Tidy && versionLess(LatestGoVersion(), ld.GoVersion) {
|
||||
ld.errorf("go: go.mod file indicates go %s, but maximum version supported by tidy is %s\n", ld.GoVersion, LatestGoVersion())
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
@ -993,7 +993,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||
if ld.Tidy {
|
||||
if ld.TidyCompatibleVersion == "" {
|
||||
ld.TidyCompatibleVersion = priorGoVersion(ld.GoVersion)
|
||||
} else if semver.Compare("v"+ld.TidyCompatibleVersion, "v"+ld.GoVersion) > 0 {
|
||||
} else if versionLess(ld.GoVersion, ld.TidyCompatibleVersion) {
|
||||
// Each version of the Go toolchain knows how to interpret go.mod and
|
||||
// go.sum files produced by all previous versions, so a compatibility
|
||||
// version higher than the go.mod version adds nothing.
|
||||
@ -1184,11 +1184,19 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||
}
|
||||
}
|
||||
|
||||
if ld.SilencePackageErrors {
|
||||
if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) && stdErr.isStd {
|
||||
// Add importer go version information to import errors of standard
|
||||
// library packages arising from newer releases.
|
||||
if importer := pkg.stack; importer != nil {
|
||||
if v, ok := rawGoVersion.Load(importer.mod); ok && versionLess(LatestGoVersion(), v.(string)) {
|
||||
stdErr.importerGoVersion = v.(string)
|
||||
}
|
||||
}
|
||||
if ld.SilenceMissingStdImports {
|
||||
continue
|
||||
}
|
||||
if stdErr := (*ImportMissingError)(nil); errors.As(pkg.err, &stdErr) &&
|
||||
stdErr.isStd && ld.SilenceMissingStdImports {
|
||||
}
|
||||
if ld.SilencePackageErrors {
|
||||
continue
|
||||
}
|
||||
if ld.SilenceNoGoErrors && errors.Is(pkg.err, imports.ErrNoGo) {
|
||||
@ -1202,6 +1210,12 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||
return ld
|
||||
}
|
||||
|
||||
// versionLess returns whether a < b according to semantic version precedence.
|
||||
// Both strings are interpreted as go version strings, e.g. "1.19".
|
||||
func versionLess(a, b string) bool {
|
||||
return semver.Compare("v"+a, "v"+b) < 0
|
||||
}
|
||||
|
||||
// updateRequirements ensures that ld.requirements is consistent with the
|
||||
// information gained from ld.pkgs.
|
||||
//
|
||||
|
17
src/cmd/go/testdata/script/mod_load_missing_std.txt
vendored
Normal file
17
src/cmd/go/testdata/script/mod_load_missing_std.txt
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Go should indicate the version the module requires when a standard library
|
||||
# import is missing. See golang.org/issue/48966.
|
||||
|
||||
! go build .
|
||||
stderr '^main.go:3:8: package nonexistent is not in GOROOT \(.*\)$'
|
||||
stderr '^note: imported by a module that requires go 1.99999$'
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
|
||||
go 1.99999
|
||||
-- main.go --
|
||||
package main
|
||||
|
||||
import _ "nonexistent"
|
||||
|
||||
func main() {}
|
Loading…
Reference in New Issue
Block a user