From d2fb4d30aef35698fab97e38ce9f803f7fc5717e Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 08:51:27 +1000 Subject: [PATCH 1/9] Support ast.IndexListExpr in substituteTypeArgs --- compiler/types.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/types.go b/compiler/types.go index f3db3ac..56d8abc 100644 --- a/compiler/types.go +++ b/compiler/types.go @@ -197,6 +197,15 @@ func substituteTypeArgs(p *packages.Package, expr ast.Expr, typeArg func(*types. X: substituteTypeArgs(p, e.X, typeArg), Index: substituteTypeArgs(p, e.Index, typeArg), } + case *ast.IndexListExpr: + indices := make([]ast.Expr, len(e.Indices)) + for i, index := range e.Indices { + indices[i] = substituteTypeArgs(p, index, typeArg) + } + return &ast.IndexListExpr{ + X: substituteTypeArgs(p, e.X, typeArg), + Indices: indices, + } case *ast.Ident: t := p.TypesInfo.TypeOf(e) tp, ok := t.(*types.TypeParam) From 872817267d52826e4818f23e085cbc079d7955e9 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 08:55:47 +1000 Subject: [PATCH 2/9] Handle ellipsis in closure type registration --- compiler/function.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/function.go b/compiler/function.go index 2a3b25f..350e12e 100644 --- a/compiler/function.go +++ b/compiler/function.go @@ -182,6 +182,11 @@ func collectFunctypes(p *packages.Package, name string, fn ast.Node, scope *func fieldName := ast.NewIdent(fmt.Sprintf("X%d", i)) fieldType := freeVar.typ + // Convert ellipsis into slice (...X => []X). + if e, ok := fieldType.(*ast.Ellipsis); ok { + fieldType = &ast.ArrayType{Elt: e.Elt} + } + // The Go compiler uses a more advanced mechanism to determine if a // free variable should be captured by pointer or by value: it looks // at whether the variable is reassigned, its address taken, and if From cd04790c20685929bc43d1941c5112233acc80c5 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 09:33:37 +1000 Subject: [PATCH 3/9] Translate generic return values correctly --- compiler/compile.go | 2 ++ compiler/function.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/compile.go b/compiler/compile.go index a29bb9f..721d38c 100644 --- a/compiler/compile.go +++ b/compiler/compile.go @@ -526,6 +526,8 @@ func (scope *scope) compileFuncLit(p *packages.Package, fn *ast.FuncLit, color * Body: scope.compileFuncBody(p, fn.Type, fn.Body, nil, color), } + p.TypesInfo.Types[gen] = types.TypeAndValue{Type: p.TypesInfo.TypeOf(fn)} + if !isExpr(gen.Body) { scope.colors[gen] = color } diff --git a/compiler/function.go b/compiler/function.go index 350e12e..f0cdbfe 100644 --- a/compiler/function.go +++ b/compiler/function.go @@ -90,7 +90,7 @@ func collectFunctypes(p *packages.Package, name string, fn ast.Node, scope *func typeArg = g.typeArgOf } - signature := copyFunctionType(functionTypeOf(fn)) + signature := copyFunctionType(funcTypeWithNamedResults(p, fn)) signature.TypeParams = nil recv := copyFieldList(functionRecvOf(fn)) From 08866fbd9e929fd982a05c3f9ff8094a265848f8 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 09:39:28 +1000 Subject: [PATCH 4/9] Support interfaces with embeds --- compiler/types.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/types.go b/compiler/types.go index 56d8abc..d0f31b3 100644 --- a/compiler/types.go +++ b/compiler/types.go @@ -52,9 +52,6 @@ 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) @@ -63,8 +60,16 @@ func typeExpr(p *packages.Package, typ types.Type, typeArg func(*types.TypeParam Type: typeExpr(p, m.Type(), typeArg), } } + embeddeds := make([]*ast.Field, t.NumEmbeddeds()) + for i := range embeddeds { + embeddeds[i] = &ast.Field{ + Type: typeExpr(p, t.EmbeddedType(i), typeArg), + } + } return &ast.InterfaceType{ - Methods: &ast.FieldList{List: methods}, + Methods: &ast.FieldList{ + List: append(methods, embeddeds...), + }, } case *types.Signature: return newFuncType(p, t, typeArg) From 99ae4ba6c96f1da16ee7e99975b77f1faf082ed3 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 09:44:20 +1000 Subject: [PATCH 5/9] Preserve underscore imports --- compiler/compile.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/compile.go b/compiler/compile.go index 721d38c..8efe8e1 100644 --- a/compiler/compile.go +++ b/compiler/compile.go @@ -372,7 +372,7 @@ func (c *compiler) compilePackage(p *packages.Package, colors functionColors) er c.generateFunctypes(p, gen, colorsByFunc) // Find all the required imports for this file. - gen = addImports(p, gen) + gen = addImports(p, f, gen) outputPath := strings.TrimSuffix(p.GoFiles[i], ".go") outputPath += "_durable.go" @@ -400,7 +400,7 @@ func containsColoredFuncLit(decl *ast.FuncDecl, colorsByFunc map[ast.Node]*types return } -func addImports(p *packages.Package, gen *ast.File) *ast.File { +func addImports(p *packages.Package, f *ast.File, gen *ast.File) *ast.File { imports := map[string]string{} ast.Inspect(gen, func(n ast.Node) bool { @@ -438,6 +438,15 @@ func addImports(p *packages.Package, gen *ast.File) *ast.File { } importspecs := make([]ast.Spec, 0, len(imports)) + + // Preserve underscore (side effect) imports. + for _, imp := range f.Imports { + if imp.Name != nil && imp.Name.Name == "_" { + importspecs = append(importspecs, imp) + } + } + + // Add imports for all packages used in the file. for name, path := range imports { importspecs = append(importspecs, &ast.ImportSpec{ Name: ast.NewIdent(name), From fbd5d8c2af0c340fe35832787238eca2b836a6d4 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 11:16:36 +1000 Subject: [PATCH 6/9] Support serializing reflect.Type --- types/reflect.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/types/reflect.go b/types/reflect.go index 6500092..0d2cfc6 100644 --- a/types/reflect.go +++ b/types/reflect.go @@ -40,6 +40,9 @@ func serializeAny(s *Serializer, t reflect.Type, p unsafe.Pointer) { } switch t { + case reflectTypeType: + serializeType(s, t) + return case reflectValueType: v := *(*reflect.Value)(p) serializeType(s, v.Type()) @@ -114,6 +117,11 @@ func deserializeAny(d *Deserializer, t reflect.Type, p unsafe.Pointer) { } switch t { + case reflectTypeType: + rt, _ := deserializeType(d) + reflect.NewAt(reflectTypeType, p).Elem().Set(reflect.ValueOf(rt)) + return + case reflectValueType: rt, length := deserializeType(d) if length >= 0 { @@ -187,7 +195,8 @@ func deserializeAny(d *Deserializer, t reflect.Type, p unsafe.Pointer) { } } -var reflectValueType = reflect.TypeOf(reflect.Value{}) +var reflectValueType = reflect.TypeFor[reflect.Value]() +var reflectTypeType = reflect.TypeFor[reflect.Type]() func serializeReflectValue(s *Serializer, t reflect.Type, v reflect.Value) { switch t.Kind() { From 0f722c3c810dc9061866dbfa1ed65a553cf27b0e Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 14:28:38 +1000 Subject: [PATCH 7/9] Exercise some of the changes --- compiler/coroutine_test.go | 5 + compiler/testdata/coroutine.go | 28 ++++++ compiler/testdata/coroutine_durable.go | 134 ++++++++++++++++++++++++- 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/compiler/coroutine_test.go b/compiler/coroutine_test.go index 491858f..4d24a7f 100644 --- a/compiler/coroutine_test.go +++ b/compiler/coroutine_test.go @@ -220,6 +220,11 @@ func TestCoroutineYield(t *testing.T) { coro: func() { StructClosure(3) }, yields: []int{10, 100, 1000, 11, 101, 1000, 12, 102, 1000}, }, + { + name: "generic closure capturing receiver and param", + coro: func() { StructGenericClosure(3) }, + yields: []int{10, 100, 1000, 11, 101, 1000, 12, 102, 1000}, + }, { name: "generic function", coro: func() { IdentityGenericInt(11) }, diff --git a/compiler/testdata/coroutine.go b/compiler/testdata/coroutine.go index 7d312a6..6d424b5 100644 --- a/compiler/testdata/coroutine.go +++ b/compiler/testdata/coroutine.go @@ -586,6 +586,34 @@ func StructClosure(n int) { } } +type GenericBox[T integer] struct { + x T +} + +func (b *GenericBox[T]) YieldAndInc() { + coroutine.Yield[T, any](b.x) + b.x++ +} + +func (b *GenericBox[T]) Closure(y T) func(T) { + return func(z T) { + coroutine.Yield[T, any](b.x) + coroutine.Yield[T, any](y) + coroutine.Yield[T, any](z) + b.x++ + y++ + z++ // mutation is lost + } +} + +func StructGenericClosure(n int) { + box := GenericBox[int]{10} + fn := box.Closure(100) + for i := 0; i < n; i++ { + fn(1000) + } +} + func IdentityGeneric[T any](n T) { coroutine.Yield[T, any](n) } diff --git a/compiler/testdata/coroutine_durable.go b/compiler/testdata/coroutine_durable.go index 3fd4aa6..5949223 100644 --- a/compiler/testdata/coroutine_durable.go +++ b/compiler/testdata/coroutine_durable.go @@ -3385,6 +3385,127 @@ func StructClosure(_fn0 int) { } } +type GenericBox[T integer] struct { + x T +} + +func (b *GenericBox[T]) YieldAndInc() { + coroutine.Yield[T, any](b.x) + b.x++ +} + +//go:noinline +func (_fn0 *GenericBox[T]) Closure(_fn1 T) (_ func(T)) { + var _f0 *struct { + IP int + X0 *GenericBox[T] + X1 T + } = &struct { + IP int + X0 *GenericBox[T] + X1 T + }{X0: _fn0, X1: _fn1} + return func(_fn0 T) { + _c := coroutine.LoadContext[int, any]() + var _f1 *struct { + IP int + X0 T + } = coroutine.Push[struct { + IP int + X0 T + }](&_c.Stack) + if _f1.IP == 0 { + *_f1 = struct { + IP int + X0 T + }{X0: _fn0} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f1.IP < 2: + coroutine.Yield[T, any](_f0.X0.x) + _f1.IP = 2 + fallthrough + case _f1.IP < 3: + coroutine.Yield[T, any](_f0.X1) + _f1.IP = 3 + fallthrough + case _f1.IP < 4: + coroutine.Yield[T, any](_f1.X0) + _f1.IP = 4 + fallthrough + case _f1.IP < 5: + _f0.X0. + x++ + _f1.IP = 5 + fallthrough + case _f1.IP < 6: + _f0.X1++ + _f1.IP = 6 + fallthrough + case _f1.IP < 7: + _f1.X0++ + } + } +} + +//go:noinline +func StructGenericClosure(_fn0 int) { + _c := coroutine.LoadContext[int, any]() + var _f0 *struct { + IP int + X0 int + X1 GenericBox[int] + X2 func(int) + X3 int + } = coroutine.Push[struct { + IP int + X0 int + X1 GenericBox[int] + X2 func(int) + X3 int + }](&_c.Stack) + if _f0.IP == 0 { + *_f0 = struct { + IP int + X0 int + X1 GenericBox[int] + X2 func(int) + X3 int + }{X0: _fn0} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f0.IP < 2: + _f0.X1 = GenericBox[int]{10} + _f0.IP = 2 + fallthrough + case _f0.IP < 3: + _f0.X2 = _f0.X1.Closure(100) + _f0.IP = 3 + fallthrough + case _f0.IP < 5: + switch { + case _f0.IP < 4: + _f0.X3 = 0 + _f0.IP = 4 + fallthrough + case _f0.IP < 5: + for ; _f0.X3 < _f0.X0; _f0.X3, _f0.IP = _f0.X3+1, 4 { + _f0.X2(1000) + } + } + } +} + //go:noinline func IdentityGeneric[T any](n T) { coroutine.Yield[T, any](n) } @@ -3692,6 +3813,16 @@ func init() { } }]("github.com/dispatchrun/coroutine/compiler/testdata.(*Box).Closure.func1") _types.RegisterFunc[func()]("github.com/dispatchrun/coroutine/compiler/testdata.(*Box).YieldAndInc") + _types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/dispatchrun/coroutine/compiler/testdata.(*GenericBox[go.shape.int]).Closure") + _types.RegisterClosure[func(_fn0 int), struct { + F uintptr + X0 *struct { + IP int + X0 *GenericBox[int] + X1 int + } + D uintptr + }]("github.com/dispatchrun/coroutine/compiler/testdata.(*GenericBox[go.shape.int]).Closure.func1") _types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/dispatchrun/coroutine/compiler/testdata.(*IdentityGenericStruct[go.shape.int]).Closure") _types.RegisterClosure[func(_fn0 int), struct { F uintptr @@ -3746,7 +3877,7 @@ func init() { } }]("github.com/dispatchrun/coroutine/compiler/testdata.Range10ClosureCapturingValues.func2") _types.RegisterFunc[func()]("github.com/dispatchrun/coroutine/compiler/testdata.Range10ClosureHeterogenousCapture") - _types.RegisterClosure[func() int, struct { + _types.RegisterClosure[func() (_ int), struct { F uintptr X0 *struct { IP int @@ -3814,6 +3945,7 @@ func init() { _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.SquareGeneratorTwice") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.SquareGeneratorTwiceLoop") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.StructClosure") + _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.StructGenericClosure") _types.RegisterFunc[func(_ int)]("github.com/dispatchrun/coroutine/compiler/testdata.TypeSwitchingGenerator") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.VarArgs") _types.RegisterFunc[func(_fn0 *int, _fn1, _fn2 int)]("github.com/dispatchrun/coroutine/compiler/testdata.YieldAndDeferAssign") From bac9b4703231666c6b4ba86fa571f9769f30c535 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 14:41:37 +1000 Subject: [PATCH 8/9] Test reflect.Type serialization --- compiler/coroutine_test.go | 10 +++ compiler/testdata/coroutine.go | 13 +++ compiler/testdata/coroutine_durable.go | 119 ++++++++++++++++++++++++- types/reflect.go | 2 +- 4 files changed, 142 insertions(+), 2 deletions(-) diff --git a/compiler/coroutine_test.go b/compiler/coroutine_test.go index 4d24a7f..3f50e61 100644 --- a/compiler/coroutine_test.go +++ b/compiler/coroutine_test.go @@ -1,6 +1,8 @@ package compiler import ( + "math" + "reflect" "slices" "testing" @@ -260,6 +262,14 @@ func TestCoroutineYield(t *testing.T) { coro: func() { RangeOverInt(3) }, yields: []int{0, 1, 2}, }, + + { + name: "reflect type", + coro: func() { + ReflectType(reflect.TypeFor[uint8](), reflect.TypeFor[uint16]()) + }, + yields: []int{math.MaxUint8, math.MaxUint16}, + }, } // This emulates the installation of function type information by the diff --git a/compiler/testdata/coroutine.go b/compiler/testdata/coroutine.go index 6d424b5..063e9d7 100644 --- a/compiler/testdata/coroutine.go +++ b/compiler/testdata/coroutine.go @@ -3,6 +3,8 @@ package testdata import ( + "math" + "reflect" "time" "unsafe" @@ -690,3 +692,14 @@ func RangeOverInt(n int) { coroutine.Yield[int, any](i) } } + +func ReflectType(types ...reflect.Type) { + for _, t := range types { + v := reflect.New(t).Elem() + if !v.CanUint() { + panic("expected uint type") + } + v.SetUint(math.MaxUint64) + coroutine.Yield[int, any](int(v.Uint())) + } +} diff --git a/compiler/testdata/coroutine_durable.go b/compiler/testdata/coroutine_durable.go index 5949223..903f419 100644 --- a/compiler/testdata/coroutine_durable.go +++ b/compiler/testdata/coroutine_durable.go @@ -4,6 +4,8 @@ package testdata import ( coroutine "github.com/dispatchrun/coroutine" + math "math" + reflect "reflect" time "time" unsafe "unsafe" ) @@ -3514,7 +3516,7 @@ func IdentityGenericInt(n int) { IdentityGeneric[int](n) } //go:noinline func IdentityGenericClosure[T any](_fn0 T) { - _c := coroutine.LoadContext[T, any]() + _c := coroutine.LoadContext[int, any]() var _f0 *struct { IP int X0 T @@ -3802,6 +3804,120 @@ func RangeOverInt(_fn0 int) { } } } + +//go:noinline +func ReflectType(_fn0 ...reflect.Type) { + _c := coroutine.LoadContext[int, any]() + var _f0 *struct { + IP int + X0 []reflect.Type + X1 []reflect.Type + X2 int + X3 reflect.Type + X4 reflect.Value + X5 reflect.Value + X6 bool + X7 bool + X8 uint64 + X9 int + } = coroutine.Push[struct { + IP int + X0 []reflect.Type + X1 []reflect.Type + X2 int + X3 reflect.Type + X4 reflect.Value + X5 reflect.Value + X6 bool + X7 bool + X8 uint64 + X9 int + }](&_c.Stack) + if _f0.IP == 0 { + *_f0 = struct { + IP int + X0 []reflect.Type + X1 []reflect.Type + X2 int + X3 reflect.Type + X4 reflect.Value + X5 reflect.Value + X6 bool + X7 bool + X8 uint64 + X9 int + }{X0: _fn0} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f0.IP < 2: + _f0.X1 = _f0.X0 + _f0.IP = 2 + fallthrough + case _f0.IP < 13: + switch { + case _f0.IP < 3: + _f0.X2 = 0 + _f0.IP = 3 + fallthrough + case _f0.IP < 13: + for ; _f0.X2 < len(_f0.X1); _f0.X2, _f0.IP = _f0.X2+1, 3 { + switch { + case _f0.IP < 4: + _f0.X3 = _f0.X1[_f0.X2] + _f0.IP = 4 + fallthrough + case _f0.IP < 5: + _f0.X4 = reflect.New(_f0.X3) + _f0.IP = 5 + fallthrough + case _f0.IP < 6: + _f0.X5 = _f0.X4.Elem() + _f0.IP = 6 + fallthrough + case _f0.IP < 9: + switch { + case _f0.IP < 7: + _f0.X6 = _f0.X5. + CanUint() + _f0.IP = 7 + fallthrough + case _f0.IP < 8: + _f0.X7 = !_f0.X6 + _f0.IP = 8 + fallthrough + case _f0.IP < 9: + if _f0.X7 { + panic("expected uint type") + } + } + _f0.IP = 9 + fallthrough + case _f0.IP < 10: + _f0.X5. + SetUint(math.MaxUint64) + _f0.IP = 10 + fallthrough + case _f0.IP < 11: + _f0.X8 = _f0.X5. + Uint() + _f0.IP = 11 + fallthrough + case _f0.IP < 12: + _f0.X9 = int(_f0.X8) + _f0.IP = 12 + fallthrough + case _f0.IP < 13: + coroutine.Yield[int, any](_f0.X9) + } + } + } + } +} func init() { _types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/dispatchrun/coroutine/compiler/testdata.(*Box).Closure") _types.RegisterClosure[func(_fn0 int), struct { @@ -3937,6 +4053,7 @@ func init() { _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.RangeTripleFuncValue") _types.RegisterFunc[func(i int)]("github.com/dispatchrun/coroutine/compiler/testdata.RangeTripleFuncValue.func2") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.RangeYieldAndDeferAssign") + _types.RegisterFunc[func(_fn0 ...reflect.Type)]("github.com/dispatchrun/coroutine/compiler/testdata.ReflectType") _types.RegisterFunc[func() (_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.ReturnNamedValue") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.Select") _types.RegisterFunc[func(_ int)]("github.com/dispatchrun/coroutine/compiler/testdata.Shadowing") diff --git a/types/reflect.go b/types/reflect.go index 0d2cfc6..948e5b1 100644 --- a/types/reflect.go +++ b/types/reflect.go @@ -41,7 +41,7 @@ func serializeAny(s *Serializer, t reflect.Type, p unsafe.Pointer) { switch t { case reflectTypeType: - serializeType(s, t) + serializeType(s, *(*reflect.Type)(p)) return case reflectValueType: v := *(*reflect.Value)(p) From 4eca87e649376792bd18377aabc4fc4e0108fbd9 Mon Sep 17 00:00:00 2001 From: Chris O'Hara Date: Mon, 17 Jun 2024 14:52:47 +1000 Subject: [PATCH 9/9] Test the remaining changes --- compiler/coroutine_test.go | 12 ++ compiler/testdata/coroutine.go | 38 +++++ compiler/testdata/coroutine_durable.go | 218 ++++++++++++++++++++++++- 3 files changed, 267 insertions(+), 1 deletion(-) diff --git a/compiler/coroutine_test.go b/compiler/coroutine_test.go index 3f50e61..a0bd7ee 100644 --- a/compiler/coroutine_test.go +++ b/compiler/coroutine_test.go @@ -270,6 +270,18 @@ func TestCoroutineYield(t *testing.T) { }, yields: []int{math.MaxUint8, math.MaxUint16}, }, + + { + name: "ellipsis closure", + coro: func() { EllipsisClosure(3) }, + yields: []int{-1, 0, 1, 2}, + }, + + { + name: "interface embedded", + coro: func() { InterfaceEmbedded() }, + yields: []int{1, 1, 1}, + }, } // This emulates the installation of function type information by the diff --git a/compiler/testdata/coroutine.go b/compiler/testdata/coroutine.go index 063e9d7..7f8c092 100644 --- a/compiler/testdata/coroutine.go +++ b/compiler/testdata/coroutine.go @@ -703,3 +703,41 @@ func ReflectType(types ...reflect.Type) { coroutine.Yield[int, any](int(v.Uint())) } } + +func MakeEllipsisClosure(ints ...int) func() { + return func() { + x := ints + for _, v := range x { + coroutine.Yield[int, any](v) + } + } +} + +func EllipsisClosure(n int) { + ints := make([]int, n) + for i := range ints { + ints[i] = i + } + c := MakeEllipsisClosure(ints...) + coroutine.Yield[int, any](-1) + c() +} + +type innerInterface interface { + Value() int +} + +type innerInterfaceImpl int + +func (i innerInterfaceImpl) Value() int { return int(i) } + +type outerInterface interface { + innerInterface +} + +func InterfaceEmbedded() { + var x interface{ outerInterface } = innerInterfaceImpl(1) + coroutine.Yield[int, any](x.Value()) + coroutine.Yield[int, any](x.Value()) + coroutine.Yield[int, any](x.Value()) +} diff --git a/compiler/testdata/coroutine_durable.go b/compiler/testdata/coroutine_durable.go index 903f419..35d157b 100644 --- a/compiler/testdata/coroutine_durable.go +++ b/compiler/testdata/coroutine_durable.go @@ -3516,7 +3516,7 @@ func IdentityGenericInt(n int) { IdentityGeneric[int](n) } //go:noinline func IdentityGenericClosure[T any](_fn0 T) { - _c := coroutine.LoadContext[int, any]() + _c := coroutine.LoadContext[T, any]() var _f0 *struct { IP int X0 T @@ -3918,6 +3918,211 @@ func ReflectType(_fn0 ...reflect.Type) { } } } + +//go:noinline +func MakeEllipsisClosure(_fn0 ...int) (_ func()) { + var _f0 *struct { + IP int + X0 []int + } = &struct { + IP int + X0 []int + }{X0: _fn0} + return func() { + _c := coroutine.LoadContext[int, any]() + var _f1 *struct { + IP int + X0 []int + X1 []int + X2 int + X3 int + } = coroutine.Push[struct { + IP int + X0 []int + X1 []int + X2 int + X3 int + }](&_c.Stack) + if _f1.IP == 0 { + *_f1 = struct { + IP int + X0 []int + X1 []int + X2 int + X3 int + }{} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f1.IP < 2: + _f1.X0 = _f0.X0 + _f1.IP = 2 + fallthrough + case _f1.IP < 6: + switch { + case _f1.IP < 3: + _f1.X1 = _f1.X0 + _f1.IP = 3 + fallthrough + case _f1.IP < 6: + switch { + case _f1.IP < 4: + _f1.X2 = 0 + _f1.IP = 4 + fallthrough + case _f1.IP < 6: + for ; _f1.X2 < len(_f1.X1); _f1.X2, _f1.IP = _f1.X2+1, 4 { + switch { + case _f1.IP < 5: + _f1.X3 = _f1.X1[_f1.X2] + _f1.IP = 5 + fallthrough + case _f1.IP < 6: + + coroutine.Yield[int, any](_f1.X3) + } + } + } + } + } + } +} + +//go:noinline +func EllipsisClosure(_fn0 int) { + _c := coroutine.LoadContext[int, any]() + var _f0 *struct { + IP int + X0 int + X1 []int + X2 func() + } = coroutine.Push[struct { + IP int + X0 int + X1 []int + X2 func() + }](&_c.Stack) + if _f0.IP == 0 { + *_f0 = struct { + IP int + X0 int + X1 []int + X2 func() + }{X0: _fn0} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f0.IP < 2: + _f0.X1 = make([]int, _f0.X0) + _f0.IP = 2 + fallthrough + case _f0.IP < 3: + for i := range _f0.X1 { + _f0.X1[i] = i + } + _f0.IP = 3 + fallthrough + case _f0.IP < 4: + _f0.X2 = MakeEllipsisClosure(_f0.X1...) + _f0.IP = 4 + fallthrough + case _f0.IP < 5: + coroutine.Yield[int, any](-1) + _f0.IP = 5 + fallthrough + case _f0.IP < 6: + _f0.X2() + } +} + +type innerInterface interface { + Value() int +} + +type innerInterfaceImpl int + +func (i innerInterfaceImpl) Value() int { return int(i) } + +type outerInterface interface { + innerInterface +} + +//go:noinline +func InterfaceEmbedded() { + _c := coroutine.LoadContext[int, any]() + var _f0 *struct { + IP int + X0 interface { + outerInterface + } + X1 int + X2 int + X3 int + } = coroutine.Push[struct { + IP int + X0 interface { + outerInterface + } + X1 int + X2 int + X3 int + }](&_c.Stack) + if _f0.IP == 0 { + *_f0 = struct { + IP int + X0 interface { + outerInterface + } + X1 int + X2 int + X3 int + }{} + } + defer func() { + if !_c.Unwinding() { + coroutine.Pop(&_c.Stack) + } + }() + switch { + case _f0.IP < 2: + _f0.X0 = innerInterfaceImpl(1) + _f0.IP = 2 + fallthrough + case _f0.IP < 3: + _f0.X1 = _f0.X0. + Value() + _f0.IP = 3 + fallthrough + case _f0.IP < 4: + coroutine.Yield[int, any](_f0.X1) + _f0.IP = 4 + fallthrough + case _f0.IP < 5: + _f0.X2 = _f0.X0. + Value() + _f0.IP = 5 + fallthrough + case _f0.IP < 6: + coroutine.Yield[int, any](_f0.X2) + _f0.IP = 6 + fallthrough + case _f0.IP < 7: + _f0.X3 = _f0.X0. + Value() + _f0.IP = 7 + fallthrough + case _f0.IP < 8: + coroutine.Yield[int, any](_f0.X3) + } +} func init() { _types.RegisterFunc[func(_fn1 int) (_ func(int))]("github.com/dispatchrun/coroutine/compiler/testdata.(*Box).Closure") _types.RegisterClosure[func(_fn0 int), struct { @@ -3952,6 +4157,7 @@ func init() { _types.RegisterFunc[func()]("github.com/dispatchrun/coroutine/compiler/testdata.(*IdentityGenericStruct[go.shape.int]).Run") _types.RegisterFunc[func(_fn1 int)]("github.com/dispatchrun/coroutine/compiler/testdata.(*MethodGeneratorState).MethodGenerator") _types.RegisterFunc[func(n int)]("github.com/dispatchrun/coroutine/compiler/testdata.Double") + _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.EllipsisClosure") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.EvenSquareGenerator") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.FizzBuzzIfGenerator") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.FizzBuzzSwitchGenerator") @@ -3963,7 +4169,16 @@ func init() { _types.RegisterFunc[func(n int)]("github.com/dispatchrun/coroutine/compiler/testdata.IdentityGenericStructInt") _types.RegisterFunc[func(n int)]("github.com/dispatchrun/coroutine/compiler/testdata.IdentityGeneric[go.shape.int]") _types.RegisterFunc[func(_fn0 int)]("github.com/dispatchrun/coroutine/compiler/testdata.IndirectClosure") + _types.RegisterFunc[func()]("github.com/dispatchrun/coroutine/compiler/testdata.InterfaceEmbedded") _types.RegisterFunc[func(_ int)]("github.com/dispatchrun/coroutine/compiler/testdata.LoopBreakAndContinue") + _types.RegisterFunc[func(_fn0 ...int) (_ func())]("github.com/dispatchrun/coroutine/compiler/testdata.MakeEllipsisClosure") + _types.RegisterClosure[func(), struct { + F uintptr + X0 *struct { + IP int + X0 []int + } + }]("github.com/dispatchrun/coroutine/compiler/testdata.MakeEllipsisClosure.func1") _types.RegisterFunc[func(_fn0 int) (_ int)]("github.com/dispatchrun/coroutine/compiler/testdata.NestedLoops") _types.RegisterFunc[func(_fn0 int, _fn1 func(int))]("github.com/dispatchrun/coroutine/compiler/testdata.Range") _types.RegisterFunc[func()]("github.com/dispatchrun/coroutine/compiler/testdata.Range10ClosureCapturingPointers") @@ -4111,5 +4326,6 @@ func init() { } } }]("github.com/dispatchrun/coroutine/compiler/testdata.indirectClosure.func2") + _types.RegisterFunc[func() (_ int)]("github.com/dispatchrun/coroutine/compiler/testdata.innerInterfaceImpl.Value") _types.RegisterFunc[func(_fn0 ...int)]("github.com/dispatchrun/coroutine/compiler/testdata.varArgs") }