Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coroc: support interface types #139

Merged
merged 3 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/coroutine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ func TestCoroutineYield(t *testing.T) {
coro: func() { IdentityGenericStructClosureInt(11) },
yields: []int{11, 100, 23, 12, 101, 45},
},

{
name: "indirect closure",
coro: func() { IndirectClosure(1) },
yields: []int{-1, 1, 2, 3},
},
}

// This emulates the installation of function type information by the
Expand Down
20 changes: 20 additions & 0 deletions compiler/testdata/coroutine.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,11 @@ type Box struct {
x int
}

func (b *Box) YieldAndInc() {
coroutine.Yield[int, any](b.x)
b.x++
}

func (b *Box) Closure(y int) func(int) {
return func(z int) {
coroutine.Yield[int, any](b.x)
Expand Down Expand Up @@ -636,3 +641,18 @@ func IdentityGenericStructClosureInt(n int) {
fn(23)
fn(45)
}

func IndirectClosure(n int) {
box := &Box{n}
fn := indirectClosure(box)
fn()
fn()
fn()
}

func indirectClosure(m interface{ YieldAndInc() }) func() {
coroutine.Yield[int, any](-1)
return func() {
m.YieldAndInc()
}
}
130 changes: 130 additions & 0 deletions compiler/testdata/coroutine_durable.go
Original file line number Diff line number Diff line change
Expand Up @@ -3241,6 +3241,38 @@ type Box struct {
x int
}

//go:noinline
func (_fn0 *Box) YieldAndInc() {
_c := coroutine.LoadContext[int, any]()
var _f0 *struct {
IP int
X0 *Box
} = coroutine.Push[struct {
IP int
X0 *Box
}](&_c.Stack)
if _f0.IP == 0 {
*_f0 = struct {
IP int
X0 *Box
}{X0: _fn0}
}
defer func() {
if !_c.Unwinding() {
coroutine.Pop(&_c.Stack)
}
}()
switch {
case _f0.IP < 2:
coroutine.Yield[int, any](_f0.X0.x)
_f0.IP = 2
fallthrough
case _f0.IP < 3:
_f0.X0.
x++
}
}

//go:noinline
func (_fn0 *Box) Closure(_fn1 int) (_ func(int)) {
var _f0 *struct {
Expand Down Expand Up @@ -3518,6 +3550,90 @@ func IdentityGenericStructClosureInt(_fn0 int) {
_f0.X1(45)
}
}

//go:noinline
func IndirectClosure(_fn0 int) {
_c := coroutine.LoadContext[int, any]()
var _f0 *struct {
IP int
X0 int
X1 *Box
X2 func()
} = coroutine.Push[struct {
IP int
X0 int
X1 *Box
X2 func()
}](&_c.Stack)
if _f0.IP == 0 {
*_f0 = struct {
IP int
X0 int
X1 *Box
X2 func()
}{X0: _fn0}
}
defer func() {
if !_c.Unwinding() {
coroutine.Pop(&_c.Stack)
}
}()
switch {
case _f0.IP < 2:
_f0.X1 = &Box{_f0.X0}
_f0.IP = 2
fallthrough
case _f0.IP < 3:
_f0.X2 = indirectClosure(_f0.X1)
_f0.IP = 3
fallthrough
case _f0.IP < 4:
_f0.X2()
_f0.IP = 4
fallthrough
case _f0.IP < 5:
_f0.X2()
_f0.IP = 5
fallthrough
case _f0.IP < 6:
_f0.X2()
}
}

//go:noinline
func indirectClosure(_fn0 interface{ YieldAndInc() }) (_ func()) {
_c := coroutine.LoadContext[int, any]()
var _f0 *struct {
IP int
X0 interface{ YieldAndInc() }
} = coroutine.Push[struct {
IP int
X0 interface{ YieldAndInc() }
}](&_c.Stack)
if _f0.IP == 0 {
*_f0 = struct {
IP int
X0 interface{ YieldAndInc() }
}{X0: _fn0}
}
defer func() {
if !_c.Unwinding() {
coroutine.Pop(&_c.Stack)
}
}()
switch {
case _f0.IP < 2:
coroutine.Yield[int, any](-1)
_f0.IP = 2
fallthrough
case _f0.IP < 3:
return func() {
_f0.X0.
YieldAndInc()
}
}
panic("unreachable")
}
func init() {
_types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/stealthrocket/coroutine/compiler/testdata.(*Box).Closure")
_types.RegisterClosure[func(_fn0 int), struct {
Expand All @@ -3528,6 +3644,7 @@ func init() {
X1 int
}
}]("github.com/stealthrocket/coroutine/compiler/testdata.(*Box).Closure.func1")
_types.RegisterFunc[func()]("github.com/stealthrocket/coroutine/compiler/testdata.(*Box).YieldAndInc")
_types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/stealthrocket/coroutine/compiler/testdata.(*IdentityGenericStruct[go.shape.int]).Closure")
_types.RegisterClosure[func(_fn0 int), struct {
F uintptr
Expand All @@ -3551,6 +3668,7 @@ func init() {
_types.RegisterFunc[func(_fn0 int)]("github.com/stealthrocket/coroutine/compiler/testdata.IdentityGenericStructClosureInt")
_types.RegisterFunc[func(n int)]("github.com/stealthrocket/coroutine/compiler/testdata.IdentityGenericStructInt")
_types.RegisterFunc[func(n int)]("github.com/stealthrocket/coroutine/compiler/testdata.IdentityGeneric[go.shape.int]")
_types.RegisterFunc[func(_fn0 int)]("github.com/stealthrocket/coroutine/compiler/testdata.IndirectClosure")
_types.RegisterFunc[func(_ int)]("github.com/stealthrocket/coroutine/compiler/testdata.LoopBreakAndContinue")
_types.RegisterFunc[func(_fn0 int) (_ int)]("github.com/stealthrocket/coroutine/compiler/testdata.NestedLoops")
_types.RegisterFunc[func(_fn0 int, _fn1 func(int))]("github.com/stealthrocket/coroutine/compiler/testdata.Range")
Expand Down Expand Up @@ -3684,5 +3802,17 @@ func init() {
}
D uintptr
}]("github.com/stealthrocket/coroutine/compiler/testdata.buildClosure[go.shape.int].func1")
_types.RegisterFunc[func(_fn0 interface {
YieldAndInc()
}) (_ func())]("github.com/stealthrocket/coroutine/compiler/testdata.indirectClosure")
_types.RegisterClosure[func(), struct {
F uintptr
X0 *struct {
IP int
X0 interface {
YieldAndInc()
}
}
}]("github.com/stealthrocket/coroutine/compiler/testdata.indirectClosure.func2")
_types.RegisterFunc[func(_fn0 ...int)]("github.com/stealthrocket/coroutine/compiler/testdata.varArgs")
}
18 changes: 18 additions & 0 deletions compiler/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ func typeExpr(p *packages.Package, typ types.Type, typeArg func(*types.TypeParam
if t.Empty() {
return ast.NewIdent("any")
}
if t.NumEmbeddeds() > 0 {
panic("not implemented: interface with embeddeds")
}
methods := make([]*ast.Field, t.NumExplicitMethods())
for i := range methods {
m := t.ExplicitMethod(i)
methods[i] = &ast.Field{
Names: []*ast.Ident{ast.NewIdent(m.Name())},
Type: typeExpr(p, m.Type(), typeArg),
}
}
return &ast.InterfaceType{
Methods: &ast.FieldList{List: methods},
}
case *types.Signature:
return newFuncType(p, t, typeArg)
case *types.Named:
Expand Down Expand Up @@ -165,6 +179,10 @@ func substituteTypeArgs(p *packages.Package, expr ast.Expr, typeArg func(*types.
return &ast.StructType{
Fields: substituteFieldList(p, e.Fields, typeArg),
}
case *ast.InterfaceType:
return &ast.InterfaceType{
Methods: substituteFieldList(p, e.Methods, typeArg),
}
case *ast.StarExpr:
return &ast.StarExpr{
X: substituteTypeArgs(p, e.X, typeArg),
Expand Down
2 changes: 1 addition & 1 deletion types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (m *typemap) ToType(t reflect.Type) typeid {
Kind: kindOf(t.Kind()),
}

if t.Name() != "" {
if t.Name() != "" || t.Kind() == reflect.Interface {
ti.MemoryOffset = uint64(offsetForType(t))
}

Expand Down