Avoid type-inference warnings due to partial type info.

Signed-off-by: Joe Tsai <joetsai@google.com>
diff --git a/lint.go b/lint.go
index 3aaaf2a..14cc626 100644
--- a/lint.go
+++ b/lint.go
@@ -935,18 +935,6 @@
 	"0i":  true,
 }
 
-// knownWeakerTypes is a set of types that are commonly used to weaken var declarations.
-// A common form of var declarations that legitimately mentions an explicit LHS type
-// is where the LHS type is "weaker" than the exact RHS type, where "weaker" means an
-// interface compared to a concrete type, or an interface compared to a superset interface.
-// A canonical example is `var out io.Writer = os.Stdout`.
-// This is only used when type checking fails to determine the exact types.
-var knownWeakerTypes = map[string]bool{
-	"io.Reader":     true,
-	"io.Writer":     true,
-	"proto.Message": true,
-}
-
 // lintVarDecls examines variable declarations. It complains about declarations with
 // redundant LHS types that can be inferred from the RHS.
 func (f *file) lintVarDecls() {
@@ -986,7 +974,13 @@
 			}
 			lhsTyp := f.pkg.typeOf(v.Type)
 			rhsTyp := f.pkg.typeOf(rhs)
-			if lhsTyp != nil && rhsTyp != nil && !types.Identical(lhsTyp, rhsTyp) {
+
+			if !validType(lhsTyp) || !validType(rhsTyp) {
+				// Type checking failed (often due to missing imports).
+				return false
+			}
+
+			if !types.Identical(lhsTyp, rhsTyp) {
 				// Assignment to a different type is not redundant.
 				return false
 			}
@@ -1005,13 +999,6 @@
 			if defType, ok := f.isUntypedConst(rhs); ok && !isIdent(v.Type, defType) {
 				return false
 			}
-			// If the LHS is a known weaker type, and we couldn't type check both sides,
-			// don't warn.
-			if lhsTyp == nil || rhsTyp == nil {
-				if knownWeakerTypes[f.render(v.Type)] {
-					return false
-				}
-			}
 
 			f.errorf(v.Type, 0.8, category("type-inference"), "should omit type %s from declaration of var %s; it will be inferred from the right-hand side", f.render(v.Type), v.Names[0])
 			return false
@@ -1020,6 +1007,12 @@
 	})
 }
 
+func validType(T types.Type) bool {
+	return T != nil &&
+		T != types.Typ[types.Invalid] &&
+		!strings.Contains(T.String(), "invalid type") // good but not foolproof
+}
+
 // lintElses examines else blocks. It complains about any else block whose if block ends in a return.
 func (f *file) lintElses() {
 	// We don't want to flag if { } else if { } else { } constructions.
diff --git a/testdata/var-decl.go b/testdata/var-decl.go
index d382bee..9201d18 100644
--- a/testdata/var-decl.go
+++ b/testdata/var-decl.go
@@ -3,8 +3,13 @@
 // Package foo ...
 package foo
 
-import "fmt"
-import "net/http"
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"nosuchpkg" // export data unavailable
+	"os"
+)
 
 // Q is a test type.
 type Q bool
@@ -63,16 +68,17 @@
 // LHS is a different type than the RHS.
 var myStringer fmt.Stringer = q(0)
 
-// We don't figure out the true types of LHS and RHS here,
-// but io.Writer is a known weaker type for many common uses,
-// so the suggestion should be suppressed here.
+// LHS is a different type than the RHS.
 var out io.Writer = os.Stdout
 
-// This next one, however, should be type checked.
-var out2 io.Writer = newWriter() // MATCH /should.*io\.Writer/
+var out2 io.Writer = newWriter() // MATCH /should omit.*io\.Writer/
 
 func newWriter() io.Writer { return nil }
 
+// We don't figure out the true types of LHS and RHS here,
+// so we suppress the check.
+var ni nosuchpkg.Interface = nosuchpkg.NewConcrete()
+
 var y string = q(1).String() // MATCH /should.*string/
 
 type q int