gomacro icon indicating copy to clipboard operation
gomacro copied to clipboard

Cannot use co-dependent types with each other that implement a common interface

Open kettek opened this issue 3 years ago • 1 comments

The following code produces cannot use <*main.SceneB> as <main.Scene> in argument to switchTo:

package main

import (
        "github.com/cosmos72/gomacro/fast"
)

func main() {
        interp := fast.New()

        interp.Eval(`
                import "fmt"

                type Scene interface {
                        Init()
                        Destroy()
                }
                var globalScene Scene

                func switchTo(s Scene) {
                        if globalScene != nil {
                                globalScene.Destroy()
                        }
                        globalScene = s
                        s.Init()
                }

                type SceneA struct {
                }
                func (s *SceneA) Init() {
                        fmt.Println("Init")
                        switchTo(&SceneB{})
                }
                func (s *SceneA) Destroy() {
                        fmt.Println("Destroy")
                }

                type SceneB struct {
                }
                func (s *SceneB) Init() {
                        fmt.Println("Init")
                        switchTo(&SceneA{})
                }
                func (s *SceneB) Destroy() {
                        fmt.Println("Destroy")
                }

                switchTo(&SceneA{})
        `)
}

In the actual code I'm using, where this problem cropped up, the switchTo function isn't called in the global scope, but rather by an interpreter function that is invoked by the host-side. Same problem in that context.

This deviates from expected Go behavior, as the evaluated code compiles and runs under standard Go.

kettek avatar Mar 17 '22 07:03 kettek

Hello @kettek, your code really pushes the interpreter to its limits, for several reasons:

  1. support for out-of-order code, i.e. code that refers to declarations appearing later, was added as an after-thought and has some limitations.
  2. interpreted interfaces are emulated, because there is no reflect.InterfaceOf function
  3. mutually recursive types are emulated too, because reflect.StructOf does not support them. In this case, only methods of the two types mutually reference the each other, but the first call to switchTo(Scene) appears before the type SceneB and its methods are declared, thus I suspect gomacro will not recognize that *SceneB implements Scene at the call site switchTo(&SceneB{})

cosmos72 avatar Mar 17 '22 19:03 cosmos72