Skip to content

Commit

Permalink
fix: handle interface values in map and arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
mvertes authored Mar 3, 2020
1 parent 94e0b58 commit cfb7344
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 32 deletions.
12 changes: 12 additions & 0 deletions _test/interface20.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
var a interface{}
a = string("A")
fmt.Println(a)
}

// Output:
// A
12 changes: 12 additions & 0 deletions _test/interface21.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
s := make([]interface{}, 1)
s[0] = 1
fmt.Println(s[0])
}

// Output:
// 1
12 changes: 12 additions & 0 deletions _test/interface22.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
s := make([]interface{}, 0)
s = append(s, 1)
fmt.Println(s[0])
}

// Output:
// 1
12 changes: 12 additions & 0 deletions _test/interface23.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
m := make(map[string]interface{})
m["A"] = string("A")
fmt.Println(m["A"])
}

// Output:
// A
11 changes: 11 additions & 0 deletions _test/interface24.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func main() {
m := make(map[string]interface{})
fmt.Println(m["B"])
}

// Output:
// <nil>
14 changes: 14 additions & 0 deletions _test/interface25.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "fmt"

func main() {
m := make(map[string]interface{})
m["A"] = 1
for _, v := range m {
fmt.Println(v)
}
}

// Output:
// 1
14 changes: 14 additions & 0 deletions _test/interface26.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "fmt"

func main() {
s := make([]interface{}, 0)
s = append(s, 1)
for _, v := range s {
fmt.Println(v)
}
}

// Output:
// 1
15 changes: 8 additions & 7 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = n.cfgErrorf("illegal operand types for '%v' operator", n.action)
}
default:
// Detect invalid float truncate
// Detect invalid float truncate.
if isInt(t0) && isFloat(t1) {
err = src.cfgErrorf("invalid float truncate")
return
Expand All @@ -475,15 +475,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
// Propagate type
// TODO: Check that existing destination type matches source type
switch {
case n.action == aAssign && src.action == aCall:
case n.action == aAssign && src.action == aCall && dest.typ.cat != interfaceT:
// Call action may perform the assignment directly.
n.gen = nop
src.level = level
src.findex = dest.findex
if src.typ.untyped && !dest.typ.untyped {
src.typ = dest.typ
}
case n.action == aAssign && src.action == aRecv:
// Assign by reading from a receiving channel
// Assign by reading from a receiving channel.
n.gen = nop
src.findex = dest.findex // Set recv address to LHS
dest.typ = src.typ
Expand All @@ -492,16 +493,16 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
src.findex = dest.findex
src.level = level
case src.kind == basicLit:
// TODO: perform constant folding and propagation here
// TODO: perform constant folding and propagation here.
switch {
case dest.typ.cat == interfaceT:
case isComplex(dest.typ.TypeOf()):
// value set in genValue
// Value set in genValue.
case !src.rval.IsValid():
// Assign to nil
// Assign to nil.
src.rval = reflect.New(dest.typ.TypeOf()).Elem()
default:
// Convert literal value to destination type
// Convert literal value to destination type.
src.rval = src.rval.Convert(dest.typ.TypeOf())
src.typ = dest.typ
}
Expand Down
111 changes: 86 additions & 25 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -1025,12 +1025,13 @@ func getIndexMap(n *node) {
dest := genValue(n)
value0 := genValue(n.child[0]) // map
tnext := getExec(n.tnext)
z := reflect.New(n.child[0].typ.TypeOf().Elem()).Elem()
z := reflect.New(n.child[0].typ.frameType().Elem()).Elem()

if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval

if n.fnext != nil {
switch {
case n.fnext != nil:
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() {
Expand All @@ -1040,7 +1041,17 @@ func getIndexMap(n *node) {
dest(f).Set(z)
return fnext
}
} else {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(mi); v.IsValid() {
dest(f).Set(v)
Expand All @@ -1053,7 +1064,8 @@ func getIndexMap(n *node) {
} else {
value1 := genValue(n.child[1]) // map index

if n.fnext != nil {
switch {
case n.fnext != nil:
fnext := getExec(n.fnext)
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() {
Expand All @@ -1063,7 +1075,17 @@ func getIndexMap(n *node) {
dest(f).Set(z)
return fnext
}
} else {
case n.typ.cat == interfaceT:
z = reflect.New(n.child[0].typ.val.frameType()).Elem()
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v.Elem())
} else {
dest(f).Set(z)
}
return tnext
}
default:
n.exec = func(f *frame) bltn {
if v := value0(f).MapIndex(value1(f)); v.IsValid() {
dest(f).Set(v)
Expand All @@ -1082,26 +1104,49 @@ func getIndexMap2(n *node) {
value0 := genValue(n.child[0]) // map
value2 := genValue(n.anc.child[1]) // status
next := getExec(n.tnext)
typ := n.anc.child[0].typ

if n.child[1].rval.IsValid() { // constant map index
mi := n.child[1].rval
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
if typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v.Elem())
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(mi)
if v.IsValid() {
dest(f).Set(v)
}
value2(f).SetBool(v.IsValid())
return next
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
value1 := genValue(n.child[1]) // map index
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
if typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v.Elem())
}
value2(f).SetBool(v.IsValid())
return next
}
} else {
n.exec = func(f *frame) bltn {
v := value0(f).MapIndex(value1(f))
if v.IsValid() {
dest(f).Set(v)
}
value2(f).SetBool(v.IsValid())
return next
}
value2(f).SetBool(v.IsValid())
return next
}
}
}
Expand Down Expand Up @@ -1785,14 +1830,26 @@ func rangeMap(n *node) {
if len(n.child) == 4 {
index1 := n.child[1].findex // map value location in frame
value = genValue(n.child[2]) // map
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
if n.child[1].typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value().Elem())
return tnext
}
} else {
n.exec = func(f *frame) bltn {
iter := f.data[index2].Interface().(*reflect.MapIter)
if !iter.Next() {
return fnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
f.data[index0].Set(iter.Key())
f.data[index1].Set(iter.Value())
return tnext
}
} else {
value = genValue(n.child[1]) // map
Expand Down Expand Up @@ -1960,6 +2017,8 @@ func _append(n *node) {
values := make([]func(*frame) reflect.Value, l)
for i, arg := range args {
switch {
case n.typ.val.cat == interfaceT:
values[i] = genValueInterface(arg)
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
values[i] = genValueInterfacePtr(arg)
case arg.typ.untyped:
Expand All @@ -1980,6 +2039,8 @@ func _append(n *node) {
} else {
var value0 func(*frame) reflect.Value
switch {
case n.typ.val.cat == interfaceT:
value0 = genValueInterface(n.child[2])
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
value0 = genValueInterfacePtr(n.child[2])
case n.child[2].typ.untyped:
Expand Down Expand Up @@ -2113,7 +2174,7 @@ func _new(n *node) {
func _make(n *node) {
dest := genValue(n)
next := getExec(n.tnext)
typ := n.child[1].typ.TypeOf()
typ := n.child[1].typ.frameType()

switch typ.Kind() {
case reflect.Array, reflect.Slice:
Expand Down

0 comments on commit cfb7344

Please sign in to comment.