Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Equality is incorrect when nil is used as the left argument of == #1500

Merged
merged 14 commits into from
Mar 23, 2023
16 changes: 16 additions & 0 deletions _test/issue-1496.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

func main() {
a := []byte{} == nil
b := nil == []byte{}
c := nil == &struct{}{}
i := 100
d := nil == &i
var v interface{}
f := nil == v
g := v == nil
println(a, b, c, d, f, g)
}

// Output:
// false false false false true true
6 changes: 5 additions & 1 deletion interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,11 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
n.typ = sc.getType("bool")
if c0.sym == nilSym || c1.sym == nilSym {
if n.action == aEqual {
n.gen = isNil
if c1.sym == nilSym {
n.gen = isNilChild(0)
} else {
n.gen = isNilChild(1)
}
} else {
n.gen = isNotNil
}
Expand Down
107 changes: 54 additions & 53 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3863,31 +3863,44 @@ func slice0(n *node) {
}
}

func isNil(n *node) {
var value func(*frame) reflect.Value
c0 := n.child[0]
value = genValue(c0)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
tnext := getExec(n.tnext)
dest := genValue(n)

if n.fnext == nil {
if !isInterfaceSrc(c0.typ) {
if isInterface {
func isNilChild(child int) func(n *node) {
return func(n *node) {
var value func(*frame) reflect.Value
child := n.child[child]
value = genValue(child)
typ := n.typ.concrete().TypeOf()
isInterface := n.typ.TypeOf().Kind() == reflect.Interface
tnext := getExec(n.tnext)
dest := genValue(n)
if n.fnext == nil {
if !isInterfaceSrc(child.typ) {
if isInterface {
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(value(f).IsNil()).Convert(typ))
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).Set(reflect.ValueOf(value(f).IsNil()).Convert(typ))
dest(f).SetBool(value(f).IsNil())
return tnext
}
return
}
n.exec = func(f *frame) bltn {
dest(f).SetBool(value(f).IsNil())
return tnext
if isInterface {
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
r = v.IsNil()
}
dest(f).Set(reflect.ValueOf(r).Convert(typ))
return tnext
}
return
}
return
}
if isInterface {
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
Expand All @@ -3896,55 +3909,43 @@ func isNil(n *node) {
} else {
r = v.IsNil()
}
dest(f).Set(reflect.ValueOf(r).Convert(typ))
dest(f).SetBool(r)
return tnext
}
return
}
n.exec = func(f *frame) bltn {
v := value(f)
var r bool
if vi, ok := v.Interface().(valueInterface); ok {
r = (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
r = v.IsNil()
}
dest(f).SetBool(r)
return tnext
}
return
}

fnext := getExec(n.fnext)
fnext := getExec(n.fnext)

if !isInterfaceSrc(c0.typ) {
n.exec = func(f *frame) bltn {
if value(f).IsNil() {
dest(f).SetBool(true)
return tnext
if !isInterfaceSrc(child.typ) {
n.exec = func(f *frame) bltn {
if value(f).IsNil() {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
dest(f).SetBool(false)
return fnext
return
}
return
}

n.exec = func(f *frame) bltn {
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
if (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
n.exec = func(f *frame) bltn {
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
if (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
if v.IsNil() {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
if v.IsNil() {
dest(f).SetBool(true)
return tnext
}
dest(f).SetBool(false)
return fnext
}
}

Expand Down