@@ -405,9 +405,38 @@ func LoadModFile(ctx context.Context) {
405
405
readVendorList ()
406
406
checkVendorConsistency ()
407
407
}
408
- if index .goVersionV == "" && cfg .BuildMod == "mod" {
409
- addGoStmt ()
410
- WriteGoMod ()
408
+ if index .goVersionV == "" {
409
+ // The main module necessarily has a go.mod file, and that file lacks a
410
+ // 'go' directive. The 'go' command has been adding that directive
411
+ // automatically since Go 1.12, so this module either dates to Go 1.11 or
412
+ // has been erroneously hand-edited.
413
+ //
414
+ // If we are able to modify the go.mod file, we will add a 'go' directive
415
+ // to at least make the situation explicit going forward.
416
+ if cfg .BuildMod == "mod" {
417
+ // TODO(#44976): If we implicitly upgrade to the latest Go version once
418
+ // lazy loading is implemented, we could accidentally prune out
419
+ // dependencies from what was formerly a Go 1.11 module, resulting in
420
+ // downgrades (if only lower requirements on that module remain) and/or
421
+ // upgrades (if no requirement remains and we end up re-resolving to
422
+ // latest).
423
+ //
424
+ // We should probably instead load the dependencies using Go 1.11
425
+ // semantics to ensure that we capture everything that is relevant, or
426
+ // perhaps error out and let the user tell us which version they intend.
427
+ //
428
+ // If we are running 'go mod tidy' in particular, we will have enough
429
+ // information to upgrade the 'go' version after loading is complete.
430
+ addGoStmt (latestGoVersion ())
431
+ WriteGoMod ()
432
+ } else {
433
+ // Reproducibility requires that if we change the semantics of a module,
434
+ // we write some explicit change to its go.mod file. We cannot write to
435
+ // the go.mod file (because we are in readonly or vendor mode), so we must
436
+ // not change its semantics either. The go.mod file looks as if it were
437
+ // created by Go 1.11, so assume Go 1.11 semantics.
438
+ rawGoVersion .Store (Target , "1.11" )
439
+ }
411
440
}
412
441
}
413
442
@@ -442,7 +471,7 @@ func CreateModFile(ctx context.Context, modPath string) {
442
471
modFile = new (modfile.File )
443
472
modFile .AddModuleStmt (modPath )
444
473
initTarget (modFile .Module .Mod )
445
- addGoStmt () // Add the go directive before converted module requirements.
474
+ addGoStmt (latestGoVersion () ) // Add the go directive before converted module requirements.
446
475
447
476
convertedFrom , err := convertLegacyConfig (modPath )
448
477
if convertedFrom != "" {
@@ -680,19 +709,18 @@ func convertLegacyConfig(modPath string) (from string, err error) {
680
709
// addGoStmt adds a go directive to the go.mod file if it does not already
681
710
// include one. The 'go' version added, if any, is the latest version supported
682
711
// by this toolchain.
683
- func addGoStmt () {
712
+ func addGoStmt (v string ) {
684
713
if modFile .Go != nil && modFile .Go .Version != "" {
685
714
return
686
715
}
687
- v := latestGoVersion ()
688
716
if err := modFile .AddGoStmt (v ); err != nil {
689
717
base .Fatalf ("go: internal error: %v" , err )
690
718
}
691
719
rawGoVersion .Store (Target , v )
692
720
}
693
721
694
722
// latestGoVersion returns the latest version of the Go language supported by
695
- // this toolchain.
723
+ // this toolchain, like "1.17" .
696
724
func latestGoVersion () string {
697
725
tags := build .Default .ReleaseTags
698
726
version := tags [len (tags )- 1 ]
0 commit comments