cmd/go/internal/mvs: in Req, omit versions implied by older-than-selected versions already in the graph

Fixes #31248

Change-Id: Ia54f2098c3b85549681198a487a31e8ce8fc59eb
Reviewed-on: https://go-review.googlesource.com/c/go/+/186557
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go
index f9292a0..4e7a828 100644
--- a/src/cmd/go/internal/mvs/mvs.go
+++ b/src/cmd/go/internal/mvs/mvs.go
@@ -288,12 +288,12 @@
 	}
 
 	// Walk modules in reverse post-order, only adding those not implied already.
-	have := map[string]string{}
+	have := map[module.Version]bool{}
 	walk = func(m module.Version) error {
-		if v, ok := have[m.Path]; ok && reqs.Max(m.Version, v) == v {
+		if have[m] {
 			return nil
 		}
-		have[m.Path] = m.Version
+		have[m] = true
 		for _, m1 := range reqCache[m] {
 			walk(m1)
 		}
@@ -321,7 +321,7 @@
 			// Older version.
 			continue
 		}
-		if have[m.Path] != m.Version {
+		if !have[m] {
 			min = append(min, m)
 			walk(m)
 		}
diff --git a/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go
index ea27966..72d3ea9 100644
--- a/src/cmd/go/internal/mvs/mvs_test.go
+++ b/src/cmd/go/internal/mvs/mvs_test.go
@@ -295,6 +295,14 @@
 req A: G1
 req A G: G1
 req A H: H1
+
+name: req3
+M: A1 B1
+A1: X1
+B1: X2
+X1: I1
+X2: 
+req M: A1 B1
 `
 
 func Test(t *testing.T) {
diff --git a/src/cmd/go/testdata/script/mod_indirect_tidy.txt b/src/cmd/go/testdata/script/mod_indirect_tidy.txt
new file mode 100644
index 0000000..a12b35c
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_indirect_tidy.txt
@@ -0,0 +1,60 @@
+env GO111MODULE=on
+
+# golang.org/issue/31248: loading the build list must not add explicit entries
+# for indirect dependencies already implied by older-than-selected versions
+# already in the build list.
+
+cp go.mod.orig go.mod
+go mod tidy
+cmp go.mod go.mod.orig
+
+cp go.mod.orig go.mod
+go list -m all
+cmp go.mod go.mod.orig
+
+-- go.mod.orig --
+module main
+
+go 1.13
+
+require a v0.0.0
+
+replace (
+	a v0.0.0 => ./a
+	b v0.0.0 => ./b
+	i v0.0.0 => ./i
+	x v0.1.0 => ./x1
+	x v0.2.0 => ./x2
+)
+-- main.go --
+package main
+
+import _ "a"
+
+func main() {}
+-- a/go.mod --
+module a
+go 1.13
+require (
+	x v0.2.0
+	b v0.0.0
+)
+-- a/a.go --
+package a
+-- b/go.mod --
+module b
+go 1.13
+require x v0.1.0
+-- x1/go.mod --
+module x
+go 1.13
+require (
+	b v0.0.0
+	i v0.0.0
+)
+-- x2/go.mod --
+module x
+go 1.13
+-- i/go.mod --
+module i
+go 1.13