fix: add method checks for interface types
This commit is contained in:
committed by
Traefiker Bot
parent
488e491bf8
commit
1ff1a50753
17
_test/interface14.go
Normal file
17
_test/interface14.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (t *T) Error() string { return "T: error" }
|
||||
|
||||
var invalidT = &T{}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
if err != invalidT {
|
||||
println("ok")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
28
_test/interface15.go
Normal file
28
_test/interface15.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
type Fooer interface {
|
||||
Foo() string
|
||||
}
|
||||
|
||||
type Barer interface {
|
||||
//fmt.Stringer
|
||||
Fooer
|
||||
Bar()
|
||||
}
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (t *T) Foo() string { return "T: foo" }
|
||||
func (*T) Bar() { println("in bar") }
|
||||
|
||||
var t = &T{}
|
||||
|
||||
func main() {
|
||||
var f Barer
|
||||
if f != t {
|
||||
println("ok")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
25
_test/interface16.go
Normal file
25
_test/interface16.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Barer interface {
|
||||
fmt.Stringer
|
||||
Bar()
|
||||
}
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (*T) String() string { return "T: nothing" }
|
||||
func (*T) Bar() { println("in bar") }
|
||||
|
||||
var t = &T{}
|
||||
|
||||
func main() {
|
||||
var f Barer
|
||||
if f != t {
|
||||
println("ok")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
17
_test/interface17.go
Normal file
17
_test/interface17.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (t T) Error() string { return "T: error" }
|
||||
|
||||
var invalidT = T{}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
if err != invalidT {
|
||||
println("ok")
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
@@ -547,7 +547,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf()
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// All other binary operators require both parameter types to be the same
|
||||
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && c0.typ.id() != c1.typ.id() {
|
||||
if !isShiftNode(n) && !c0.typ.untyped && !c1.typ.untyped && !c0.typ.equal(c1.typ) {
|
||||
err = n.cfgErrorf("mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
||||
break
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ func assign(n *node) {
|
||||
switch {
|
||||
case dest.typ.cat == interfaceT:
|
||||
svalue[i] = genValueInterface(src)
|
||||
case dest.typ.cat == valueT && dest.typ.rtype.Kind() == reflect.Interface:
|
||||
case (dest.typ.cat == valueT || dest.typ.cat == errorT) && dest.typ.rtype.Kind() == reflect.Interface:
|
||||
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
|
||||
case dest.typ.cat == valueT && src.typ.cat == funcT:
|
||||
svalue[i] = genFunctionWrapper(src)
|
||||
|
||||
@@ -636,6 +636,51 @@ func (t *itype) finalize() (*itype, error) {
|
||||
return t, err
|
||||
}
|
||||
|
||||
// equal returns true if the given type is identical to the receiver one
|
||||
func (t *itype) equal(o *itype) bool {
|
||||
if isInterface(t) || isInterface(o) {
|
||||
// Check for identical methods sets
|
||||
return reflect.DeepEqual(t.methods(), o.methods())
|
||||
}
|
||||
return t.id() == o.id()
|
||||
}
|
||||
|
||||
// methods returns a map of method type strings, indexed by method names
|
||||
func (t *itype) methods() map[string]string {
|
||||
res := make(map[string]string)
|
||||
switch t.cat {
|
||||
case interfaceT:
|
||||
// Get methods from recursive analysis of interface fields
|
||||
for _, f := range t.field {
|
||||
if f.typ.cat == funcT {
|
||||
res[f.name] = f.typ.TypeOf().String()
|
||||
} else {
|
||||
for k, v := range f.typ.methods() {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case valueT, errorT:
|
||||
// Get method from corresponding reflect.Type
|
||||
for i := t.rtype.NumMethod() - 1; i >= 0; i-- {
|
||||
m := t.rtype.Method(i)
|
||||
res[m.Name] = m.Type.String()
|
||||
}
|
||||
case ptrT:
|
||||
// Consider only methods where receiver is a pointer to type t
|
||||
for _, m := range t.val.method {
|
||||
if m.child[0].child[0].lastChild().typ.cat == ptrT {
|
||||
res[m.ident] = m.typ.TypeOf().String()
|
||||
}
|
||||
}
|
||||
default:
|
||||
for _, m := range t.method {
|
||||
res[m.ident] = m.typ.TypeOf().String()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// id returns a unique type identificator string
|
||||
func (t *itype) id() string {
|
||||
// TODO: if res is nil, build identity from String()
|
||||
|
||||
Reference in New Issue
Block a user