return
}
- if !lookdot(n, t, 0) {
- if lookdot(n, t, 1) {
+ if lookdot(n, t, 0) == nil {
+ // Legitimate field or method lookup failed, try to explain the error
+ switch {
+ case isnilinter(t):
+ Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
+
+ case Isptr[t.Etype] && Isinter(t.Type):
+ // Pointer to interface is almost always a mistake.
+ Yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
+
+ case lookdot(n, t, 1) != nil:
+ // Field or method matches by name, but it is not exported.
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym)
- } else {
- Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
+
+ default:
+ if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
+ Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym)
+ } else {
+ Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
+ }
}
n.Type = nil
return
if dostrcmp != 0 && f.Sym.Name == s.Name {
return f
}
+ if dostrcmp == 2 && strings.EqualFold(f.Sym.Name, s.Name) {
+ return f
+ }
if f.Sym != s {
continue
}
return t
}
-func lookdot(n *Node, t *Type, dostrcmp int) bool {
+func lookdot(n *Node, t *Type, dostrcmp int) *Type {
s := n.Right.Sym
dowidth(t)
}
if f1 != nil {
+ if dostrcmp > 1 {
+ // Already in the process of diagnosing an error.
+ return f1
+ }
if f2 != nil {
Yyerror("%v is both field and method", n.Right.Sym)
}
n.Op = ODOTINTER
}
- return true
+ return f1
}
if f2 != nil {
+ if dostrcmp > 1 {
+ // Already in the process of diagnosing an error.
+ return f2
+ }
tt := n.Left.Type
dowidth(tt)
rcvr := getthisx(f2.Type).Type.Type
// It is invalid to automatically dereference a named pointer type when selecting a method.
// Make n->left == ll to clarify error message.
n.Left = ll
- return false
+ return nil
}
}
// print("lookdot found [%p] %T\n", f2->type, f2->type);
n.Op = ODOTMETH
- return true
+ return f2
}
- return false
+ return nil
}
func nokeys(l *NodeList) bool {
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package other
+
+type Exported interface {
+ Do()
+ secret()
+}
--- /dev/null
+// errorcheck -0 -m -l
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./other"
+
+type Imported interface {
+ Do()
+}
+
+type HasAMethod struct {
+ x int
+}
+
+func (me *HasAMethod) Do() {
+ println(me.x)
+}
+
+func InMyCode(x *Imported, y *HasAMethod, z *other.Exported) {
+ x.Do() // ERROR "x\.Do undefined \(type \*Imported is pointer to interface, not interface\)"
+ x.do() // ERROR "x\.do undefined \(type \*Imported is pointer to interface, not interface\)"
+ (*x).Do()
+ x.Dont() // ERROR "x\.Dont undefined \(type \*Imported is pointer to interface, not interface\)"
+ (*x).Dont() // ERROR "\(\*x\)\.Dont undefined \(type Imported has no field or method Dont\)"
+
+ y.Do()
+ y.do() // ERROR "y\.do undefined \(type \*HasAMethod has no field or method do, but does have Do\)"
+ (*y).Do()
+ (*y).do() // ERROR "\(\*y\)\.do undefined \(type HasAMethod has no field or method do, but does have Do\)"
+ y.Dont() // ERROR "y\.Dont undefined \(type \*HasAMethod has no field or method Dont\)"
+ (*y).Dont() // ERROR "\(\*y\)\.Dont undefined \(type HasAMethod has no field or method Dont\)"
+
+ z.Do() // ERROR "z\.Do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+ z.do() // ERROR "z\.do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+ (*z).Do()
+ (*z).do() // ERROR "\(\*z\)\.do undefined \(type other.Exported has no field or method do, but does have Do\)"
+ z.Dont() // ERROR "z\.Dont undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+ (*z).Dont() // ERROR "\(\*z\)\.Dont undefined \(type other\.Exported has no field or method Dont\)"
+ z.secret() // ERROR "z\.secret undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+ (*z).secret() // ERROR "\(\*z\)\.secret undefined \(cannot refer to unexported field or method secret\)"
+
+}
+
+func main() {
+}
--- /dev/null
+// errorcheckdir
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
const Value = 1e12
-type Inter interface { M() int64 }
+type Inter interface {
+ M() int64
+}
type T int64
+
func (t T) M() int64 { return int64(t) }
+
var t = T(Value)
var pt = &t
var ti Inter = t
var pti = &ti
-type S struct { Inter }
-var s = S{ ti }
+type S struct{ Inter }
+
+var s = S{ti}
var ps = &s
-type SP struct { *Inter } // ERROR "interface"
+type SP struct{ *Inter } // ERROR "interface"
var i Inter
var pi = &i
check("t.M()", t.M())
check("pt.M()", pt.M())
check("ti.M()", ti.M())
- check("pti.M()", pti.M()) // ERROR "method"
+ check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface"
check("s.M()", s.M())
check("ps.M()", ps.M())
i = t
check("i = t; i.M()", i.M())
- check("i = t; pi.M()", pi.M()) // ERROR "method"
+ check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
i = pt
check("i = pt; i.M()", i.M())
- check("i = pt; pi.M()", pi.M()) // ERROR "method"
+ check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
i = s
check("i = s; i.M()", i.M())
- check("i = s; pi.M()", pi.M()) // ERROR "method"
+ check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
i = ps
check("i = ps; i.M()", i.M())
- check("i = ps; pi.M()", pi.M()) // ERROR "method"
+ check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
if !ok {
println("BUG: interface10")