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.
This commit is contained in:
Marc Vertes
2022-09-12 22:30:08 +02:00
committed by GitHub
parent b8301f10a8
commit 021824930d
4 changed files with 34 additions and 2 deletions

22
_test/issue-1454.go Normal file
View File

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

View File

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

View File

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

View File

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