Skip to content

Commit

Permalink
interp: improve type assertions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mvertes committed Sep 12, 2022
1 parent b8301f1 commit 0218249
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 2 deletions.
22 changes: 22 additions & 0 deletions _test/issue-1454.go
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
7 changes: 6 additions & 1 deletion interp/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions interp/typecheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0218249

Please sign in to comment.