New vet checks can make old code's tests stop passing. An example is #57059, where the printf format checker got more precise in Go 1.18. Code that tested fine with Go 1.17 stops passing tests in Go 1.18.
Vet needs to know which Go version each package was written for anyway. Perhaps it should use that information to disable checks that are newer than that version, so that tests don't start failing due to new vet reports until you update the go.mod go line.
For the go command, we can forward the module information from go/packages. I am not really sure where one gets the go version of the package from bazel builds yet. sdk_version is on go_cross_binary.
It would be nice if knew we were going to use this before we commit to supporting it. I am not sure we would use this for #57059 at the moment. A range variable semantic change would require this for loopclosure (related #56010).
A somewhat related problem is rolling out precision improvements to existing checks incrementally. Perhaps using the version number would have been a good way to gate the t.Parallel improvement to loopclosure? It gives a good and consistent story of "as a part of updating to the new version, you must also fix new warning from new checks". A problem with doing this is that this particular check can still flag issues in older code. It seems a pity to not warn and get those unit tests fixed due to the go.mod file not being updated.
I would use it for any new analysis that we add in a particular version of Go. I think we could have used this for the Printf check when we did the expansion in Go 1.18 to look at constant values.
The analysis doesn't run when the go.mod go line says an earlier version than when it was introduced. That way if people update to a new Go toolchain and run 'go test ./...', the test failures don't happen until they update the go.mod to opt in to the new release semantics. I would have done the same for the loopclosure fix. If people want the warnings, they are welcome to update the Go version and get them. If they just want to build some old code with a new toolchain, we should make that the least disruptive we can. We want to prioritize compatibility over new test errors.
Everything is going to have to be updated to understand per-module language versions when it's time for the for loop fix. The go command and the compiler obviously already understand that. We will need to pass it to vet as well. And Bazel will need to understand it too, I assume by gazelle writing something per BUILD file or per Go rule. So the version is going to be there already.