interp: fix setting interface objects from operators

This is a follow-up of #1017, generalizing the use of reflect.Set
method to set, and possibly overwrite, the concrete value of
interface objects all accross the implementation of operators.
Previous optimized implementation for non-interface objects is
preserved.
This commit is contained in:
Marc Vertes
2021-02-08 18:00:04 +01:00
committed by GitHub
parent 2e17cfab4f
commit ac80d1b3ed
4 changed files with 881 additions and 173 deletions

View File

@@ -1998,24 +1998,54 @@ func neg(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
next := getExec(n.tnext)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(-value(f).Int()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetInt(-value(f).Int())
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(-value(f).Uint()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetUint(-value(f).Uint())
return next
}
case reflect.Float32, reflect.Float64:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(-value(f).Float()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetFloat(-value(f).Float())
return next
}
case reflect.Complex64, reflect.Complex128:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(-value(f).Complex()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetComplex(-value(f).Complex())
return next
@@ -2038,15 +2068,30 @@ func bitNot(n *node) {
dest := genValue(n)
value := genValue(n.child[0])
next := getExec(n.tnext)
typ := n.typ.TypeOf()
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(^value(f).Int()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetInt(^value(f).Int())
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(^value(f).Uint()).Convert(typ))
return next
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetUint(^value(f).Uint())
return next
@@ -2059,6 +2104,8 @@ func land(n *node) {
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
dest := genValue(n)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
if n.fnext != nil {
fnext := getExec(n.fnext)
@@ -2070,11 +2117,18 @@ func land(n *node) {
dest(f).SetBool(false)
return fnext
}
} else {
return
}
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).SetBool(value0(f).Bool() && value1(f).Bool())
dest(f).Set(reflect.ValueOf(value0(f).Bool() && value1(f).Bool()).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetBool(value0(f).Bool() && value1(f).Bool())
return tnext
}
}
@@ -2083,6 +2137,8 @@ func lor(n *node) {
value1 := genValue(n.child[1])
tnext := getExec(n.tnext)
dest := genValue(n)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
if n.fnext != nil {
fnext := getExec(n.fnext)
@@ -2094,11 +2150,18 @@ func lor(n *node) {
dest(f).SetBool(false)
return fnext
}
} else {
return
}
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).SetBool(value0(f).Bool() || value1(f).Bool())
dest(f).Set(reflect.ValueOf(value0(f).Bool() || value1(f).Bool()).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetBool(value0(f).Bool() || value1(f).Bool())
return tnext
}
}
@@ -3556,24 +3619,49 @@ func isNil(n *node) {
} else {
value = genValue(c0)
}
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
tnext := getExec(n.tnext)
dest := genValue(n)
if n.fnext == nil {
if c0.typ.cat != interfaceT {
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(value(f).IsNil()).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetBool(value(f).IsNil())
return tnext
}
return
}
if isInterface {
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
r = v.IsNil()
}
dest(f).Set(reflect.ValueOf(r).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
dest(f).SetBool(v.IsNil())
r = v.IsNil()
}
dest(f).SetBool(r)
return tnext
}
return
@@ -3620,11 +3708,20 @@ func isNotNil(n *node) {
} else {
value = genValue(c0)
}
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
tnext := getExec(n.tnext)
dest := genValue(n)
if n.fnext == nil {
if c0.typ.cat != interfaceT {
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(!value(f).IsNil()).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetBool(!value(f).IsNil())
return tnext
@@ -3632,13 +3729,29 @@ func isNotNil(n *node) {
return
}
if isInterface {
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
r = v.IsNil()
}
dest(f).Set(reflect.ValueOf(!r).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(!(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT))
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
dest(f).SetBool(!v.IsNil())
r = v.IsNil()
}
dest(f).SetBool(!r)
return tnext
}
return