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

13
_test/interface50.go Normal file
View File

@@ -0,0 +1,13 @@
package main
func main() {
a := true
var b interface{} = 5
println(b.(int))
b = a == true
println(b.(bool))
}
// Output:
// 5
// true

View File

@@ -24,6 +24,7 @@ import (
func {{$name}}(n *node) {
next := getExec(n.tnext)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
dest := genValueOutput(n, typ)
c0, c1 := n.child[0], n.child[1]
@@ -31,6 +32,13 @@ func {{$name}}(n *node) {
{{- if $op.Str}}
case reflect.String:
switch {
case isInterface:
v0 := genValue(c0)
v1 := genValue(c1)
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(v0(f).String() {{$op.Name}} v1(f).String()).Convert(typ))
return next
}
case c0.rval.IsValid():
s0 := vString(c0.rval)
v1 := genValue(c1)
@@ -56,6 +64,19 @@ func {{$name}}(n *node) {
{{- end}}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch {
case isInterface:
v0 := genValueInt(c0)
{{- if $op.Shift}}
v1 := genValueUint(c1)
{{else}}
v1 := genValueInt(c1)
{{end -}}
n.exec = func(f *frame) bltn {
_, i := v0(f)
_, j := v1(f)
dest(f).Set(reflect.ValueOf(i {{$op.Name}} j).Convert(typ))
return next
}
case c0.rval.IsValid():
i := vInt(c0.rval)
{{- if $op.Shift}}
@@ -63,38 +84,11 @@ func {{$name}}(n *node) {
{{else}}
v1 := genValueInt(c1)
{{end -}}
{{- if (eq $name "add")}}
if n.typ.cat != interfaceT || len(n.typ.field) > 0 {
n.exec = func(f *frame) bltn {
_, j := v1(f)
dest(f).SetInt(i + j)
return next
}
return
}
var valf func(sum int64) reflect.Value
// TODO: cover other int types, and actually other numbers, and even all
// relevant operations, not just add.
switch typ.Kind() {
case reflect.Int:
valf = func(sum int64) reflect.Value { return reflect.ValueOf(int(sum)) }
case reflect.Int32:
valf = func(sum int64) reflect.Value { return reflect.ValueOf(int32(sum)) }
default: // int64
valf = func(sum int64) reflect.Value { return reflect.ValueOf(sum) }
}
n.exec = func(f *frame) bltn {
_, j := v1(f)
dest(f).Set(valf(i + j))
return next
}
{{else -}}
n.exec = func(f *frame) bltn {
_, j := v1(f)
dest(f).SetInt(i {{$op.Name}} j)
return next
}
{{end -}}
case c1.rval.IsValid():
v0 := genValueInt(c0)
{{- if $op.Shift}}
@@ -102,38 +96,11 @@ func {{$name}}(n *node) {
{{else}}
j := vInt(c1.rval)
{{end -}}
{{- if (eq $name "add")}}
var valf func(sum int64) reflect.Value
// TODO: cover other int types, and actually other numbers, and even all
// relevant operations, not just add.
switch typ.Kind() {
case reflect.Int:
valf = func(sum int64) reflect.Value { return reflect.ValueOf(int(sum)) }
case reflect.Int32:
valf = func(sum int64) reflect.Value { return reflect.ValueOf(int32(sum)) }
default: // int64
valf = func(sum int64) reflect.Value { return reflect.ValueOf(sum) }
}
if wantEmptyInterface(n) {
n.exec = func(f *frame) bltn {
_, i := v0(f)
dest(f).Set(valf(i + j))
return next
}
return
}
n.exec = func(f *frame) bltn {
_, i := v0(f)
dest(f).SetInt(i + j)
return next
}
{{else -}}
n.exec = func(f *frame) bltn {
_, i := v0(f)
dest(f).SetInt(i {{$op.Name}} j)
return next
}
{{end -}}
default:
v0 := genValueInt(c0)
{{- if $op.Shift}}
@@ -150,6 +117,15 @@ func {{$name}}(n *node) {
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
switch {
case isInterface:
v0 := genValueUint(c0)
v1 := genValueUint(c1)
n.exec = func(f *frame) bltn {
_, i := v0(f)
_, j := v1(f)
dest(f).Set(reflect.ValueOf(i {{$op.Name}} j).Convert(typ))
return next
}
case c0.rval.IsValid():
i := vUint(c0.rval)
v1 := genValueUint(c1)
@@ -179,6 +155,15 @@ func {{$name}}(n *node) {
{{- if $op.Float}}
case reflect.Float32, reflect.Float64:
switch {
case isInterface:
v0 := genValueFloat(c0)
v1 := genValueFloat(c1)
n.exec = func(f *frame) bltn {
_, i := v0(f)
_, j := v1(f)
dest(f).Set(reflect.ValueOf(i {{$op.Name}} j).Convert(typ))
return next
}
case c0.rval.IsValid():
i := vFloat(c0.rval)
v1 := genValueFloat(c1)
@@ -207,25 +192,32 @@ func {{$name}}(n *node) {
}
case reflect.Complex64, reflect.Complex128:
switch {
case isInterface:
v0 := genComplex(c0)
v1 := genComplex(c1)
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(v0(f) {{$op.Name}} v1(f)).Convert(typ))
return next
}
case c0.rval.IsValid():
r0 := vComplex(c0.rval)
v1 := genValue(c1)
v1 := genComplex(c1)
n.exec = func(f *frame) bltn {
dest(f).SetComplex(r0 {{$op.Name}} v1(f).Complex())
dest(f).SetComplex(r0 {{$op.Name}} v1(f))
return next
}
case c1.rval.IsValid():
r1 := vComplex(c1.rval)
v0 := genValue(c0)
v0 := genComplex(c0)
n.exec = func(f *frame) bltn {
dest(f).SetComplex(v0(f).Complex() {{$op.Name}} r1)
dest(f).SetComplex(v0(f) {{$op.Name}} r1)
return next
}
default:
v0 := genValue(c0)
v1 := genValue(c1)
v0 := genComplex(c0)
v1 := genComplex(c1)
n.exec = func(f *frame) bltn {
dest(f).SetComplex(v0(f).Complex() {{$op.Name}} v1(f).Complex())
dest(f).SetComplex(v0(f) {{$op.Name}} v1(f))
return next
}
}
@@ -483,12 +475,24 @@ func {{$name}}Const(n *node) {
func {{$name}}(n *node) {
tnext := getExec(n.tnext)
dest := genValueOutput(n, reflect.TypeOf(true))
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
c0, c1 := n.child[0], n.child[1]
{{- if or (eq $op.Name "==") (eq $op.Name "!=") }}
if c0.typ.cat == aliasT || c1.typ.cat == aliasT {
switch {
case isInterface:
v0 := genValue(c0)
v1 := genValue(c1)
dest := genValue(n)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).Set(reflect.ValueOf(i0 {{$op.Name}} i1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)
@@ -565,9 +569,18 @@ func {{$name}}(n *node) {
switch t0, t1 := c0.typ.TypeOf(), c1.typ.TypeOf(); {
case isString(t0) || isString(t1):
switch {
case isInterface:
v0 := genValueString(c0)
v1 := genValueString(c1)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).Set(reflect.ValueOf(s0 {{$op.Name}} s1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
s0 := vString(c0.rval)
v1 := genValueString(n.child[1])
v1 := genValueString(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
@@ -588,7 +601,7 @@ func {{$name}}(n *node) {
}
case c1.rval.IsValid():
s1 := vString(c1.rval)
v0 := genValueString(n.child[0])
v0 := genValueString(c0)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
@@ -608,8 +621,8 @@ func {{$name}}(n *node) {
}
}
default:
v0 := genValueString(n.child[0])
v1 := genValueString(n.child[1])
v0 := genValueString(c0)
v1 := genValueString(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
@@ -633,6 +646,15 @@ func {{$name}}(n *node) {
}
case isFloat(t0) || isFloat(t1):
switch {
case isInterface:
v0 := genValueFloat(c0)
v1 := genValueFloat(c1)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).Set(reflect.ValueOf(s0 {{$op.Name}} s1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
s0 := vFloat(c0.rval)
v1 := genValueFloat(c1)
@@ -703,6 +725,15 @@ func {{$name}}(n *node) {
}
case isUint(t0) || isUint(t1):
switch {
case isInterface:
v0 := genValueUint(c0)
v1 := genValueUint(c1)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).Set(reflect.ValueOf(s0 {{$op.Name}} s1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
s0 := vUint(c0.rval)
v1 := genValueUint(c1)
@@ -774,6 +805,15 @@ func {{$name}}(n *node) {
}
case isInt(t0) || isInt(t1):
switch {
case isInterface:
v0 := genValueInt(c0)
v1 := genValueInt(c1)
n.exec = func(f *frame) bltn {
_, s0 := v0(f)
_, s1 := v1(f)
dest(f).Set(reflect.ValueOf(s0 {{$op.Name}} s1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
s0 := vInt(c0.rval)
v1 := genValueInt(c1)
@@ -846,6 +886,15 @@ func {{$name}}(n *node) {
{{- if $op.Complex}}
case isComplex(t0) || isComplex(t1):
switch {
case isInterface:
v0 := genComplex(c0)
v1 := genComplex(c1)
n.exec = func(f *frame) bltn {
s0 := v0(f)
s1 := v1(f)
dest(f).Set(reflect.ValueOf(s0 {{$op.Name}} s1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
s0 := vComplex(c0.rval)
v1 := genComplex(c1)
@@ -890,8 +939,8 @@ func {{$name}}(n *node) {
}
}
default:
v0 := genComplex(n.child[0])
v1 := genComplex(n.child[1])
v0 := genComplex(c0)
v1 := genComplex(c1)
if n.fnext != nil {
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
@@ -915,6 +964,15 @@ func {{$name}}(n *node) {
}
default:
switch {
case isInterface:
v0 := genValue(c0)
v1 := genValue(c1)
n.exec = func(f *frame) bltn {
i0 := v0(f).Interface()
i1 := v1(f).Interface()
dest(f).Set(reflect.ValueOf(i0 {{$op.Name}} i1).Convert(typ))
return tnext
}
case c0.rval.IsValid():
i0 := c0.rval.Interface()
v1 := genValue(c1)

File diff suppressed because it is too large Load Diff

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