cgen, coroutines: fix go expr handle referencing undeclared thread__tN (#27379)

This commit is contained in:
Alexander Medvednikov authored and GitHub committed 2026-06-30 12:10:31 +03:00
1 parent 44c55f6649
commit 3d22ea2334
3 files changed
+51 -2

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
// vtest build: false // This should be built with: `v -use-coroutines go_handle.v`
// Note: the Photon wrapper is not yet trivial enough to build/install on the CI.
//
// Demonstrates storing the handle returned by a `go` expression and waiting on
// it. Because the Photon coroutine wrapper exposes no joinable handle, a `go`
// whose handle is used is lowered to the regular `spawn` (pthread) path, so the
// handle can be waited on just like `spawn`.
module main
struct App {
mut:
worker thread
}
fn (a App) loop() {
println('hello from the worker coroutine')
}
fn main() {
mut a := App{}
a.worker = go a.loop()
a.worker.wait()
println('done')
}
+13 -2
View File
@@ -15,8 +15,19 @@ fn (mut g Gen) spawn_and_go_expr(node ast.SpawnExpr, mode SpawnGoMode) {
if node.call_expr.should_be_skipped {
return
}
is_spawn := mode == .spawn_
is_go := mode == .go_
mut is_spawn := mode == .spawn_
mut is_go := mode == .go_
if is_go && node.is_expr {
// A `go expr` whose handle is used as a value (e.g. `h := go f()` or
// `obj.field = go f()`) needs a real, joinable thread handle. The photon
// coroutine wrapper (`photon_thread_create*`) returns void and exposes no
// such handle, so fall back to the regular `spawn` (pthread) path here,
// which declares and assigns the `thread_<tmp>` handle that is read back
// as the expression's value. Plain statement form `go f()` (no handle
// used) keeps using the photon work-pool path below.
is_spawn = true
is_go = false
}
if is_spawn {
g.writeln('/*spawn (thread) */')
} else {
+14
View File
@@ -1079,6 +1079,20 @@ fn (mut w Walker) expr(node_ ast.Expr) {
ast.GoExpr {
if node.is_expr {
w.fn_by_name('free')
// A `go expr` whose handle is used as a value is lowered to the
// `spawn` (pthread) codegen path (see spawn_and_go_expr), since the
// photon coroutine wrapper returns no joinable handle. Mark the same
// thread-handle type and pthread error helpers that `spawn` needs,
// otherwise -skip-unused prunes them and the generated C fails to link.
w.mark_by_type(w.table.find_or_register_thread(node.call_expr.return_type))
w.uses_spawn = true
if w.pref.os == .windows {
w.fn_by_name('panic_lasterr')
w.fn_by_name('winapi_lasterr_str')
} else {
w.fn_by_name('c_error_number_str')
w.fn_by_name('panic_error_number')
}
}
w.mark_by_type(node.call_expr.return_type)
w.expr(node.call_expr)