fix: improve setting of interface objects

This commit is contained in:
Marc Vertes
2020-04-30 17:44:04 +02:00
committed by GitHub
parent 1feece61ce
commit 7d56fb067e
11 changed files with 132 additions and 76 deletions

9
_test/add0.go Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,9 @@
package main
func main() {
var a interface{} = 1 < 2
println(a.(bool))
}
// Output:
// true

View File

@@ -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
View File

@@ -0,0 +1,9 @@
package main
func main() {
var b interface{} = !(1 == 2)
println(b.(bool))
}
// Output:
// true

View File

@@ -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(); {

View File

@@ -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)
}

View File

@@ -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(); {

View File

@@ -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 {

View File

@@ -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 {