1
0
mirror of https://github.com/golang/go synced 2024-11-23 06:00:08 -07:00

cmd/go: enable lazy loading

This change activates the dormant “lazy loading” codepaths added in CL
265777 and its predecessors. Dependencies of modules that declare 'go
1.17' or higher are loaded lazily, and the dependencies in the go.mod
file maintain additional invariants to support more efficient lazy
loading for downstream dependent modules.

See https://golang.org/design/36460-lazy-module-loading for the
detailed design.

For #36460

Change-Id: Ic12ee7842aef9580357fcf8909d87654fcb2ad12
Reviewed-on: https://go-review.googlesource.com/c/go/+/314634
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Bryan C. Mills 2021-04-28 12:57:38 -04:00
parent 2bd3e48055
commit 9a81702b97
16 changed files with 396 additions and 61 deletions

View File

@ -43,7 +43,22 @@ Do not send CLs removing the interior tags from such phrases.
<h3 id="go-command">Go command</h3>
<h4 id="modules">Modules</h4>
<h4 id="lazy-loading">Lazy module loading</h4>
<p><!-- golang.org/issue/36460 -->
If a module specifies <code>go</code> <code>1.17</code> or higher in its
<code>go.mod</code> file, its transitive requirements are now loaded lazily,
avoding the need to download or read <code>go.mod</code> files for
otherwise-irrelevant dependencies. To support lazy loading, in Go 1.17 modules
the <code>go</code> command maintains <em>explicit</em> requirements in
the <code>go.mod</code> file for every dependency that provides any package
transitively imported by any package or test within the module.
See <a href="https://golang.org/design/36460-lazy-module-loading">the design
document</a> for more detail.
<!-- TODO(bcmills): replace the design-doc link with proper documentation. -->
</p>
<h4 id="module-deprecation-comments">Module deprecation comments</h4>
<p><!-- golang.org/issue/40357 -->
Module authors may deprecate a module by adding a

View File

@ -4,9 +4,12 @@ go 1.17
require (
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/mod v0.4.3-0.20210409134425-858fdbee9c24
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d
golang.org/x/tools v0.1.1-0.20210422170518-f946a157eefe
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

View File

@ -41,7 +41,7 @@ const (
// go117EnableLazyLoading toggles whether lazy-loading code paths should be
// active. It will be removed once the lazy loading implementation is stable
// and well-tested.
go117EnableLazyLoading = false
go117EnableLazyLoading = true
// go1117LazyTODO is a constant that exists only until lazy loading is
// implemented. Its use indicates a condition that will need to change if the

View File

@ -189,19 +189,22 @@ stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$'
rm vendor
# Convert all modules to go 1.16 to enable lazy loading.
go mod edit -go=1.16 a/go.mod
go mod edit -go=1.16 b/go.mod
go mod edit -go=1.16 c/go.mod
go mod edit -go=1.16 d/go.mod
go mod edit -go=1.16 q/go.mod
go mod edit -go=1.16 r/go.mod
go mod edit -go=1.16 s/go.mod
go mod edit -go=1.16 t/go.mod
go mod edit -go=1.16 u/go.mod
go mod edit -go=1.16 w/go.mod
go mod edit -go=1.16 x/go.mod
go mod edit -go=1.16
# Convert all modules to go 1.17 to enable lazy loading.
go mod edit -go=1.17 a/go.mod
go mod edit -go=1.17 b/go.mod
go mod edit -go=1.17 c/go.mod
go mod edit -go=1.17 d/go.mod
go mod edit -go=1.17 q/go.mod
go mod edit -go=1.17 r/go.mod
go mod edit -go=1.17 s/go.mod
go mod edit -go=1.17 t/go.mod
go mod edit -go=1.17 u/go.mod
go mod edit -go=1.17 w/go.mod
go mod edit -go=1.17 x/go.mod
go mod edit -go=1.17
cp go.mod go.mod.orig
go mod tidy
cmp go.mod go.mod.orig
# With lazy loading, 'go list all' with neither -mod=vendor nor -test should
# match -mod=vendor without -test in 1.15.
@ -282,20 +285,41 @@ stdout '^example.com/t_test \[example.com/t.test\]$'
stdout '^example.com/u.test$'
stdout '^example.com/u_test \[example.com/u.test\]$'
# 'go list -m all' should cover all of the modules providing packages in
# 'go list -test -deps all', but should exclude modules d and x,
# which are not relevant to the main module and are outside of the
# lazy-loading horizon.
# TODO(#36460):
# 'go list -m all' should exactly cover the packages in 'go list -test all'.
go list -m -f $MODFMT all
stdout -count=10 '^.'
stdout '^example.com/a$'
stdout '^example.com/b$'
stdout '^example.com/c$'
! stdout '^example.com/d$'
stdout '^example.com/main$'
stdout '^example.com/q$'
stdout '^example.com/r$'
stdout '^example.com/s$'
stdout '^example.com/t$'
stdout '^example.com/u$'
stdout '^example.com/w$'
! stdout '^example.com/x$'
-- go.mod --
module example.com/main
// Note: this go.mod file initially specifies go 1.15,
// but includes some redundant roots so that it
// also already obeys the 1.17 lazy loading invariants.
go 1.15
require (
example.com/a v0.1.0
example.com/b v0.1.0
example.com/q v0.1.0
example.com/r v0.1.0 // indirect
example.com/t v0.1.0
example.com/u v0.1.0 // indirect
)
replace (

View File

@ -29,7 +29,7 @@ go build -n use
-- go.mod --
module use
go 1.17
go 1.16
require rsc.io/quote v1.5.2
-- go.sum.tidy --

View File

@ -67,9 +67,9 @@ cd tmp
go mod init tmp
go mod edit -require=rsc.io/fortune@v1.0.0
! go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
stderr '^rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
! go install -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0
stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
stderr '^rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
go get -d rsc.io/fortune@v1.0.0
go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
exists $GOPATH/bin/fortune$GOEXE

View File

@ -1,5 +1,5 @@
# This test illustrates the interaction between lazy loading and downgrading in
# 'go get.
# 'go get'.
# The package import graph used in this test looks like:
#
@ -46,7 +46,7 @@ go list -m all
# outside of the deepening scan should not affect the downgrade.
cp go.mod.orig go.mod
go mod edit -go=1.16
go mod edit -go=1.17
go list -m all
stdout '^example.com/a v0.1.0 '
@ -59,12 +59,50 @@ stdout '^example.com/a v0.1.0 '
stdout '^example.com/b v0.2.0 '
stdout '^example.com/c v0.1.0 '
# At this point, b.2 is still an explicit root, so its dependency on c
# is still tracked, and it will still be downgraded away if we remove c.
# ('go get' never makes a root into a non-root. Only 'go mod tidy' does that.)
go get -d example.com/c@none
go list -m all
! stdout '^example.com/a ' # TODO(#36460): example.com/a v0.1.0
! stdout '^example.com/b ' # TODO(#36460): example.com/b v0.1.0
! stdout '^example.com/a '
! stdout '^example.com/b '
! stdout '^example.com/c '
# This time, we drop the explicit 'b' root by downgrading it to v0.1.0
# (the version required by a.1) and running 'go mod tidy'.
# It is still selected at v0.1.0 (as a dependency of a),
# but its dependency on c is now pruned from the module graph, so it doesn't
# result in any downgrades to b or a if we run 'go get c@none'.
cp go.mod.orig go.mod
go mod edit -go=1.17
go list -m all
stdout '^example.com/a v0.1.0 '
stdout '^example.com/b v0.3.0 '
stdout '^example.com/c v0.2.0 '
go get -d example.com/c@v0.1.0 example.com/b@v0.1.0
go list -m all
stdout '^example.com/a v0.1.0 '
stdout '^example.com/b v0.1.0 '
stdout '^example.com/c v0.1.0 '
go mod tidy
go list -m all
stdout '^example.com/a v0.1.0 '
stdout '^example.com/b v0.1.0 '
! stdout '^example.com/c '
go get -d example.com/c@none
go list -m all
stdout '^example.com/a v0.1.0'
stdout '^example.com/b v0.1.0'
! stdout '^example.com/c '
-- go.mod --
module example.com/lazy
@ -91,7 +129,7 @@ import _ "example.com/a"
-- a/go.mod --
module example.com/a
go 1.15
go 1.17
require example.com/b v0.1.0
-- a/a.go --
@ -104,7 +142,7 @@ import _ "example.com/b"
-- b1/go.mod --
module example.com/b
go 1.15
go 1.17
require example.com/c v0.1.0
-- b1/b.go --
@ -116,7 +154,7 @@ import _ "example.com/c"
-- b2/go.mod --
module example.com/b
go 1.15
go 1.17
require example.com/c v0.1.0
-- b2/b.go --
@ -128,7 +166,7 @@ import _ "example.com/c"
-- b3/go.mod --
module example.com/b
go 1.15
go 1.17
require example.com/c v0.2.0
-- b3/b.go --
@ -140,6 +178,6 @@ import _ "example.com/c"
-- c/go.mod --
module example.com/c
go 1.15
go 1.17
-- c/c.go --
package c

View File

@ -53,8 +53,8 @@ stdout '^c v0.1.0 '
cp m.go.orig m.go
cp go.mod.orig go.mod
go mod edit -go=1.16
go mod edit -go=1.16 go.mod.new
go mod edit -go=1.17
go mod edit -go=1.17 go.mod.new
cp go.mod go.mod.orig
go mod tidy
@ -63,14 +63,15 @@ cmp go.mod.orig go.mod
go list -m all
stdout '^a v0.1.0 '
stdout '^b v0.1.0 '
stdout '^c v0.1.0 ' # TODO(#36460): This should be pruned out.
! stdout '^c '
# After adding a new import of b/y,
# the import of c from b/y should again resolve to the version required by b.
# After adding a new direct import of b/y,
# the existing verison of b should be promoted to a root,
# bringing the version of c required by b into the build list.
cp m.go.new m.go
go mod tidy
cmp go.mod.new go.mod
cmp go.mod.lazy go.mod
go list -m all
stdout '^a v0.1.0 '
@ -124,6 +125,23 @@ require (
b v0.1.0
)
replace (
a v0.1.0 => ./a1
b v0.1.0 => ./b1
c v0.1.0 => ./c1
c v0.2.0 => ./c2
)
-- go.mod.lazy --
module m
go 1.17
require (
a v0.1.0
b v0.1.0
c v0.1.0 // indirect
)
replace (
a v0.1.0 => ./a1
b v0.1.0 => ./b1
@ -133,7 +151,7 @@ replace (
-- a1/go.mod --
module a
go 1.16
go 1.17
require b v0.1.0
-- a1/a.go --
@ -145,7 +163,7 @@ import _ "b/x"
-- b1/go.mod --
module b
go 1.16
go 1.17
require c v0.1.0
-- b1/x/x.go --
@ -161,7 +179,7 @@ func CVersion() string {
-- c1/go.mod --
module c
go 1.16
go 1.17
-- c1/c.go --
package c

View File

@ -5,7 +5,7 @@
#
# lazy ---- a/x ---- b
# \
# ---- a/y ---- c
# ---- a/y (new) ---- c
#
# Where a/x and x/y are disjoint packages, but both contained in module a.
#
@ -35,14 +35,29 @@ go list -m all
stdout '^example.com/c v0.1.0' # not v0.2.0 as would be resolved by 'latest'
cmp go.mod go.mod.old
# TODO(#36460):
# Now, we repeat the test with a lazy main module.
cp lazy.go.old lazy.go
cp go.mod.old go.mod
go mod edit -go=1.16
cp go.mod.117 go.mod
# Before adding a new import, the go.mod file should
# enumerate modules for all packages already imported.
go list all
cmp go.mod go.mod.117
# When a new import is found, we should perform a deepening scan of the existing
# dependencies and add a requirement on the version required by those
# dependencies — not re-resolve 'latest'.
cp lazy.go.new lazy.go
! go list all
stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy$'
go mod tidy
go list all
go list -m all
stdout '^example.com/c v0.1.0' # not v0.2.0 as would be resolved by 'latest'
cmp go.mod go.mod.new
-- go.mod --
@ -52,6 +67,39 @@ go 1.15
require example.com/a v0.1.0
replace (
example.com/a v0.1.0 => ./a
example.com/b v0.1.0 => ./b
example.com/c v0.1.0 => ./c1
example.com/c v0.2.0 => ./c2
)
-- go.mod.117 --
module example.com/lazy
go 1.17
require (
example.com/a v0.1.0
example.com/b v0.1.0 // indirect
)
replace (
example.com/a v0.1.0 => ./a
example.com/b v0.1.0 => ./b
example.com/c v0.1.0 => ./c1
example.com/c v0.2.0 => ./c2
)
-- go.mod.new --
module example.com/lazy
go 1.17
require (
example.com/a v0.1.0
example.com/b v0.1.0 // indirect
example.com/c v0.1.0 // indirect
)
replace (
example.com/a v0.1.0 => ./a
example.com/b v0.1.0 => ./b

View File

@ -32,12 +32,12 @@ stdout '^c v0.2.0 '
# but the irrelevant dependency on c v0.2.0 should be pruned out,
# leaving only the relevant dependency on c v0.1.0.
go mod edit -go=1.16
go mod edit -go=1.17
go list -m c
stdout '^c v0.2.0' # TODO(#36460): v0.1.0
stdout '^c v0.1.0'
[!short] go test -v x
[!short] stdout ' c v0.2.0$' # TODO(#36460): v0.1.0
[!short] stdout ' c v0.1.0$'
-- m.go --
package m
@ -66,7 +66,7 @@ replace (
-- a1/go.mod --
module a
go 1.16
go 1.17
require b v0.1.0
-- a1/a.go --
@ -78,7 +78,7 @@ import _ "b"
-- b1/go.mod --
module b
go 1.16
go 1.17
require c v0.2.0
-- b1/b.go --
@ -97,7 +97,7 @@ func TestCVersion(t *testing.T) {
-- c1/go.mod --
module c
go 1.16
go 1.17
-- c1/c.go --
package c
@ -105,7 +105,7 @@ const Version = "v0.1.0"
-- c2/go.mod --
module c
go 1.16
go 1.17
-- c2/c.go --
package c
@ -113,7 +113,7 @@ const Version = "v0.2.0"
-- x1/go.mod --
module x
go 1.16
go 1.17
require c v0.1.0
-- x1/x.go --

View File

@ -21,12 +21,13 @@ cp go.mod go.mod.old
go mod tidy
cmp go.mod go.mod.old
# In Go 1.15 mode, 'go list -m all' includes modules needed by the
# transitive closure of tests of dependencies of tests of dependencies of ….
go list -m all
stdout 'example.com/b v0.1.0'
stdout 'example.com/c v0.1.0'
stdout '^example.com/b v0.1.0 '
stdout '^example.com/c v0.1.0 '
cmp go.mod go.mod.old
# 'go test' (or equivalent) of any such dependency, no matter how remote, does
@ -36,18 +37,24 @@ go list -test -deps example.com/a
stdout example.com/b
! stdout example.com/c
[!short] go test -c example.com/a
[!short] go test -c -o $devnull example.com/a
[!short] cmp go.mod go.mod.old
go list -test -deps example.com/b
stdout example.com/c
[!short] go test -c example.com/b
[!short] go test -c -o $devnull example.com/b
[!short] cmp go.mod go.mod.old
# TODO(#36460):
go mod edit -go=1.17 a/go.mod
go mod edit -go=1.17 b1/go.mod
go mod edit -go=1.17 b2/go.mod
go mod edit -go=1.17 c1/go.mod
go mod edit -go=1.17 c2/go.mod
go mod edit -go=1.17
# After changing to 'go 1.16` uniformly, 'go list -m all' should prune out
# After changing to 'go 1.17` uniformly, 'go list -m all' should prune out
# example.com/c, because it is not imported by any package (or test of a package)
# transitively imported by the main module.
#
@ -62,10 +69,66 @@ stdout example.com/c
# version of its module.
# However, if we reach c by running successive tests starting from the main
# module, we should end up with exactly the version require by c, with an update
# module, we should end up with exactly the version required by b, with an update
# to the go.mod file as soon as we test a test dependency that is not itself in
# "all".
cp go.mod go.mod.117
go mod tidy
cmp go.mod go.mod.117
go list -m all
stdout '^example.com/b v0.1.0 '
! stdout '^example.com/c '
# 'go test' of a package (transitively) imported by the main module
# should work without changes to the go.mod file.
go list -test -deps example.com/a
stdout example.com/b
! stdout example.com/c
[!short] go test -c -o $devnull example.com/a
# However, 'go test' of a package that is itself a dependency should require an
# update to the go.mod file.
! go list -test -deps example.com/b
# TODO(#36460): The hint here is wrong. We should suggest
# 'go get -t example.com/b@v0.1.0' instead of 'go mod tidy'.
stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
[!short] ! go test -c -o $devnull example.com/b
[!short] stderr '^go: updates to go\.mod needed; to update it:\n\tgo mod tidy$'
go get -t example.com/b@v0.1.0
go list -test -deps example.com/b
stdout example.com/c
[!short] go test -c -o $devnull example.com/b
# The update should bring the version required by b, not the latest version of c.
go list -m example.com/c
stdout '^example.com/c v0.1.0 '
cmp go.mod go.mod.b
# We should reach the same state if we arrive at it via `go test -mod=mod`.
cp go.mod.117 go.mod
[short] go list -mod=mod -test -deps example.com/a
[!short] go test -mod=mod -c -o $devnull example.com/a
[short] go list -mod=mod -test -deps example.com/b
[!short] go test -mod=mod -c -o $devnull example.com/b
cmp go.mod go.mod.b
-- go.mod --
module example.com/lazy
@ -73,6 +136,23 @@ go 1.15
require example.com/a v0.1.0
replace (
example.com/a v0.1.0 => ./a
example.com/b v0.1.0 => ./b1
example.com/b v0.2.0 => ./b2
example.com/c v0.1.0 => ./c1
example.com/c v0.2.0 => ./c2
)
-- go.mod.b --
module example.com/lazy
go 1.17
require (
example.com/a v0.1.0
example.com/b v0.1.0 // indirect
)
replace (
example.com/a v0.1.0 => ./a
example.com/b v0.1.0 => ./b1

View File

@ -0,0 +1,35 @@
# https://golang.org/issue/41297: 'go list -m' should not require go.sum with
# -versions or when all args are version queries.
go mod init m
go mod edit -require=rsc.io/quote@v1.5.1
# 'go list' currently loads the whole build list, even when listing only
# non-dependencies.
#
# TODO(#41297): Thes should not be errors.
! go list -m -mod=readonly rsc.io/quote@latest
stderr '^go list -m: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
! go list -m -mod=readonly -versions rsc.io/quote
stderr '^go list -m: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
# Incidentally fetching the required version of a module records its checksum,
# just because it happens to be in the build list, and recording the checksum
# triggers an error under -mod=readonly.
#
# TODO(#41297): This should not be an error.
! go list -m -mod=readonly rsc.io/quote@<v1.5.2
stderr '^go list -m: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'
! stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
# Attempting to list the versions of a module that is not a root dependency
# causes the build list to be resolved (so that the selected version can *also*
# be identified, even though it is not relevant to this particular output).
# That, in turn, causes us to need checksums for the go.sum files for the
# modules in the module graph.
#
# TODO(#41297): This should not be an error either.
! go list -m -mod=readonly -versions rsc.io/sampler
stderr '^go list -m: rsc\.io/quote@v1\.5\.1: missing go\.sum entry; to add it:\n\tgo mod download rsc\.io/quote$'

View File

@ -64,9 +64,9 @@ cd tmp
go mod init tmp
go mod edit -require=rsc.io/fortune@v1.0.0
! go run -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
stderr '^rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
! go run -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0
stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
stderr '^rsc.io/fortune@v1.0.0: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
cd ..
rm tmp

View File

@ -84,8 +84,22 @@ go mod tidy
cmp go.mod go.mod.postget
# The 'tidy' logic for a lazy main module is somewhat different from that for an
# eager main module, but the overall behavior is the same.
# TODO(#36460): Repeat this test with a lazy main module.
cp go.mod.orig go.mod
go mod edit -go=1.17 go.mod
go mod edit -go=1.17 go.mod.tidye
go mod edit -go=1.17 go.mod.postget
go mod tidy -e
cmp go.mod go.mod.tidye
stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
go mod tidy
cmp go.mod go.mod.postget
-- go.mod --

View File

@ -101,7 +101,64 @@ go mod tidy -e
cmp go.mod go.mod.postget
# TODO(#36460): Repeat this test with a lazy main module.
# The 'tidy' logic for a lazy main module requires more iterations to converge,
# because it is willing to drop dependencies on non-root modules that do not
# otherwise provide imported packages.
#
# On the first iteration, it adds x.1 as a root, which upgrades z and w,
# dropping w.1's requirement on y. w.1 was initially a root, so the upgraded
# w.2-pre is retained as a root.
#
# On the second iteration, it adds y.1 as a root, which upgrades w and x,
# dropping x.1's requirement on z. x.1 was added as a root in the previous step,
# so the upgraded x.2-pre is retained as a root.
#
# On the third iteration, it adds z.1 as a root, which upgrades x and y.
# x and y were already roots (from the previous steps), so their upgraded versions
# are retained (not dropped) and the iteration stops.
#
# At that point, we have z.1 as a root providing package z,
# and w, x, and y have all been upgraded to no longer provide any packages.
# So only z is retained as a new root.
#
# (From the above, we can see that in a lazy module we still cycle through the
# same possible root states, but in a different order from the eager case.)
#
# TODO(bcmills): if we retained the upgrades on w, x, and y (since they are
# lexical prefixes for unresolved packages w, x, and y, respectively), then 'go
# mod tidy -e' itself would become stable and no longer cycle through states.
cp go.mod.orig go.mod
go mod edit -go=1.17 go.mod
cp go.mod go.mod.117
go mod edit -go=1.17 go.mod.tidye1
go mod edit -go=1.17 go.mod.tidye2
go mod edit -go=1.17 go.mod.tidye3
go mod edit -go=1.17 go.mod.postget
go list -m all
go mod tidy -e
cmp go.mod go.mod.tidye3
go mod tidy -e
cmp go.mod go.mod.tidye2
go mod tidy -e
cmp go.mod go.mod.tidye1
go mod tidy -e
cmp go.mod go.mod.117
# As in the eager case, for the lazy module the fully-upgraded dependency graph
# becomes empty, and the empty graph is stable.
go get -d example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
go mod tidy -e
cmp go.mod go.mod.postget
go mod tidy -e
cmp go.mod go.mod.postget
-- m.go --

View File

@ -16,6 +16,7 @@ github.com/google/pprof/third_party/d3
github.com/google/pprof/third_party/d3flamegraph
github.com/google/pprof/third_party/svgpan
# github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639
## explicit
github.com/ianlancetaylor/demangle
# golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72
## explicit
@ -39,6 +40,7 @@ golang.org/x/mod/sumdb/note
golang.org/x/mod/sumdb/tlog
golang.org/x/mod/zip
# golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
## explicit
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/plan9
golang.org/x/sys/unix
@ -91,5 +93,6 @@ golang.org/x/tools/go/types/typeutil
golang.org/x/tools/internal/analysisinternal
golang.org/x/tools/internal/lsp/fuzzy
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
## explicit
golang.org/x/xerrors
golang.org/x/xerrors/internal