@@ -176,10 +176,13 @@ func findGoModFiles(root string) []string {
176176 return util .FindAllFilesWithName (root , "go.mod" , "vendor" )
177177}
178178
179+ // A regular expression for the Go toolchain version syntax.
180+ var toolchainVersionRe * regexp.Regexp = regexp .MustCompile (`(?m)^([0-9]+\.[0-9]+\.[0-9]+)$` )
181+
179182// Given a list of `go.mod` file paths, try to parse them all. The resulting array of `GoModule` objects
180183// will be the same length as the input array and the objects will contain at least the `go.mod` path.
181184// If parsing the corresponding file is successful, then the parsed contents will also be available.
182- func LoadGoModules (goModFilePaths []string ) []* GoModule {
185+ func LoadGoModules (emitDiagnostics bool , goModFilePaths []string ) []* GoModule {
183186 results := make ([]* GoModule , len (goModFilePaths ))
184187
185188 for i , goModFilePath := range goModFilePaths {
@@ -201,6 +204,15 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
201204 }
202205
203206 results [i ].Module = modFile
207+
208+ // If this `go.mod` file specifies a Go language version, that version is `1.21` or greater, and
209+ // there is no `toolchain` directive, check that it is a valid Go toolchain version. Otherwise,
210+ // `go` commands which try to download the right version of the Go toolchain will fail. We detect
211+ // this situation and emit a diagnostic.
212+ if modFile .Toolchain == nil && modFile .Go != nil &&
213+ ! toolchainVersionRe .Match ([]byte (modFile .Go .Version )) && semver .Compare ("v" + modFile .Go .Version , "v1.21.0" ) >= 0 {
214+ diagnostics .EmitInvalidToolchainVersion (goModFilePath , modFile .Go .Version )
215+ }
204216 }
205217
206218 return results
@@ -209,7 +221,7 @@ func LoadGoModules(goModFilePaths []string) []*GoModule {
209221// Given a path to a `go.work` file, this function attempts to parse the `go.work` file. If unsuccessful,
210222// we attempt to discover `go.mod` files within subdirectories of the directory containing the `go.work`
211223// file ourselves.
212- func discoverWorkspace (workFilePath string ) GoWorkspace {
224+ func discoverWorkspace (emitDiagnostics bool , workFilePath string ) GoWorkspace {
213225 log .Printf ("Loading %s...\n " , workFilePath )
214226 baseDir := filepath .Dir (workFilePath )
215227 workFileSrc , err := os .ReadFile (workFilePath )
@@ -223,7 +235,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
223235
224236 return GoWorkspace {
225237 BaseDir : baseDir ,
226- Modules : LoadGoModules (goModFilePaths ),
238+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
227239 DepMode : GoGetWithModules ,
228240 ModMode : getModMode (GoGetWithModules , baseDir ),
229241 }
@@ -240,7 +252,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
240252
241253 return GoWorkspace {
242254 BaseDir : baseDir ,
243- Modules : LoadGoModules (goModFilePaths ),
255+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
244256 DepMode : GoGetWithModules ,
245257 ModMode : getModMode (GoGetWithModules , baseDir ),
246258 }
@@ -263,7 +275,7 @@ func discoverWorkspace(workFilePath string) GoWorkspace {
263275 return GoWorkspace {
264276 BaseDir : baseDir ,
265277 WorkspaceFile : workFile ,
266- Modules : LoadGoModules (goModFilePaths ),
278+ Modules : LoadGoModules (emitDiagnostics , goModFilePaths ),
267279 DepMode : GoGetWithModules ,
268280 ModMode : ModReadonly , // Workspaces only support "readonly"
269281 }
@@ -286,7 +298,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
286298 for i , goModFile := range goModFiles {
287299 results [i ] = GoWorkspace {
288300 BaseDir : filepath .Dir (goModFile ),
289- Modules : LoadGoModules ([]string {goModFile }),
301+ Modules : LoadGoModules (emitDiagnostics , []string {goModFile }),
290302 DepMode : GoGetWithModules ,
291303 ModMode : getModMode (GoGetWithModules , filepath .Dir (goModFile )),
292304 }
@@ -303,7 +315,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
303315
304316 results := make ([]GoWorkspace , len (goWorkFiles ))
305317 for i , workFilePath := range goWorkFiles {
306- results [i ] = discoverWorkspace (workFilePath )
318+ results [i ] = discoverWorkspace (emitDiagnostics , workFilePath )
307319 }
308320
309321 // Add all stray `go.mod` files (i.e. those not referenced by `go.work` files)
@@ -335,7 +347,7 @@ func discoverWorkspaces(emitDiagnostics bool) []GoWorkspace {
335347 log .Printf ("Module %s is not referenced by any go.work file; adding it separately.\n " , goModFile )
336348 results = append (results , GoWorkspace {
337349 BaseDir : filepath .Dir (goModFile ),
338- Modules : LoadGoModules ([]string {goModFile }),
350+ Modules : LoadGoModules (emitDiagnostics , []string {goModFile }),
339351 DepMode : GoGetWithModules ,
340352 ModMode : getModMode (GoGetWithModules , filepath .Dir (goModFile )),
341353 })
0 commit comments