Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use IO.Std; | |
| 3 | ||
| 4 | use System.Text.StringBuilder; | |
| 5 | ||
| 6 | use IoC; | |
| 7 | use Logging; | |
| 8 | use Source; | |
| 9 | ||
| 10 | use IR.Values.Value; | |
| 11 | ||
| 12 | use Types.Type; | |
| 13 | ||
| 14 | // Per-`let await` bookkeeping recorded by await IL emission. | |
| 15 | // The resume label is placed immediately after the per-await | |
| 16 | // `leave` that suspends MoveNext; entry-dispatch jumps here | |
| 17 | // when the builder re-enters MoveNext on awaiter completion. | |
| 18 | class ASYNC_STATE_LABEL is | |
| 19 | state: int public; | |
| 20 | awaiter_field: Field public; | |
| 21 | label: IR.LABEL public; | |
| 22 | ||
| 23 | init(state: int, awaiter_field: Field, label: IR.LABEL) is | |
| 24 | self.state = state; | |
| 25 | self.awaiter_field = awaiter_field; | |
| 26 | self.label = label; | |
| 27 | si | |
| 28 | si | |
| 29 | ||
| 30 | // State held on an async function symbol: the synthesised frame | |
| 31 | // class, the running state-number counter, the recorded | |
| 32 | // (state, awaiter_field, resume_label) triples for entry-dispatch | |
| 33 | // emission. Lives as a non-null field on each *_ASYNC_* | |
| 34 | // function; checked-for via `async_state_machine_for(...)`. | |
| 35 | class ASYNC_STATE_MACHINE is | |
| 36 | function: Function public; | |
| 37 | ||
| 38 | _frame: ASYNC_STATE_MACHINE_FRAME?; | |
| 39 | _next_state: int; | |
| 40 | _await_labels: Collections.LIST[ASYNC_STATE_LABEL]; | |
| 41 | ||
| 42 | init(function: Function) is | |
| 43 | self.function = function; | |
| 44 | ||
| 45 | _next_state = 1; | |
| 46 | _await_labels = Collections.LIST[ASYNC_STATE_LABEL](); | |
| 47 | si | |
| 48 | ||
| 49 | // Lazy: the frame class is materialised on first access, | |
| 50 | // pulling its result type from the (now-resolved) function | |
| 51 | // return type (Tasks.TASK[T] → T, Tasks.TASK → void). Returns | |
| 52 | // null only when the return type isn't a Task — which is an | |
| 53 | // upstream diagnostic, not something the frame can recover | |
| 54 | // from. | |
| 55 | frame: ASYNC_STATE_MACHINE_FRAME? is | |
| 56 | let lookup = IoC.CONTAINER.instance.innate_symbol_lookup; | |
| 57 | ||
| 58 | if !_frame? then | |
| 59 | if !function.return_type? then | |
| 60 | return null; | |
| 61 | fi | |
| 62 | ||
| 63 | let result_type: Type? mut = null; | |
| 64 | let is_void mut = false; | |
| 65 | ||
| 66 | // Named functions + closures with pinned return type | |
| 67 | // extract directly from `-> Tasks.TASK[T]` / | |
| 68 | // `-> Tasks.TASK`. Lambdas with INFERRED_RETURN_TYPE | |
| 69 | // can't (an inferred placeholder `matches` anything) so fall back | |
| 70 | // to the AST flag `is_void_async`; `result_type` | |
| 71 | // fills in later via `ensure_result_field`. | |
| 72 | let extracted = _extract_result_type(lookup); | |
| 73 | ||
| 74 | if extracted? then | |
| 75 | result_type = extracted; | |
| 76 | elif function.return_type!.is_inferred then | |
| 77 | is_void = function.is_void_async; | |
| 78 | else | |
| 79 | let void_task = lookup.get_void_task_type(); | |
| 80 | if void_task? /\ function.return_type!.matches(void_task) then | |
| 81 | is_void = true; | |
| 82 | else | |
| 83 | return null; | |
| 84 | fi | |
| 85 | fi | |
| 86 | ||
| 87 | _frame = ASYNC_STATE_MACHINE_FRAME( | |
| 88 | function.owner!, | |
| 89 | function, | |
| 90 | result_type, | |
| 91 | is_void | |
| 92 | ); | |
| 93 | else | |
| 94 | // Re-poll on each access: a value-async lambda whose | |
| 95 | // return type wasn't yet settled when the frame was | |
| 96 | // first realised needs its _result_type filled in | |
| 97 | // once the type pins. Idempotent. | |
| 98 | _frame.ensure_result_field(lookup); | |
| 99 | fi | |
| 100 | ||
| 101 | return _frame; | |
| 102 | si | |
| 103 | ||
| 104 | _extract_result_type(lookup: Lookups.InnateSymbolLookup) -> Type? => | |
| 105 | TYPE_ARGUMENT_EXTRACTOR.extract(function.return_type, lookup.get_unspecialized_task_type()); | |
| 106 | ||
| 107 | allocate_state() -> int is | |
| 108 | let n = _next_state; | |
| 109 | ||
| 110 | _next_state = _next_state + 1; | |
| 111 | ||
| 112 | return n; | |
| 113 | si | |
| 114 | ||
| 115 | record_label(state: int, awaiter_field: Field, label: IR.LABEL) is | |
| 116 | _await_labels.add(ASYNC_STATE_LABEL(state, awaiter_field, label)); | |
| 117 | si | |
| 118 | ||
| 119 | await_labels: Collections.Iterable[ASYNC_STATE_LABEL] => _await_labels; | |
| 120 | ||
| 121 | // See `STATE_MACHINE_TYPE_PARAMS` — generator + async use | |
| 122 | // the same capture order so the helper handles both. | |
| 123 | install_body_emission_overrides() is | |
| 124 | STATE_MACHINE_TYPE_PARAMS.walk_install(function, true); | |
| 125 | si | |
| 126 | ||
| 127 | uninstall_body_emission_overrides() is | |
| 128 | STATE_MACHINE_TYPE_PARAMS.walk_install(function, false); | |
| 129 | si | |
| 130 | ||
| 131 | get_construction_type_arguments() -> Collections.List[Type]? => | |
| 132 | STATE_MACHINE_TYPE_PARAMS.construction_type_arguments(function); | |
| 133 | si | |
| 134 | ||
| 135 | // Frame class synthesised for each async function. Implements | |
| 136 | // `IAsyncStateMachine` (MoveNext, SetStateMachine); holds the | |
| 137 | // current state, a builder, per-await awaiter fields, captured | |
| 138 | // arguments + locals + outer-self, and a result slot for | |
| 139 | // value-async (omitted for void-async). The class itself is | |
| 140 | // generic in any type parameters visible inside the owning | |
| 141 | // function (mirrors `STATE_MACHINE_FRAME`). | |
| 142 | class ASYNC_STATE_MACHINE_FRAME: STATE_MACHINE_FRAME_BASE is | |
| 143 | _next_id: int static; | |
| 144 | ||
| 145 | // Null for void-async, and for a value-async lambda whose | |
| 146 | // inferred return type hasn't pinned yet (filled in by | |
| 147 | // ensure_result_field). | |
| 148 | _result_type: Type?; | |
| 149 | _is_void: bool; | |
| 150 | ||
| 151 | // Null until declare() runs. Builder, result and outer-self | |
| 152 | // stay null past declare() on some paths: builder when the | |
| 153 | // builder type cannot be resolved, result for void-async, | |
| 154 | // outer-self for statics and globals. | |
| 155 | _state_field: Field?; | |
| 156 | _builder_field: Field?; | |
| 157 | _result_field: Field?; | |
| 158 | _outer_self_field: Field?; | |
| 159 | _constructor: Method?; | |
| 160 | ||
| 161 | result_type: Type? => _result_type; | |
| 162 | is_void: bool => _is_void; | |
| 163 | ||
| 164 | class_result_type: Type? => | |
| 165 | if _result_type? then | |
| 166 | _class_relative(_result_type) | |
| 167 | else | |
| 168 | null | |
| 169 | fi; | |
| 170 | ||
| 171 | // Non-null once declare() has run. | |
| 172 | state_field: Field => _state_field!; | |
| 173 | constructor: Method => _constructor!; | |
| 174 | ||
| 175 | builder_field: Field? => _builder_field; | |
| 176 | result_field: Field? => _result_field; | |
| 177 | outer_self_field: Field? => _outer_self_field; | |
| 178 | ||
| 179 | next_id: int static is | |
| 180 | let result = _next_id; | |
| 181 | _next_id = _next_id + 1; | |
| 182 | return result; | |
| 183 | si | |
| 184 | ||
| 185 | init(owner: Scope, owning_function: Function, result_type: Type?, is_void: bool) is | |
| 186 | let owner_owner: Scope mut; | |
| 187 | ||
| 188 | if isa Symbol(owner) then | |
| 189 | let owner_symbol = owner; | |
| 190 | owner_owner = owner_symbol.owner!; | |
| 191 | else | |
| 192 | owner_owner = owner; | |
| 193 | fi | |
| 194 | ||
| 195 | super.init( | |
| 196 | LOCATION.internal, | |
| 197 | LOCATION.internal, | |
| 198 | owner_owner, | |
| 199 | "$AsyncStateMachine_{owning_function.name}_{next_id}", | |
| 200 | owner, | |
| 201 | owning_function | |
| 202 | ); | |
| 203 | ||
| 204 | _result_type = result_type; | |
| 205 | _is_void = is_void; | |
| 206 | ||
| 207 | _argument_fields = Collections.LIST[Field](); | |
| 208 | _awaiter_fields = Collections.LIST[Field](); | |
| 209 | ||
| 210 | set_type(Types.NAMED(self)); | |
| 211 | si | |
| 212 | ||
| 213 | _argument_fields: Collections.LIST[Field]; | |
| 214 | ||
| 215 | argument_fields: Collections.Iterable[Field] => _argument_fields; | |
| 216 | ||
| 217 | _awaiter_fields: Collections.LIST[Field]; | |
| 218 | ||
| 219 | awaiter_fields: Collections.Iterable[Field] => _awaiter_fields; | |
| 220 | ||
| 221 | // Lazy + idempotent realisation of frame members. Value-async | |
| 222 | // frames short-circuit until `_result_type` is available | |
| 223 | // (otherwise we'd resolve `AsyncTaskMethodBuilder<null>`). | |
| 224 | declare() is | |
| 225 | if _state_field? then | |
| 226 | return; | |
| 227 | fi | |
| 228 | ||
| 229 | if !_is_void /\ !_result_type? then | |
| 230 | return; | |
| 231 | fi | |
| 232 | ||
| 233 | let listener = IoC.CONTAINER.instance.symbol_definition_locations; | |
| 234 | ||
| 235 | declare_captured_type_params(listener); | |
| 236 | ||
| 237 | let int_type = IoC.CONTAINER.instance.innate_symbol_lookup.get_int_type(); | |
| 238 | ||
| 239 | let state_field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$state"); | |
| 240 | state_field.set_type(int_type); | |
| 241 | declare(LOCATION.internal, state_field, listener); | |
| 242 | _state_field = state_field; | |
| 243 | ||
| 244 | // Builder field — `AsyncTaskMethodBuilder<T>` for | |
| 245 | // value-async, non-generic for void-async. Omitted when | |
| 246 | // the type cannot be resolved; IL emission supplies it | |
| 247 | // literally. | |
| 248 | let builder_type = _resolve_builder_type(); | |
| 249 | if builder_type? then | |
| 250 | let builder_field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$builder"); | |
| 251 | builder_field.set_type(builder_type); | |
| 252 | declare(LOCATION.internal, builder_field, listener); | |
| 253 | _builder_field = builder_field; | |
| 254 | fi | |
| 255 | ||
| 256 | // `$result` only for value-async. Lambdas with | |
| 257 | // unresolved result_type defer to `ensure_result_field`. | |
| 258 | if !_is_void /\ _result_type? then | |
| 259 | let result_type = _result_type; | |
| 260 | ||
| 261 | let result_field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$result"); | |
| 262 | result_field.set_type(_class_relative(result_type)); | |
| 263 | declare(LOCATION.internal, result_field, listener); | |
| 264 | _result_field = result_field; | |
| 265 | fi | |
| 266 | ||
| 267 | let ctor_argument_names = Collections.LIST[string](); | |
| 268 | let ctor_argument_types = Collections.LIST[Type](); | |
| 269 | ||
| 270 | // Outer-self target: enclosing user class for an | |
| 271 | // instance method, or the closure's captures-holding | |
| 272 | // FRAME for an async closure (whose launch is emitted as | |
| 273 | // an instance method on the FRAME). | |
| 274 | let outer_classy: Classy? mut = null; | |
| 275 | ||
| 276 | if owning_function.is_instance /\ isa Classy(owning_function.owner) then | |
| 277 | outer_classy = cast Classy?(owning_function.owner)!; | |
| 278 | elif let closure: Closure = owning_function then | |
| 279 | if closure.frame? then | |
| 280 | outer_classy = closure.frame; | |
| 281 | fi | |
| 282 | fi | |
| 283 | ||
| 284 | if outer_classy? then | |
| 285 | let self_type = outer_self_type(outer_classy); | |
| 286 | ||
| 287 | let outer_self_field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$outer_self"); | |
| 288 | outer_self_field.set_type(self_type); | |
| 289 | declare(LOCATION.internal, outer_self_field, listener); | |
| 290 | _outer_self_field = outer_self_field; | |
| 291 | ||
| 292 | ctor_argument_names.add("$outer_self"); | |
| 293 | ctor_argument_types.add(self_type); | |
| 294 | fi | |
| 295 | ||
| 296 | if owning_function.argument_names.count > 0 then | |
| 297 | for arg_name in owning_function.argument_names do | |
| 298 | let local = cast Symbols.LOCAL_ARGUMENT?(owning_function.find_direct(arg_name)); | |
| 299 | ||
| 300 | if !local? then | |
| 301 | continue; | |
| 302 | fi | |
| 303 | ||
| 304 | let arg_field_type = _class_relative(local.type!); | |
| 305 | ||
| 306 | let arg_field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$arg_{arg_name}"); | |
| 307 | arg_field.set_type(arg_field_type); | |
| 308 | declare(LOCATION.internal, arg_field, listener); | |
| 309 | ||
| 310 | _argument_fields.add(arg_field); | |
| 311 | ||
| 312 | local.state_machine_field = arg_field; | |
| 313 | ||
| 314 | ctor_argument_names.add(arg_name); | |
| 315 | ctor_argument_types.add(arg_field_type); | |
| 316 | od | |
| 317 | fi | |
| 318 | ||
| 319 | let ctor = Symbols.INSTANCE_METHOD(LOCATION.internal, LOCATION.internal, self, "init", self); | |
| 320 | ctor.set_arguments(ctor_argument_names, ctor_argument_types); | |
| 321 | ctor.set_void_return_type(); | |
| 322 | declare(LOCATION.internal, ctor, listener); | |
| 323 | _constructor = ctor; | |
| 324 | ||
| 325 | // Ancestors: Object as base class, IAsyncStateMachine as | |
| 326 | // implemented interface. The frame doesn't expose | |
| 327 | // Iterable/Iterator like the generator frame; the runtime | |
| 328 | // calls MoveNext via the builder. | |
| 329 | let lookup = IoC.CONTAINER.instance.innate_symbol_lookup; | |
| 330 | ||
| 331 | add_ancestor(lookup.get_object_type()); | |
| 332 | ||
| 333 | let async_state_machine_type = _resolve_async_state_machine_type(); | |
| 334 | if async_state_machine_type? then | |
| 335 | add_ancestor(async_state_machine_type); | |
| 336 | fi | |
| 337 | si | |
| 338 | ||
| 339 | // Resolves to `System.Runtime.CompilerServices.AsyncTaskMethodBuilder<T>` | |
| 340 | // for value-async or `System.Runtime.CompilerServices.AsyncTaskMethodBuilder` | |
| 341 | // for void-async. Goes via the innate lookup so reflection | |
| 342 | // supplies the actual Type. | |
| 343 | _resolve_builder_type() -> Type? is | |
| 344 | let lookup = IoC.CONTAINER.instance.innate_symbol_lookup; | |
| 345 | if _is_void then | |
| 346 | return lookup.get_async_task_method_builder_void_type(); | |
| 347 | else | |
| 348 | if !_result_type? then | |
| 349 | return null; | |
| 350 | fi | |
| 351 | let class_result = _class_relative(_result_type); | |
| 352 | return lookup.get_async_task_method_builder_type(class_result); | |
| 353 | fi | |
| 354 | si | |
| 355 | ||
| 356 | _resolve_async_state_machine_type() -> Type? is | |
| 357 | let lookup = IoC.CONTAINER.instance.innate_symbol_lookup; | |
| 358 | return lookup.get_async_state_machine_interface_type(); | |
| 359 | si | |
| 360 | ||
| 361 | // Late-fill `_result_type` once the owning lambda's | |
| 362 | // wrap-as-task pin settles. Unblocks declare() for value- | |
| 363 | // async closures whose return type was inferred. Idempotent. | |
| 364 | ensure_result_field(lookup: Lookups.InnateSymbolLookup) is | |
| 365 | if _is_void \/ _result_type? then | |
| 366 | return; | |
| 367 | fi | |
| 368 | if !owning_function.return_type? then | |
| 369 | return; | |
| 370 | fi | |
| 371 | ||
| 372 | let extracted = TYPE_ARGUMENT_EXTRACTOR.extract( | |
| 373 | owning_function.return_type, | |
| 374 | lookup.get_unspecialized_task_type() | |
| 375 | ); | |
| 376 | ||
| 377 | if extracted? then | |
| 378 | _result_type = extracted; | |
| 379 | fi | |
| 380 | si | |
| 381 | ||
| 382 | // Per-await awaiter field. Each call site gets its own slot | |
| 383 | // since the awaiter is typically a value type | |
| 384 | // (`TaskAwaiter<T>` / its non-generic sibling). | |
| 385 | declare_awaiter_field(awaiter_type: Type) -> Field is | |
| 386 | let id = next_local_id(); | |
| 387 | ||
| 388 | let listener = IoC.CONTAINER.instance.symbol_definition_locations; | |
| 389 | ||
| 390 | let `field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$awaiter_{id}"); | |
| 391 | `field.set_type(_class_relative(awaiter_type)); | |
| 392 | declare(LOCATION.internal, `field, listener); | |
| 393 | ||
| 394 | _awaiter_fields.add(`field); | |
| 395 | ||
| 396 | return `field; | |
| 397 | si | |
| 398 | ||
| 399 | // Allocate a fresh field for a spilled intermediate value | |
| 400 | // (SPILL_AWAITS pass + visit(SPILL) in generate-il) or for | |
| 401 | // an await's result. The frame holds them so they survive | |
| 402 | // across MoveNext re-entries. | |
| 403 | declare_spill_field(type: Type) -> Field => | |
| 404 | declare_anonymous_field("spill", type); | |
| 405 | si | |
| 406 | ||
| 407 | // Free helper: returns the ASYNC_STATE_MACHINE held by any of | |
| 408 | // the async function or closure forms, or null if `f` is a plain | |
| 409 | // function / generator / sync closure. | |
| 410 | async_state_machine_for(f: Function?) -> ASYNC_STATE_MACHINE? is | |
| 411 | if !f? then | |
| 412 | return null; | |
| 413 | fi | |
| 414 | ||
| 415 | if isa STATIC_ASYNC_METHOD(f) then | |
| 416 | return f.async_state_machine; | |
| 417 | fi | |
| 418 | ||
| 419 | if isa INSTANCE_ASYNC_METHOD(f) then | |
| 420 | return f.async_state_machine; | |
| 421 | fi | |
| 422 | ||
| 423 | if isa GLOBAL_ASYNC_FUNCTION(f) then | |
| 424 | return f.async_state_machine; | |
| 425 | fi | |
| 426 | ||
| 427 | if isa INSTANCE_ASYNC_CLOSURE(f) then | |
| 428 | return f.async_state_machine; | |
| 429 | fi | |
| 430 | ||
| 431 | if isa STATIC_ASYNC_CLOSURE(f) then | |
| 432 | return f.async_state_machine; | |
| 433 | fi | |
| 434 | ||
| 435 | if isa GLOBAL_ASYNC_CLOSURE(f) then | |
| 436 | return f.async_state_machine; | |
| 437 | fi | |
| 438 | ||
| 439 | return null; | |
| 440 | si | |
| 441 | ||
| 442 | // Concrete async-function forms — thin extensions of the | |
| 443 | // STATIC_METHOD / INSTANCE_METHOD / GLOBAL_FUNCTION classes | |
| 444 | // that additionally carry an ASYNC_STATE_MACHINE. | |
| 445 | ||
| 446 | class STATIC_ASYNC_METHOD: STATIC_METHOD is | |
| 447 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 448 | ||
| 449 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 450 | "class async"; | |
| 451 | ||
| 452 | gen_access(buffer: System.Text.StringBuilder) is | |
| 453 | _gen_underscore_access(buffer); | |
| 454 | si | |
| 455 | ||
| 456 | is_accessible_to(accessor: Classy?) -> bool => | |
| 457 | _underscore_is_accessible_to(accessor); | |
| 458 | ||
| 459 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is | |
| 460 | super.init(location, span, owner, name, enclosing_scope); | |
| 461 | ||
| 462 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 463 | si | |
| 464 | si | |
| 465 | ||
| 466 | class INSTANCE_ASYNC_METHOD: INSTANCE_METHOD is | |
| 467 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 468 | ||
| 469 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 470 | "async"; | |
| 471 | ||
| 472 | gen_access(buffer: System.Text.StringBuilder) is | |
| 473 | _gen_underscore_access(buffer); | |
| 474 | si | |
| 475 | ||
| 476 | is_accessible_to(accessor: Classy?) -> bool => | |
| 477 | _underscore_is_accessible_to(accessor); | |
| 478 | ||
| 479 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is | |
| 480 | super.init(location, span, owner, name, enclosing_scope); | |
| 481 | ||
| 482 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 483 | si | |
| 484 | ||
| 485 | // Inside the body, `self` and instance-member access go via | |
| 486 | // the async state-machine frame's _outer_self field rather | |
| 487 | // than ldarg.0 (which inside MoveNext refers to the state | |
| 488 | // machine itself). Mirrors INSTANCE_GENERATOR_METHOD.load_self. | |
| 489 | load_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 490 | let frame = async_state_machine.frame; | |
| 491 | ||
| 492 | if frame? then | |
| 493 | frame.declare(); | |
| 494 | ||
| 495 | let outer_self_field = frame.outer_self_field; | |
| 496 | ||
| 497 | if outer_self_field? then | |
| 498 | let context = IoC.CONTAINER.instance.symbol_table.current_instance_context; | |
| 499 | if context? then | |
| 500 | return IR.Values.Load.OUTER_SELF(context, context.type, outer_self_field); | |
| 501 | fi | |
| 502 | fi | |
| 503 | fi | |
| 504 | ||
| 505 | return super.load_self(location, loader); | |
| 506 | si | |
| 507 | si | |
| 508 | ||
| 509 | // An async method declared in a trait body. Always has a body — the | |
| 510 | // async classification comes from finding `await` in one — so there | |
| 511 | // is no abstract counterpart, and it is a default trait method for | |
| 512 | // inheritance purposes like any other bodied trait member. | |
| 513 | class DEFAULT_TRAIT_ASYNC_METHOD: INSTANCE_ASYNC_METHOD is | |
| 514 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 515 | "default trait async"; | |
| 516 | ||
| 517 | is_default_trait_method: bool => true; | |
| 518 | ||
| 519 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is | |
| 520 | super.init(location, span, owner, name, enclosing_scope); | |
| 521 | si | |
| 522 | ||
| 523 | try_instance_override_me(into: Classy, overrider: Function, logger: Logger) is | |
| 524 | super.try_instance_override_me(into, overrider, logger); | |
| 525 | ||
| 526 | _check_ineffective_trait_override(into, overrider, logger); | |
| 527 | si | |
| 528 | si | |
| 529 | ||
| 530 | class GLOBAL_ASYNC_FUNCTION: GLOBAL_FUNCTION is | |
| 531 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 532 | ||
| 533 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 534 | "global async"; | |
| 535 | ||
| 536 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is | |
| 537 | super.init(location, span, owner, name, enclosing_scope); | |
| 538 | ||
| 539 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 540 | si | |
| 541 | si | |
| 542 | ||
| 543 | // Async closure forms — parallel to the *_ASYNC_METHOD / | |
| 544 | // GLOBAL_ASYNC_FUNCTION trio, but for user-written async lambdas. | |
| 545 | // Each is a thin extension of the corresponding sync closure that | |
| 546 | // additionally carries an ASYNC_STATE_MACHINE; generate-il dispatches | |
| 547 | // on `async_state_machine_for(symbol)` to route lambda emission down | |
| 548 | // the state-machine path. Nested lambdas inside an async closure | |
| 549 | // are sync by default — `declare_closure` returns the regular | |
| 550 | // form, matching the named-function convention. | |
| 551 | ||
| 552 | class INSTANCE_ASYNC_CLOSURE: INSTANCE_CLOSURE is | |
| 553 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 554 | ||
| 555 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 556 | super.init(location, owner, name, enclosing_scope, is_recursive); | |
| 557 | ||
| 558 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 559 | si | |
| 560 | ||
| 561 | to_string() -> string => "[instance async closure {name}]"; | |
| 562 | si | |
| 563 | ||
| 564 | class STATIC_ASYNC_CLOSURE: STATIC_CLOSURE is | |
| 565 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 566 | ||
| 567 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 568 | super.init(location, owner, name, enclosing_scope, is_recursive); | |
| 569 | ||
| 570 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 571 | si | |
| 572 | ||
| 573 | to_string() -> string => "[static async closure {name}]"; | |
| 574 | si | |
| 575 | ||
| 576 | class GLOBAL_ASYNC_CLOSURE: GLOBAL_CLOSURE is | |
| 577 | async_state_machine: ASYNC_STATE_MACHINE public; | |
| 578 | ||
| 579 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 580 | super.init(location, owner, name, enclosing_scope, is_recursive); | |
| 581 | ||
| 582 | async_state_machine = ASYNC_STATE_MACHINE(self); | |
| 583 | si | |
| 584 | ||
| 585 | to_string() -> string => "[global async closure {name}]"; | |
| 586 | si | |
| 587 | si |