From 7037424edfea6919ac0224d85514b75a919c3314 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Fri, 14 Feb 2020 16:26:04 +0100 Subject: [PATCH] fix: correctly store boolean result for branching operations --- _test/a41.go | 10 +++++ _test/and3.go | 10 +++++ _test/chan8.go | 12 ++++++ _test/map20.go | 10 +++++ _test/or2.go | 10 +++++ _test/ptr8.go | 10 +++++ _test/struct31.go | 14 +++++++ interp/run.go | 93 +++++++++++++++++++++++++++++++++-------------- interp/type.go | 3 ++ 9 files changed, 144 insertions(+), 28 deletions(-) create mode 100644 _test/a41.go create mode 100644 _test/and3.go create mode 100644 _test/chan8.go create mode 100644 _test/map20.go create mode 100644 _test/or2.go create mode 100644 _test/ptr8.go create mode 100644 _test/struct31.go diff --git a/_test/a41.go b/_test/a41.go new file mode 100644 index 00000000..05b2f50f --- /dev/null +++ b/_test/a41.go @@ -0,0 +1,10 @@ +package main + +var a = [...]bool{true, true} + +func main() { + println(a[0] && true) +} + +// Output: +// true diff --git a/_test/and3.go b/_test/and3.go new file mode 100644 index 00000000..264662b9 --- /dev/null +++ b/_test/and3.go @@ -0,0 +1,10 @@ +package main + +var a = true && true + +func main() { + println(a) +} + +// Output: +// true diff --git a/_test/chan8.go b/_test/chan8.go new file mode 100644 index 00000000..cdd53463 --- /dev/null +++ b/_test/chan8.go @@ -0,0 +1,12 @@ +package main + +func main() { + messages := make(chan bool) + + go func() { messages <- true }() + + println(<-messages && true) +} + +// Output: +// true diff --git a/_test/map20.go b/_test/map20.go new file mode 100644 index 00000000..6ac5b4d1 --- /dev/null +++ b/_test/map20.go @@ -0,0 +1,10 @@ +package main + +var a = map[int]bool{1: true, 2: true} + +func main() { + println(a[1] && true) +} + +// Output: +// true diff --git a/_test/or2.go b/_test/or2.go new file mode 100644 index 00000000..57a68d6d --- /dev/null +++ b/_test/or2.go @@ -0,0 +1,10 @@ +package main + +var a = false || true + +func main() { + println(a) +} + +// Output: +// true diff --git a/_test/ptr8.go b/_test/ptr8.go new file mode 100644 index 00000000..9e1138f6 --- /dev/null +++ b/_test/ptr8.go @@ -0,0 +1,10 @@ +package main + +var a = func() *bool { b := true; return &b }() + +func main() { + println(*a && true) +} + +// Output: +// true diff --git a/_test/struct31.go b/_test/struct31.go new file mode 100644 index 00000000..9546bc58 --- /dev/null +++ b/_test/struct31.go @@ -0,0 +1,14 @@ +package main + +type T struct { + bool +} + +var t = T{true} + +func main() { + println(t.bool && true) +} + +// Output: +// true diff --git a/interp/run.go b/interp/run.go index 6c86e55f..375830e7 100644 --- a/interp/run.go +++ b/interp/run.go @@ -355,16 +355,15 @@ func not(n *node) { dest := genValue(n) value := genValue(n.child[0]) tnext := getExec(n.tnext) - i := n.findex if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { if !value(f).Bool() { - f.data[i].SetBool(true) + dest(f).SetBool(true) return tnext } - f.data[i].SetBool(false) + dest(f).SetBool(false) return fnext } } else { @@ -389,17 +388,18 @@ func addr(n *node) { func deref(n *node) { value := genValue(n.child[0]) tnext := getExec(n.tnext) + i := n.findex if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - if value(f).Elem().Bool() { + f.data[i] = value(f).Elem() + if f.data[i].Bool() { return tnext } return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { f.data[i] = value(f).Elem() return tnext @@ -978,21 +978,21 @@ func getIndexBinPtrMethod(n *node) { func getIndexArray(n *node) { tnext := getExec(n.tnext) value0 := genValueArray(n.child[0]) // array + i := n.findex if n.child[1].rval.IsValid() { // constant array index ai := int(vInt(n.child[1].rval)) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - if value0(f).Index(ai).Bool() { + f.data[i] = value0(f).Index(ai) + if f.data[i].Bool() { return tnext } return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { - // Can not use .Set due to constraint of being able to assign an array element f.data[i] = value0(f).Index(ai) return tnext } @@ -1004,16 +1004,15 @@ func getIndexArray(n *node) { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { _, vi := value1(f) - if value0(f).Index(int(vi)).Bool() { + f.data[i] = value0(f).Index(int(vi)) + if f.data[i].Bool() { return tnext } return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { _, vi := value1(f) - // Can not use .Set due to constraint of being able to assign an array element f.data[i] = value0(f).Index(int(vi)) return tnext } @@ -1035,8 +1034,10 @@ func getIndexMap(n *node) { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { if v := value0(f).MapIndex(mi); v.IsValid() && v.Bool() { + dest(f).SetBool(true) return tnext } + dest(f).Set(z) return fnext } } else { @@ -1056,8 +1057,10 @@ func getIndexMap(n *node) { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { if v := value0(f).MapIndex(value1(f)); v.IsValid() && v.Bool() { + dest(f).SetBool(true) return tnext } + dest(f).Set(z) return fnext } } else { @@ -1155,17 +1158,28 @@ func getIndexSeq(n *node) { value := genValue(n.child[0]) index := n.val.([]int) tnext := getExec(n.tnext) + i := n.findex + + // Note: + // Here we have to store the result using + // f.data[i] = value(...) + // instead of normal + // dest(f).Set(value(...) + // because the value returned by FieldByIndex() must be preserved + // for possible future Set operations on the struct field (avoid a + // dereference from Set, resulting in setting a copy of the + // original field). if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - if value(f).FieldByIndex(index).Bool() { + f.data[i] = value(f).FieldByIndex(index) + if f.data[i].Bool() { return tnext } return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { f.data[i] = value(f).FieldByIndex(index) return tnext @@ -1183,17 +1197,18 @@ func getPtrIndexSeq(n *node) { } else { value = genValue(n.child[0]) } + i := n.findex if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - if value(f).Elem().FieldByIndex(index).Bool() { + f.data[i] = value(f).Elem().FieldByIndex(index) + if f.data[i].Bool() { return tnext } return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { f.data[i] = value(f).Elem().FieldByIndex(index) return tnext @@ -1205,17 +1220,38 @@ func getIndexSeqField(n *node) { value := genValue(n.child[0]) index := n.val.([]int) i := n.findex - next := getExec(n.tnext) + tnext := getExec(n.tnext) - if n.child[0].typ.TypeOf().Kind() == reflect.Ptr { - n.exec = func(f *frame) bltn { - f.data[i] = value(f).Elem().FieldByIndex(index) - return next + if n.fnext != nil { + fnext := getExec(n.fnext) + if n.child[0].typ.TypeOf().Kind() == reflect.Ptr { + n.exec = func(f *frame) bltn { + f.data[i] = value(f).Elem().FieldByIndex(index) + if f.data[i].Bool() { + return tnext + } + return fnext + } + } else { + n.exec = func(f *frame) bltn { + f.data[i] = value(f).FieldByIndex(index) + if f.data[i].Bool() { + return tnext + } + return fnext + } } } else { - n.exec = func(f *frame) bltn { - f.data[i] = value(f).FieldByIndex(index) - return next + if n.child[0].typ.TypeOf().Kind() == reflect.Ptr { + n.exec = func(f *frame) bltn { + f.data[i] = value(f).Elem().FieldByIndex(index) + return tnext + } + } else { + n.exec = func(f *frame) bltn { + f.data[i] = value(f).FieldByIndex(index) + return tnext + } } } } @@ -2170,16 +2206,18 @@ func reset(n *node) { func recv(n *node) { value := genValue(n.child[0]) tnext := getExec(n.tnext) + i := n.findex if n.interp.cancelChan { // Cancellable channel read if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - ch := value(f) // Fast: channel read doesn't block - if x, ok := ch.TryRecv(); ok { - if x.Bool() { + var ok bool + ch := value(f) + if f.data[i], ok = ch.TryRecv(); ok { + if f.data[i].Bool() { return tnext } return fnext @@ -2195,7 +2233,6 @@ func recv(n *node) { return fnext } } else { - i := n.findex n.exec = func(f *frame) bltn { // Fast: channel read doesn't block var ok bool @@ -2217,7 +2254,7 @@ func recv(n *node) { if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - if v, _ := value(f).Recv(); v.Bool() { + if f.data[i], _ = value(f).Recv(); f.data[i].Bool() { return tnext } return fnext diff --git a/interp/type.go b/interp/type.go index 9671e8a3..7583077e 100644 --- a/interp/type.go +++ b/interp/type.go @@ -431,6 +431,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) { } } + case landExpr, lorExpr: + t.cat = boolT + case mapType: t.cat = mapT if t.key, err = nodeType(interp, sc, n.child[0]); err != nil {