`gopls` disagrees with `go test` on interface implementation

57 views Asked by At

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 :)

0

There are 0 answers