diff --git a/_demo/interf/foo/foo.go b/_demo/interf/foo/foo.go new file mode 100644 index 00000000..e385a31d --- /dev/null +++ b/_demo/interf/foo/foo.go @@ -0,0 +1,9 @@ +package foo + +func Bar() any { + return struct{ V int }{1} +} + +func F() any { + return struct{ v int }{1} +} diff --git a/_demo/interf/interf.go b/_demo/interf/interf.go new file mode 100644 index 00000000..457e9e41 --- /dev/null +++ b/_demo/interf/interf.go @@ -0,0 +1,35 @@ +package main + +import ( + "github.com/goplus/llgo/_demo/interf/foo" +) + +func Foo() any { + return struct{ v int }{1} +} + +func main() { + v := Foo() + if x, ok := v.(struct{ v int }); ok { + println(x.v) + } else { + println("Foo: not ok") + } + bar := foo.Bar() + if x, ok := bar.(struct{ V int }); ok { + println(x.V) + } else { + println("Bar: not ok") + } + if x, ok := foo.F().(struct{ v int }); ok { + println(x.v) + } else { + println("F: not ok") + } +} + +/* Expected output: +1 +1 +F: not ok +*/ diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index f2db6c47..0d23b976 100644 Binary files a/internal/abi/llgo_autogen.lla and b/internal/abi/llgo_autogen.lla differ diff --git a/internal/abi/type.go b/internal/abi/type.go index e7ecaf8f..b43621a9 100644 --- a/internal/abi/type.go +++ b/internal/abi/type.go @@ -193,6 +193,21 @@ type FuncType struct { OutCount uint16 // top bit is set if last input parameter is ... } +// In returns the number of input parameters of a function type. +func (p *FuncType) In() int { + return int(p.InCount) +} + +// Out returns the number of output results of a function type. +func (p *FuncType) Out() int { + return int(p.OutCount &^ (1 << 15)) +} + +// Variadic reports whether the function type is variadic. +func (p *FuncType) Variadic() bool { + return p.OutCount&(1<<15) != 0 +} + type StructField struct { Name Name // name is always non-empty Typ *Type // type of field @@ -219,10 +234,10 @@ type Text = unsafe.Pointer // TODO(xsw): to be confirmed // Method on non-interface type type Method struct { - Name_ Name // name of method - Mtyp_ *Type // method type (without receiver) - Ifn_ Text // fn used in interface call (one-word receiver) - Tfn_ Text // fn used for normal method call + Name_ Name // name of method + Mtyp_ *FuncType // method type (without receiver) + Ifn_ Text // fn used in interface call (one-word receiver) + Tfn_ Text // fn used for normal method call } // UncommonType is present only for defined types or types with methods diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 0de68c73..e2f90b84 100644 Binary files a/internal/runtime/llgo_autogen.lla and b/internal/runtime/llgo_autogen.lla differ diff --git a/internal/runtime/type.go b/internal/runtime/type.go index 6b8f0e8e..36ce1a0f 100644 --- a/internal/runtime/type.go +++ b/internal/runtime/type.go @@ -10,9 +10,6 @@ import ( "github.com/goplus/llgo/internal/abi" ) -// type nameOff = abi.NameOff -// type typeOff = abi.TypeOff - type _type = abi.Type type interfacetype = abi.InterfaceType diff --git a/internal/runtime/z_type.go b/internal/runtime/z_type.go index 99de71c5..403c37b0 100644 --- a/internal/runtime/z_type.go +++ b/internal/runtime/z_type.go @@ -20,6 +20,7 @@ import ( "unsafe" "github.com/goplus/llgo/internal/abi" + "github.com/goplus/llgo/internal/runtime/c" ) type ( @@ -31,10 +32,61 @@ type ( type Kind = abi.Kind type Type = abi.Type +type FuncType = abi.FuncType type InterfaceType = abi.InterfaceType // ----------------------------------------------------------------------------- +// Func returns a function type. +func Func(in, out []*Type, variadic bool) *FuncType { + const ( + funcTypeHdrSize = unsafe.Sizeof(abi.FuncType{}) + pointerSize = unsafe.Sizeof(uintptr(0)) + ) + + n := len(in) + len(out) + ptr := AllocU(funcTypeHdrSize + uintptr(n)*pointerSize) + c.Memset(ptr, 0, funcTypeHdrSize) + + ret := (*abi.FuncType)(ptr) + ret.Size_ = pointerSize + ret.Hash = uint32(abi.Func) // TODO(xsw): hash + ret.Kind_ = uint8(abi.Func) + ret.InCount = uint16(len(in)) + ret.OutCount = uint16(len(out)) + if variadic { + ret.OutCount |= 1 << 15 + } + + data := (**Type)(c.Advance(ptr, int(funcTypeHdrSize))) + params := unsafe.Slice(data, n) + copy(params, in) + copy(params[len(in):], out) + return ret +} + +// Imethod returns an interface method. +func Imethod(name string, typ *FuncType, exported bool) abi.Imethod { + n := abi.NewName(name, "", exported, false) + return abi.Imethod{ + Name_: n, + Typ_: typ, + } +} + +// Method returns a method. +func Method(name string, typ *FuncType, fn abi.Text, exported bool) abi.Method { + n := abi.NewName(name, "", exported, false) + return abi.Method{ + Name_: n, + Mtyp_: typ, + Ifn_: fn, + Tfn_: fn, + } +} + +// ----------------------------------------------------------------------------- + // Named returns a named type. func Named(name string, typ *Type) *Type { ret := *typ // TODO(xsw): named type