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 Ghul.Pipes | |
| 13 | ||
| 14 | class Closure: Function, Types.Typed abstract is | |
| 15 | _is_loading_captures: bool | |
| 16 | ||
| 17 | // A null element is the `$self` capture: the frame's captured | |
| 18 | // instance has no symbol of its own, and its position in the set | |
| 19 | // fixes its position in the frame constructor's argument list. | |
| 20 | captured_values: Collections.SET[Symbol?]? | |
| 21 | captured_type_arguments: Collections.MAP[Symbol, CAPTURED_TYPE_ARGUMENT]? | |
| 22 | next_type_argument_index: int | |
| 23 | ||
| 24 | is_self_captured: bool | |
| 25 | is_delegate: bool | |
| 26 | is_anon_func: bool => !frame? /\ !is_delegate | |
| 27 | ||
| 28 | // The named delegate type this literal was compiled as, when its | |
| 29 | // context expected one. The literal's own type stays the | |
| 30 | // equivalent function type, so inference and the body walk are | |
| 31 | // unaffected; only the constructed delegate differs. | |
| 32 | delegate_target_type: Types.Type? public | |
| 33 | ||
| 34 | // The parameters a literal written with an argument pack spread | |
| 35 | // out declares in place of the one tuple it is emitted taking, in | |
| 36 | // order, and absent for every other literal. The emitted method | |
| 37 | // takes `pack_group` and unpacks it into a local for each on entry. | |
| 38 | packed_parameters: Collections.List[Variable]? public | |
| 39 | pack_group: LOCAL_ARGUMENT? public | |
| 40 | ||
| 41 | // Set for a generated argument pack thunk, which has no literal | |
| 42 | // behind it and whose body is emitted from this. | |
| 43 | pack_thunk: PACK_THUNK? public | |
| 44 | ||
| 45 | is_packed_parameter(symbol: Symbol) -> bool is | |
| 46 | if let packed = packed_parameters then | |
| 47 | for p in packed do | |
| 48 | if p == symbol then | |
| 49 | return true | |
| 50 | fi | |
| 51 | od | |
| 52 | fi | |
| 53 | ||
| 54 | return false | |
| 55 | si | |
| 56 | ||
| 57 | // The type of the delegate this literal constructs, and so of the | |
| 58 | // value its load yields. | |
| 59 | // The target a context pushed may name a placeholder whose origin | |
| 60 | // has since settled; the delegate is constructed at what it | |
| 61 | // settled to. | |
| 62 | constructed_delegate_type: Types.Type => | |
| 63 | if let target = delegate_target_type then | |
| 64 | if target.contains_inferred then | |
| 65 | SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(target) | |
| 66 | else | |
| 67 | target | |
| 68 | fi | |
| 69 | else | |
| 70 | type! | |
| 71 | fi | |
| 72 | ||
| 73 | could_be_delegate: bool => false | |
| 74 | ||
| 75 | frame: FRAME? | |
| 76 | ||
| 77 | short_description: string => description | |
| 78 | ||
| 79 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 80 | PARTS.type_ref(type!) | |
| 81 | ||
| 82 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => "closure" | |
| 83 | ||
| 84 | symbol_kind: SymbolKind => SymbolKind.FUNCTION | |
| 85 | completion_kind: CompletionKind => CompletionKind.FUNCTION | |
| 86 | ||
| 87 | qualified_name: string => "[closure]{name}" // FIXME | |
| 88 | ||
| 89 | il_name: string => name // FIXME | |
| 90 | owner_il_name: string => "[closure]" // FIXME | |
| 91 | ||
| 92 | is_closure: bool => true | |
| 93 | ||
| 94 | // The local a nested named function statement declared for this | |
| 95 | // literal. The local is not assigned until that statement | |
| 96 | // completes, so a reference to the name from inside the body - | |
| 97 | // the function calling itself - is served from the recurse field | |
| 98 | // rather than from the local, which is still empty there. | |
| 99 | self_reference_variable: Variable? public | |
| 100 | is_recursive: bool | |
| 101 | ||
| 102 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 103 | super.init(location, location, owner, name, enclosing_scope) | |
| 104 | ||
| 105 | self.is_recursive = is_recursive | |
| 106 | si | |
| 107 | ||
| 108 | is_stateless_delegate: bool | |
| 109 | ||
| 110 | // Latched when the load site emits this delegate as a static | |
| 111 | // method with a null target instead of an instance method bound | |
| 112 | // to self. The load-site IL is frozen at load time while the | |
| 113 | // method definition is emitted later by generate-il, so the | |
| 114 | // decision is recorded here rather than recomputed - both must | |
| 115 | // agree on the calling convention. | |
| 116 | is_static_delegate: bool | |
| 117 | ||
| 118 | // Set when the delegate's body loads self (its `ldarg.0` target). | |
| 119 | // Such a delegate, e.g. `() => self`, returns a self-dependent | |
| 120 | // result, so it must not be shared across receivers even though it | |
| 121 | // captures no values. | |
| 122 | _delegate_body_loads_self: bool | |
| 123 | ||
| 124 | delegate_body_loads_self: bool => _delegate_body_loads_self | |
| 125 | ||
| 126 | note_delegate_body_loads_self() is | |
| 127 | _delegate_body_loads_self = true | |
| 128 | si | |
| 129 | ||
| 130 | // True only while this closure's own literal body is being walked, | |
| 131 | // so a self-load can be attributed to the body rather than to a | |
| 132 | // separate scope constructing the delegate (binding its target). | |
| 133 | _walking_literal_body: bool | |
| 134 | ||
| 135 | enter_literal_body() is | |
| 136 | _walking_literal_body = true | |
| 137 | ||
| 138 | // Each walk of the body answers for itself: a self-load an | |
| 139 | // earlier walk saw - a nested delegate bound to the receiver | |
| 140 | // before it was found capture-free, say - is not one this | |
| 141 | // walk makes. | |
| 142 | _delegate_body_loads_self = false | |
| 143 | si | |
| 144 | ||
| 145 | leave_literal_body() is | |
| 146 | _walking_literal_body = false | |
| 147 | si | |
| 148 | ||
| 149 | // A receiver load (`ldarg.0`) is about to be emitted; mark the | |
| 150 | // closure whose body it lands in. That is the innermost closure | |
| 151 | // currently walking its literal body - not necessarily the closure | |
| 152 | // that answered the load: a nested literal's construction site sits | |
| 153 | // in its enclosing literal's body, so binding the nested delegate's | |
| 154 | // target loads the receiver in the enclosing body. | |
| 155 | note_enclosing_body_loads_self() is | |
| 156 | let stack = IoC.CONTAINER.instance.symbol_table.stack | |
| 157 | let index mut = stack.count - 1 | |
| 158 | ||
| 159 | while index >= 0 do | |
| 160 | if let closure: Closure = stack[index] then | |
| 161 | if closure._walking_literal_body then | |
| 162 | closure.note_delegate_body_loads_self() | |
| 163 | return | |
| 164 | fi | |
| 165 | fi | |
| 166 | ||
| 167 | index = index - 1 | |
| 168 | od | |
| 169 | si | |
| 170 | ||
| 171 | convert_to_delegate() is | |
| 172 | assert could_be_delegate | |
| 173 | ||
| 174 | is_stateless_delegate = !captured_values? | |
| 175 | ||
| 176 | is_self_captured = false | |
| 177 | captured_values = null | |
| 178 | frame = null | |
| 179 | is_delegate = true | |
| 180 | ||
| 181 | _drop_carried_type_arguments() | |
| 182 | si | |
| 183 | ||
| 184 | // A frame is a class of its own, so it declares every type | |
| 185 | // parameter the closure's signature names. A delegate's method | |
| 186 | // is emitted on the enclosing class instead and reaches that | |
| 187 | // class's parameters through the receiver, so it must not | |
| 188 | // declare them again - only an enclosing generic method's are | |
| 189 | // left for it to carry. | |
| 190 | _drop_carried_type_arguments() is | |
| 191 | if !captured_type_arguments? then | |
| 192 | return | |
| 193 | fi | |
| 194 | ||
| 195 | let kept = | |
| 196 | get_sorted_captured_type_argument_symbols()! |> | |
| 197 | filter(p => !is_type_argument_carried_by_emitting_class(p)) |> | |
| 198 | collect() | |
| 199 | ||
| 200 | // The slots that remain number from zero again: the position | |
| 201 | // each installs is its index in the emitted method's own | |
| 202 | // parameter list. Renumbered in place rather than recorded | |
| 203 | // again, because recording goes back through the guard that | |
| 204 | // treats a frozen copy of a parameter as that parameter, and | |
| 205 | // a survivor that is a frozen copy of another survivor would | |
| 206 | // be dropped there instead of renumbered. | |
| 207 | let renumbered = Collections.MAP[Symbol, CAPTURED_TYPE_ARGUMENT]() | |
| 208 | ||
| 209 | for i in 0..kept.count do | |
| 210 | renumbered.add(kept[i], CAPTURED_TYPE_ARGUMENT(i)) | |
| 211 | od | |
| 212 | ||
| 213 | next_type_argument_index = renumbered.count | |
| 214 | ||
| 215 | if renumbered.count > 0 then | |
| 216 | captured_type_arguments = renumbered | |
| 217 | else | |
| 218 | captured_type_arguments = null | |
| 219 | fi | |
| 220 | si | |
| 221 | ||
| 222 | // True when this closure is emitted into the class that declares | |
| 223 | // `parameter`, which then reaches the closure's body through the | |
| 224 | // receiver rather than through a parameter of its own. A trait's | |
| 225 | // parameter never is: the closure is not emitted on the trait. | |
| 226 | is_type_argument_carried_by_emitting_class(parameter: Symbol) -> bool is | |
| 227 | let symbol: Symbol? mut = self | |
| 228 | ||
| 229 | while symbol? do | |
| 230 | if let classy: Classy = symbol then | |
| 231 | return !classy.is_trait /\ parameter.owner == classy | |
| 232 | fi | |
| 233 | ||
| 234 | let enclosing = cast Symbol?(symbol.owner) | |
| 235 | ||
| 236 | // A namespace is its own owner, so a chain that reaches | |
| 237 | // one without passing a class ends there. | |
| 238 | if enclosing == symbol then | |
| 239 | return false | |
| 240 | fi | |
| 241 | ||
| 242 | symbol = enclosing | |
| 243 | od | |
| 244 | ||
| 245 | return false | |
| 246 | si | |
| 247 | ||
| 248 | // A stateless, ground function literal whose delegate carries no | |
| 249 | // per-evaluation state, so it can be built once and cached in a | |
| 250 | // static field instead of reallocated on every use. Two shapes | |
| 251 | // qualify, both with no captured type arguments and a fully-settled, | |
| 252 | // ground function type: | |
| 253 | // | |
| 254 | // - a static or global anonymous function (`ldnull` target, no | |
| 255 | // captures), cached on the enclosing namespace's `$globals`; | |
| 256 | // - an instance-context delegate that captures no values and never | |
| 257 | // loads self in its body: it is emitted as a static method with | |
| 258 | // a null target and cached on its enclosing non-generic class, | |
| 259 | // so the cache retains no receiver instance. | |
| 260 | // | |
| 261 | // The settled/ground-type gate excludes literals whose inference | |
| 262 | // never resolved or whose type mentions a type variable (either | |
| 263 | // would produce an invalid cache field). The self-load gate | |
| 264 | // excludes a delegate like `() => self` whose result depends on the | |
| 265 | // receiver even though it captures nothing. | |
| 266 | is_memoizable_delegate: bool is | |
| 267 | if captured_type_arguments? then | |
| 268 | return false | |
| 269 | fi | |
| 270 | ||
| 271 | let function_type = type | |
| 272 | ||
| 273 | if !function_type? \/ !function_type.is_settled \/ !_is_ground_type(function_type) then | |
| 274 | return false | |
| 275 | fi | |
| 276 | ||
| 277 | if is_anon_func then | |
| 278 | return _enclosing_namespace()? | |
| 279 | fi | |
| 280 | ||
| 281 | if is_delegate /\ is_stateless_delegate /\ !_delegate_body_loads_self then | |
| 282 | // Async literals lower through the state-machine path; | |
| 283 | // their delegate creation is not worth caching (the state | |
| 284 | // machine allocation dominates) and is left untouched. | |
| 285 | if async_state_machine_for(self)? then | |
| 286 | return false | |
| 287 | fi | |
| 288 | ||
| 289 | if let owner_class: CLASS = get_il_owner() then | |
| 290 | return !owner_class.is_generic | |
| 291 | fi | |
| 292 | ||
| 293 | return false | |
| 294 | fi | |
| 295 | ||
| 296 | return false | |
| 297 | si | |
| 298 | ||
| 299 | _is_ground_type(candidate: Semantic.Types.Type) -> bool is | |
| 300 | let mentions_type_variable mut = false | |
| 301 | ||
| 302 | candidate.walk((element: Semantic.Types.Type) is | |
| 303 | if element.is_type_variable then | |
| 304 | mentions_type_variable = true | |
| 305 | fi | |
| 306 | ||
| 307 | // A plain named reference to a generic type's own symbol - | |
| 308 | // a union variant among these - rather than an | |
| 309 | // instantiation of it names the open generic. It carries no | |
| 310 | // arguments for a type-argument walk to see, and an open | |
| 311 | // generic in a static field signature fails to load. A | |
| 312 | // pack wrapper whose generic callee has not yet had its | |
| 313 | // type arguments bound reaches this shape. | |
| 314 | if | |
| 315 | isa Semantic.Types.NAMED(element) /\ | |
| 316 | !isa Semantic.Types.GENERIC(element) /\ | |
| 317 | isa Semantic.Symbols.Classy(element.symbol) /\ | |
| 318 | cast Semantic.Symbols.Classy(element.symbol).is_generic | |
| 319 | then | |
| 320 | mentions_type_variable = true | |
| 321 | fi | |
| 322 | si) | |
| 323 | ||
| 324 | return !mentions_type_variable | |
| 325 | si | |
| 326 | ||
| 327 | // Static field caching this literal's delegate. A static/global | |
| 328 | // anonymous function caches on the enclosing namespace's `$globals` | |
| 329 | // class; a stateless instance-context delegate caches on its | |
| 330 | // enclosing class. Built lazily and shared between the load-site | |
| 331 | // reference and the definition emitted by generate-il. | |
| 332 | _delegate_cache_field: Field? | |
| 333 | ||
| 334 | // True once a load site has referenced the cache field; the field | |
| 335 | // definition is emitted iff this holds, so the definition tracks | |
| 336 | // what the frozen load-site IL actually references. | |
| 337 | has_delegate_cache_field: bool => _delegate_cache_field? | |
| 338 | ||
| 339 | delegate_cache_field: Field is | |
| 340 | if !_delegate_cache_field? then | |
| 341 | let `field: Field = | |
| 342 | if is_anon_func then | |
| 343 | Symbols.GLOBAL_VARIABLE(LOCATION.internal, _enclosing_namespace()!, "{name}$cache") | |
| 344 | else | |
| 345 | Symbols.STATIC_FIELD(LOCATION.internal, get_il_owner(), "{name}$cache") | |
| 346 | fi | |
| 347 | `field.set_type(constructed_delegate_type) | |
| 348 | _delegate_cache_field = `field | |
| 349 | fi | |
| 350 | ||
| 351 | // Retyped on every access: the closure's own type is | |
| 352 | // rebuilt whenever its return is settled again, and the | |
| 353 | // field created by an earlier walk has to hold what the | |
| 354 | // final walk constructs. | |
| 355 | let `field = _delegate_cache_field! | |
| 356 | ||
| 357 | `field.set_type(constructed_delegate_type) | |
| 358 | ||
| 359 | return `field | |
| 360 | si | |
| 361 | ||
| 362 | // Wrap a delegate-creation value so it is built once and reused. | |
| 363 | // A no-op for literals that aren't memoizable. | |
| 364 | memoize_delegate(value: Value) -> Value is | |
| 365 | if !is_memoizable_delegate then | |
| 366 | return value | |
| 367 | fi | |
| 368 | ||
| 369 | return IR.Values.MEMOIZED_DELEGATE( | |
| 370 | value, delegate_cache_field, constructed_delegate_type) | |
| 371 | si | |
| 372 | ||
| 373 | _enclosing_namespace() -> NAMESPACE? is | |
| 374 | let scope: Scope? mut = owner | |
| 375 | ||
| 376 | let guard mut = 0 | |
| 377 | while scope? /\ guard < 64 do | |
| 378 | if let ns: NAMESPACE = scope then | |
| 379 | return ns | |
| 380 | fi | |
| 381 | ||
| 382 | if let ns_scope: Semantic.NAMESPACE_SCOPE = scope then | |
| 383 | return ns_scope.containing_namespace | |
| 384 | fi | |
| 385 | ||
| 386 | if let symbol: Symbol = scope then | |
| 387 | scope = symbol.owner | |
| 388 | else | |
| 389 | return null | |
| 390 | fi | |
| 391 | ||
| 392 | guard = guard + 1 | |
| 393 | od | |
| 394 | ||
| 395 | return null | |
| 396 | si | |
| 397 | ||
| 398 | // The frame and its captured-value set materialise together on | |
| 399 | // first capture. | |
| 400 | _ensure_frame() -> FRAME is | |
| 401 | if !frame? then | |
| 402 | captured_values = Collections.SET[Symbol?]() | |
| 403 | ||
| 404 | frame = Semantic.Symbols.FRAME(owner!, self) | |
| 405 | fi | |
| 406 | ||
| 407 | return frame! | |
| 408 | si | |
| 409 | ||
| 410 | // A captured value's type is what makes the frame generic, and | |
| 411 | // the frame is a class of its own, so every parameter that type | |
| 412 | // names has to be one of its own. Recording it where the | |
| 413 | // capture is made rather than where the frame is built is what | |
| 414 | // lets anything compiled against the frame agree with it: the | |
| 415 | // set is otherwise empty until emission. | |
| 416 | _capture_type_arguments_of(type: Types.Type?) is | |
| 417 | if !type? then | |
| 418 | return | |
| 419 | fi | |
| 420 | ||
| 421 | type.walk( | |
| 422 | t is | |
| 423 | if t.is_type_variable then | |
| 424 | add_type_argument_reference(t.symbol) | |
| 425 | fi | |
| 426 | si) | |
| 427 | si | |
| 428 | ||
| 429 | find_or_add_capture(variable: Symbol?) -> Field is | |
| 430 | let frame = _ensure_frame() | |
| 431 | let captured_values = self.captured_values! | |
| 432 | ||
| 433 | if variable? then | |
| 434 | if !captured_values.contains(variable) then | |
| 435 | captured_values.add(variable) | |
| 436 | ||
| 437 | // `storage_type` is the slot/field type at IL | |
| 438 | // level — `Ghul.BOX[T]` when the captured | |
| 439 | // local is boxed, plain `T` otherwise. For | |
| 440 | // boxed locals the frame holds a reference to | |
| 441 | // the shared box, so closure and enclosing | |
| 442 | // scope agree on the cell. | |
| 443 | let `field_type = | |
| 444 | if isa Variable(variable) then | |
| 445 | variable.storage_type | |
| 446 | else | |
| 447 | cast Types.Typed?(variable)!.type | |
| 448 | fi | |
| 449 | ||
| 450 | let captured = frame.declare_captured(variable.name, `field_type, IoC.CONTAINER.instance.symbol_definition_locations) | |
| 451 | ||
| 452 | captured.captured_symbol = variable | |
| 453 | ||
| 454 | _capture_type_arguments_of(`field_type) | |
| 455 | ||
| 456 | return captured | |
| 457 | else | |
| 458 | let existing = frame.get_captured(variable.name) | |
| 459 | ||
| 460 | if should_refresh_capture(existing, variable) then | |
| 461 | // Mirror the boxed/unboxed distinction | |
| 462 | // from declaration time — see comment in | |
| 463 | // the declare-new branch above. | |
| 464 | let refreshed_type = | |
| 465 | if isa Variable(variable) then | |
| 466 | variable.storage_type | |
| 467 | else | |
| 468 | cast Types.Typed?(variable)!.type | |
| 469 | fi | |
| 470 | ||
| 471 | existing!.set_type(refreshed_type!) | |
| 472 | ||
| 473 | _capture_type_arguments_of(refreshed_type) | |
| 474 | fi | |
| 475 | ||
| 476 | return existing! | |
| 477 | fi | |
| 478 | else | |
| 479 | if !is_self_captured then | |
| 480 | is_self_captured = true | |
| 481 | ||
| 482 | captured_values.add(null) | |
| 483 | ||
| 484 | return frame.declare_captured("$self", _self_capture_type(), IoC.CONTAINER.instance.symbol_definition_locations) | |
| 485 | else | |
| 486 | // is_self_captured guarantees a prior declare_captured | |
| 487 | // populated the "$self" slot. | |
| 488 | return frame.get_captured("$self")! | |
| 489 | fi | |
| 490 | fi | |
| 491 | si | |
| 492 | ||
| 493 | // Type of the frame's captured `$self` field. The enclosing | |
| 494 | // instance type comes from the scope stack rather than from the | |
| 495 | // closure's owner, which for a body written in a `partial` or | |
| 496 | // `impl` block is the block's own scope and carries no type. | |
| 497 | _self_capture_type() -> Types.Type? is | |
| 498 | let context = IoC.CONTAINER.instance.symbol_table.current_instance_context ?? cast Classy?(owner) | |
| 499 | ||
| 500 | if !context? then | |
| 501 | return owner!.type | |
| 502 | fi | |
| 503 | ||
| 504 | let resolved = Collections.LIST[Symbol]() | |
| 505 | ||
| 506 | let result = SELF_CAPTURE_TYPE((classy, name) => _own_type_argument(classy, name, resolved)).of(context) | |
| 507 | ||
| 508 | // Recording is what gives the frame class the parameters the | |
| 509 | // instantiated reference resolves against, so it applies only | |
| 510 | // once every parameter resolved and that reference was built. | |
| 511 | if isa Types.GENERIC(result) then | |
| 512 | for argument in resolved do | |
| 513 | add_type_argument_reference(argument) | |
| 514 | od | |
| 515 | fi | |
| 516 | ||
| 517 | return result | |
| 518 | si | |
| 519 | ||
| 520 | _own_type_argument(context: Classy, name: string, resolved: Collections.LIST[Symbol]) -> Types.Type? is | |
| 521 | let argument = context.find_direct(name) | |
| 522 | ||
| 523 | if !argument? \/ !argument.type? then | |
| 524 | return null | |
| 525 | fi | |
| 526 | ||
| 527 | resolved.add(argument) | |
| 528 | ||
| 529 | return argument.type | |
| 530 | si | |
| 531 | ||
| 532 | // True iff the captured field's recorded type should be replaced | |
| 533 | // on a re-capture pass. The previous iteration may have captured | |
| 534 | // `source` before its type was IL-emit-stable, leaving the field | |
| 535 | // pinned to an `INFERRED_VARIABLE_TYPE` sentinel or a null slot. | |
| 536 | // Refresh when the source has a usable shape AND the existing | |
| 537 | // field's recorded type is itself still un-settled. Two source- | |
| 538 | // side gates: | |
| 539 | // | |
| 540 | // - `!is_sentinel` rather than `is_settled` so a composite like | |
| 541 | // `Function[T,U]` with inner placeholders still promotes the | |
| 542 | // field from `INFERRED_VARIABLE_TYPE` to `Function[T,U]`, | |
| 543 | // letting call sites on the captured value see a NAMED | |
| 544 | // function rather than an opaque sentinel. Inner T/U slots | |
| 545 | // refine via the next body-retry iteration. | |
| 546 | // | |
| 547 | // - `is_defined` (for LOCAL_VARIABLE sources) guards against a | |
| 548 | // `let f = ... f ...` forward self-reference silently | |
| 549 | // "fixing" itself before the user-visible "cannot emit IL for | |
| 550 | // function with unresolved return type" diagnostic fires. | |
| 551 | // Destructured locals set `is_defined` ahead of the inner | |
| 552 | // closure reference, so they still refresh correctly. | |
| 553 | should_refresh_capture(existing: Field?, source: Symbol?) -> bool static is | |
| 554 | if !existing? \/ !source? then | |
| 555 | return false | |
| 556 | fi | |
| 557 | ||
| 558 | let source_type = source.type | |
| 559 | ||
| 560 | if !source_type? \/ source_type.is_sentinel then | |
| 561 | return false | |
| 562 | fi | |
| 563 | ||
| 564 | let local = cast LOCAL_VARIABLE?(source) | |
| 565 | if local? /\ !local.is_defined then | |
| 566 | return false | |
| 567 | fi | |
| 568 | ||
| 569 | let existing_type = existing.type | |
| 570 | ||
| 571 | return !existing_type? \/ !existing_type.is_settled | |
| 572 | si | |
| 573 | ||
| 574 | find_or_add_recurse() -> Field is | |
| 575 | let frame = _ensure_frame() | |
| 576 | ||
| 577 | let recurse = frame.find_member("$recurse") | |
| 578 | ||
| 579 | if recurse? then | |
| 580 | return cast Field?(recurse)! | |
| 581 | else | |
| 582 | return frame.declare_recurse(IoC.CONTAINER.instance.symbol_definition_locations) | |
| 583 | fi | |
| 584 | si | |
| 585 | ||
| 586 | find_or_add_capture_self() -> Field => find_or_add_capture(null) | |
| 587 | ||
| 588 | outer_recurse_field_name(outer: Closure) -> string => | |
| 589 | "$outer_recurse_{outer.name}" | |
| 590 | ||
| 591 | // Captures the recurse-target of an outer recursive ancestor | |
| 592 | // so `rec` can be used from a nested non-recursive lambda. | |
| 593 | // The captured Symbol stored in `captured_values` is the | |
| 594 | // outer Closure itself, used as a sentinel by | |
| 595 | // `_get_actual_arguments` to dispatch to the outer-recurse | |
| 596 | // codepath. Declaration order in `captured_values` mirrors | |
| 597 | // declaration order in the frame, so the constructor-arg | |
| 598 | // ordering stays in step with the frame-field ordering. | |
| 599 | find_or_add_captured_outer_recurse(outer: Closure) -> Field is | |
| 600 | assert outer != self else "cannot capture self as outer recurse" | |
| 601 | ||
| 602 | let frame = _ensure_frame() | |
| 603 | let captured_values = self.captured_values! | |
| 604 | ||
| 605 | let field_name = outer_recurse_field_name(outer) | |
| 606 | let existing = frame.find_member(field_name) | |
| 607 | ||
| 608 | if existing? then | |
| 609 | let `field = cast Field?(existing)! | |
| 610 | ||
| 611 | // Always refresh from outer.type when non-error. | |
| 612 | // outer.type is rebuilt by Function.set_return_type | |
| 613 | // each iteration so a stale field would miss any | |
| 614 | // widening (arg slot CONS[int] → List[int] from rec | |
| 615 | // match propagation) or any return-slot resolution (INFERRED | |
| 616 | // → string). Type-level `matches` returns true whenever | |
| 617 | // one side is INFERRED, so it can't distinguish | |
| 618 | // "still placeholder" from "now concrete". | |
| 619 | // Refreshing unconditionally is safe: gen_type on | |
| 620 | // placeholders emits a comment (per | |
| 621 | // INFERRED_VARIABLE_TYPE / INFERRED_RETURN_TYPE | |
| 622 | // overrides) and the next iter's freeze produces a | |
| 623 | // cleaner RAW. | |
| 624 | let outer_type = outer.type | |
| 625 | ||
| 626 | if outer_type? /\ !outer_type.is_error then | |
| 627 | `field.set_type(outer_type) | |
| 628 | fi | |
| 629 | ||
| 630 | return `field | |
| 631 | fi | |
| 632 | ||
| 633 | captured_values.add(outer) | |
| 634 | ||
| 635 | return frame.declare_captured(field_name, outer.type, IoC.CONTAINER.instance.symbol_definition_locations) | |
| 636 | si | |
| 637 | ||
| 638 | load_captured_outer_recurse(location: LOCATION, outer: Closure, loader: SYMBOL_LOADER) -> Value is | |
| 639 | let `field = find_or_add_captured_outer_recurse(outer) | |
| 640 | let frame = self.frame! | |
| 641 | ||
| 642 | return loader.load_instance_variable(LOCATION.internal, IR.Values.Load.REFERENCE_SELF(frame, frame.type), `field) | |
| 643 | si | |
| 644 | ||
| 645 | // Called from the enclosing closure's _get_actual_arguments to | |
| 646 | // produce the value to pass for an inner frame's | |
| 647 | // $outer_recurse_<outer> capture. If we are outer directly, | |
| 648 | // load $recurse from our own frame; otherwise we must have | |
| 649 | // captured outer's recurse ourselves (the chain-establish loop | |
| 650 | // in visit(RECURSE) guarantees it). | |
| 651 | load_outer_recurse_value(outer: Closure, location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 652 | if self == outer then | |
| 653 | return load_recurse(location, loader) | |
| 654 | fi | |
| 655 | ||
| 656 | // the chain-establish loop captured outer's recurse here, | |
| 657 | // so the frame exists | |
| 658 | let frame = self.frame! | |
| 659 | ||
| 660 | let field_name = outer_recurse_field_name(outer) | |
| 661 | let `field = cast Field?(frame.find_member(field_name)) | |
| 662 | ||
| 663 | assert `field? else "outer recurse field {field_name} not found on intermediate closure {name}" | |
| 664 | ||
| 665 | return loader.load_instance_variable(LOCATION.internal, IR.Values.Load.REFERENCE_SELF(frame, frame.type), `field) | |
| 666 | si | |
| 667 | ||
| 668 | // Walks the live scope stack to find the closure that | |
| 669 | // lexically encloses self — i.e. the closure into whose body | |
| 670 | // the IR currently being built will be inserted. `current_function` | |
| 671 | // is no good here: when this runs, self is still on the stack so | |
| 672 | // `current_function` returns self. | |
| 673 | _find_enclosing_closure() -> Closure? is | |
| 674 | let stack = IoC.CONTAINER.instance.symbol_table.stack | |
| 675 | let i mut = stack.count - 1 | |
| 676 | let seen_self mut = false | |
| 677 | ||
| 678 | while i >= 0 do | |
| 679 | let scope = stack[i] | |
| 680 | ||
| 681 | if seen_self /\ isa Closure(scope) then | |
| 682 | return scope | |
| 683 | fi | |
| 684 | ||
| 685 | if scope == self then | |
| 686 | seen_self = true | |
| 687 | fi | |
| 688 | ||
| 689 | i = i - 1 | |
| 690 | od | |
| 691 | return null | |
| 692 | si | |
| 693 | ||
| 694 | type_updated(type: Semantic.Types.Type) is | |
| 695 | if let self.frame? /\ is_recursive then | |
| 696 | frame.try_update_recurse_type(type) | |
| 697 | fi | |
| 698 | si | |
| 699 | ||
| 700 | add_type_argument_reference(type: Symbol) is | |
| 701 | if !captured_type_arguments? then | |
| 702 | captured_type_arguments = Collections.MAP[Symbol,CAPTURED_TYPE_ARGUMENT]() | |
| 703 | fi | |
| 704 | ||
| 705 | let captures = captured_type_arguments! | |
| 706 | ||
| 707 | if captures.contains_key(type) then | |
| 708 | return | |
| 709 | fi | |
| 710 | ||
| 711 | // One frame slot per parameter, not per symbol standing for | |
| 712 | // one. A captured type can arrive as the parameter's own | |
| 713 | // symbol or as a frozen copy of it, and those are different | |
| 714 | // objects; giving each a slot would number one parameter | |
| 715 | // twice, and the position each slot installs is held against | |
| 716 | // the parameter, so the second would overwrite the first and | |
| 717 | // leave one of the two frame indices unreachable. | |
| 718 | if _is_captured_parameter(captures, type) then | |
| 719 | return | |
| 720 | fi | |
| 721 | ||
| 722 | captures.add(type, CAPTURED_TYPE_ARGUMENT(next_type_argument_index)) | |
| 723 | next_type_argument_index = next_type_argument_index + 1 | |
| 724 | si | |
| 725 | ||
| 726 | _is_captured_parameter( | |
| 727 | captures: Collections.MAP[Symbol,CAPTURED_TYPE_ARGUMENT], | |
| 728 | type: Symbol | |
| 729 | ) -> bool is | |
| 730 | let argument = cast GenericArgument?(type) | |
| 731 | ||
| 732 | if !argument? then | |
| 733 | return false | |
| 734 | fi | |
| 735 | ||
| 736 | let key = TYPE_PARAMETER_KEY.of(argument) | |
| 737 | ||
| 738 | for captured in captures.keys do | |
| 739 | if let captured_argument: GenericArgument = captured then | |
| 740 | if TYPE_PARAMETER_KEY.of(captured_argument) =~ key then | |
| 741 | return true | |
| 742 | fi | |
| 743 | fi | |
| 744 | od | |
| 745 | ||
| 746 | return false | |
| 747 | si | |
| 748 | ||
| 749 | set_type_arguments() is | |
| 750 | if !captured_type_arguments? then | |
| 751 | // not needed | |
| 752 | return | |
| 753 | fi | |
| 754 | ||
| 755 | if let self.frame? then | |
| 756 | frame.set_type_arguments(get_sorted_captured_type_argument_symbols()!) | |
| 757 | return | |
| 758 | fi | |
| 759 | ||
| 760 | if generic_arguments.count > 0 then | |
| 761 | // already done | |
| 762 | return | |
| 763 | fi | |
| 764 | ||
| 765 | let args = get_sorted_captured_type_argument_symbols()! | |
| 766 | ||
| 767 | generic_arguments = args |> map(a => a.type!) |> collect() | |
| 768 | generic_argument_names = args |> map(a => a.name) |> collect() | |
| 769 | si | |
| 770 | ||
| 771 | get_sorted_captured_type_argument_symbols() -> Collections.List[Symbol]? => | |
| 772 | if captured_type_arguments? then | |
| 773 | captured_type_arguments |> sort((a, b) => a.value.index - b.value.index) |> map(p => p.key) |> collect() | |
| 774 | else | |
| 775 | null | |
| 776 | fi | |
| 777 | ||
| 778 | get_sorted_captured_type_argument_types() -> Collections.List[Types.Type]? => | |
| 779 | if captured_type_arguments? then | |
| 780 | captured_type_arguments |> sort((a, b) => a.value.index - b.value.index) |> map(p => p.key.type!) |> collect() | |
| 781 | else | |
| 782 | null | |
| 783 | fi | |
| 784 | ||
| 785 | get_type_arguments_as_specialize_map() -> Collections.Map[Symbol,Types.Type]? => | |
| 786 | if captured_type_arguments? then | |
| 787 | Collections.MAP[Symbol,Types.Type]( | |
| 788 | // filter ensures key.type and key.type.freeze() are non-null | |
| 789 | captured_type_arguments.keys | |
| 790 | |> filter(key => let kt = key.type in kt? /\ kt.freeze()?) |> | |
| 791 | map(key => Collections.KeyValuePair[Symbol,Types.Type](key, key.type!.freeze()!)) | |
| 792 | ) | |
| 793 | else | |
| 794 | null | |
| 795 | fi | |
| 796 | ||
| 797 | // Saved emitted positions per captured type-arg symbol, set on | |
| 798 | // entry to map_type_arguments and reinstated by | |
| 799 | // unmap_type_arguments. Without this save and restore, an outer | |
| 800 | // override (e.g. the enclosing generator's | |
| 801 | // install_body_emission_overrides) would be clobbered by the | |
| 802 | // closure's nullout in unmap and any later freeze of the | |
| 803 | // outer's IR would emit the wrong type-arg index. | |
| 804 | // | |
| 805 | // It is a stack because the same closure's bracket nests inside | |
| 806 | // itself: emitting a signature within a body already bracketed | |
| 807 | // for that closure enters it a second time. With one slot per | |
| 808 | // symbol the inner entry saves the closure's own position over | |
| 809 | // the outer entry's saved value, and the matching pair of unmaps | |
| 810 | // then clears the position instead of reinstating what was | |
| 811 | // installed before the outermost entry. | |
| 812 | _saved_emitted_positions: Collections.MAP[Symbol, Collections.LIST[(() -> TYPE_PARAMETER_POSITION)?]]? | |
| 813 | ||
| 814 | map_type_arguments() is | |
| 815 | if !captured_type_arguments? then | |
| 816 | return | |
| 817 | fi | |
| 818 | ||
| 819 | let saved = | |
| 820 | _saved_emitted_positions ?? | |
| 821 | Collections.MAP[Symbol, Collections.LIST[(() -> TYPE_PARAMETER_POSITION)?]]() | |
| 822 | ||
| 823 | _saved_emitted_positions = saved | |
| 824 | ||
| 825 | for symbol_cta in captured_type_arguments! do | |
| 826 | let symbol = symbol_cta.key | |
| 827 | let cta = symbol_cta.value | |
| 828 | ||
| 829 | let prior_positions: Collections.LIST[(() -> TYPE_PARAMETER_POSITION)?] mut | |
| 830 | ||
| 831 | if !saved.try_get_value(symbol, prior_positions ref) then | |
| 832 | prior_positions = Collections.LIST[(() -> TYPE_PARAMETER_POSITION)?]() | |
| 833 | saved[symbol] = prior_positions | |
| 834 | fi | |
| 835 | ||
| 836 | prior_positions.add(symbol.current_emitted_position) | |
| 837 | ||
| 838 | // A closure with a frame reaches the argument as one of | |
| 839 | // the frame class's own; without one it stays on the | |
| 840 | // method. Which it is can still change after this point, | |
| 841 | // so the answer is deferred rather than decided here. | |
| 842 | symbol.set_emitted_position( | |
| 843 | () => TYPE_PARAMETER_POSITION(frame?, cta.index)) | |
| 844 | od | |
| 845 | si | |
| 846 | ||
| 847 | unmap_type_arguments() is | |
| 848 | if !captured_type_arguments? then | |
| 849 | return | |
| 850 | fi | |
| 851 | ||
| 852 | let saved = _saved_emitted_positions | |
| 853 | ||
| 854 | for symbol_cta in captured_type_arguments do | |
| 855 | let symbol = symbol_cta.key | |
| 856 | ||
| 857 | let prior_positions: Collections.LIST[(() -> TYPE_PARAMETER_POSITION)?] mut | |
| 858 | ||
| 859 | if | |
| 860 | saved? /\ | |
| 861 | saved.try_get_value(symbol, prior_positions ref) /\ | |
| 862 | prior_positions.count > 0 | |
| 863 | then | |
| 864 | let last = prior_positions.count - 1 | |
| 865 | ||
| 866 | symbol.set_emitted_position(prior_positions[last]) | |
| 867 | prior_positions.remove_at(last) | |
| 868 | else | |
| 869 | symbol.set_emitted_position(null) | |
| 870 | fi | |
| 871 | od | |
| 872 | si | |
| 873 | ||
| 874 | load(location: LOCATION, loader: SYMBOL_LOADER) -> Value => throw System.NotImplementedException("abstract") | |
| 875 | load_closure(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 876 | try | |
| 877 | return _load_closure(location, loader) | |
| 878 | catch e: System.Exception | |
| 879 | IoC.CONTAINER.instance.logger.exception(location, e, "exception loading closure") | |
| 880 | ||
| 881 | return IR.Values.DUMMY(Types.ERROR(), location) | |
| 882 | yrt | |
| 883 | si | |
| 884 | ||
| 885 | _get_actual_arguments(loader: SYMBOL_LOADER) -> Collections.LIST[Value] is | |
| 886 | let actual_arguments = Collections.LIST[Value]() | |
| 887 | ||
| 888 | let capture_type_argument = (t: Types.Type) is | |
| 889 | if t.is_type_variable then | |
| 890 | add_type_argument_reference(t.symbol) | |
| 891 | fi | |
| 892 | si | |
| 893 | ||
| 894 | let enclosing: Closure? mut = null | |
| 895 | ||
| 896 | for c in captured_values! do | |
| 897 | if !c? then | |
| 898 | // The "captured self" passed to the closure's | |
| 899 | // frame constructor. Same construction-site | |
| 900 | // distinction as `_load_delegate`: inside a | |
| 901 | // generator's MoveNext, route through the state- | |
| 902 | // machine frame's `_outer_self` so the frame ctor | |
| 903 | // receives the user's instance and not the state | |
| 904 | // machine. | |
| 905 | let context = IoC.CONTAINER.instance.symbol_table.current_instance_context | |
| 906 | let outer_self: Value? mut = null | |
| 907 | if context? then | |
| 908 | outer_self = _try_load_self_for_construction_via_outer_self(context) | |
| 909 | fi | |
| 910 | if !outer_self? then | |
| 911 | outer_self = loader.load_outer_self(location) | |
| 912 | fi | |
| 913 | ||
| 914 | actual_arguments.add(outer_self) | |
| 915 | ||
| 916 | // Guard: a forward-reference capture (e.g. | |
| 917 | // mutual recursion between two let-bound | |
| 918 | // lambdas) leaves the capture's type null | |
| 919 | // during the first walk. Skipping the type-var | |
| 920 | // discovery here is correct — the outer | |
| 921 | // function's body retry will re-walk the | |
| 922 | // closure with the resolved type. NRE-ing here | |
| 923 | // would mask the underlying "variable is not | |
| 924 | // defined here" diagnostic. | |
| 925 | if outer_self.type? then | |
| 926 | outer_self.type.walk(capture_type_argument) | |
| 927 | fi | |
| 928 | elif isa Closure(c) then | |
| 929 | let outer = c | |
| 930 | ||
| 931 | if !enclosing? then | |
| 932 | enclosing = _find_enclosing_closure() | |
| 933 | fi | |
| 934 | ||
| 935 | let value = enclosing!.load_outer_recurse_value(outer, location, loader) | |
| 936 | ||
| 937 | actual_arguments.add(value) | |
| 938 | ||
| 939 | if value.type? then | |
| 940 | value.type.walk(capture_type_argument) | |
| 941 | fi | |
| 942 | else | |
| 943 | let outer_captured_value = | |
| 944 | c.load_outer( | |
| 945 | location, | |
| 946 | null, | |
| 947 | loader | |
| 948 | ) | |
| 949 | ||
| 950 | actual_arguments.add(outer_captured_value) | |
| 951 | ||
| 952 | if outer_captured_value.type? then | |
| 953 | outer_captured_value.type.walk(capture_type_argument) | |
| 954 | fi | |
| 955 | fi | |
| 956 | od | |
| 957 | ||
| 958 | return actual_arguments | |
| 959 | si | |
| 960 | ||
| 961 | // A closure emitted on the enclosing class reaches that class's | |
| 962 | // type parameters as `!N` through the instance, which is why | |
| 963 | // RECORD_TYPE_ARGUMENT_USES leaves them uncaptured. A closure | |
| 964 | // with captured values is emitted on a frame instead, and the | |
| 965 | // frame is a class of its own with no parameters of the | |
| 966 | // enclosing one, so whatever its signature names it must carry. | |
| 967 | // Whether there is a frame is not known when that pass runs. | |
| 968 | capture_signature_type_arguments() is | |
| 969 | let capture = (t: Types.Type) is | |
| 970 | if t.is_type_variable then | |
| 971 | add_type_argument_reference(t.symbol) | |
| 972 | fi | |
| 973 | si | |
| 974 | ||
| 975 | for argument in arguments do | |
| 976 | argument.walk(capture) | |
| 977 | od | |
| 978 | ||
| 979 | if let self.return_type? then | |
| 980 | return_type.walk(capture) | |
| 981 | fi | |
| 982 | si | |
| 983 | ||
| 984 | _load_closure(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 985 | let closure_type = type | |
| 986 | ||
| 987 | if !closure_type? then | |
| 988 | return IR.Values.DUMMY(Types.ERROR(), LOCATION.internal) | |
| 989 | fi | |
| 990 | ||
| 991 | if closure_type.is_error then | |
| 992 | return IR.Values.DUMMY(closure_type, LOCATION.internal) | |
| 993 | fi | |
| 994 | ||
| 995 | if is_delegate then | |
| 996 | return loader.load_instance_anonymous_function(self, constructed_delegate_type) | |
| 997 | fi | |
| 998 | ||
| 999 | let actual_arguments = _get_actual_arguments(loader) | |
| 1000 | ||
| 1001 | capture_signature_type_arguments() | |
| 1002 | ||
| 1003 | if captured_type_arguments? then | |
| 1004 | return _load_closure_generic(actual_arguments, loader) | |
| 1005 | else | |
| 1006 | return _load_closure_non_generic(actual_arguments, loader) | |
| 1007 | fi | |
| 1008 | si | |
| 1009 | ||
| 1010 | _load_closure_generic(actual_arguments: Collections.LIST[Value], loader: SYMBOL_LOADER) -> Value is | |
| 1011 | // See _load_closure_non_generic for the failed-speculation | |
| 1012 | // try-catch rationale. | |
| 1013 | try | |
| 1014 | return _load_closure_generic_body(actual_arguments, loader) | |
| 1015 | catch ex: System.Exception | |
| 1016 | IoC.CONTAINER.instance.logger.mark_consumed_any() | |
| 1017 | return IR.Values.DUMMY(self.type!, location) | |
| 1018 | yrt | |
| 1019 | si | |
| 1020 | ||
| 1021 | _load_closure_generic_body(actual_arguments: Collections.LIST[Value], loader: SYMBOL_LOADER) -> Value is | |
| 1022 | let frame = self.frame! | |
| 1023 | ||
| 1024 | let block = IR.Values.BLOCK(constructed_delegate_type) | |
| 1025 | ||
| 1026 | owner = frame | |
| 1027 | ||
| 1028 | set_type_arguments() | |
| 1029 | ||
| 1030 | // we want these type arguments to remain in the current context. | |
| 1031 | // Frozen forms are filtered for non-null so we hand a real | |
| 1032 | // List[Type] to get_create_instance — a captured generic with | |
| 1033 | // no resolved freeze would point at an unresolved slot. | |
| 1034 | let frozen_argument_types = get_sorted_captured_type_argument_types()! | |
| 1035 | |> map(t => t.freeze()) |> | |
| 1036 | filter(f => f?) |> | |
| 1037 | map(f => f!) |> | |
| 1038 | collect() | |
| 1039 | ||
| 1040 | // but the formal arguments of the frame class constructor need to be in the frame's context | |
| 1041 | map_type_arguments() | |
| 1042 | let frame_instance = frame.get_create_instance(actual_arguments, frozen_argument_types) | |
| 1043 | unmap_type_arguments() | |
| 1044 | ||
| 1045 | let frame_instance_copier = frame_instance!.get_temp_copier(block, "frame-instance") | |
| 1046 | ||
| 1047 | owner = frame_instance.type!.symbol | |
| 1048 | ||
| 1049 | map_type_arguments() | |
| 1050 | let function = IR.Values.Load.FUNCTION_POINTER(self) | |
| 1051 | unmap_type_arguments() | |
| 1052 | ||
| 1053 | let result = IR.Values.Load.DELEGATE(constructed_delegate_type, function, frame_instance_copier()) | |
| 1054 | ||
| 1055 | let result_copier = result.get_temp_copier(block, "closure") | |
| 1056 | ||
| 1057 | let rec_member_symbol = owner!.find_member("$recurse") | |
| 1058 | ||
| 1059 | if rec_member_symbol? /\ !frame_instance.type!.is_error then | |
| 1060 | let ff = frame_instance_copier() | |
| 1061 | let rr = result_copier() | |
| 1062 | map_type_arguments() | |
| 1063 | block.add(rec_member_symbol.store(location, ff, rr, loader, true)) | |
| 1064 | unmap_type_arguments() | |
| 1065 | fi | |
| 1066 | ||
| 1067 | block.add(result_copier()) | |
| 1068 | block.close() | |
| 1069 | return block | |
| 1070 | si | |
| 1071 | ||
| 1072 | _load_closure_non_generic(actual_arguments: Collections.LIST[Value], loader: SYMBOL_LOADER) -> Value is | |
| 1073 | // Bail early when any captured value has an error or | |
| 1074 | // unresolved type. Trying to construct the frame | |
| 1075 | // instance with ERROR-typed captures cascades into IL | |
| 1076 | // gen_type throws further down the path. | |
| 1077 | for a in actual_arguments do | |
| 1078 | if !a.type? \/ a.type.is_error then | |
| 1079 | return IR.Values.DUMMY(Types.ERROR(), location) | |
| 1080 | fi | |
| 1081 | od | |
| 1082 | ||
| 1083 | // The iterative-inference body-retry loop may reach | |
| 1084 | // closure loading during an early iter where the FRAME's | |
| 1085 | // declare_constructor defensive-defaulted a not-yet-typed | |
| 1086 | // field to Types.ERROR — gen_type throws on that. | |
| 1087 | // Treat the exception as failed speculation: return a | |
| 1088 | // DUMMY of the closure's own type so downstream paths | |
| 1089 | // see a placeholder closure rather than a poison value, | |
| 1090 | // and mark_consumed_any so the body-retry loop iterates | |
| 1091 | // again from improved types. | |
| 1092 | try | |
| 1093 | return _load_closure_non_generic_body(actual_arguments, loader) | |
| 1094 | catch ex: System.Exception | |
| 1095 | IoC.CONTAINER.instance.logger.mark_consumed_any() | |
| 1096 | return IR.Values.DUMMY(self.type!, location) | |
| 1097 | yrt | |
| 1098 | si | |
| 1099 | ||
| 1100 | _load_closure_non_generic_body(actual_arguments: Collections.LIST[Value], loader: SYMBOL_LOADER) -> Value is | |
| 1101 | let frame = self.frame! | |
| 1102 | ||
| 1103 | let block = IR.Values.BLOCK(constructed_delegate_type) | |
| 1104 | ||
| 1105 | owner = frame | |
| 1106 | ||
| 1107 | let frame_instance = frame.get_create_instance(actual_arguments, null) | |
| 1108 | let frame_instance_copier = frame_instance!.get_temp_copier(block, "frame-instance") | |
| 1109 | ||
| 1110 | owner = frame_instance.type!.symbol | |
| 1111 | ||
| 1112 | let function = IR.Values.Load.FUNCTION_POINTER(self) | |
| 1113 | let result = IR.Values.Load.DELEGATE(constructed_delegate_type, function, frame_instance_copier()) | |
| 1114 | ||
| 1115 | let result_copier = result.get_temp_copier(block, "closure") | |
| 1116 | ||
| 1117 | let rec_member_symbol = frame.find_member("$recurse") | |
| 1118 | ||
| 1119 | if rec_member_symbol? /\ !frame_instance.type!.is_error then | |
| 1120 | block.add(rec_member_symbol.store(location, frame_instance_copier(), result_copier(), loader, true)) | |
| 1121 | fi | |
| 1122 | ||
| 1123 | block.add(result_copier()) | |
| 1124 | block.close() | |
| 1125 | return block | |
| 1126 | si | |
| 1127 | ||
| 1128 | _load_lambda() -> Value is | |
| 1129 | let closure_type = type | |
| 1130 | ||
| 1131 | if !closure_type? then | |
| 1132 | return IR.Values.DUMMY(Types.ERROR(), LOCATION.internal) | |
| 1133 | fi | |
| 1134 | ||
| 1135 | if closure_type.is_error then | |
| 1136 | return IR.Values.DUMMY(closure_type, LOCATION.internal) | |
| 1137 | fi | |
| 1138 | ||
| 1139 | if captured_type_arguments? then | |
| 1140 | return _load_lambda_generic() | |
| 1141 | else | |
| 1142 | return _load_lambda_non_generic() | |
| 1143 | fi | |
| 1144 | si | |
| 1145 | ||
| 1146 | _load_lambda_generic() -> Value is | |
| 1147 | set_type_arguments() | |
| 1148 | ||
| 1149 | // Generic lambdas always capture type arguments, so the | |
| 1150 | // specialize map is present on this path. | |
| 1151 | let args_map = get_type_arguments_as_specialize_map()! | |
| 1152 | ||
| 1153 | map_type_arguments() | |
| 1154 | ||
| 1155 | let specialized_lambda = specialize_function(args_map, null) | |
| 1156 | ||
| 1157 | let function_pointer = IR.Values.Load.FUNCTION_POINTER(specialized_lambda) | |
| 1158 | let delegate = IR.Values.Load.DELEGATE(delegate_target_type ?? specialized_lambda.type!, function_pointer, IR.Values.NULL(Types.NULL())) | |
| 1159 | ||
| 1160 | unmap_type_arguments() | |
| 1161 | ||
| 1162 | return delegate | |
| 1163 | si | |
| 1164 | ||
| 1165 | _load_lambda_non_generic() -> Value is | |
| 1166 | let function_pointer = IR.Values.Load.FUNCTION_POINTER(self) | |
| 1167 | let delegate = IR.Values.Load.DELEGATE(constructed_delegate_type, function_pointer, IR.Values.NULL(Types.NULL())) | |
| 1168 | ||
| 1169 | return memoize_delegate(delegate) | |
| 1170 | si | |
| 1171 | ||
| 1172 | _load_delegate(loader: SYMBOL_LOADER) -> Value is | |
| 1173 | let closure_type = type | |
| 1174 | ||
| 1175 | if !closure_type? then | |
| 1176 | return IR.Values.DUMMY(Types.ERROR(), LOCATION.internal) | |
| 1177 | fi | |
| 1178 | ||
| 1179 | if closure_type.is_error then | |
| 1180 | return IR.Values.DUMMY(closure_type, LOCATION.internal) | |
| 1181 | fi | |
| 1182 | ||
| 1183 | // A delegate is converted from a literal that captured no | |
| 1184 | // type arguments, but the walk that follows the conversion | |
| 1185 | // can still settle a parameter type naming one. Such a | |
| 1186 | // delegate is emitted as a generic method and reached | |
| 1187 | // through an instantiation, as a frameless literal is. | |
| 1188 | if captured_type_arguments? then | |
| 1189 | return _load_delegate_generic(loader) | |
| 1190 | fi | |
| 1191 | ||
| 1192 | let function_pointer = IR.Values.Load.FUNCTION_POINTER(self) | |
| 1193 | ||
| 1194 | // A stateless delegate that never reads self doesn't need a | |
| 1195 | // receiver at all: emit it as a static method with a null | |
| 1196 | // target (the same shape as a static anonymous function) and | |
| 1197 | // cache it, so no receiver instance is retained by the cache. | |
| 1198 | is_static_delegate = is_memoizable_delegate | |
| 1199 | ||
| 1200 | if is_static_delegate then | |
| 1201 | let delegate = IR.Values.Load.DELEGATE(constructed_delegate_type, function_pointer, IR.Values.NULL(Types.NULL())) | |
| 1202 | ||
| 1203 | return memoize_delegate(delegate) | |
| 1204 | fi | |
| 1205 | ||
| 1206 | return IR.Values.Load.DELEGATE(constructed_delegate_type, function_pointer, _load_delegate_target(loader)) | |
| 1207 | si | |
| 1208 | ||
| 1209 | // Delegate target: the receiver the runtime binds to the | |
| 1210 | // delegate. Inside a generator's MoveNext, `ldarg.0` is | |
| 1211 | // the state machine, so a plain `loader.load_self` would | |
| 1212 | // bind the delegate to it rather than the user's | |
| 1213 | // instance. Route through the state-machine frame's | |
| 1214 | // `_outer_self` field at construction-time when there's | |
| 1215 | // an enclosing generator; otherwise fall back to the | |
| 1216 | // ordinary load_self path. | |
| 1217 | _load_delegate_target(loader: SYMBOL_LOADER) -> Value is | |
| 1218 | let context = IoC.CONTAINER.instance.symbol_table.current_instance_context | |
| 1219 | let self_pointer: Value? mut = null | |
| 1220 | if context? then | |
| 1221 | self_pointer = _try_load_self_for_construction_via_outer_self(context) | |
| 1222 | fi | |
| 1223 | if !self_pointer? then | |
| 1224 | self_pointer = loader.load_self(LOCATION.internal) | |
| 1225 | fi | |
| 1226 | ||
| 1227 | // Binding the target loads the receiver at the construction | |
| 1228 | // site, which sits in the enclosing literal's body when this | |
| 1229 | // delegate is nested inside another literal. | |
| 1230 | note_enclosing_body_loads_self() | |
| 1231 | ||
| 1232 | return self_pointer | |
| 1233 | si | |
| 1234 | ||
| 1235 | // The delegate's own method carries the type parameters its | |
| 1236 | // signature names, and the construction site reaches it through | |
| 1237 | // an instantiation of them. Mirrors the frameless literal path; | |
| 1238 | // a generic delegate is never memoised, since the cache field | |
| 1239 | // would have to be one per instantiation. | |
| 1240 | _load_delegate_generic(loader: SYMBOL_LOADER) -> Value is | |
| 1241 | let self_pointer = _load_delegate_target(loader) | |
| 1242 | ||
| 1243 | set_type_arguments() | |
| 1244 | ||
| 1245 | let args_map = get_type_arguments_as_specialize_map()! | |
| 1246 | ||
| 1247 | map_type_arguments() | |
| 1248 | ||
| 1249 | let specialized = specialize_function(args_map, null) | |
| 1250 | ||
| 1251 | let function_pointer = IR.Values.Load.FUNCTION_POINTER(specialized) | |
| 1252 | let delegate = | |
| 1253 | IR.Values.Load.DELEGATE( | |
| 1254 | delegate_target_type ?? specialized.type!, | |
| 1255 | function_pointer, | |
| 1256 | self_pointer | |
| 1257 | ) | |
| 1258 | ||
| 1259 | unmap_type_arguments() | |
| 1260 | ||
| 1261 | return delegate | |
| 1262 | si | |
| 1263 | ||
| 1264 | load_outer_self(location: Source.LOCATION, loader: SYMBOL_LOADER) -> Value? is | |
| 1265 | let symbol_table = IoC.CONTAINER.instance.symbol_table | |
| 1266 | let context = symbol_table.current_instance_context | |
| 1267 | ||
| 1268 | if is_delegate then | |
| 1269 | note_enclosing_body_loads_self() | |
| 1270 | ||
| 1271 | return IR.Values.Load.REFERENCE_SELF(context!, context.type) | |
| 1272 | fi | |
| 1273 | ||
| 1274 | let is_captured = false | |
| 1275 | ||
| 1276 | let stack = symbol_table.stack | |
| 1277 | ||
| 1278 | let index mut = stack.count - 1 | |
| 1279 | let seen_self mut = false | |
| 1280 | ||
| 1281 | while index >= 0 do | |
| 1282 | let scope = stack[index] | |
| 1283 | ||
| 1284 | if scope.is_namespace then | |
| 1285 | break | |
| 1286 | fi | |
| 1287 | ||
| 1288 | if seen_self /\ scope.is_capture_context then | |
| 1289 | if scope.is_closure then | |
| 1290 | let c = cast Closure?(scope)! | |
| 1291 | ||
| 1292 | // FIXME: may not be needed - load_self() should capture self: | |
| 1293 | c.find_or_add_capture_self() | |
| 1294 | ||
| 1295 | return c.load_self(location, loader) | |
| 1296 | fi | |
| 1297 | fi | |
| 1298 | ||
| 1299 | if scope == self then | |
| 1300 | seen_self = true | |
| 1301 | fi | |
| 1302 | ||
| 1303 | index = index - 1 | |
| 1304 | od | |
| 1305 | ||
| 1306 | if !is_captured then | |
| 1307 | // load self normally: | |
| 1308 | return IR.Values.Load.REFERENCE_SELF(context!, context.type) | |
| 1309 | fi | |
| 1310 | return null | |
| 1311 | si | |
| 1312 | ||
| 1313 | load_self(location: Source.LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 1314 | if is_delegate then | |
| 1315 | let context = IoC.CONTAINER.instance.symbol_table.current_instance_context! | |
| 1316 | ||
| 1317 | note_enclosing_body_loads_self() | |
| 1318 | ||
| 1319 | // A delegate is emitted as a method on the enclosing type, | |
| 1320 | // so its receiver is normally `ldarg.0`. For an async | |
| 1321 | // literal the body lives in the state machine's MoveNext, | |
| 1322 | // where `ldarg.0` is the state machine — the receiver is | |
| 1323 | // reached through its `$outer_self` field instead. Only the | |
| 1324 | // body is inside MoveNext: the load that binds the | |
| 1325 | // delegate's target sits in the enclosing method, where | |
| 1326 | // `ldarg.0` is the receiver as usual. | |
| 1327 | if _walking_literal_body then | |
| 1328 | if let redirected = _state_machine_outer_self_load(context) then | |
| 1329 | return redirected | |
| 1330 | fi | |
| 1331 | fi | |
| 1332 | ||
| 1333 | return IR.Values.Load.REFERENCE_SELF(context, context.type) | |
| 1334 | fi | |
| 1335 | ||
| 1336 | let `field = find_or_add_capture_self() | |
| 1337 | ||
| 1338 | return loader.load_instance_variable(location, _capture_frame_self_load(), `field) | |
| 1339 | si | |
| 1340 | ||
| 1341 | // At a closure-construction emission site that ends up inside | |
| 1342 | // an enclosing function's MoveNext, `ldarg.0` refers to that | |
| 1343 | // function's state machine — so the closure's delegate target | |
| 1344 | // / captured-self value can't be loaded via REFERENCE_SELF | |
| 1345 | // (which would emit `ldarg.0` of the state machine). Instead | |
| 1346 | // load through the state-machine frame's `_outer_self` field, | |
| 1347 | // which the outer method populates with the user's instance at | |
| 1348 | // .ctor time. | |
| 1349 | // | |
| 1350 | // Walks outward from this closure to find the closest | |
| 1351 | // enclosing Function. If that function compiles into a state | |
| 1352 | // machine whose frame carries `_outer_self`, returns the | |
| 1353 | // matching `OUTER_SELF` IR Value; otherwise returns null and | |
| 1354 | // the caller falls back to a plain REFERENCE_SELF. | |
| 1355 | // | |
| 1356 | // Called only at construction sites (`_load_delegate`, | |
| 1357 | // `_get_actual_arguments`), which is what makes the *enclosing* | |
| 1358 | // function's state machine the right one to look for. A | |
| 1359 | // self-load in the closure's own body wants its own state | |
| 1360 | // machine instead, and `load_self` handles that separately off | |
| 1361 | // `_walking_literal_body`. | |
| 1362 | _try_load_self_for_construction_via_outer_self(context: Symbol) -> Value? is | |
| 1363 | let stack = IoC.CONTAINER.instance.symbol_table.stack | |
| 1364 | let index mut = stack.count - 1 | |
| 1365 | ||
| 1366 | while index >= 0 do | |
| 1367 | let scope = stack[index] | |
| 1368 | ||
| 1369 | if scope == self then | |
| 1370 | index = index - 1 | |
| 1371 | continue | |
| 1372 | fi | |
| 1373 | ||
| 1374 | if let function: Function = scope then | |
| 1375 | if let outer_self_field = _enclosing_state_machine_outer_self_field(function) then | |
| 1376 | return IR.Values.Load.OUTER_SELF(context, context.type, outer_self_field) | |
| 1377 | fi | |
| 1378 | ||
| 1379 | return null | |
| 1380 | fi | |
| 1381 | ||
| 1382 | index = index - 1 | |
| 1383 | od | |
| 1384 | ||
| 1385 | return null | |
| 1386 | si | |
| 1387 | ||
| 1388 | // The `$outer_self` field of whichever state machine `function` | |
| 1389 | // compiles into — generator or async. Null when it compiles into | |
| 1390 | // neither, or when the frame carries no outer self (statics and | |
| 1391 | // globals have none). declare() materialises the field; it is lazy | |
| 1392 | // and idempotent, and required because the frame property only | |
| 1393 | // constructs the bare FRAME object. | |
| 1394 | _enclosing_state_machine_outer_self_field(function: Function) -> Field? is | |
| 1395 | if let sm = state_machine_for(function) then | |
| 1396 | if let frame = sm.frame then | |
| 1397 | frame.declare() | |
| 1398 | ||
| 1399 | return frame.outer_self_field | |
| 1400 | fi | |
| 1401 | elif let async_sm = async_state_machine_for(function) then | |
| 1402 | if let frame = async_sm.frame then | |
| 1403 | frame.declare() | |
| 1404 | ||
| 1405 | return frame.outer_self_field | |
| 1406 | fi | |
| 1407 | fi | |
| 1408 | ||
| 1409 | return null | |
| 1410 | si | |
| 1411 | ||
| 1412 | load_outer_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value? is | |
| 1413 | let is_captured = false | |
| 1414 | ||
| 1415 | let stack = IoC.CONTAINER.instance.symbol_table.stack | |
| 1416 | ||
| 1417 | let index mut = stack.count - 1 | |
| 1418 | let seen_self mut = false | |
| 1419 | ||
| 1420 | while index >= 0 do | |
| 1421 | let scope = stack[index] | |
| 1422 | ||
| 1423 | if seen_self /\ scope.is_capture_context then | |
| 1424 | if symbol.owner == scope then | |
| 1425 | // FIXME: use the symbol loader | |
| 1426 | if isa LOCAL_ARGUMENT(symbol) then | |
| 1427 | return IR.Values.Load.LOCAL_ARGUMENT(symbol) | |
| 1428 | else | |
| 1429 | return IR.Values.Load.LOCAL_VARIABLE(symbol) | |
| 1430 | fi | |
| 1431 | elif scope.is_closure then | |
| 1432 | let c = cast Closure?(scope)! | |
| 1433 | ||
| 1434 | // FIXME: probably redundant | |
| 1435 | c.find_or_add_capture(symbol) | |
| 1436 | ||
| 1437 | c.load_captured_value(location, symbol, loader) | |
| 1438 | ||
| 1439 | let result = c.load_captured_value(location, symbol, loader) | |
| 1440 | ||
| 1441 | return result | |
| 1442 | fi | |
| 1443 | fi | |
| 1444 | ||
| 1445 | if scope == self then | |
| 1446 | seen_self = true | |
| 1447 | fi | |
| 1448 | ||
| 1449 | index = index - 1 | |
| 1450 | od | |
| 1451 | return null | |
| 1452 | si | |
| 1453 | ||
| 1454 | load_recurse(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 1455 | let recurse = find_or_add_recurse() | |
| 1456 | let frame = self.frame! | |
| 1457 | ||
| 1458 | return recurse.load(location, IR.Values.Load.REFERENCE_SELF(frame, frame.type), loader) | |
| 1459 | si | |
| 1460 | ||
| 1461 | // Closure-body store into an outer-scope captured local. | |
| 1462 | // Only legal when the captured local is boxed — outer | |
| 1463 | // scope and closure share a heap cell, so writing via | |
| 1464 | // `.value` on the captured box updates the cell visible | |
| 1465 | // to the outer scope. Unboxed captures are still | |
| 1466 | // rejected upstream by the symbol-loader diagnostic. | |
| 1467 | store_captured_value(location: LOCATION, symbol: Variable, value: Value, loader: SYMBOL_LOADER) -> Value is | |
| 1468 | symbol.is_captured = true | |
| 1469 | ||
| 1470 | let `field = find_or_add_capture(symbol) | |
| 1471 | ||
| 1472 | let frame_field_load = | |
| 1473 | loader.load_instance_variable(LOCATION.internal, _capture_frame_self_load(), `field) | |
| 1474 | ||
| 1475 | if symbol.is_boxed then | |
| 1476 | let value_member = loader.resolve_box_value_member(symbol) | |
| 1477 | ||
| 1478 | if value_member? then | |
| 1479 | return value_member.store(LOCATION.internal, frame_field_load, value, loader, false) | |
| 1480 | fi | |
| 1481 | fi | |
| 1482 | ||
| 1483 | // Fall back to a frame-field store for the unboxed | |
| 1484 | // case — should not be reached in practice because | |
| 1485 | // the upstream diagnostic blocks unboxed captured | |
| 1486 | // assignment, but the defensive path keeps us out of | |
| 1487 | // NRE territory if it ever does. | |
| 1488 | return loader.store_instance_variable(LOCATION.internal, _capture_frame_self_load(), `field, value) | |
| 1489 | si | |
| 1490 | ||
| 1491 | // A `T ref` parameter's slot lives on the enclosing method's | |
| 1492 | // stack and dies when it returns, so a frame field cannot hold | |
| 1493 | // it: the emitted ctor would store the byref through a raw | |
| 1494 | // pointer whose pointee is gone by the time the closure runs. | |
| 1495 | captures_reference(symbol: Variable) -> bool static is | |
| 1496 | if let symbol_type = symbol.type then | |
| 1497 | return isa Types.REFERENCE(symbol_type) | |
| 1498 | fi | |
| 1499 | ||
| 1500 | return false | |
| 1501 | si | |
| 1502 | ||
| 1503 | load_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value is | |
| 1504 | if captures_reference(symbol) then | |
| 1505 | IoC.CONTAINER.instance.logger.error( | |
| 1506 | location, | |
| 1507 | "a function literal cannot capture a ref parameter, copy the value into a local variable first") | |
| 1508 | fi | |
| 1509 | ||
| 1510 | // Capture-before-define is detected by LOCAL_VARIABLE.load | |
| 1511 | // (`variable.ghul`) via its own check_is_defined call; | |
| 1512 | // duplicating the check here fired the same diagnostic | |
| 1513 | // twice for the captured-load path. The capture field is | |
| 1514 | // built with whatever type the variable has at this | |
| 1515 | // point (often null/ERROR), which without the upstream | |
| 1516 | // check would crash Type.gen_type at IL emission — but | |
| 1517 | // the upstream check is the only place we need. | |
| 1518 | symbol.is_captured = true | |
| 1519 | ||
| 1520 | let `field = find_or_add_capture(symbol) | |
| 1521 | ||
| 1522 | // Returns the raw frame field — for boxed captures | |
| 1523 | // this is the BOX[T] reference. The user-code-side | |
| 1524 | // unwrap to `.value` happens in | |
| 1525 | // `SYMBOL_LOADER.load_local_variable` after this | |
| 1526 | // returns, so that inter-frame capture transfers | |
| 1527 | // (via `load_outer_captured_value`) keep passing the | |
| 1528 | // box reference between frames untouched. | |
| 1529 | return loader.load_instance_variable(LOCATION.internal, _capture_frame_self_load(), `field) | |
| 1530 | si | |
| 1531 | ||
| 1532 | // Load the captures-frame `this` for capture access. Normally | |
| 1533 | // REFERENCE_SELF (`ldarg.0` of the frame's type). For an | |
| 1534 | // ASYNC_CLOSURE compiled down the state-machine path, the | |
| 1535 | // body lives in the SM's MoveNext where `ldarg.0` is the SM | |
| 1536 | // instance — the captures-frame is reached via the SM's | |
| 1537 | // `_outer_self` field. Mirror of INSTANCE_ASYNC_METHOD's | |
| 1538 | // load_self. | |
| 1539 | _capture_frame_self_load() -> Value is | |
| 1540 | let frame = self.frame! | |
| 1541 | ||
| 1542 | return _state_machine_outer_self_load(frame) ?? IR.Values.Load.REFERENCE_SELF(frame, frame.type) | |
| 1543 | si | |
| 1544 | ||
| 1545 | // The `$outer_self` load that stands in for `ldarg.0` inside this | |
| 1546 | // literal's own MoveNext, where `ldarg.0` is the state machine | |
| 1547 | // rather than whatever the body means by self. `context` is the | |
| 1548 | // symbol the loaded value is typed against — the captures frame | |
| 1549 | // for a framed literal, the enclosing instance for a delegate. | |
| 1550 | // Null when this literal does not compile into a state machine, | |
| 1551 | // leaving the caller to emit an ordinary self reference. | |
| 1552 | // | |
| 1553 | // In practice that means an async literal: `yield` in a literal | |
| 1554 | // is not supported, so there is no generator closure kind for | |
| 1555 | // the shared lookup's generator half to match. Should one ever | |
| 1556 | // be added its body would be inside its own MoveNext for the | |
| 1557 | // same reason, and would want the same redirect. | |
| 1558 | _state_machine_outer_self_load(context: Symbol) -> Value? is | |
| 1559 | if let outer_self_field = _enclosing_state_machine_outer_self_field(self) then | |
| 1560 | return IR.Values.Load.OUTER_SELF(context, context.type, outer_self_field) | |
| 1561 | fi | |
| 1562 | ||
| 1563 | return null | |
| 1564 | si | |
| 1565 | ||
| 1566 | get_il_owner() -> Scope is | |
| 1567 | if frame? \/ is_delegate then | |
| 1568 | return owner! | |
| 1569 | fi | |
| 1570 | ||
| 1571 | let temp_owner = owner | |
| 1572 | ||
| 1573 | let classy_owner = cast Classy?(owner) | |
| 1574 | ||
| 1575 | if classy_owner? /\ classy_owner.owner? then | |
| 1576 | return classy_owner.owner | |
| 1577 | fi | |
| 1578 | ||
| 1579 | // owner may be incorrect | |
| 1580 | debug_always("suspect closure owner: {owner}") | |
| 1581 | ||
| 1582 | return owner! | |
| 1583 | si | |
| 1584 | ||
| 1585 | gen_frame(context: IR.CONTEXT, symbol_loader: SYMBOL_LOADER) is | |
| 1586 | if let self.frame? then | |
| 1587 | map_type_arguments() | |
| 1588 | set_type_arguments() | |
| 1589 | ||
| 1590 | frame.gen_all(context, symbol_loader) | |
| 1591 | ||
| 1592 | unmap_type_arguments() | |
| 1593 | fi | |
| 1594 | si | |
| 1595 | ||
| 1596 | // Whether the method emitted for this closure takes a receiver, | |
| 1597 | // which is not the same question as `is_instance`: a closure is | |
| 1598 | // not an instance member of anything the language can see, while | |
| 1599 | // the method emitted for one whose captures live on a frame does | |
| 1600 | // take that frame, and reaches the captures through it. | |
| 1601 | // | |
| 1602 | // Its flags and its calling convention both turn on this, and | |
| 1603 | // they have to agree. | |
| 1604 | is_emitted_with_receiver: bool => !is_anon_func /\ !is_static_delegate | |
| 1605 | ||
| 1606 | to_string() -> string => "[closure {name}]" | |
| 1607 | si | |
| 1608 | ||
| 1609 | // FIXME: pull common code across these Closure subclasses up | |
| 1610 | // into Closure | |
| 1611 | class INSTANCE_CLOSURE: Closure is | |
| 1612 | is_instance: bool => true | |
| 1613 | ||
| 1614 | could_be_delegate: bool => | |
| 1615 | let captured_values = self.captured_values in | |
| 1616 | !captured_values? \/ (is_self_captured /\ captured_values.count == 1) /\ !is_recursive /\ _can_carry_captured_type_arguments | |
| 1617 | ||
| 1618 | // A delegate's method is emitted on the enclosing class, which | |
| 1619 | // supplies that class's own type parameters and nothing else, so | |
| 1620 | // the only ones the method can declare for itself are an | |
| 1621 | // enclosing generic method's. A trait's parameter is neither - | |
| 1622 | // the method is not emitted on the trait - so a literal that | |
| 1623 | // captured one keeps its frame, which declares every parameter | |
| 1624 | // its signature names. | |
| 1625 | _can_carry_captured_type_arguments: bool is | |
| 1626 | let captures = captured_type_arguments | |
| 1627 | ||
| 1628 | if !captures? then | |
| 1629 | return true | |
| 1630 | fi | |
| 1631 | ||
| 1632 | for parameter in captures.keys do | |
| 1633 | if | |
| 1634 | !isa FUNCTION_GENERIC_ARGUMENT(parameter) /\ | |
| 1635 | !is_type_argument_carried_by_emitting_class(parameter) | |
| 1636 | then | |
| 1637 | return false | |
| 1638 | fi | |
| 1639 | od | |
| 1640 | ||
| 1641 | return true | |
| 1642 | si | |
| 1643 | ||
| 1644 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 1645 | super.init(location, owner, name, enclosing_scope, is_recursive) | |
| 1646 | si | |
| 1647 | ||
| 1648 | declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1649 | declare_closure_symbol(location, Symbols.INSTANCE_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1650 | ||
| 1651 | declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1652 | declare_closure_symbol(location, Symbols.INSTANCE_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1653 | ||
| 1654 | load(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 1655 | if frame? then | |
| 1656 | return super.load_closure(location, loader) | |
| 1657 | fi | |
| 1658 | ||
| 1659 | if is_delegate then | |
| 1660 | return _load_delegate(loader) | |
| 1661 | fi | |
| 1662 | ||
| 1663 | return _load_lambda() | |
| 1664 | si | |
| 1665 | ||
| 1666 | to_string() -> string => "[instance closure {name}]" | |
| 1667 | si | |
| 1668 | ||
| 1669 | class STATIC_CLOSURE: Closure is | |
| 1670 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 1671 | super.init(location, owner, name, enclosing_scope, is_recursive) | |
| 1672 | si | |
| 1673 | ||
| 1674 | declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1675 | declare_closure_symbol(location, Symbols.STATIC_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1676 | ||
| 1677 | declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1678 | declare_closure_symbol(location, Symbols.STATIC_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1679 | ||
| 1680 | load(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 1681 | if frame? then | |
| 1682 | return super.load_closure(location, loader) | |
| 1683 | fi | |
| 1684 | ||
| 1685 | return _load_lambda() | |
| 1686 | si | |
| 1687 | ||
| 1688 | to_string() -> string => "[static closure {name}]" | |
| 1689 | si | |
| 1690 | ||
| 1691 | class GLOBAL_CLOSURE: Closure is | |
| 1692 | init(location: LOCATION, owner: Scope, name: string, enclosing_scope: Scope, is_recursive: bool) is | |
| 1693 | super.init(location, owner, name, enclosing_scope, is_recursive) | |
| 1694 | si | |
| 1695 | ||
| 1696 | declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1697 | declare_closure_symbol(location, Symbols.GLOBAL_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1698 | ||
| 1699 | declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol => | |
| 1700 | declare_closure_symbol(location, Symbols.GLOBAL_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive)) | |
| 1701 | ||
| 1702 | load(location: LOCATION, loader: SYMBOL_LOADER) -> Value is | |
| 1703 | let closure_type = type | |
| 1704 | ||
| 1705 | if !closure_type? then | |
| 1706 | return IR.Values.DUMMY(Types.ERROR(), LOCATION.internal) | |
| 1707 | fi | |
| 1708 | ||
| 1709 | if closure_type.is_error then | |
| 1710 | return IR.Values.DUMMY(closure_type, LOCATION.internal) | |
| 1711 | fi | |
| 1712 | ||
| 1713 | if frame? then | |
| 1714 | return super.load_closure(location, loader) | |
| 1715 | fi | |
| 1716 | ||
| 1717 | set_type_arguments() | |
| 1718 | ||
| 1719 | return memoize_delegate(loader.load_global_anonymous_function(self, constructed_delegate_type)) | |
| 1720 | si | |
| 1721 | ||
| 1722 | to_string() -> string => "[global closure {name}]" | |
| 1723 | si | |
| 1724 | ||
| 1725 | // TODO: this could be replaced with plain 'int' | |
| 1726 | struct CAPTURED_TYPE_ARGUMENT is | |
| 1727 | index: int | |
| 1728 | ||
| 1729 | init(index: int) is | |
| 1730 | self.index = index | |
| 1731 | si | |
| 1732 | si | |
| 1733 | si |