diff --git a/_test/composite3.go b/_test/composite3.go new file mode 100644 index 000000000..8f4026df5 --- /dev/null +++ b/_test/composite3.go @@ -0,0 +1,12 @@ +package main + +func main() { + var err error + var ok bool + + _, ok = err.(interface{ IsSet() bool }) + println(ok) +} + +// Output: +// false diff --git a/_test/composite4.go b/_test/composite4.go new file mode 100644 index 000000000..b5e4b3f7a --- /dev/null +++ b/_test/composite4.go @@ -0,0 +1,11 @@ +package main + +func main() { + var err error + + _, ok := err.(interface{ IsSet() bool }) + println(ok) +} + +// Output: +// false diff --git a/interp/cfg.go b/interp/cfg.go index 73ad23584..8e9530a85 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -517,7 +517,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { n.child[l].gen = getIndexMap2 n.gen = nop case typeAssertExpr: - n.child[l].gen = typeAssert2 + if n.child[0].ident == "_" { + n.child[l].gen = typeAssertStatus + } else { + n.child[l].gen = typeAssert2 + } n.gen = nop case unaryExpr: if n.child[l].action == aRecv { @@ -1314,7 +1318,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { if len(n.child) > 1 { wireChild(n) if n.child[1].typ == nil { - n.child[1].typ = sc.getType(n.child[1].ident) + if n.child[1].typ, err = nodeType(interp, sc, n.child[1]); err != nil { + return + } } if n.anc.action != aAssignX { n.typ = n.child[1].typ @@ -1386,8 +1392,12 @@ func compDefineX(sc *scope, n *node) error { n.gen = nop case typeAssertExpr: + if n.child[0].ident == "_" { + n.child[l].gen = typeAssertStatus + } else { + n.child[l].gen = typeAssert2 + } types = append(types, n.child[l].child[1].typ, sc.getType("bool")) - n.child[l].gen = typeAssert2 n.gen = nop case unaryExpr: @@ -1595,7 +1605,8 @@ func isKey(n *node) bool { return n.anc.kind == fileStmt || (n.anc.kind == selectorExpr && n.anc.child[0] != n) || (n.anc.kind == funcDecl && isMethod(n.anc)) || - (n.anc.kind == keyValueExpr && isStruct(n.anc.typ) && n.anc.child[0] == n) + (n.anc.kind == keyValueExpr && isStruct(n.anc.typ) && n.anc.child[0] == n) || + (n.anc.kind == fieldExpr && len(n.anc.child) > 1 && n.anc.child[0] == n) } // isNewDefine returns true if node refers to a new definition diff --git a/interp/run.go b/interp/run.go index 4d582f672..885681c28 100644 --- a/interp/run.go +++ b/interp/run.go @@ -119,6 +119,37 @@ func runCfg(n *node, f *frame) { } } +func typeAssertStatus(n *node) { + value := genValue(n.child[0]) // input value + value1 := genValue(n.anc.child[1]) // returned status + next := getExec(n.tnext) + + switch { + case n.child[0].typ.cat == valueT: + n.exec = func(f *frame) bltn { + if !value(f).IsValid() || value(f).IsNil() { + value1(f).SetBool(false) + } + value1(f).SetBool(true) + return next + } + case n.child[1].typ.cat == interfaceT: + n.exec = func(f *frame) bltn { + _, ok := value(f).Interface().(valueInterface) + //value0(f).Set(reflect.ValueOf(valueInterface{v.node, v.value})) + value1(f).SetBool(ok) + return next + } + default: + n.exec = func(f *frame) bltn { + _, ok := value(f).Interface().(valueInterface) + //value0(f).Set(v.value) + value1(f).SetBool(ok) + return next + } + } +} + func typeAssert(n *node) { value := genValue(n.child[0]) i := n.findex