downgraded = append(downgraded, r)
}
+ // The downgrades we computed above only downgrade to versions enumerated by
+ // reqs.Previous. However, reqs.Previous omits some versions — such as
+ // pseudo-versions and retracted versions — that may be selected as transitive
+ // requirements of other modules.
+ //
+ // If one of those requirements pulls the version back up above the version
+ // identified by reqs.Previous, then the transitive dependencies of that that
+ // initially-downgraded version should no longer matter — in particular, we
+ // should not add new dependencies on module paths that nothing else in the
+ // updated module graph even requires.
+ //
+ // In order to eliminate those spurious dependencies, we recompute the build
+ // list with the actual versions of the downgraded modules as selected by MVS,
+ // instead of our initial downgrades.
+ // (See the downhiddenartifact and downhiddencross test cases).
+ actual, err := BuildList(target, &override{
+ target: target,
+ list: downgraded,
+ Reqs: reqs,
+ })
+ if err != nil {
+ return nil, err
+ }
+ actualVersion := make(map[string]string, len(actual))
+ for _, m := range actual {
+ actualVersion[m.Path] = m.Version
+ }
+
+ downgraded = downgraded[:0]
+ for _, m := range list {
+ if v, ok := actualVersion[m.Path]; ok {
+ downgraded = append(downgraded, module.Version{Path: m.Path, Version: v})
+ }
+ }
+
return BuildList(target, &override{
target: target,
list: downgraded,
# And C1 requires B2.hidden, and B2.hidden also meets our requirements:
# it is compatible with D1 and a strict downgrade from B3.
#
-# BUG(?): B2.hidden does not require E1, so there is no need for E1
-# to appear in the final build list. Nonetheless, there it is.
+# Since neither the initial nor the final build list includes B1,
+# and the nothing in the final downgraded build list requires E at all,
+# no dependency on E1 (required by only B1) should be introduced.
#
name: downhiddenartifact
A: B3 C2
build A1: A1 B3 D2
downgrade A1 D1: A1 B1 D1 E1
build A: A B3 C2 D2
-downgrade A D1: A B2.hidden C1 D1 E1
+downgrade A D1: A B2.hidden C1 D1
# Both B3 and C3 require D2.
# If we downgrade D to D1, then in isolation B3 would downgrade to B1,
go mod tidy
cmp go.mod.orig go.mod
+# When we downgrade d.2 to d.1, no dependency on e should be added
+# because nothing else in the module or import graph requires it.
go get -d example.net/d@v0.1.0
go list -m all
stdout '^example.net/b v0.2.1-0.20210219000000-000000000000 '
stdout '^example.net/c v0.1.0 '
stdout '^example.net/d v0.1.0 '
-
- # BUG: A dependency on e is added even though nothing requires it.
-stdout '^example.net/e '
-
-go mod why -m example.net/e
-stdout '^\(main module does not need module example.net/e\)'
+! stdout '^example.net/e '
-- go.mod --
module example.net/a