fix: handle defer in builtins

This commit is contained in:
Nicholas Wiersma
2020-06-25 09:28:03 +02:00
committed by GitHub
parent c11d361953
commit 4d013e4686
6 changed files with 187 additions and 31 deletions

32
_test/defer5.go Normal file
View File

@@ -0,0 +1,32 @@
package main
func f1() {
defer println("f1-begin")
f2()
defer println("f1-end")
}
func f2() {
defer println("f2-begin")
f3()
defer println("f2-end")
}
func f3() {
defer println("f3-begin")
println("hello")
defer println("f3-end")
}
func main() {
f1()
}
// Output:
// hello
// f3-end
// f3-begin
// f2-end
// f2-begin
// f1-end
// f1-begin

27
_test/defer6.go Normal file
View File

@@ -0,0 +1,27 @@
package main
func f1() {
defer print("f1-begin ")
f2()
defer print("f1-end ")
}
func f2() {
defer print("f2-begin ")
f3()
defer print("f2-end ")
}
func f3() {
defer print("f3-begin ")
print("hello ")
defer print("f3-end ")
}
func main() {
f1()
println()
}
// Output:
// hello f3-end f3-begin f2-end f2-begin f1-end f1-begin

18
_test/defer7.go Normal file
View File

@@ -0,0 +1,18 @@
package main
import "fmt"
func f1(in, out []string) {
defer copy(out, in)
}
func main() {
in := []string{"foo", "bar"}
out := make([]string, 2)
f1(in, out)
fmt.Println(out)
}
// Output:
// [foo bar]

24
_test/defer8.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import "fmt"
func f1(m map[string]string) {
defer delete(m, "foo")
defer delete(m, "test")
fmt.Println(m)
}
func main() {
m := map[string]string{
"foo": "bar",
"baz": "bat",
}
f1(m)
fmt.Println(m)
}
// Output:
// map[baz:bat foo:bar]
// map[baz:bat]

21
_test/defer9.go Normal file
View File

@@ -0,0 +1,21 @@
package main
import "fmt"
func f1(ch chan string) {
defer close(ch)
ch <- "foo"
}
func main() {
ch := make(chan string, 1)
f1(ch)
for s := range ch {
fmt.Println(s)
}
}
// Output:
// foo

View File

@@ -525,41 +525,39 @@ func deref(n *node) {
func _print(n *node) {
child := n.child[1:]
next := getExec(n.tnext)
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
n.exec = func(f *frame) bltn {
for i, value := range values {
genBuiltinDeferWrapper(n, values, nil, func(args []reflect.Value) []reflect.Value {
for i, value := range args {
if i > 0 {
fmt.Printf(" ")
}
fmt.Printf("%v", value(f))
fmt.Printf("%v", value)
}
return next
}
return nil
})
}
func _println(n *node) {
child := n.child[1:]
next := getExec(n.tnext)
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
values[i] = genValue(c)
}
n.exec = func(f *frame) bltn {
for i, value := range values {
genBuiltinDeferWrapper(n, values, nil, func(args []reflect.Value) []reflect.Value {
for i, value := range args {
if i > 0 {
fmt.Printf(" ")
}
fmt.Printf("%v", value(f))
fmt.Printf("%v", value)
}
fmt.Println("")
return next
}
return nil
})
}
func _recover(n *node) {
@@ -585,6 +583,45 @@ func _panic(n *node) {
}
}
func genBuiltinDeferWrapper(n *node, in, out []func(*frame) reflect.Value, fn func([]reflect.Value) []reflect.Value) {
next := getExec(n.tnext)
if n.anc.kind == deferStmt {
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(in)+1)
inTypes := make([]reflect.Type, len(in))
for i, v := range in {
val[i+1] = v(f)
inTypes[i] = val[i+1].Type()
}
outTypes := make([]reflect.Type, len(out))
for i, v := range out {
outTypes[i] = v(f).Type()
}
funcType := reflect.FuncOf(inTypes, outTypes, false)
val[0] = reflect.MakeFunc(funcType, fn)
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return next
}
return
}
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(in))
for i, v := range in {
val[i] = v(f)
}
dests := fn(val)
for i, dest := range dests {
out[i](f).Set(dest)
}
return next
}
}
func genFunctionWrapper(n *node) func(*frame) reflect.Value {
var def *node
var ok bool
@@ -2344,25 +2381,22 @@ func _cap(n *node) {
}
func _copy(n *node) {
dest := genValueOutput(n, reflect.TypeOf(int(0)))
value0 := genValueArray(n.child[1])
value1 := genValue(n.child[2])
next := getExec(n.tnext)
in := []func(*frame) reflect.Value{genValueArray(n.child[1]), genValue(n.child[2])}
out := []func(*frame) reflect.Value{genValueOutput(n, reflect.TypeOf(0))}
n.exec = func(f *frame) bltn {
dest(f).SetInt(int64(reflect.Copy(value0(f), value1(f))))
return next
}
genBuiltinDeferWrapper(n, in, out, func(args []reflect.Value) []reflect.Value {
cnt := reflect.Copy(args[0], args[1])
return []reflect.Value{reflect.ValueOf(cnt)}
})
}
func _close(n *node) {
value := genValue(n.child[1])
next := getExec(n.tnext)
in := []func(*frame) reflect.Value{genValue(n.child[1])}
n.exec = func(f *frame) bltn {
value(f).Close()
return next
}
genBuiltinDeferWrapper(n, in, nil, func(args []reflect.Value) []reflect.Value {
args[0].Close()
return nil
})
}
func _complex(n *node) {
@@ -2415,13 +2449,13 @@ func _real(n *node) {
func _delete(n *node) {
value0 := genValue(n.child[1]) // map
value1 := genValue(n.child[2]) // key
next := getExec(n.tnext)
in := []func(*frame) reflect.Value{value0, value1}
var z reflect.Value
n.exec = func(f *frame) bltn {
value0(f).SetMapIndex(value1(f), z)
return next
}
genBuiltinDeferWrapper(n, in, nil, func(args []reflect.Value) []reflect.Value {
args[0].SetMapIndex(args[1], z)
return nil
})
}
func _len(n *node) {