fix: partial implementation of conversion to interface (#209)

This commit is contained in:
Marc Vertes
2019-06-11 09:37:27 +02:00
committed by Ludovic Fernandez
parent 7a35d2b0b6
commit ac9c30d0bb
3 changed files with 60 additions and 5 deletions

25
_test/interface8.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import (
"fmt"
)
var _ = (HelloInterface)((*Hello)(nil))
type HelloInterface interface {
Hi() string
}
type Hello struct{}
func (h *Hello) Hi() string {
return "hi"
}
func main() {
h := &Hello{}
fmt.Println(h.Hi())
}
// Output:
// hi

View File

@@ -700,9 +700,23 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) {
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == BasicLit && isFloat(n.child[1].typ.TypeOf()) {
err = n.cfgError("truncated to integer")
}
n.gen = convert
n.typ = n.child[0].typ
n.findex = scope.add(n.typ)
if isInterface(n.child[0].typ) {
// Convert to interface: just check that all required methods are defined by concrete type.
c0, c1 := n.child[0], n.child[1]
if !c1.typ.implements(c0.typ) {
err = n.cfgError("type %v does not implement interface %v", c1.typ.id(), c0.typ.id())
}
// Pass value as is
n.gen = nop
n.typ = n.child[1].typ
n.findex = n.child[1].findex
n.val = n.child[1].val
n.rval = n.child[1].rval
} else {
n.gen = convert
n.typ = n.child[0].typ
n.findex = scope.add(n.typ)
}
case isBinCall(n):
n.gen = callBin
if typ := n.child[0].typ.rtype; typ.NumOut() > 0 {

View File

@@ -335,6 +335,9 @@ func nodeType(interp *Interpreter, scope *Scope, n *Node) (*Type, error) {
}
t.incomplete = t.key.incomplete || t.val.incomplete
case ParenExpr:
t, err = nodeType(interp, scope, n.child[0])
case SelectorExpr:
pkg, name := n.child[0].ident, n.child[1].ident
if sym, _, found := scope.lookup(pkg); found {
@@ -456,9 +459,12 @@ func (t *Type) id() string {
// TODO: if res is nil, build identity from String()
res := ""
if t.cat == ValueT {
switch t.cat {
case ValueT:
res = t.rtype.PkgPath() + "." + t.rtype.Name()
} else {
case PtrT:
res = "*" + t.val.id()
default:
res = t.pkgPath + "." + t.name
}
return res
@@ -695,6 +701,14 @@ func (t *Type) frameType() reflect.Type {
return r
}
func (t *Type) implements(it *Type) bool {
if t.cat == ValueT {
return t.TypeOf().Implements(it.TypeOf())
}
// TODO: implement method check for interpreted types
return true
}
func defRecvType(n *Node) *Type {
if n.kind != FuncDecl || len(n.child[0].child) == 0 {
return nil
@@ -713,6 +727,8 @@ func isShiftOperand(n *Node) bool {
return false
}
func isInterface(t *Type) bool { return t.cat == InterfaceT || t.TypeOf().Kind() == reflect.Interface }
func isStruct(t *Type) bool { return t.TypeOf().Kind() == reflect.Struct }
func isInt(t reflect.Type) bool {