cmd/go/internal/modload: only check root-promotion during tidy for lazy modules

In a lazy module, it is important that tidyRoots does not add any new
roots because the dependencies of non-roots are pruned out.

In an eager module, that property is not important (and does not hold
in general) because no dependencies are ever pruned out.

Fixes #45952

Change-Id: I5c95b5696b7112b9219e38af04e0dece7fb6e202
Reviewed-on: https://go-review.googlesource.com/c/go/+/316754
Trust: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index f434b39..c811029 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -1065,13 +1065,17 @@
 			ld.errorf("go: %v\n", err)
 		}
 
-		// We continuously add tidy roots to ld.requirements during loading, so at
-		// this point the tidy roots should be a subset of the roots of
-		// ld.requirements. If not, there is a bug in the loading loop above.
-		for _, m := range rs.rootModules {
-			if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version {
-				ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m)
-				base.ExitIfErrors()
+		if ld.requirements.depth == lazy {
+			// We continuously add tidy roots to ld.requirements during loading, so at
+			// this point the tidy roots should be a subset of the roots of
+			// ld.requirements, ensuring that no new dependencies are brought inside
+			// the lazy-loading horizon.
+			// If that is not the case, there is a bug in the loading loop above.
+			for _, m := range rs.rootModules {
+				if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version {
+					ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m)
+					base.ExitIfErrors()
+				}
 			}
 		}
 		ld.requirements = rs
diff --git a/src/cmd/go/testdata/script/mod_tidy_newroot.txt b/src/cmd/go/testdata/script/mod_tidy_newroot.txt
index db23a21..3abd5ef 100644
--- a/src/cmd/go/testdata/script/mod_tidy_newroot.txt
+++ b/src/cmd/go/testdata/script/mod_tidy_newroot.txt
@@ -12,8 +12,8 @@
 # dependency (or else no new root would be needed). An additional package D
 # in its own module satisfies that condition, reproducing the bug.
 
-! go mod tidy
-stderr 'internal error'
+go mod tidy
+cmp go.mod go.mod.tidy
 
 -- go.mod --
 module example.net/a
@@ -31,6 +31,22 @@
 	example.net/c v0.2.0 => ./c
 	example.net/d v0.1.0 => ./d
 )
+-- go.mod.tidy --
+module example.net/a
+
+go 1.16
+
+require (
+	example.net/c v0.2.0 // indirect
+	example.net/d v0.1.0
+)
+
+replace (
+	example.net/b v0.1.0 => ./b
+	example.net/c v0.1.0 => ./c
+	example.net/c v0.2.0 => ./c
+	example.net/d v0.1.0 => ./d
+)
 -- a.go --
 package a