refactor/rename: don't stop because of "soft" errors

Because go/types is slightly more strict than gc about certain "soft"
errors (ones that aren't necessary to interpret a Go program), gorename
rejects programs that compile under gc.  This change relaxes gorename's
error checks so that they are weaker than gc's.

This is a workaround for issue golang/go#14596 in gorename,
whose underlying problem is issue golang/go#8560 in gc.

Fixes golang/go#14596

Change-Id: Ica5006c2376c0564a575224269093c1497348ee6
Reviewed-on: https://go-review.googlesource.com/29853
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/refactor/rename/rename.go b/refactor/rename/rename.go
index 766bbc2..40ca480 100644
--- a/refactor/rename/rename.go
+++ b/refactor/rename/rename.go
@@ -384,7 +384,41 @@
 	for pkg := range pkgs {
 		conf.ImportWithTests(pkg)
 	}
-	return conf.Load()
+
+	// Ideally we would just return conf.Load() here, but go/types
+	// reports certain "soft" errors that gc does not (Go issue 14596).
+	// As a workaround, we set AllowErrors=true and then duplicate
+	// the loader's error checking but allow soft errors.
+	// It would be nice if the loader API permitted "AllowErrors: soft".
+	conf.AllowErrors = true
+	prog, err := conf.Load()
+	var errpkgs []string
+	// Report hard errors in indirectly imported packages.
+	for _, info := range prog.AllPackages {
+		if containsHardErrors(info.Errors) {
+			errpkgs = append(errpkgs, info.Pkg.Path())
+		}
+	}
+	if errpkgs != nil {
+		var more string
+		if len(errpkgs) > 3 {
+			more = fmt.Sprintf(" and %d more", len(errpkgs)-3)
+			errpkgs = errpkgs[:3]
+		}
+		return nil, fmt.Errorf("couldn't load packages due to errors: %s%s",
+			strings.Join(errpkgs, ", "), more)
+	}
+	return prog, err
+}
+
+func containsHardErrors(errors []error) bool {
+	for _, err := range errors {
+		if err, ok := err.(types.Error); ok && err.Soft {
+			continue
+		}
+		return true
+	}
+	return false
 }
 
 // requiresGlobalRename reports whether this renaming could potentially
diff --git a/refactor/rename/rename_test.go b/refactor/rename/rename_test.go
index 0b3aad6..04931a9 100644
--- a/refactor/rename/rename_test.go
+++ b/refactor/rename/rename_test.go
@@ -1061,6 +1061,29 @@
 `,
 			},
 		},
+		// Progress after "soft" type errors (Go issue 14596).
+		{
+			ctxt: fakeContext(map[string][]string{
+				"main": {`package main
+
+func main() {
+	var unused, x int
+	print(x)
+}
+`,
+				},
+			}),
+			offset: "/go/src/main/0.go:#54", to: "y", // var x
+			want: map[string]string{
+				"/go/src/main/0.go": `package main
+
+func main() {
+	var unused, y int
+	print(y)
+}
+`,
+			},
+		},
 	} {
 		if test.ctxt != nil {
 			ctxt = test.ctxt