fix: improve setting of interface objects
This commit is contained in:
9
_test/add0.go
Normal file
9
_test/add0.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 2 + 5
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
10
_test/add1.go
Normal file
10
_test/add1.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a interface{} = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
12
_test/add2.go
Normal file
12
_test/add2.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
type iface interface{}
|
||||
|
||||
func main() {
|
||||
b := 2
|
||||
var a iface = 5 + b
|
||||
println(a.(int))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 7
|
||||
9
_test/comp1.go
Normal file
9
_test/comp1.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a interface{} = 1 < 2
|
||||
println(a.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -1,15 +1,15 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
b := true
|
||||
a := 0
|
||||
b := true
|
||||
c := false
|
||||
if (b && c) {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
if b && c {
|
||||
a = 1
|
||||
} else {
|
||||
a = -1
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
|
||||
9
_test/not2.go
Normal file
9
_test/not2.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var b interface{} = !(1 == 2)
|
||||
println(b.(bool))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -17,9 +17,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
{{range $name, $op := .Arithmetic}}
|
||||
func {{$name}}(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -379,7 +379,7 @@ func {{$name}}Const(n *node) {
|
||||
{{range $name, $op := .Comparison}}
|
||||
func {{$name}}(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
@@ -625,12 +625,12 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if c0.rval.IsValid() && c1.rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // Force compute of reflection type.
|
||||
constOp[n.action](n) // Compute a constant result now rather than during exec.
|
||||
}
|
||||
@@ -654,11 +654,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.findex = pos
|
||||
default:
|
||||
// Allocate a new location in frame, and store the result here.
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
@@ -1566,13 +1561,13 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && constOp[n.action] != nil {
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: Optimisation: avoid allocation if boolean branch op (i.e. '!' in an 'if' expr)
|
||||
if n.child[0].rval.IsValid() && !isInterface(n.typ) && constOp[n.action] != nil {
|
||||
n.typ.TypeOf() // init reflect type
|
||||
constOp[n.action](n)
|
||||
}
|
||||
@@ -1589,11 +1584,6 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
n.typ = sc.def.typ.ret[pos]
|
||||
n.findex = pos
|
||||
default:
|
||||
if n.typ == nil {
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
|
||||
|
||||
56
interp/op.go
56
interp/op.go
@@ -7,9 +7,9 @@ import "reflect"
|
||||
// Arithmetic operators
|
||||
|
||||
func add(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -167,9 +167,9 @@ func addConst(n *node) {
|
||||
}
|
||||
|
||||
func and(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -245,9 +245,9 @@ func andConst(n *node) {
|
||||
}
|
||||
|
||||
func andNot(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -323,9 +323,9 @@ func andNotConst(n *node) {
|
||||
}
|
||||
|
||||
func mul(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -457,9 +457,9 @@ func mulConst(n *node) {
|
||||
}
|
||||
|
||||
func or(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -535,9 +535,9 @@ func orConst(n *node) {
|
||||
}
|
||||
|
||||
func quo(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -669,9 +669,9 @@ func quoConst(n *node) {
|
||||
}
|
||||
|
||||
func rem(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -747,9 +747,9 @@ func remConst(n *node) {
|
||||
}
|
||||
|
||||
func shl(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -825,9 +825,9 @@ func shlConst(n *node) {
|
||||
}
|
||||
|
||||
func shr(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -903,9 +903,9 @@ func shrConst(n *node) {
|
||||
}
|
||||
|
||||
func sub(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1037,9 +1037,9 @@ func subConst(n *node) {
|
||||
}
|
||||
|
||||
func xor(n *node) {
|
||||
dest := genValue(n)
|
||||
next := getExec(n.tnext)
|
||||
typ := n.typ.TypeOf()
|
||||
typ := n.typ.concrete().TypeOf()
|
||||
dest := genValueOutput(n, typ)
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch typ.Kind() {
|
||||
@@ -1917,7 +1917,7 @@ func posConst(n *node) {
|
||||
|
||||
func equal(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2346,7 +2346,7 @@ func equal(n *node) {
|
||||
|
||||
func greater(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2635,7 +2635,7 @@ func greater(n *node) {
|
||||
|
||||
func greaterEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -2924,7 +2924,7 @@ func greaterEqual(n *node) {
|
||||
|
||||
func lower(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3213,7 +3213,7 @@ func lower(n *node) {
|
||||
|
||||
func lowerEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
@@ -3502,7 +3502,7 @@ func lowerEqual(n *node) {
|
||||
|
||||
func notEqual(n *node) {
|
||||
tnext := getExec(n.tnext)
|
||||
dest := genValue(n)
|
||||
dest := genValueOutput(n, reflect.TypeOf(true))
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
|
||||
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
|
||||
|
||||
@@ -239,26 +239,33 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
t, err = nodeType(interp, sc, n.child[0])
|
||||
|
||||
case binaryExpr:
|
||||
if a := n.anc; a.kind == defineStmt && len(a.child) > a.nleft+a.nright {
|
||||
t, err = nodeType(interp, sc, a.child[a.nleft])
|
||||
} else {
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Shift operator type is inherited from first parameter only
|
||||
// For other operators, infer type in from 2nd parameter in case of untyped first
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
// Get type of first operand.
|
||||
if t, err = nodeType(interp, sc, n.child[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// For operators other than shift, get the type from the 2nd operand if the first is untyped.
|
||||
if t.untyped && !isShiftNode(n) {
|
||||
var t1 *itype
|
||||
t1, err = nodeType(interp, sc, n.child[1])
|
||||
if !(t1.untyped && isInt(t1.TypeOf()) && isFloat(t.TypeOf())) {
|
||||
t = t1
|
||||
}
|
||||
}
|
||||
// If the node is to be assigned or returned, the node type is the destination type.
|
||||
dt := t
|
||||
if a := n.anc; a.kind == defineStmt && len(a.child) > a.nleft+a.nright {
|
||||
if dt, err = nodeType(interp, sc, a.child[a.nleft]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if isInterface(dt) {
|
||||
dt.val = t
|
||||
}
|
||||
t = dt
|
||||
|
||||
case callExpr:
|
||||
if interp.isBuiltinCall(n) {
|
||||
// builtin types are special and may depend from their call arguments
|
||||
// Builtin types are special and may depend from their input arguments.
|
||||
t.cat = builtinT
|
||||
switch n.child[0].ident {
|
||||
case "complex":
|
||||
@@ -695,6 +702,13 @@ func (t *itype) referTo(name string, seen map[*itype]bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *itype) concrete() *itype {
|
||||
if isInterface(t) && t.val != nil {
|
||||
return t.val.concrete()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// IsRecursive returns true if type is recursive.
|
||||
// Only a named struct or interface can be recursive.
|
||||
func (t *itype) isRecursive() bool {
|
||||
|
||||
@@ -184,7 +184,10 @@ func zeroInterfaceValue() reflect.Value {
|
||||
|
||||
func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
value := genValue(n)
|
||||
if n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT {
|
||||
switch {
|
||||
case n.anc.action == aAssign && n.anc.typ.cat == interfaceT:
|
||||
fallthrough
|
||||
case n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT:
|
||||
// The result of the builtin has to be returned as an interface type.
|
||||
// Wrap it in a valueInterface and return the dereferenced value.
|
||||
return func(f *frame) reflect.Value {
|
||||
|
||||
Reference in New Issue
Block a user