goplus / llgo

A Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python
Apache License 2.0
309 stars 24 forks source link

Wrong ABI of methods with struct receiver #779

Closed cpunion closed 4 days ago

cpunion commented 1 week ago
package main

type Tuple[T any] struct {
    v T
}

func (t Tuple[T]) Get() T {
    return t.v
}

type Future[T any] interface {
    Then(func(T))
}

type future[T any] struct {
    fn func(func(T))
}

func (f *future[T]) Then(callback func(T)) {
    f.fn(callback)
}

func Async[T any](fn func(func(T))) Future[T] {
    return &future[T]{fn: fn}
}

func ReadFile(fileName string) Future[Tuple[error]] {
    return Async[Tuple[error]](func(resolve func(Tuple[error])) {
        resolve(Tuple[error]{v: nil})
    })
}

func main() {
    ReadFile("foo.txt").Then(func(v Tuple[error]) {
        println(v.Get())
    })
}
$ go run .
(0x0,0x0)

$ go run ../cmd/llgo run .
ld64.lld: error: undefined symbol: main.(*Tuple[error]).Get
>>> referenced by /var/folders/f2/88rgt2bx533_m89qy6pqqp8w0000gn/T/5081bd122a308d50837fc66f946302ba6472a06ba993eda2fcccbd983723d6ba-d-1227f7.o:(symbol main.init$after+0x151c)
>>> referenced by /var/folders/f2/88rgt2bx533_m89qy6pqqp8w0000gn/T/5081bd122a308d50837fc66f946302ba6472a06ba993eda2fcccbd983723d6ba-d-1227f7.o:(symbol main.init$after+0x1518)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
exit status 1
cpunion commented 1 week ago

Maybe relate to interface, the code below is OK:

package main

type Tuple[T any] struct {
    v T
}

func (t Tuple[T]) Get() T {
    return t.v
}

type Future[T any] func(func(T))

func (f Future[T]) Then(callback func(T)) {
    f(callback)
}

func Async[T any](fn func(func(T))) Future[T] {
    return func(chain func(T)) {
        fn(func(v T) {
            chain(v)
        })
    }
}

func ReadFile(fileName string) Future[Tuple[error]] {
    return Async[Tuple[error]](func(resolve func(Tuple[error])) {
        resolve(Tuple[error]{v: nil})
    })
}

func main() {
    func(resolve func(Tuple[error])) {
        resolve(Tuple[error]{v: nil})
    }(func(v Tuple[error]) {
        println(v.Get())
    })
}