fix: correctly store boolean result for branching operations

This commit is contained in:
Marc Vertes
2020-02-14 16:26:04 +01:00
committed by GitHub
parent 1b971b539c
commit 7037424edf
9 changed files with 144 additions and 28 deletions

10
_test/a41.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = [...]bool{true, true}
func main() {
println(a[0] && true)
}
// Output:
// true

10
_test/and3.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = true && true
func main() {
println(a)
}
// Output:
// true

12
_test/chan8.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
messages := make(chan bool)
go func() { messages <- true }()
println(<-messages && true)
}
// Output:
// true

10
_test/map20.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = map[int]bool{1: true, 2: true}
func main() {
println(a[1] && true)
}
// Output:
// true

10
_test/or2.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = false || true
func main() {
println(a)
}
// Output:
// true

10
_test/ptr8.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var a = func() *bool { b := true; return &b }()
func main() {
println(*a && true)
}
// Output:
// true

14
_test/struct31.go Normal file
View File

@@ -0,0 +1,14 @@
package main
type T struct {
bool
}
var t = T{true}
func main() {
println(t.bool && true)
}
// Output:
// true

View File

@@ -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

View File

@@ -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 {