internal/fetch: report DocTooLarge error in goPackage.err

loadPackage has two return values: a *goPackage and an error.

Before this CL, if a package's documentation was too large,
loadPackage would return the package and a non-nil error.

With this CL, that error is stored in the goPackage struct in a new
field, and loadPackage returns a nil error.

Aside from being more idiomatic, this change will enable future
changes needed to support multiple GOOS/GOARCH combinations.

For golang/go#37232

Change-Id: If73adde76239046eb22409659d6795c09bbb1fd4
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/279457
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/internal/fetch/load.go b/internal/fetch/load.go
index 06c87cd..1e62873 100644
--- a/internal/fetch/load.go
+++ b/internal/fetch/load.go
@@ -59,7 +59,7 @@
 // loadPackage returns nil, nil.
 //
 // If the package is fine except that its documentation is too large, loadPackage
-// returns both a package and a non-nil error with godoc.ErrTooLarge in its chain.
+// returns a package whose err field is a non-nil error with godoc.ErrTooLarge in its chain.
 func loadPackage(ctx context.Context, zipGoFiles []*zip.File, innerPath string, sourceInfo *source.Info, modInfo *godoc.ModuleInfo) (_ *goPackage, err error) {
 	defer derrors.Wrap(&err, "loadPackage(ctx, zipGoFiles, %q, sourceInfo, modInfo)", innerPath)
 	ctx, span := trace.StartSpan(ctx, "fetch.loadPackage")
@@ -70,7 +70,8 @@
 			return nil, err
 		}
 		if pkg != nil {
-			return pkg, err
+			pkg.err = err
+			return pkg, nil
 		}
 	}
 	return nil, nil
@@ -88,9 +89,9 @@
 // zipGoFiles must contain only .go files that have been verified
 // to be of reasonable size.
 //
-// The returned Package.Licenses field is not populated.
+// The returned goPackage.licenses field is not populated.
 //
-// It returns a nil Package if the directory doesn't contain a Go package
+// It returns a nil goPackage if the directory doesn't contain a Go package
 // or all .go files have been excluded by constraints.
 // A *BadPackageError error is returned if the directory
 // contains .go files but do not make up a valid package.
@@ -115,8 +116,7 @@
 		docPkg.AddFile(pf, removeNodes)
 	}
 
-	// Encode before rendering: both operations mess with the AST, but Encode restores
-	// it enough to make Render work.
+	// Encode first, because Render messes with the AST.
 	src, err := docPkg.Encode(ctx)
 	if err != nil {
 		return nil, err
diff --git a/internal/fetch/package.go b/internal/fetch/package.go
index 3aa1240..b4bed4c 100644
--- a/internal/fetch/package.go
+++ b/internal/fetch/package.go
@@ -43,6 +43,7 @@
 	// series.
 	v1path string
 	source []byte // the source files of the package, for generating doc at serving time
+	err    error  // non-fatal error when loading the package (e.g. documentation is too large)
 }
 
 // extractPackagesFromZip returns a slice of packages from the module zip r.
@@ -197,13 +198,9 @@
 			incompleteDirs[innerPath] = true
 			status = derrors.PackageInvalidContents
 			errMsg = err.Error()
-		} else if errors.Is(err, godoc.ErrTooLarge) {
-			status = derrors.PackageDocumentationHTMLTooLarge
-			errMsg = err.Error()
 		} else if err != nil {
 			return nil, nil, fmt.Errorf("unexpected error loading package: %v", err)
 		}
-
 		var pkgPath string
 		if pkg == nil {
 			// No package.
@@ -214,6 +211,10 @@
 			}
 			pkgPath = path.Join(modulePath, innerPath)
 		} else {
+			if errors.Is(pkg.err, godoc.ErrTooLarge) {
+				status = derrors.PackageDocumentationHTMLTooLarge
+				errMsg = pkg.err.Error()
+			}
 			if d != nil { //  should only be nil for tests
 				isRedist, lics := d.PackageInfo(innerPath)
 				pkg.isRedistributable = isRedist