interp: fix litteral map containing binary functions

The case of assigning a binary function to a funcT object was
solved elsewhere. Factor the case in genDestValue to apply it
at multiple places.

Fixes #1100.
This commit is contained in:
Marc Vertes
2021-05-27 12:04:11 +02:00
committed by GitHub
parent 29e912e90b
commit c86436afa6
4 changed files with 42 additions and 65 deletions

View File

@@ -6,7 +6,10 @@ func f(s string) string { return "hello " + s }
func g(s string) string { return "hi " + s }
var methods = map[string]func(string) string{"f": f}
var methods = map[string]func(string) string{
"f": f,
"h": strings.ToLower,
}
func main() {
methods["i"] = strings.ToUpper
@@ -14,9 +17,11 @@ func main() {
println(methods["f"]("test"))
println(methods["g"]("test"))
println(methods["i"]("test"))
println(methods["h"]("TEST"))
}
// Output:
// hello test
// hi test
// TEST
// test

View File

@@ -570,7 +570,7 @@ func isRecursiveType(t *itype, rtype reflect.Type) bool {
return true
}
switch t.cat {
case arrayT, mapT, ptrT, sliceT:
case aliasT, arrayT, mapT, ptrT, sliceT:
return isRecursiveType(t.val, t.val.rtype)
default:
return false
@@ -589,34 +589,10 @@ func assign(n *node) {
for i := 0; i < n.nleft; i++ {
dest, src := n.child[i], n.child[sbase+i]
switch {
case isInterfaceSrc(dest.typ):
if len(dest.typ.field) > 0 {
svalue[i] = genValueInterface(src)
break
}
svalue[i] = genValue(src)
case (dest.typ.cat == valueT || dest.typ.cat == errorT) && dest.typ.rtype.Kind() == reflect.Interface:
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
case isFuncSrc(src.typ) && dest.typ.cat == valueT:
if isFuncSrc(src.typ) && isField(dest) {
svalue[i] = genFunctionWrapper(src)
case isFuncSrc(src.typ) && isField(dest):
svalue[i] = genFunctionWrapper(src)
case isFuncSrc(dest.typ) && src.typ.cat == valueT:
svalue[i] = genValueNode(src)
case src.kind == basicLit && src.val == nil:
t := dest.typ.TypeOf()
svalue[i] = func(*frame) reflect.Value { return reflect.New(t).Elem() }
case isRecursiveType(dest.typ, dest.typ.rtype):
svalue[i] = genValueRecursiveInterface(src, dest.typ.rtype)
case isRecursiveType(src.typ, src.typ.rtype):
svalue[i] = genValueRecursiveInterfacePtrValue(src)
case src.typ.untyped && isComplex(dest.typ.TypeOf()):
svalue[i] = genValueComplex(src)
case src.typ.untyped && !dest.typ.untyped:
svalue[i] = genValueAs(src, dest.typ.TypeOf())
default:
svalue[i] = genValue(src)
} else {
svalue[i] = genDestValue(dest.typ, src)
}
if isMapEntry(dest) {
if isInterfaceSrc(dest.child[1].typ) { // key
@@ -2302,25 +2278,14 @@ func arrayLit(n *node) {
values := make([]func(*frame) reflect.Value, len(child))
index := make([]int, len(child))
rtype := n.typ.val.TypeOf()
var max, prev int
for i, c := range child {
if c.kind == keyValueExpr {
convertLiteralValue(c.child[1], rtype)
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c.child[1])
} else {
values[i] = genValue(c.child[1])
}
values[i] = genDestValue(n.typ.val, c.child[1])
index[i] = int(vInt(c.child[0].rval))
} else {
convertLiteralValue(c, rtype)
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c)
} else {
values[i] = genValue(c)
}
values[i] = genDestValue(n.typ.val, c)
index[i] = prev
}
prev = index[i] + 1
@@ -2357,18 +2322,8 @@ func mapLit(n *node) {
keys := make([]func(*frame) reflect.Value, len(child))
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c.child[0], n.typ.key.TypeOf())
convertLiteralValue(c.child[1], n.typ.val.TypeOf())
if isInterfaceSrc(n.typ.key) {
keys[i] = genValueInterface(c.child[0])
} else {
keys[i] = genValue(c.child[0])
}
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c.child[1])
} else {
values[i] = genValue(c.child[1])
}
keys[i] = genDestValue(n.typ.key, c.child[0])
values[i] = genDestValue(n.typ.val, c.child[1])
}
n.exec = func(f *frame) bltn {
@@ -3450,15 +3405,7 @@ func send(n *node) {
next := getExec(n.tnext)
c0, c1 := n.child[0], n.child[1]
value0 := genValue(c0) // Send channel.
convertLiteralValue(c1, c0.typ.val.TypeOf())
var value1 func(*frame) reflect.Value // Value to send.
switch {
case isInterfaceBin(c0.typ.val):
value1 = genInterfaceWrapper(c1, c0.typ.val.rtype)
default:
value1 = genValue(c1)
}
value1 := genDestValue(c0.typ.val, c1)
if !n.interp.cancelChan {
// Send is non-cancellable, has the least overhead.

View File

@@ -1723,7 +1723,7 @@ func isInterfaceSrc(t *itype) bool {
}
func isInterfaceBin(t *itype) bool {
return t.cat == valueT && t.rtype.Kind() == reflect.Interface
return t.cat == valueT && t.rtype.Kind() == reflect.Interface || t.cat == errorT
}
func isInterface(t *itype) bool {

View File

@@ -214,6 +214,31 @@ func genValue(n *node) func(*frame) reflect.Value {
}
}
func genDestValue(typ *itype, n *node) func(*frame) reflect.Value {
convertLiteralValue(n, typ.TypeOf())
switch {
case isInterfaceSrc(typ) && !isEmptyInterface(typ):
return genValueInterface(n)
case isFuncSrc(typ) && n.typ.cat == valueT:
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 isRecursiveType(typ, typ.rtype):
return genValueRecursiveInterface(n, typ.rtype)
case isRecursiveType(n.typ, n.typ.rtype):
return genValueRecursiveInterfacePtrValue(n)
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
@@ -310,7 +335,7 @@ func zeroInterfaceValue() reflect.Value {
}
func wantEmptyInterface(n *node) bool {
return n.typ.cat == interfaceT && len(n.typ.field) == 0 ||
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
}