Skip to content
← Back

src/semantic/symbols/closure.ghul

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