cmd/go/internal/vgo: speed up go.mod parsing

CL 106799 changed the mod file parser to be call
the fixer function for every module, version pair,
not just the ones with non-canonical semantic versions.
Of course, we don't want to hit the network for every line
of every go.mod, when most of them are fine.
Skip the network for the ones that are syntactically OK,
including proper matching between the module path and
major version.

For golang/go#24369.

Change-Id: Id101d8f3c10bccde8a755ae734dbacf4d0a36f8d
Reviewed-on: https://go-review.googlesource.com/107655
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/vendor/cmd/go/internal/vgo/init.go b/vendor/cmd/go/internal/vgo/init.go
index 09704ac..6da6f5d 100644
--- a/vendor/cmd/go/internal/vgo/init.go
+++ b/vendor/cmd/go/internal/vgo/init.go
@@ -14,6 +14,7 @@
 	"cmd/go/internal/module"
 	"cmd/go/internal/mvs"
 	"cmd/go/internal/search"
+	"cmd/go/internal/semver"
 	"encoding/json"
 	"flag"
 	"fmt"
@@ -338,6 +339,17 @@
 }
 
 func fixVersion(path, vers string) (string, error) {
+	// fixVersion is called speculatively on every
+	// module, version pair from every go.mod file.
+	// Avoid the query if it looks OK.
+	_, pathMajor, ok := module.SplitPathVersion(path)
+	if !ok {
+		return "", fmt.Errorf("malformed module path: %s", path)
+	}
+	if semver.IsValid(vers) && vers == semver.Canonical(vers) && module.MatchPathMajor(vers, pathMajor) {
+		return vers, nil
+	}
+
 	info, err := modfetch.Query(path, vers, nil)
 	if err != nil {
 		return "", err