cmd/go: don't try to add replaced versions that won't be selected

In Go 1.12, we added a heuristic to 'go mod tidy' to resolve packages
by adding replaced-but-not-required modules before falling back to
searching for modules from the network. Unfortunately, that heuristic
fails when the replaced version is already lower than the selected
version: adding such a module to the build list doesn't change the
selected version of that module, and so it doesn't make progress
toward resolving the missing package.

Fixes #46659

Change-Id: I75e2387d5290e769f6b0fa1231dcc4605db68597
Reviewed-on: https://go-review.googlesource.com/c/go/+/330432
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Bryan C. Mills 2021-06-23 23:29:10 -04:00
parent a9bb38222a
commit 600a2a4ffb
2 changed files with 43 additions and 0 deletions

View file

@ -428,6 +428,15 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
mv = module.ZeroPseudoVersion("v0")
}
}
mg, err := rs.Graph(ctx)
if err != nil {
return module.Version{}, err
}
if cmpVersion(mg.Selected(mp), mv) >= 0 {
// We can't resolve the import by adding mp@mv to the module graph,
// because the selected version of mp is already at least mv.
continue
}
mods = append(mods, module.Version{Path: mp, Version: mv})
}

View file

@ -0,0 +1,34 @@
# Regression test for https://golang.org/issue/46659.
#
# If a 'replace' directive specifies an older-than-selected version of a module,
# 'go mod tidy' shouldn't try to add that version to the build list to resolve a
# missing package: it won't be selected, and would cause the module loader to
# loop indefinitely trying to resolve the package.
cp go.mod go.mod.orig
! go mod tidy
! stderr panic
stderr '^golang\.org/issue46659 imports\n\texample\.com/missingpkg/deprecated: package example\.com/missingpkg/deprecated provided by example\.com/missingpkg at latest version v1\.0\.0 but not at required version v1\.0\.1-beta$'
go mod tidy -e
cmp go.mod go.mod.orig
-- go.mod --
module golang.org/issue46659
go 1.17
replace example.com/missingpkg v1.0.1-alpha => example.com/missingpkg v1.0.0
require example.com/usemissingpre v1.0.0
require example.com/missingpkg v1.0.1-beta // indirect
-- m.go --
package m
import (
_ "example.com/missingpkg/deprecated"
_ "example.com/usemissingpre"
)