Consider the following code:
package ifaces
import (
"fmt"
"testing"
)
type IFace1 interface {
Do1()
}
type IFace2 interface {
Do2()
}
type Inner struct {
}
func (i *Inner) Do2() {
fmt.Printf("Do2\n")
}
type Outer struct {
Inner
}
func (o *Outer) Do1() {
fmt.Printf("Do2\n")
}
func TestInterface(t *testing.T) {
o := Outer{}
var i interface{}
i = o
a := i.(IFace2)
a.Do2()
}
In summary, Inner
implements Iface2
, while Outer
implements Iface1
and embeds Inner
.
Checking Outer
via gopls
(with vim-go
's command GoImplements
) gives the following response:
test/ifaces/interfaces_test.go|8 col 6| type IFace1 interface {
test/ifaces/interfaces_test.go|12 col 6| type IFace2 interface {
However, running the test results in the following error:
$ go test test/ifaces/interfaces_test.go
--- FAIL: TestInterface (0.00s)
panic: interface conversion: ifaces.Outer is not ifaces.IFace2: missing method Do2 [recovered]
panic: interface conversion: ifaces.Outer is not ifaces.IFace2: missing method Do2
goroutine 18 [running]:
testing.tRunner.func1.2({0x5095c0, 0xc0000a23c0})
/home/x/sdk/go1.19.3/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
/home/x/sdk/go1.19.3/src/testing/testing.go:1399 +0x39f
panic({0x5095c0, 0xc0000a23c0})
/home/x/sdk/go1.19.3/src/runtime/panic.go:884 +0x212
command-line-arguments.TestInterface(0x0?)
/home/x/D/git/personal/go/test/ifaces/interfaces_test.go:36 +0x27
testing.tRunner(0xc0000829c0, 0x52f520)
/home/x/sdk/go1.19.3/src/testing/testing.go:1446 +0x10b
created by testing.(*T).Run
/home/x/sdk/go1.19.3/src/testing/testing.go:1493 +0x35f
FAIL command-line-arguments 0.004s
FAIL
As shown in the snippet, this is Go 1.19: why does the program panic, if gopls
says the interface is implemented?
Does holding Outer
inside an interface{}
variable have anything to do with this error? Note the error explicitly mentions Outer
(ifaces.Outer is not ifaces.IFace2
).
Running the same code against 1.13.15 produces the same panic, so this does not seem to be a bug (or it is a very old bug :)