Skip to content

Commit 9a81702

Browse files
author
Bryan C. Mills
committed
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 <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Michael Matloob <[email protected]>
1 parent 2bd3e48 commit 9a81702

16 files changed

+396
-61
lines changed

doc/go1.17.html

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,22 @@ <h2 id="tools">Tools</h2>
4343

4444
<h3 id="go-command">Go command</h3>
4545

46-
<h4 id="modules">Modules</h4>
46+
<h4 id="lazy-loading">Lazy module loading</h4>
47+
48+
<p><!-- golang.org/issue/36460 -->
49+
If a module specifies <code>go</code> <code>1.17</code> or higher in its
50+
<code>go.mod</code> file, its transitive requirements are now loaded lazily,
51+
avoding the need to download or read <code>go.mod</code> files for
52+
otherwise-irrelevant dependencies. To support lazy loading, in Go 1.17 modules
53+
the <code>go</code> command maintains <em>explicit</em> requirements in
54+
the <code>go.mod</code> file for every dependency that provides any package
55+
transitively imported by any package or test within the module.
56+
See <a href="https://golang.org/design/36460-lazy-module-loading">the design
57+
document</a> for more detail.
58+
<!-- TODO(bcmills): replace the design-doc link with proper documentation. -->
59+
</p>
60+
61+
<h4 id="module-deprecation-comments">Module deprecation comments</h4>
4762

4863
<p><!-- golang.org/issue/40357 -->
4964
Module authors may deprecate a module by adding a

src/cmd/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ go 1.17
44

55
require (
66
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5
7+
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
78
golang.org/x/arch v0.0.0-20210308155006-05f8f0431f72
89
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
910
golang.org/x/mod v0.4.3-0.20210409134425-858fdbee9c24
11+
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
1012
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d
1113
golang.org/x/tools v0.1.1-0.20210422170518-f946a157eefe
14+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
1215
)

src/cmd/go/internal/modload/modfile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const (
4141
// go117EnableLazyLoading toggles whether lazy-loading code paths should be
4242
// active. It will be removed once the lazy loading implementation is stable
4343
// and well-tested.
44-
go117EnableLazyLoading = false
44+
go117EnableLazyLoading = true
4545

4646
// go1117LazyTODO is a constant that exists only until lazy loading is
4747
// implemented. Its use indicates a condition that will need to change if the

src/cmd/go/testdata/script/mod_all.txt

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,19 +189,22 @@ stdout '^example.com/main/testonly_test \[example.com/main/testonly.test\]$'
189189

190190
rm vendor
191191

192-
# Convert all modules to go 1.16 to enable lazy loading.
193-
go mod edit -go=1.16 a/go.mod
194-
go mod edit -go=1.16 b/go.mod
195-
go mod edit -go=1.16 c/go.mod
196-
go mod edit -go=1.16 d/go.mod
197-
go mod edit -go=1.16 q/go.mod
198-
go mod edit -go=1.16 r/go.mod
199-
go mod edit -go=1.16 s/go.mod
200-
go mod edit -go=1.16 t/go.mod
201-
go mod edit -go=1.16 u/go.mod
202-
go mod edit -go=1.16 w/go.mod
203-
go mod edit -go=1.16 x/go.mod
204-
go mod edit -go=1.16
192+
# Convert all modules to go 1.17 to enable lazy loading.
193+
go mod edit -go=1.17 a/go.mod
194+
go mod edit -go=1.17 b/go.mod
195+
go mod edit -go=1.17 c/go.mod
196+
go mod edit -go=1.17 d/go.mod
197+
go mod edit -go=1.17 q/go.mod
198+
go mod edit -go=1.17 r/go.mod
199+
go mod edit -go=1.17 s/go.mod
200+
go mod edit -go=1.17 t/go.mod
201+
go mod edit -go=1.17 u/go.mod
202+
go mod edit -go=1.17 w/go.mod
203+
go mod edit -go=1.17 x/go.mod
204+
go mod edit -go=1.17
205+
cp go.mod go.mod.orig
206+
go mod tidy
207+
cmp go.mod go.mod.orig
205208

206209
# With lazy loading, 'go list all' with neither -mod=vendor nor -test should
207210
# match -mod=vendor without -test in 1.15.
@@ -282,20 +285,41 @@ stdout '^example.com/t_test \[example.com/t.test\]$'
282285
stdout '^example.com/u.test$'
283286
stdout '^example.com/u_test \[example.com/u.test\]$'
284287

288+
# 'go list -m all' should cover all of the modules providing packages in
289+
# 'go list -test -deps all', but should exclude modules d and x,
290+
# which are not relevant to the main module and are outside of the
291+
# lazy-loading horizon.
285292

286-
# TODO(#36460):
287-
# 'go list -m all' should exactly cover the packages in 'go list -test all'.
293+
go list -m -f $MODFMT all
294+
stdout -count=10 '^.'
295+
stdout '^example.com/a$'
296+
stdout '^example.com/b$'
297+
stdout '^example.com/c$'
298+
! stdout '^example.com/d$'
299+
stdout '^example.com/main$'
300+
stdout '^example.com/q$'
301+
stdout '^example.com/r$'
302+
stdout '^example.com/s$'
303+
stdout '^example.com/t$'
304+
stdout '^example.com/u$'
305+
stdout '^example.com/w$'
306+
! stdout '^example.com/x$'
288307

289308
-- go.mod --
290309
module example.com/main
291310

311+
// Note: this go.mod file initially specifies go 1.15,
312+
// but includes some redundant roots so that it
313+
// also already obeys the 1.17 lazy loading invariants.
292314
go 1.15
293315

294316
require (
295317
example.com/a v0.1.0
296318
example.com/b v0.1.0
297319
example.com/q v0.1.0
320+
example.com/r v0.1.0 // indirect
298321
example.com/t v0.1.0
322+
example.com/u v0.1.0 // indirect
299323
)
300324

301325
replace (

src/cmd/go/testdata/script/mod_get_missing_ziphash.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ go build -n use
2929
-- go.mod --
3030
module use
3131

32-
go 1.17
32+
go 1.16
3333

3434
require rsc.io/quote v1.5.2
3535
-- go.sum.tidy --

src/cmd/go/testdata/script/mod_install_pkg_version.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ cd tmp
6767
go mod init tmp
6868
go mod edit -require=rsc.io/[email protected]
6969
! go install -mod=readonly $GOPATH/pkg/mod/rsc.io/[email protected]
70-
stderr '^go: rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
70+
stderr '^rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
7171
! go install -mod=readonly ../../pkg/mod/rsc.io/[email protected]
72-
stderr '^go: rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
72+
stderr '^rsc.io/[email protected]: missing go.sum entry; to add it:\n\tgo mod download rsc.io/fortune$'
7373
go get -d rsc.io/[email protected]
7474
go install -mod=readonly $GOPATH/pkg/mod/rsc.io/[email protected]
7575
exists $GOPATH/bin/fortune$GOEXE

src/cmd/go/testdata/script/mod_lazy_downgrade.txt

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This test illustrates the interaction between lazy loading and downgrading in
2-
# 'go get.
2+
# 'go get'.
33

44
# The package import graph used in this test looks like:
55
#
@@ -46,7 +46,7 @@ go list -m all
4646
# outside of the deepening scan should not affect the downgrade.
4747

4848
cp go.mod.orig go.mod
49-
go mod edit -go=1.16
49+
go mod edit -go=1.17
5050

5151
go list -m all
5252
stdout '^example.com/a v0.1.0 '
@@ -59,12 +59,50 @@ stdout '^example.com/a v0.1.0 '
5959
stdout '^example.com/b v0.2.0 '
6060
stdout '^example.com/c v0.1.0 '
6161

62+
# At this point, b.2 is still an explicit root, so its dependency on c
63+
# is still tracked, and it will still be downgraded away if we remove c.
64+
# ('go get' never makes a root into a non-root. Only 'go mod tidy' does that.)
65+
6266
go get -d example.com/c@none
6367
go list -m all
64-
! stdout '^example.com/a ' # TODO(#36460): example.com/a v0.1.0
65-
! stdout '^example.com/b ' # TODO(#36460): example.com/b v0.1.0
68+
! stdout '^example.com/a '
69+
! stdout '^example.com/b '
6670
! stdout '^example.com/c '
6771

72+
73+
# This time, we drop the explicit 'b' root by downgrading it to v0.1.0
74+
# (the version required by a.1) and running 'go mod tidy'.
75+
# It is still selected at v0.1.0 (as a dependency of a),
76+
# but its dependency on c is now pruned from the module graph, so it doesn't
77+
# result in any downgrades to b or a if we run 'go get c@none'.
78+
79+
cp go.mod.orig go.mod
80+
go mod edit -go=1.17
81+
82+
go list -m all
83+
stdout '^example.com/a v0.1.0 '
84+
stdout '^example.com/b v0.3.0 '
85+
stdout '^example.com/c v0.2.0 '
86+
87+
go get -d example.com/[email protected] example.com/[email protected]
88+
go list -m all
89+
stdout '^example.com/a v0.1.0 '
90+
stdout '^example.com/b v0.1.0 '
91+
stdout '^example.com/c v0.1.0 '
92+
93+
go mod tidy
94+
go list -m all
95+
stdout '^example.com/a v0.1.0 '
96+
stdout '^example.com/b v0.1.0 '
97+
! stdout '^example.com/c '
98+
99+
go get -d example.com/c@none
100+
go list -m all
101+
stdout '^example.com/a v0.1.0'
102+
stdout '^example.com/b v0.1.0'
103+
! stdout '^example.com/c '
104+
105+
68106
-- go.mod --
69107
module example.com/lazy
70108

@@ -91,7 +129,7 @@ import _ "example.com/a"
91129
-- a/go.mod --
92130
module example.com/a
93131

94-
go 1.15
132+
go 1.17
95133

96134
require example.com/b v0.1.0
97135
-- a/a.go --
@@ -104,7 +142,7 @@ import _ "example.com/b"
104142
-- b1/go.mod --
105143
module example.com/b
106144

107-
go 1.15
145+
go 1.17
108146

109147
require example.com/c v0.1.0
110148
-- b1/b.go --
@@ -116,7 +154,7 @@ import _ "example.com/c"
116154
-- b2/go.mod --
117155
module example.com/b
118156

119-
go 1.15
157+
go 1.17
120158

121159
require example.com/c v0.1.0
122160
-- b2/b.go --
@@ -128,7 +166,7 @@ import _ "example.com/c"
128166
-- b3/go.mod --
129167
module example.com/b
130168

131-
go 1.15
169+
go 1.17
132170

133171
require example.com/c v0.2.0
134172
-- b3/b.go --
@@ -140,6 +178,6 @@ import _ "example.com/c"
140178
-- c/go.mod --
141179
module example.com/c
142180

143-
go 1.15
181+
go 1.17
144182
-- c/c.go --
145183
package c

src/cmd/go/testdata/script/mod_lazy_import_allmod.txt

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ stdout '^c v0.1.0 '
5353

5454
cp m.go.orig m.go
5555
cp go.mod.orig go.mod
56-
go mod edit -go=1.16
57-
go mod edit -go=1.16 go.mod.new
56+
go mod edit -go=1.17
57+
go mod edit -go=1.17 go.mod.new
5858

5959
cp go.mod go.mod.orig
6060
go mod tidy
@@ -63,14 +63,15 @@ cmp go.mod.orig go.mod
6363
go list -m all
6464
stdout '^a v0.1.0 '
6565
stdout '^b v0.1.0 '
66-
stdout '^c v0.1.0 ' # TODO(#36460): This should be pruned out.
66+
! stdout '^c '
6767

68-
# After adding a new import of b/y,
69-
# the import of c from b/y should again resolve to the version required by b.
68+
# After adding a new direct import of b/y,
69+
# the existing verison of b should be promoted to a root,
70+
# bringing the version of c required by b into the build list.
7071

7172
cp m.go.new m.go
7273
go mod tidy
73-
cmp go.mod.new go.mod
74+
cmp go.mod.lazy go.mod
7475

7576
go list -m all
7677
stdout '^a v0.1.0 '
@@ -124,6 +125,23 @@ require (
124125
b v0.1.0
125126
)
126127

128+
replace (
129+
a v0.1.0 => ./a1
130+
b v0.1.0 => ./b1
131+
c v0.1.0 => ./c1
132+
c v0.2.0 => ./c2
133+
)
134+
-- go.mod.lazy --
135+
module m
136+
137+
go 1.17
138+
139+
require (
140+
a v0.1.0
141+
b v0.1.0
142+
c v0.1.0 // indirect
143+
)
144+
127145
replace (
128146
a v0.1.0 => ./a1
129147
b v0.1.0 => ./b1
@@ -133,7 +151,7 @@ replace (
133151
-- a1/go.mod --
134152
module a
135153

136-
go 1.16
154+
go 1.17
137155

138156
require b v0.1.0
139157
-- a1/a.go --
@@ -145,7 +163,7 @@ import _ "b/x"
145163
-- b1/go.mod --
146164
module b
147165

148-
go 1.16
166+
go 1.17
149167

150168
require c v0.1.0
151169
-- b1/x/x.go --
@@ -161,7 +179,7 @@ func CVersion() string {
161179
-- c1/go.mod --
162180
module c
163181

164-
go 1.16
182+
go 1.17
165183
-- c1/c.go --
166184
package c
167185

0 commit comments

Comments
 (0)