Description
There is an interesting wrinkle in the upgrade path to lazy module loading in Go 1.17 (#36460), illustrated in this example:
package main
import (
"encoding/json"
"fmt"
"runtime/debug"
_ "golang.org/x/text/number"
_ "golang.org/x/tools/txtar"
)
func main() {
info, _ := debug.ReadBuildInfo()
b, _ := json.MarshalIndent(info, "", "\t")
fmt.Printf("%s\n", b)
}
-- go.mod --
module example.com/m
go 1.17
require (
golang.org/x/text v0.3.0
golang.org/x/tools v0.1.1
)
gotip run .
shows that the program is successfully built against the declared version of golang.org/x/text
(v0.3.0
):
$ gotip run .
{ "Path": "example.com/m", "Main": { "Path": "example.com/m", "Version": "(devel)", "Sum": "", "Replace": null }, "Deps": [ { "Path": "golang.org/x/text", "Version": "v0.3.0", "Sum": "h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=", "Replace": null }, { "Path": "golang.org/x/tools", "Version": "v0.1.1", "Sum": "h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=", "Replace": null } ] }
go1.16.4 run .
with Go 1.16.4, on the other hand, errors out:
$ go1.16.4 run .
go: example.com/m: package golang.org/x/text/number imported from implicitly required module; to add missing requirements, run: go get golang.org/x/text/number@v0.3.3
And go1.15.12 run .
successfully builds, but against a different version of x/text
(v0.3.3
instead of v0.3.0
):
$ go1.15.12 run .
{ "Path": "example.com/m", "Main": { "Path": "example.com/m", "Version": "(devel)", "Sum": "", "Replace": null }, "Deps": [ { "Path": "golang.org/x/text", "Version": "v0.3.3", "Sum": "h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=", "Replace": null }, { "Path": "golang.org/x/tools", "Version": "v0.1.1", "Sum": "h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=", "Replace": null } ] }
These differences are because:
-
Go 1.17 prunes out the dependencies of
golang.org/x/net
, which is required indirectly bygolang.org/x/tools
, because no package relevant to the main module imports anything fromgolang.org/x/net
. -
Go 1.16.4 includes the dependencies of
golang.org/x/net
, and notices that the selected version ofgolang.org/x/text
is different from what is listed in thego.mod
file. Since Go 1.16 defaults to-mod=readonly
(cmd/go: default to & improve -mod=readonly #40728), it cannot change thego.mod
file to restore consistency, and so it errors out. -
Go 1.15.12 includes the dependencies of
golang.org/x/net
, but defaults to-mod=mod
, so it happily overwrites thego.mod
file to restore what it sees as “consistent”, and then builds using the updated requirements.
$ gotip mod graph
example.com/m golang.org/x/text@v0.3.0 example.com/m golang.org/x/tools@v0.1.1 golang.org/x/tools@v0.1.1 github.com/yuin/goldmark@v1.3.5 golang.org/x/tools@v0.1.1 golang.org/x/mod@v0.4.2 golang.org/x/tools@v0.1.1 golang.org/x/net@v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/tools@v0.1.1 golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c golang.org/x/tools@v0.1.1 golang.org/x/sys@v0.0.0-20210510120138-977fb7262007 golang.org/x/tools@v0.1.1 golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1
$ go1.16.4 mod graph
example.com/m golang.org/x/text@v0.3.3 example.com/m golang.org/x/tools@v0.1.1 golang.org/x/text@v0.3.3 golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e golang.org/x/tools@v0.1.1 github.com/yuin/goldmark@v1.3.5 golang.org/x/tools@v0.1.1 golang.org/x/mod@v0.4.2 golang.org/x/tools@v0.1.1 golang.org/x/net@v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/tools@v0.1.1 golang.org/x/sync@v0.0.0-20210220032951-036812b2e83c golang.org/x/tools@v0.1.1 golang.org/x/sys@v0.0.0-20210510120138-977fb7262007 golang.org/x/tools@v0.1.1 golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1 golang.org/x/mod@v0.4.2 golang.org/x/crypto@v0.0.0-20191011191535-87dc89f01550 golang.org/x/mod@v0.4.2 golang.org/x/tools@v0.0.0-20191119224855-298f0cb1881e golang.org/x/mod@v0.4.2 golang.org/x/xerrors@v0.0.0-20191011141410-1b5146add898 golang.org/x/net@v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/sys@v0.0.0-20210330210617-4fbd30eecc44 golang.org/x/net@v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/term@v0.0.0-20201126162022-7de9c90e9dd1 golang.org/x/net@v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/text@v0.3.3 golang.org/x/crypto@v0.0.0-20191011191535-87dc89f01550 golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/crypto@v0.0.0-20191011191535-87dc89f01550 golang.org/x/sys@v0.0.0-20190412213103-97732733099d golang.org/x/tools@v0.0.0-20191119224855-298f0cb1881e golang.org/x/net@v0.0.0-20190620200207-3b0461eec859 golang.org/x/tools@v0.0.0-20191119224855-298f0cb1881e golang.org/x/sync@v0.0.0-20190423024810-112230192c58 golang.org/x/tools@v0.0.0-20191119224855-298f0cb1881e golang.org/x/xerrors@v0.0.0-20190717185122-a985d3407aa7 golang.org/x/term@v0.0.0-20201126162022-7de9c90e9dd1 golang.org/x/sys@v0.0.0-20201119102817-f84b799fce68 golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/net@v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/text@v0.3.0 golang.org/x/net@v0.0.0-20190620200207-3b0461eec859 golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/net@v0.0.0-20190620200207-3b0461eec859 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a golang.org/x/net@v0.0.0-20190620200207-3b0461eec859 golang.org/x/text@v0.3.0 golang.org/x/crypto@v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/sys@v0.0.0-20190215142949-d0b11bdaac8a
To some extent this is working as intended: part of the point of lazy loading is to allow users to more easily upgrade away from transitive dependencies on cyclic, retracted, irretrievable, or otherwise broken module versions that are not otherwise relevant to the main module, so it should not be surprising that the transitive dependencies change between go1.16.4
and gotip
.
We would like Go users who are actively developing with a mix of Go 1.16 and Go 1.17 to be able to continue to do so, as long as they only run go mod tidy
using the version listed in the module's go
directive or higher.
To make that work, we plan to change the go
command so that inconsistent requirements in the main module's go.mod
file are not treated as an error in -mod=readonly
mode if the go
version in that go.mod
file is higher than the version of the go
command in use.
We can then backport (really, reimplement) that change in upcoming minor releases of Go 1.15 and Go 1.16, so that users still on those versions can continue to use them in go 1.17
modules in readonly
mode.