diff --git a/cmd/vet/types.go b/cmd/vet/types.go index 055f403ad7..084be85d68 100644 --- a/cmd/vet/types.go +++ b/cmd/vet/types.go @@ -19,8 +19,8 @@ var imports = make(map[string]*types.Package) var ( errorType *types.Interface - stringerType *types.Interface - formatterType *types.Interface + stringerType *types.Interface // possibly nil + formatterType *types.Interface // possibly nil ) func init() { @@ -37,13 +37,12 @@ func init() { // importType returns the type denoted by the qualified identifier // path.name, and adds the respective package to the imports map -// as a side effect. +// as a side effect. In case of an error, importType returns nil. func importType(path, name string) types.Type { pkg, err := types.DefaultImport(imports, path) if err != nil { - // This can happen if fmt hasn't been compiled yet. - // Since nothing uses formatterType anyway, don't complain. - //warnf("import failed: %v", err) + // This can happen if the package at path hasn't been compiled yet. + warnf("import failed: %v", err) return nil } if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok { @@ -136,16 +135,13 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp } } // If the type implements fmt.Formatter, we have nothing to check. - // But (see issue 6259) that's not easy to verify, so instead we see - // if its method set contains a Format function. We could do better, - // even now, but we don't need to be 100% accurate. Wait for 6259 to - // be fixed instead. TODO. - if f.hasMethod(typ, "Format") { + // formatterTyp may be nil - be conservative and check for Format method in that case. + if formatterType != nil && types.Implements(typ, formatterType) || f.hasMethod(typ, "Format") { return true } // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? if t&argString != 0 { - if types.AssertableTo(errorType, typ) || types.AssertableTo(stringerType, typ) { + if types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) { return true } } @@ -319,7 +315,9 @@ func (f *File) isErrorMethodCall(call *ast.CallExpr) bool { if typ != nil { // We know it's called "Error", so just check the function signature // (stringerType has exactly one method, String). - return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type()) + if stringerType != nil && stringerType.NumMethods() == 1 { + return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type()) + } } // Without types, we can still check by hand. // Is it a selector expression? Otherwise it's a function call, not a method call.