From 021824930d8dabd253170687cc21c09ed917d5e5 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Mon, 12 Sep 2022 22:30:08 +0200 Subject: [PATCH] interp: improve type assertions In type assertion at compile time, compare signatures between function types only. Make `itype.numOut()` return the correct value for Go builtins (this was not strictly necessary due to above fix, but it is correct and improves maintainability). Fixes #1454. --- _test/issue-1454.go | 22 ++++++++++++++++++++++ interp/cfg.go | 2 +- interp/type.go | 7 ++++++- interp/typecheck.go | 5 +++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 _test/issue-1454.go diff --git a/_test/issue-1454.go b/_test/issue-1454.go new file mode 100644 index 000000000..caa7b9df6 --- /dev/null +++ b/_test/issue-1454.go @@ -0,0 +1,22 @@ +package main + +type I2 interface { + I2() string +} + +type I interface { + I2 +} + +type S struct{} + +func (*S) I2() string { return "foo" } + +func main() { + var i I + _, ok := i.(*S) + println(ok) +} + +// Output: +// false diff --git a/interp/cfg.go b/interp/cfg.go index 5b9037e75..e562e139c 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -1060,7 +1060,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string } n.gen = c0.sym.builtin - c0.typ = &itype{cat: builtinT} + c0.typ = &itype{cat: builtinT, name: bname} if n.typ, err = nodeType(interp, sc, n); err != nil { return } diff --git a/interp/type.go b/interp/type.go index 91d6b25d4..718274307 100644 --- a/interp/type.go +++ b/interp/type.go @@ -1249,8 +1249,13 @@ func (t *itype) numOut() int { if t.rtype.Kind() == reflect.Func { return t.rtype.NumOut() } + case builtinT: + switch t.name { + case "append", "cap", "complex", "copy", "imag", "len", "make", "new", "real", "recover": + return 1 + } } - return 1 + return 0 } func (t *itype) out(i int) *itype { diff --git a/interp/typecheck.go b/interp/typecheck.go index e0473cbf6..a51a3fc20 100644 --- a/interp/typecheck.go +++ b/interp/typecheck.go @@ -625,6 +625,11 @@ func (check typecheck) typeAssertionExpr(n *node, typ *itype) error { return n.cfgErrorf("impossible type assertion: %s does not implement %s as %q method has a pointer receiver", typ.id(), n.typ.id(), name) } + if im.cat != funcT || tm.cat != funcT { + // It only makes sense to compare in/out parameter types if both types are functions. + continue + } + err := n.cfgErrorf("impossible type assertion: %s does not implement %s", typ.id(), n.typ.id()) if im.numIn() != tm.numIn() || im.numOut() != tm.numOut() { return err