Infer coroutine effects automatically

This commit is contained in:
pavel 2026-08-27 21:53:34 +02:00
commit 5b30e49486
15 changed files with 339 additions and 103 deletions

View file

@ -5,17 +5,17 @@ import (
"strings"
)
var coroutineBuiltins = map[string]bool{"runBlocking": true, "coroutineScope": true, "launch": true, "async": true, "delay": true, "withTimeout": true, "isActive": true}
var coroutineBuiltins = map[string]bool{"runBlocking": true, "coroutineScope": true, "launch": true, "async": true, "delay": true, "withTimeout": true, "isActive": true, "coroutineContext": true}
func programUsesCoroutines(program *Program) bool {
for _, fn := range program.Functions {
if fn.Suspend || statementsUseCoroutines(fn.Body) {
if statementsUseCoroutines(fn.Body) {
return true
}
}
for _, class := range program.Classes {
for _, fn := range class.Methods {
if fn.Suspend || statementsUseCoroutines(fn.Body) {
if statementsUseCoroutines(fn.Body) {
return true
}
}
@ -94,6 +94,7 @@ func (g *goGenerator) emitCoroutineSupport() {
g.line("func (scope *GotlinCoroutineScope) Scope(block func(*GotlinCoroutineScope)) { child:=gotlinNewCoroutineScope(scope.ctx); defer child.cancel(); defer func(){if value:=recover();value!=nil{child.cancel();child.workers.Wait();panic(value)}}(); block(child); child.wait() }")
g.line("func (scope *GotlinCoroutineScope) Delay(ms int) { timer:=time.NewTimer(time.Duration(ms)*time.Millisecond); defer timer.Stop(); select { case <-timer.C: case <-scope.ctx.Done(): panic(scope.ctx.Err()) } }")
g.line("func (scope *GotlinCoroutineScope) IsActive() bool { return scope.ctx.Err()==nil }")
g.line("func (scope *GotlinCoroutineScope) Context() context.Context { return scope.ctx }")
g.line("func (scope *GotlinCoroutineScope) WithTimeout(ms int, block func(*GotlinCoroutineScope)) { ctx,cancel:=context.WithTimeout(scope.ctx,time.Duration(ms)*time.Millisecond); defer cancel(); child:=gotlinNewCoroutineScope(ctx); defer child.cancel(); block(child); child.wait() }")
g.line("func gotlinRunBlocking(block func(*GotlinCoroutineScope)) { scope:=gotlinNewCoroutineScope(context.Background()); defer scope.cancel(); defer func(){if value:=recover();value!=nil{scope.cancel();scope.workers.Wait();panic(value)}}(); block(scope); scope.wait() }")
g.line("type GotlinDeferred[T any] struct { done chan struct{}; value T; failure any }")