Files
moxa/interp/value.go
Marc Vertes 63825e7201 interp: fix use of interfaces in composite types
The representation of non empty interfaces defined in the interpreter is now identical between refType() and frameType() functions, which are used to generate interpreter objects.

Fixes #1447 and #1426.
2022-09-01 12:18:08 +02:00

603 lines
16 KiB
Go

package interp
import (
"go/constant"
"reflect"
)
const (
notInFrame = -1 // value of node.findex for literal values (not in frame)
globalFrame = -1 // value of node.level for global symbols
)
func valueGenerator(n *node, i int) func(*frame) reflect.Value {
switch n.level {
case globalFrame:
return func(f *frame) reflect.Value { return valueOf(f.root.data, i) }
case 0:
return func(f *frame) reflect.Value { return valueOf(f.data, i) }
case 1:
return func(f *frame) reflect.Value { return valueOf(f.anc.data, i) }
case 2:
return func(f *frame) reflect.Value { return valueOf(f.anc.anc.data, i) }
default:
return func(f *frame) reflect.Value {
for level := n.level; level > 0; level-- {
f = f.anc
}
return valueOf(f.data, i)
}
}
}
// valueOf safely recovers the ith element of data. This is necessary
// because a cancellation prior to any evaluation result may leave
// the frame's data empty.
func valueOf(data []reflect.Value, i int) reflect.Value {
if i < 0 || i >= len(data) {
return reflect.Value{}
}
return data[i]
}
func genValueBinMethodOnInterface(n *node, defaultGen func(*frame) reflect.Value) func(*frame) reflect.Value {
if n == nil || n.child == nil || n.child[0] == nil ||
n.child[0].child == nil || n.child[0].child[0] == nil {
return defaultGen
}
c0 := n.child[0]
if c0.child[1] == nil || c0.child[1].ident == "" {
return defaultGen
}
value0 := genValue(c0.child[0])
return func(f *frame) reflect.Value {
v := value0(f)
var nod *node
for v.IsValid() {
// Traverse interface indirections to find out concrete type.
vi, ok := v.Interface().(valueInterface)
if !ok {
break
}
v = vi.value
nod = vi.node
}
if nod == nil || nod.typ.rtype == nil {
return defaultGen(f)
}
// Try to get the bin method, if it doesnt exist, fall back to
// the default generator function.
meth, ok := nod.typ.rtype.MethodByName(c0.child[1].ident)
if !ok {
return defaultGen(f)
}
return meth.Func
}
}
func genValueRecvIndirect(n *node) func(*frame) reflect.Value {
vr := genValueRecv(n)
return func(f *frame) reflect.Value {
v := vr(f)
if vi, ok := v.Interface().(valueInterface); ok {
return vi.value
}
return v.Elem()
}
}
func genValueRecv(n *node) func(*frame) reflect.Value {
v := genValue(n.recv.node)
fi := n.recv.index
if len(fi) == 0 {
return v
}
return func(f *frame) reflect.Value {
r := v(f)
if r.Kind() == reflect.Ptr {
r = r.Elem()
}
return r.FieldByIndex(fi)
}
}
func genValueBinRecv(n *node, recv *receiver) func(*frame) reflect.Value {
value := genValue(n)
binValue := genValue(recv.node)
v := func(f *frame) reflect.Value {
if def, ok := value(f).Interface().(*node); ok {
if def != nil && def.recv != nil && def.recv.val.IsValid() {
return def.recv.val
}
}
ival, _ := binValue(f).Interface().(valueInterface)
return ival.value
}
fi := recv.index
if len(fi) == 0 {
return v
}
return func(f *frame) reflect.Value {
r := v(f)
if r.Kind() == reflect.Ptr {
r = r.Elem()
}
return r.FieldByIndex(fi)
}
}
func genValueAsFunctionWrapper(n *node) func(*frame) reflect.Value {
value := genValue(n)
typ := n.typ.TypeOf()
return func(f *frame) reflect.Value {
v := value(f)
if v.IsNil() {
return reflect.New(typ).Elem()
}
vn, ok := v.Interface().(*node)
if ok && vn.rval.Kind() == reflect.Func {
// The node value is already a callable func, no need to wrap it.
return vn.rval
}
return genFunctionWrapper(vn)(f)
}
}
func genValueAs(n *node, t reflect.Type) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
v := value(f)
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice, reflect.UnsafePointer:
if v.IsNil() {
return reflect.New(t).Elem()
}
}
return v.Convert(t)
}
}
func genValue(n *node) func(*frame) reflect.Value {
switch n.kind {
case basicLit:
convertConstantValue(n)
v := n.rval
if !v.IsValid() {
v = reflect.New(emptyInterfaceType).Elem()
}
return func(f *frame) reflect.Value { return v }
case funcDecl:
var v reflect.Value
if w, ok := n.val.(reflect.Value); ok {
v = w
} else {
v = reflect.ValueOf(n.val)
}
return func(f *frame) reflect.Value { return v }
default:
if n.rval.IsValid() {
convertConstantValue(n)
v := n.rval
return func(f *frame) reflect.Value { return v }
}
if n.sym != nil {
i := n.sym.index
if i < 0 && n != n.sym.node {
return genValue(n.sym.node)
}
if n.sym.global {
return func(f *frame) reflect.Value { return f.root.data[i] }
}
return valueGenerator(n, i)
}
if n.findex == notInFrame {
var v reflect.Value
if w, ok := n.val.(reflect.Value); ok {
v = w
} else {
v = reflect.ValueOf(n.val)
}
return func(f *frame) reflect.Value { return v }
}
return valueGenerator(n, n.findex)
}
}
func genDestValue(typ *itype, n *node) func(*frame) reflect.Value {
convertLiteralValue(n, typ.TypeOf())
switch {
case isInterfaceSrc(typ) && (!isEmptyInterface(typ) || len(n.typ.method) > 0):
return genValueInterface(n)
case isFuncSrc(typ) && (n.typ.cat == valueT || n.typ.cat == nilT):
return genValueNode(n)
case typ.cat == valueT && isFuncSrc(n.typ):
return genFunctionWrapper(n)
case isInterfaceBin(typ):
return genInterfaceWrapper(n, typ.rtype)
case n.kind == basicLit && n.val == nil:
return func(*frame) reflect.Value { return reflect.New(typ.rtype).Elem() }
case n.typ.untyped && isComplex(typ.TypeOf()):
return genValueComplex(n)
case n.typ.untyped && !typ.untyped:
return genValueAs(n, typ.TypeOf())
}
return genValue(n)
}
func genValueArray(n *node) func(*frame) reflect.Value {
value := genValue(n)
// dereference array pointer, to support array operations on array pointer
if n.typ.TypeOf().Kind() == reflect.Ptr {
return func(f *frame) reflect.Value {
return value(f).Elem()
}
}
return value
}
func genValueRangeArray(n *node) func(*frame) reflect.Value {
value := genValue(n)
switch {
case n.typ.TypeOf().Kind() == reflect.Ptr:
// dereference array pointer, to support array operations on array pointer
return func(f *frame) reflect.Value {
return value(f).Elem()
}
case n.typ.val != nil && n.typ.val.cat == interfaceT:
if len(n.typ.val.field) > 0 {
return func(f *frame) reflect.Value {
val := value(f)
v := []valueInterface{}
for i := 0; i < val.Len(); i++ {
switch av := val.Index(i).Interface().(type) {
case []valueInterface:
v = append(v, av...)
case valueInterface:
v = append(v, av)
default:
panic(n.cfgErrorf("invalid type %v", val.Index(i).Type()))
}
}
return reflect.ValueOf(v)
}
}
// empty interface, do not wrap.
fallthrough
default:
return func(f *frame) reflect.Value {
// This is necessary to prevent changes in the returned
// reflect.Value being reflected back to the value used
// for the range expression.
return reflect.ValueOf(value(f).Interface())
}
}
}
func genValueInterface(n *node) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
v := value(f)
nod := n
for v.IsValid() {
// traverse interface indirections to find out concrete type
vi, ok := v.Interface().(valueInterface)
if !ok {
break
}
v = vi.value
nod = vi.node
}
// empty interface, do not wrap.
if nod != nil && isEmptyInterface(nod.typ) {
return v
}
return reflect.ValueOf(valueInterface{nod, v})
}
}
func getConcreteValue(val reflect.Value) reflect.Value {
v := val
for {
vi, ok := v.Interface().(valueInterface)
if !ok {
break
}
v = vi.value
}
if v.NumMethod() > 0 {
return v
}
if v.Kind() != reflect.Struct {
return v
}
// Search a concrete value in fields of an emulated interface.
for i := v.NumField() - 1; i >= 0; i-- {
vv := v.Field(i)
if vv.Kind() == reflect.Interface {
vv = vv.Elem()
}
if vv.IsValid() {
return vv
}
}
return v
}
func zeroInterfaceValue() reflect.Value {
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true, str: "nil"}}
v := reflect.New(emptyInterfaceType).Elem()
return reflect.ValueOf(valueInterface{n, v})
}
func wantEmptyInterface(n *node) bool {
return isEmptyInterface(n.typ) ||
n.anc.action == aAssign && n.anc.typ.cat == interfaceT && len(n.anc.typ.field) == 0 ||
n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT && len(n.anc.val.(*node).typ.ret[0].field) == 0
}
func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
value := genValue(n)
switch {
case n.anc.action == aAssign && n.anc.typ.cat == interfaceT:
if len(n.anc.typ.field) == 0 {
// empty interface, do not wrap
return value
}
fallthrough
case n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT:
if nod, ok := n.anc.val.(*node); !ok || len(nod.typ.ret[0].field) == 0 {
// empty interface, do not wrap
return value
}
// 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 {
d := value(f)
v := reflect.New(t).Elem()
d.Set(reflect.ValueOf(valueInterface{n, v}))
return v
}
}
return value
}
func getBinValue(getMapType func(*itype) reflect.Type, value func(*frame) reflect.Value, f *frame) reflect.Value {
v := value(f)
if getMapType == nil {
return v
}
val, ok := v.Interface().(valueInterface)
if !ok || val.node == nil {
return v
}
if rt := getMapType(val.node.typ); rt != nil {
return genInterfaceWrapper(val.node, rt)(f)
}
return v
}
func valueInterfaceValue(v reflect.Value) reflect.Value {
for {
vv, ok := v.Interface().(valueInterface)
if !ok {
break
}
v = vv.value
}
return v
}
func genValueInterfaceValue(n *node) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok && vi.node == nil {
// Uninitialized interface value, set it to a correct zero value.
v.Set(zeroInterfaceValue())
v = value(f)
}
return valueInterfaceValue(v)
}
}
func genValueNode(n *node) func(*frame) reflect.Value {
value := genValue(n)
return func(f *frame) reflect.Value {
v := value(f)
if _, ok := v.Interface().(*node); ok {
return v
}
return reflect.ValueOf(&node{rval: v})
}
}
func vInt(v reflect.Value) (i int64) {
if c := vConstantValue(v); c != nil {
i, _ = constant.Int64Val(constant.ToInt(c))
return i
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = v.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i = int64(v.Uint())
case reflect.Float32, reflect.Float64:
i = int64(v.Float())
case reflect.Complex64, reflect.Complex128:
i = int64(real(v.Complex()))
}
return
}
func vUint(v reflect.Value) (i uint64) {
if c := vConstantValue(v); c != nil {
i, _ = constant.Uint64Val(constant.ToInt(c))
return i
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = uint64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i = v.Uint()
case reflect.Float32, reflect.Float64:
i = uint64(v.Float())
case reflect.Complex64, reflect.Complex128:
i = uint64(real(v.Complex()))
}
return
}
func vComplex(v reflect.Value) (c complex128) {
if c := vConstantValue(v); c != nil {
c = constant.ToComplex(c)
rel, _ := constant.Float64Val(constant.Real(c))
img, _ := constant.Float64Val(constant.Imag(c))
return complex(rel, img)
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
c = complex(float64(v.Int()), 0)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
c = complex(float64(v.Uint()), 0)
case reflect.Float32, reflect.Float64:
c = complex(v.Float(), 0)
case reflect.Complex64, reflect.Complex128:
c = v.Complex()
}
return
}
func vFloat(v reflect.Value) (i float64) {
if c := vConstantValue(v); c != nil {
i, _ = constant.Float64Val(constant.ToFloat(c))
return i
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = float64(v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i = float64(v.Uint())
case reflect.Float32, reflect.Float64:
i = v.Float()
case reflect.Complex64, reflect.Complex128:
i = real(v.Complex())
}
return
}
func vString(v reflect.Value) (s string) {
if c := vConstantValue(v); c != nil {
s = constant.StringVal(c)
return s
}
return v.String()
}
func vConstantValue(v reflect.Value) (c constant.Value) {
if v.Type().Implements(constVal) {
c = v.Interface().(constant.Value)
}
return
}
func genValueInt(n *node) func(*frame) (reflect.Value, int64) {
value := genValue(n)
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, v.Int() }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Uint()) }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Float()) }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(real(v.Complex())) }
}
}
return nil
}
func genValueUint(n *node) func(*frame) (reflect.Value, uint64) {
value := genValue(n)
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(v.Int()) }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, v.Uint() }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(v.Float()) }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(real(v.Complex())) }
}
}
return nil
}
func genValueFloat(n *node) func(*frame) (reflect.Value, float64) {
value := genValue(n)
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, float64(v.Int()) }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, float64(v.Uint()) }
case reflect.Float32, reflect.Float64:
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, v.Float() }
case reflect.Complex64, reflect.Complex128:
if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 {
return func(f *frame) (reflect.Value, float64) { v := value(f); return v, real(v.Complex()) }
}
}
return nil
}
func genValueComplex(n *node) func(*frame) reflect.Value {
vc := genComplex(n)
return func(f *frame) reflect.Value { return reflect.ValueOf(vc(f)) }
}
func genComplex(n *node) func(*frame) complex128 {
value := genValue(n)
switch n.typ.TypeOf().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return func(f *frame) complex128 { return complex(float64(value(f).Int()), 0) }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return func(f *frame) complex128 { return complex(float64(value(f).Uint()), 0) }
case reflect.Float32, reflect.Float64:
return func(f *frame) complex128 { return complex(value(f).Float(), 0) }
case reflect.Complex64, reflect.Complex128:
return func(f *frame) complex128 { return value(f).Complex() }
}
return nil
}
func genValueString(n *node) func(*frame) (reflect.Value, string) {
value := genValue(n)
return func(f *frame) (reflect.Value, string) { v := value(f); return v, v.String() }
}