fix: partial implementation of conversion to interface (#209)
This commit is contained in:
committed by
Ludovic Fernandez
parent
7a35d2b0b6
commit
ac9c30d0bb
25
_test/interface8.go
Normal file
25
_test/interface8.go
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user