Skip to content
← Back

src/syntax/process/compile-expressions/compile_lambdas.ghul

1
namespace Syntax.Process is
2
use Logging
3
use Ghul.Disposable
4
5
use Semantic.Types.Type
6
7
use IR.Values
8
9
use Ghul.Pipes
10
11
// Compiles function bodies and function literals: the method-body
12
// walk with its iterative type-inference retry loop, lambda
13
// (closure) literals and `rec` references. Split out of
14
// COMPILE_EXPRESSIONS, which delegates the matching visit methods
15
// here. The `super.pre` / `super.visit` base-visitor calls and
16
// the exception / environment-save wrapper of visit(function
17
// literal) stay in the visitor; the methods here are the enclosed
18
// logic.
19
class COMPILE_LAMBDAS is
20
_logger: Logger
21
_symbol_table: Semantic.SYMBOL_TABLE
22
_symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS
23
_symbol_loader: Semantic.SYMBOL_LOADER
24
_innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup
25
_task_conversion: Semantic.TASK_CONVERSION
26
_task_like_resolver: Semantic.TASK_LIKE_RESOLVER
27
_closure_arg_resolver: Semantic.CLOSURE_ARG_RESOLVER
28
_type_arg_placeholder_registry: Semantic.TYPE_ARG_PLACEHOLDER_REGISTRY
29
_flow: NARROWING_FLOW
30
_build_flags: Compiler.GLOBAL_BUILD_FLAGS
31
_visitor: ScopedVisitor
32
33
_field_assignment_checker: FIELD_ASSIGNMENT_CHECKER
34
_delegate_shape: Semantic.DELEGATE_SHAPE
35
_attribute_resolver: ATTRIBUTE_RESOLVER
36
_composite_spill_state: COMPOSITE_SPILL_STORE
37
_function_reference_adapter: FUNCTION_REFERENCE_ADAPTER
38
39
init(
40
logger: Logger,
41
symbol_table: Semantic.SYMBOL_TABLE,
42
symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS,
43
symbol_loader: Semantic.SYMBOL_LOADER,
44
innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup,
45
task_conversion: Semantic.TASK_CONVERSION,
46
closure_arg_resolver: Semantic.CLOSURE_ARG_RESOLVER,
47
type_arg_placeholder_registry: Semantic.TYPE_ARG_PLACEHOLDER_REGISTRY,
48
flow: NARROWING_FLOW,
49
build_flags: Compiler.GLOBAL_BUILD_FLAGS,
50
visitor: ScopedVisitor,
51
attribute_resolver: ATTRIBUTE_RESOLVER,
52
composite_spill_state: COMPOSITE_SPILL_STORE,
53
function_reference_adapter: FUNCTION_REFERENCE_ADAPTER
54
) is
55
super.init()
56
57
_function_reference_adapter = function_reference_adapter
58
59
_logger = logger
60
_symbol_table = symbol_table
61
_symbol_use_locations = symbol_use_locations
62
_symbol_loader = symbol_loader
63
_innate_symbol_lookup = innate_symbol_lookup
64
_task_conversion = task_conversion
65
_task_like_resolver = Semantic.TASK_LIKE_RESOLVER(logger)
66
_closure_arg_resolver = closure_arg_resolver
67
_type_arg_placeholder_registry = type_arg_placeholder_registry
68
_flow = flow
69
_build_flags = build_flags
70
_visitor = visitor
71
_field_assignment_checker = FIELD_ASSIGNMENT_CHECKER(logger)
72
_attribute_resolver = attribute_resolver
73
_composite_spill_state = composite_spill_state
74
_delegate_shape = Semantic.DELEGATE_SHAPE()
75
si
76
77
visit_function_definition(function: Trees.Definitions.FUNCTION) is
78
KILL_LEDGER.current_function = function
79
KILL_LEDGER.current_file = function.location.file_name
80
81
if function.name? then
82
function.name.walk(_visitor)
83
fi
84
85
function.type_expression.walk(_visitor)
86
87
function.arguments.walk(_visitor)
88
89
if function.body? then
90
// Implicit tail return: a body's final statement is a
91
// tail candidate, terminated or not - the tail is judged
92
// by its type, never by its terminator. Under a declared
93
// non-void return type - generators exempted - the body
94
// list is compiled as value-demanding but void-tolerant,
95
// so a tail assignable to the return type flows to the
96
// function's return while a void one stays the statement
97
// it is. Void-returning bodies tolerate any tail and are
98
// left untouched here.
99
let body_block = cast Trees.Bodies.BLOCK?(function.body)
100
let function_symbol = _symbol_table.current_function
101
102
let tail_demand mut = false
103
104
// `try` has no expression form yet, labelled loops are
105
// statement-only, and a trailing `return`/`throw` already
106
// diverges on its own - none of them can stand as a value
107
// tail.
108
if let bb = body_block, fs = function_symbol, rt = fs.return_type then
109
// A body lowered through an async state machine and
110
// returning a result-less task-like completes via its
111
// builder at fall-through: no tail can deliver
112
// anything the return wants, so no demand is set and
113
// the tail stays the statement it is.
114
let machine_completed =
115
Semantic.Symbols.async_state_machine_for(fs)? /\
116
_returns_result_less_task_like(fs)
117
118
let tail = bb.statements.last
119
120
if
121
!machine_completed /\
122
!rt.is_sentinel /\
123
!rt.is_inferred /\
124
!Semantic.Symbols.state_machine_for(fs)? /\
125
!rt.matches(_innate_symbol_lookup.get_void_type())
126
then
127
// A machine-less return of a result-less task
128
// return type completes at fall-through: the body
129
// is marked a function tail whatever shape its
130
// tail is, so the statement-list visitor appends
131
// the completing return when the tail delivers
132
// nothing - a value tail may still deliver a
133
// handle to return directly, and an empty body, a
134
// `try` or a labelled loop complete like any other
135
// fall-through. A `return` tail settles itself and
136
// a `throw` tail diverges, so neither wants the
137
// append.
138
let completes_at_fall_through =
139
_task_conversion.completes_without_machine(rt)
140
141
let tail_settles_itself =
142
if let t = tail then
143
isa Trees.Statements.RETURN(t) \/ isa Trees.Statements.THROW(t)
144
else
145
false
146
fi
147
148
if completes_at_fall_through /\ !tail_settles_itself then
149
bb.statements.function_tail = true
150
fi
151
152
let tail_is_value =
153
if let t = tail then
154
t.provides_value /\
155
!isa Trees.Statements.TRY(t) /\
156
!isa Trees.Statements.LABELLED(t) /\
157
!isa Trees.Statements.THROW(t) /\
158
!isa Trees.Statements.RETURN(t)
159
else
160
false
161
fi
162
163
if tail_is_value then
164
bb.statements.function_tail = true
165
bb.statements.compile_expressions_state.want_value = true
166
bb.statements.compile_expressions_state.void_tolerated = true
167
168
bb.statements.set_expected_type(
169
rt,
170
"cannot return value of type {{0}} where {{1}} expected"
171
)
172
173
tail_demand = true
174
fi
175
fi
176
fi
177
_type_arg_placeholder_registry.begin_body()
178
Semantic.OBLIGATIONS.begin_body()
179
180
let retry_body = RETRY_SITE_STATS.begin_body()
181
let trace_body = Semantic.INFERENCE_TRACE.begin_body(function_symbol, function.location)
182
183
// Recorded symbol uses follow the diagnostics speculation
184
// discipline through this walk: every roll_back below is
185
// followed by a full body re-walk, so uses recorded
186
// against not-yet-settled types are discarded with the
187
// diagnostics of the walk that produced them rather than
188
// surviving to shadow the settled walk's records.
189
_logger.speculate()
190
_symbol_use_locations.speculate()
191
192
let retries = 20
193
let walks mut = 0
194
195
for i in 1::retries do
196
walks = i
197
RETRY_SITE_STATS.begin_walk()
198
Semantic.OBLIGATIONS.begin_walk()
199
Semantic.INFERENCE_TRACE.begin_walk(i)
200
201
// Narrowing is method-local — start each body
202
// walk (and each inference-retry re-walk) from
203
// an empty environment.
204
_flow.reset()
205
206
function.body!.walk(_visitor)
207
208
Semantic.INFERENCE_TRACE.end_walk(_logger.is_clean, _logger.has_consumed_any)
209
210
// Convergence: clean or no progress signal raised.
211
// Without a `has_consumed_any` flag from somewhere
212
// in the walk, errors that did fire are real and
213
// persistent — re-walking won't change them, and
214
// re-walking AST nodes that hold partial state
215
// produces *different* (often worse) error sets
216
// because the second walk sees state left over
217
// from the first. So retry only when something
218
// explicitly flagged "I consumed an unresolved
219
// type" — that's the case where iteration N+1
220
// might find narrower constraints and make
221
// progress.
222
// An obligation left standing is a progress signal in
223
// its own right - the mark it set can be lost to a local
224
// retry's roll back - until a walk leaves exactly the
225
// obligations the walk before it did, which is a walk
226
// that can only repeat.
227
let waiting = Semantic.OBLIGATIONS.standing.count > 0
228
229
if _logger.is_clean /\ !waiting then
230
break
231
fi
232
233
// A walk that leaves exactly the obligations the walk
234
// before it did, and that learned no bound or
235
// constraint while doing so, can only repeat - whatever
236
// else it marked as consumed. The default for what is
237
// still standing is taken below.
238
if waiting /\ Semantic.OBLIGATIONS.is_stuck then
239
break
240
fi
241
242
if !_logger.has_consumed_any /\ !waiting then
243
break
244
fi
245
246
if i < retries then
247
_logger.roll_back()
248
_logger.speculate()
249
250
_symbol_use_locations.roll_back()
251
_symbol_use_locations.speculate()
252
253
// Prototype: start the re-walk from the state a
254
// first walk would see, keeping only what lives
255
// on symbols and in the placeholder registry.
256
if RETRY_STATS.iteration_clear then
257
CLEAR_STATE_VISITOR(true, true).apply(function.body!)
258
fi
259
fi
260
od
261
262
// The loop has stopped with obligations standing, and
263
// some rule that recorded one has a default the language
264
// defines. Taking it here rather than during a walk is
265
// what keeps a walk from pre-empting the uses that would
266
// have settled the origin properly; the default then
267
// needs one more walk to reach the site that waited and
268
// everything typed from it.
269
if Semantic.OBLIGATIONS.take_defaults() then
270
_logger.roll_back()
271
_logger.speculate()
272
273
_symbol_use_locations.roll_back()
274
_symbol_use_locations.speculate()
275
276
if RETRY_STATS.iteration_clear then
277
CLEAR_STATE_VISITOR(true, true).apply(function.body!)
278
fi
279
280
walks = walks + 1
281
282
RETRY_SITE_STATS.begin_walk()
283
Semantic.OBLIGATIONS.begin_walk()
284
Semantic.INFERENCE_TRACE.begin_walk(walks)
285
286
_flow.reset()
287
288
function.body!.walk(_visitor)
289
290
Semantic.INFERENCE_TRACE.end_walk(_logger.is_clean, _logger.has_consumed_any)
291
fi
292
293
RETRY_STATS.note(walks, function_symbol, function.location)
294
RETRY_SITE_STATS.end_body(retry_body, walks, function_symbol, function.location)
295
Semantic.INFERENCE_TRACE.end_body(trace_body, walks, retries, _logger.is_clean, _logger.has_consumed_any)
296
297
// Any constructor-type-arg placeholder that didn't
298
// acquire a concrete constraint from any usage has no
299
// type to settle to - report rather than guess. This
300
// is also the backstop that keeps such a placeholder
301
// from surviving to IL emission, where the signature
302
// encoder would refuse it.
303
//
304
// Only sweep when the retry loop failed to converge.
305
// A walk that converged clean consumed no unresolved
306
// types, so every phantom that matters has settled -
307
// but the registry also holds phantom sets minted for
308
// overload candidates that lost their resolution and
309
// were rolled back, and those stay unresolved without
310
// being errors. Non-convergence is the signal that an
311
// unresolved phantom actually reached committed code.
312
if _logger.has_consumed_any /\ !_logger.is_clean then
313
_type_arg_placeholder_registry.report_unresolved(_logger)
314
fi
315
316
// Likewise an obligation still waiting on a placeholder
317
// nothing in the body settled: reported at the variable it
318
// names, since the loop has stopped walking.
319
if !_logger.is_clean then
320
Semantic.OBLIGATIONS.fix(_logger)
321
fi
322
323
Semantic.OBLIGATIONS.end_body()
324
325
// Definite return: control can reach the end of a
326
// non-void, block-bodied function's body without a
327
// value having been returned. `_flow.is_unreachable`
328
// is false here only when at least one path falls
329
// off the end — every path that returns / throws
330
// leaves the flow at `bottom`.
331
//
332
// With a tail demand set up before the walk, the
333
// outcome is judged like an explicit `return` instead:
334
// a value assignable to the declared return type consumes
335
// the obligation, and an incompatible non-void value is
336
// an error at the tail with no warning doubled on top.
337
let is_generator = Semantic.Symbols.state_machine_for(function_symbol)?
338
339
// A demanded tail is judged during the walk, by the
340
// function-tail branch of the statement-list visitor,
341
// which records whether the tail delivered. A void or
342
// valueless tail delivers nothing and is compiled as the
343
// statement it is - so a demand left standing undelivered
344
// is exactly the fall-through case, and the
345
// definite-return warning judges it.
346
let tail_delivered =
347
tail_demand /\
348
body_block? /\
349
body_block.statements.compile_expressions_state.function_tail_delivered
350
351
if
352
!tail_delivered /\
353
!_build_flags.no_warn_definite_return /\
354
!is_generator /\
355
function.body!.is_block /\
356
!_flow.is_unreachable /\
357
function_symbol? /\
358
function_symbol.return_type? /\
359
!function_symbol.return_type.is_sentinel /\
360
!function_symbol.return_type.is_inferred /\
361
!function_symbol.return_type.matches(_innate_symbol_lookup.get_void_type()) /\
362
!_completes_at_fall_through(function_symbol) /\
363
!(function_symbol.is_top_level_entry /\ _build_flags.submission_name?)
364
then
365
let header = function.location.start_position :: function.type_expression.location
366
_logger.warn(header, "definite-return", "function may not return a value on all paths")
367
fi
368
369
_record_field_assignment_summary(function, function_symbol)
370
371
_logger.commit()
372
_symbol_use_locations.commit()
373
fi
374
375
KILL_LEDGER.current_function = null
376
si
377
378
// Called once every method has been walked - see
379
// FIELD_ASSIGNMENT_CHECKER.
380
report_field_assignments() is
381
_field_assignment_checker.report()
382
si
383
384
// What a method did, for the constructor field check that runs once
385
// every method has been walked. Two facts, both taken from the
386
// must-domains at the end of the body: the fields it definitely
387
// assigned, and the methods on `self` it definitely called.
388
//
389
// The check itself cannot run here. A constructor is routinely
390
// written before the helper it delegates to, so the helper's own
391
// summary does not exist yet; FIELD_ASSIGNMENT_CHECKER closes over
392
// the call graph after the build and reports then.
393
_record_field_assignment_summary(
394
function: Trees.Definitions.FUNCTION,
395
function_symbol: Semantic.Symbols.Function?
396
) is
397
if
398
_build_flags.no_warn_field_definite_assignment \/
399
!function_symbol? \/
400
!function_symbol.is_instance
401
then
402
return
403
fi
404
405
if !isa Semantic.Symbols.Classy(function_symbol.owner) then
406
return
407
fi
408
409
let assigned = Collections.LIST[Semantic.Symbols.Symbol]()
410
411
for v in _flow.assigned_variables do
412
assigned.add(v)
413
od
414
415
let called = Collections.LIST[Semantic.Symbols.Symbol]()
416
417
for f in _flow.called_methods do
418
called.add(f)
419
od
420
421
// function_symbol.location is the constructor name alone
422
// (declare-members hands declare_function the name's own
423
// location as the symbol location, function.location - the
424
// whole declaration - as its separate span), so the warning
425
// this summary eventually produces squiggles just "init"
426
// rather than the entire constructor body.
427
_field_assignment_checker.record(
428
function_symbol,
429
function_symbol.location,
430
assigned,
431
called,
432
_flow.is_unreachable
433
)
434
si
435
436
// A function whose fall-through completes its return rather
437
// than owing a value: a state-machine body returning a
438
// result-less task-like (its builder completes the handle),
439
// and a machine-less return that can be completed without a
440
// machine - Tasks.TASK via completed_task, any other
441
// result-less task-like via its own builder (the statement-
442
// list visitor appends the completing return).
443
_completes_at_fall_through(function_symbol: Semantic.Symbols.Function) -> bool is
444
if
445
Semantic.Symbols.async_state_machine_for(function_symbol)? /\
446
_returns_result_less_task_like(function_symbol)
447
then
448
return true
449
fi
450
451
return _task_conversion.completes_without_machine(function_symbol.return_type)
452
si
453
454
// A declared return type that carries no result - `Tasks.TASK`,
455
// or any task-like with no type argument.
456
_returns_result_less_task_like(function_symbol: Semantic.Symbols.Function) -> bool is
457
let return_type = function_symbol.return_type
458
459
if !return_type? then
460
return false
461
fi
462
463
if let void_task = _innate_symbol_lookup.get_void_task_type() then
464
if return_type.matches(void_task) then
465
return true
466
fi
467
fi
468
469
let task_like = _task_like_resolver.try_resolve(return_type)
470
471
return task_like? /\ task_like.is_void_like
472
si
473
474
// The task-like a closure's slot asks its async body to return,
475
// when the slot's return type names one other than Task. Task
476
// keeps its own path: the wrap-as-task pin and the from_result
477
// wrap both spell it directly.
478
_slot_task_like(slot_return_type: Type?) -> Semantic.TASK_LIKE? is
479
if !slot_return_type? then
480
return null
481
fi
482
483
let task_like = _task_like_resolver.try_resolve(slot_return_type)
484
485
if !task_like? then
486
return null
487
fi
488
489
if _task_conversion.is_task_type(slot_return_type) then
490
return null
491
fi
492
493
return task_like
494
si
495
496
// Whether a literal's body might end on a value the literal
497
// returns: an expression body always does, and a block body
498
// does when its last statement is one a tail demand would be
499
// put to. Syntactic, because it is asked before the body is
500
// walked - the tail's type settles later, and only then is
501
// the question answerable for certain.
502
_body_may_yield_value(function: Trees.Expressions.FUNCTION) -> bool is
503
if isa Trees.Bodies.EXPRESSION(function.body) then
504
return true
505
fi
506
507
if let block = cast Trees.Bodies.BLOCK?(function.body) then
508
if let tail = block.statements.last then
509
return
510
tail.provides_value /\
511
!isa Trees.Statements.TRY(tail) /\
512
!isa Trees.Statements.LABELLED(tail) /\
513
!isa Trees.Statements.THROW(tail) /\
514
!isa Trees.Statements.RETURN(tail)
515
fi
516
fi
517
518
return false
519
si
520
521
// A literal two or more returns from the marker whose body is not
522
// itself a literal - a name, a local, a call - evaluates to a
523
// function that returns the N-ary one. It is expanded into a
524
// literal over its own parameters, so that the marker has a body
525
// to go on to, and the body is walked again around it.
526
_expand_deeper_pack_body(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) -> bool is
527
let depth = function.nested_pack_depth
528
529
if depth < 2 then
530
return false
531
fi
532
533
let body = cast Trees.Bodies.EXPRESSION?(function.body)
534
535
if !body? \/ isa Trees.Expressions.FUNCTION(body.expression) then
536
return false
537
fi
538
539
let type = body.expression.value?.type
540
541
if !type? \/ !type.is_function \/ type.is_action then
542
return false
543
fi
544
545
let inner = _function_reference_adapter.try_adapt(body.expression, Semantic.ARGUMENT_PACK.parameter_count(type))
546
547
if !inner? then
548
return false
549
fi
550
551
body.expression = inner
552
553
inner.set_expects_pack(depth - 1)
554
555
if closure.return_type_was_inferred then
556
closure.set_return_type(Semantic.Types.INFERRED_RETURN_TYPE())
557
else
558
_present_declared_return_as_packed(function, depth - 1)
559
fi
560
561
return true
562
si
563
564
// A literal at a marked position may write its return as the
565
// N-ary function type the marker licenses there, at whatever
566
// depth the marker sits. What it returns is the wrapper, so
567
// its return is rewritten to the shape the wrapper has: at the
568
// marked hop the parameters are packed into the tuple the pack
569
// binds to, and the hops above it are kept as written.
570
_present_declared_return_as_packed(function: Trees.Expressions.FUNCTION, depth: int) is
571
let declared = function.type_expression.type
572
573
if !declared? then
574
return
575
fi
576
577
let closure = cast Semantic.Symbols.Closure?(_symbol_table.scope_for(function))
578
579
if !closure? then
580
return
581
fi
582
583
if let packed = _pack_spine(declared, depth) then
584
closure.set_return_type(packed)
585
fi
586
si
587
588
// `type` with the function `depth` returns along its spine
589
// rewritten to take its parameters as one tuple. Absent where
590
// the spine is shorter than that, or where what it arrives at
591
// is not a function of two to seven parameters.
592
_pack_spine(type: Type, depth: int) -> Type? is
593
if !type.is_function then
594
return null
595
fi
596
597
let count = Semantic.ARGUMENT_PACK.parameter_count(type)
598
let types = Collections.LIST[Type]()
599
600
if depth > 0 then
601
if type.is_action then
602
return null
603
fi
604
605
let inner = _pack_spine(type.arguments[count], depth - 1)
606
607
if !inner? then
608
return null
609
fi
610
611
for i in 0..count do
612
types.add(type.arguments[i])
613
od
614
615
types.add(inner)
616
617
return _innate_symbol_lookup.get_function_type(types, type.is_pure_function)
618
fi
619
620
if count < 2 \/ count > Semantic.ARGUMENT_PACK.MAXIMUM_ARITY then
621
return null
622
fi
623
624
let elements = Collections.LIST[Type]()
625
626
for i in 0..count do
627
elements.add(type.arguments[i])
628
od
629
630
types.add(_innate_symbol_lookup.get_tuple_type(elements, null))
631
types.add(
632
if type.is_action then
633
_innate_symbol_lookup.get_void_type()
634
else
635
type.arguments[count]
636
fi
637
)
638
639
return _innate_symbol_lookup.get_function_type(types, type.is_pure_function)
640
si
641
642
// What the slot a literal goes into says it returns, where the
643
// slot is known and says anything a body could be held to.
644
_slot_return_type(function: Trees.Expressions.FUNCTION) -> Type? is
645
let expected = function.expected_type
646
647
if !expected? then
648
return null
649
fi
650
651
let shape =
652
if expected.is_function then
653
expected
654
else
655
_delegate_shape.try_get_function_type(expected, _innate_symbol_lookup)
656
fi
657
658
if !shape? then
659
return null
660
fi
661
662
let raw = Semantic.SLOT_RETURN_TYPE.of(shape, _innate_symbol_lookup.get_void_type())
663
664
if !raw? then
665
return null
666
fi
667
668
let candidate = Semantic.SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(raw)
669
670
if !Semantic.LAMBDA_RETURN_CONSTRAINT.should_push(candidate, null) then
671
return null
672
fi
673
674
return candidate
675
si
676
677
// The tuple a literal's parameters are the elements of, where the
678
// literal is written with an argument pack spread out and is
679
// going into a formal that takes the pack as one tuple. Absent
680
// for every other literal, and for one that cannot be compiled
681
// taking the tuple directly.
682
_packed_literal_tuple(function: Trees.Expressions.FUNCTION, expected_type: Type?) -> Type? is
683
if !_is_packed_literal(function, expected_type) \/ !expected_type? then
684
return null
685
fi
686
687
return expected_type.arguments[Semantic.ARGUMENT_PACK.fixed_count(expected_type)]
688
si
689
690
// Whether this literal is compiled taking the pack's tuple. The
691
// marker says the position takes one; an expected type, where one
692
// has arrived, has to be the shape that does.
693
_is_packed_literal(function: Trees.Expressions.FUNCTION, expected_type: Type?) -> bool is
694
if !function.expects_pack then
695
return false
696
fi
697
698
if !expected_type? then
699
return PACKED_LITERAL.is_eligible(function)
700
fi
701
702
return
703
Semantic.ARGUMENT_PACK.is_pack_slot(expected_type) /\
704
PACKED_LITERAL.is_eligible(function, Semantic.ARGUMENT_PACK.fixed_count(expected_type))
705
si
706
707
// The types of the parameters a pack slot takes of its own before
708
// the pack.
709
_fixed_parameter_types(expected_type: Type?) -> Collections.List[Type] is
710
let types = Collections.LIST[Type]()
711
712
if let expected = expected_type /\ Semantic.ARGUMENT_PACK.is_pack_slot(expected) then
713
for i in 0..Semantic.ARGUMENT_PACK.fixed_count(expected) do
714
types.add(expected.arguments[i])
715
od
716
fi
717
718
return types
719
si
720
721
// A pack nothing else has pinned is what the literal's own
722
// parameters say it is: once they have settled, their tuple is
723
// offered to the pack the formal names.
724
_feed_pack_from_parameters(expected_tuple: Type, closure: Semantic.Symbols.Closure) is
725
if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected_tuple then
726
if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin /\ origin.is_argument_pack then
727
let group_type = closure.arguments[closure.arguments.count - 1]
728
729
if group_type.is_settled /\ !_is_origin_settled(origin) then
730
_logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_from_parameters", origin, group_type))
731
fi
732
fi
733
fi
734
si
735
736
// The same for a parameter the formal takes of its own before the
737
// pack, where nothing but the literal says what it is.
738
_feed_fixed_from_parameters(expected_type: Type?, closure: Semantic.Symbols.Closure) is
739
if !expected_type? \/ !Semantic.ARGUMENT_PACK.is_pack_slot(expected_type) then
740
return
741
fi
742
743
for i in 0..Semantic.ARGUMENT_PACK.fixed_count(expected_type) do
744
if i >= closure.arguments.count then
745
return
746
fi
747
748
if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected_type.arguments[i] then
749
if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin then
750
if closure.arguments[i].is_settled /\ !_is_origin_settled(origin) then
751
_logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_fixed_from_parameters", origin, closure.arguments[i]))
752
fi
753
fi
754
fi
755
od
756
si
757
758
_is_origin_settled(origin: Semantic.Symbols.Variable) -> bool is
759
let settled = origin.try_get_inferred_type()
760
761
return settled? /\ settled.is_settled
762
si
763
764
visit_function(function: Trees.Expressions.FUNCTION) is
765
if !function.value? then
766
function.compile_expressions_state.value = IR.Values.WRAPPER()
767
fi
768
769
let closure = cast Semantic.Symbols.Closure?(_symbol_table.scope_for(function))!
770
771
closure.map_type_arguments()
772
773
// Every walk of an async closure starts from a fresh
774
// state-machine frame: the return type this walk settles on
775
// decides the frame's builder and result, and nothing
776
// registered against an earlier walk's frame may survive.
777
if function.contains_let_await then
778
if let state_machine = Semantic.Symbols.async_state_machine_for(closure) then
779
if let dropped = state_machine.reset() then
780
_composite_spill_state.drop_owned_by(dropped)
781
fi
782
fi
783
fi
784
785
let implied_type: Type mut
786
let implied_argument_types: Collections.List[Type]? mut = null
787
let constraint_return_type: Type? mut = null
788
let slot_return_type: Type? mut = null
789
790
// have we been passed expected arguments types? If so we'll use them
791
// to argument types of any anonymous function literal arguments.
792
// Single source of truth: function.expected_type, set by the parent
793
// context — LHS of an assignment, typed variable initializer, or
794
// overload-resolution second-pass when this lambda was an actual
795
// arg whose chosen-formal type is now known (#1174).
796
// A context expecting a named delegate constrains the literal
797
// exactly as a function type does: the literal is compiled to
798
// the delegate's call shape and the delegate itself is
799
// constructed at the load site.
800
let expected_type: Type? mut = function.expected_type
801
802
if let expected = expected_type then
803
if !expected.is_function then
804
let shape = _delegate_shape.try_get_function_type(expected, _innate_symbol_lookup)
805
806
// A delegate is constructed over the literal's own method,
807
// which the runtime never checks against the delegate's
808
// signature, so a literal of another arity is not the
809
// delegate: left as the function it is, it is reported
810
// where it fails to fit.
811
if shape? then
812
expected_type = shape
813
814
if Semantic.ARGUMENT_PACK.parameter_count(shape) == function.arguments.count then
815
closure.delegate_target_type = expected
816
fi
817
fi
818
fi
819
fi
820
821
if let effective = expected_type /\ effective.is_function then
822
// The slot's types are listed parameters first and return last,
823
// so a literal of more parameters than the slot has would, read
824
// by position, take the return as a parameter's type.
825
let slot_parameters = Collections.LIST[Type]()
826
827
for i in 0..Semantic.ARGUMENT_PACK.parameter_count(effective) do
828
slot_parameters.add(effective.arguments[i])
829
od
830
831
implied_argument_types = slot_parameters
832
833
if let
834
raw =
835
Semantic.SLOT_RETURN_TYPE.of(
836
effective,
837
_innate_symbol_lookup.get_void_type()
838
)
839
then
840
// The slot type may embed placeholders whose
841
// origins settled on an earlier iteration -
842
// collapse them, or the stale composite gets
843
// pushed onto the body and committed as the
844
// closure's return type every iteration,
845
// keeping the retry loop from converging.
846
let candidate = Semantic.SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(raw)
847
848
slot_return_type = candidate
849
850
if Semantic.LAMBDA_RETURN_CONSTRAINT.should_push(candidate, closure) then
851
constraint_return_type = candidate
852
fi
853
fi
854
fi
855
856
_symbol_table.current_closure_context.add_closure(closure)
857
858
// we are walking the arguments here while speculating
859
let is_packed = _is_packed_literal(function, expected_type)
860
let packed_tuple = _packed_literal_tuple(function, expected_type)
861
862
let arguments_resolved =
863
if is_packed then
864
_closure_arg_resolver.resolve_packed(function.arguments.expressions, closure, packed_tuple, _fixed_parameter_types(expected_type))
865
else
866
_closure_arg_resolver.resolve(function.arguments.expressions, closure, implied_argument_types)
867
fi
868
869
if packed_tuple? /\ arguments_resolved then
870
_feed_pack_from_parameters(packed_tuple, closure)
871
fi
872
873
if is_packed /\ arguments_resolved then
874
_feed_fixed_from_parameters(expected_type, closure)
875
fi
876
877
_resolve_argument_attributes(function, closure)
878
879
if arguments_resolved then
880
let return_type: Type mut
881
882
if function.type_expression.type? then
883
return_type = function.type_expression.type
884
else
885
return_type = Semantic.Types.INFERRED_RETURN_TYPE()
886
closure.return_type_was_inferred = true
887
fi
888
889
// Body contains `await` → the closure returns a
890
// task-like. A declared return type names it outright.
891
// Otherwise the slot's return type does, when it names
892
// one: adopted as-is when settled, and kept as the
893
// template the body's value is applied to when its
894
// result argument is still to be inferred. With neither,
895
// void-async (no value returns) pins to non-generic
896
// `Tasks.TASK` and value-async stays
897
// INFERRED_RETURN_TYPE, pinning to `Tasks.TASK[T]` via
898
// the wrap-paths.
899
if function.contains_let_await then
900
closure.is_void_async = false
901
closure.wrap_inferred_return_as_task = false
902
closure.async_task_like_template = null
903
904
if function.type_expression.type? then
905
let declared = _task_like_resolver.resolve(function.location, return_type)
906
907
closure.is_void_async =
908
if declared? then declared.is_void_like else function.is_void_async fi
909
elif let slot_task_like = _slot_task_like(slot_return_type) then
910
if constraint_return_type? /\ constraint_return_type.is_settled then
911
return_type = constraint_return_type
912
closure.return_type_was_inferred = false
913
closure.is_void_async = slot_task_like.is_void_like
914
else
915
closure.wrap_inferred_return_as_task = true
916
closure.async_task_like_template =
917
cast Semantic.Symbols.Classy?(slot_task_like.task_type.symbol.unspecialized_symbol)
918
fi
919
elif function.is_void_async /\ !_body_may_yield_value(function) then
920
let void_task = _innate_symbol_lookup.get_void_task_type()
921
if void_task? then
922
return_type = void_task
923
closure.return_type_was_inferred = false
924
closure.is_void_async = true
925
fi
926
else
927
closure.wrap_inferred_return_as_task = true
928
fi
929
elif
930
closure.return_type_was_inferred /\
931
constraint_return_type? /\
932
_task_conversion.try_get_task_element_type(constraint_return_type)?
933
then
934
// Slot expects `Tasks.TASK[T]`; mark the closure
935
// so a bare-T body return wraps to
936
// `Tasks.TASK.from_result(orig)` via the same
937
// inferred-return paths used for async closures.
938
closure.wrap_inferred_return_as_task = true
939
elif
940
closure.return_type_was_inferred /\
941
closure.is_carrier_adapter /\
942
slot_return_type? /\
943
slot_return_type.is_settled /\
944
!slot_return_type.is_void
945
then
946
// An adapter literal is there to present the slot's
947
// shape: its body's own carrier is what the
948
// adaptation is coercing away from, so the return is
949
// the slot's and the boundary makes the coercion.
950
return_type = slot_return_type
951
closure.return_type_was_inferred = false
952
elif
953
closure.return_type_was_inferred /\
954
slot_return_type? /\
955
slot_return_type.is_maybe
956
then
957
// The slot's `U?` is `MAYBE[U]` whatever U turns out to
958
// be, and a `string?` or bare `int` body is not that
959
// type: mark the closure so the body's value pins the
960
// return as `MAYBE[T]` over itself.
961
closure.wrap_inferred_return_as_maybe = true
962
elif
963
closure.return_type_was_inferred /\
964
slot_return_type? /\
965
slot_return_type.is_void
966
then
967
// A void slot settles the return the body would
968
// otherwise have inferred, so a body producing a
969
// value is discarded rather than making the literal
970
// the wrong shape for the only formal on offer.
971
// This is reached on the constrained re-walk alone -
972
// the first walk carries no expected type - so a
973
// candidate that wants the body's value is chosen
974
// before a void one is ever considered.
975
return_type = slot_return_type
976
closure.return_type_was_inferred = false
977
fi
978
979
closure.set_return_type(return_type)
980
fi
981
982
// Push the constraint's return-type slot onto the body's
983
// last expression before walking. The implicit-return path
984
// (pre(Bodies.EXPRESSION)) is gated on
985
// `!function.return_type.is_sentinel` and skips when the closure
986
// hasn't been given an explicit return-type annotation —
987
// but that's exactly the case where a bare variant
988
// constructor (`DONE()`) in the body would benefit from
989
// knowing the expected type. Set it here so the body's
990
// CALL nodes see the constraint; without setting
991
// closure.return_type, the lambda's emitted return type
992
// is still inferred from the body so covariant-return-via-
993
// assignment is unaffected.
994
if
995
constraint_return_type? /\
996
!function.type_expression.type? /\
997
isa Trees.Bodies.EXPRESSION(function.body)
998
then
999
let body = cast Trees.Bodies.EXPRESSION?(function.body)!
1000
1001
body.expression.set_expected_type(constraint_return_type, "cannot return value of type {{0}} where {{1}} expected")
1002
fi
1003
1004
// A formal that wrote the pack marker past its own function
1005
// type asked for the N-ary function this literal returns. The
1006
// marker goes on to the value the body evaluates to, one
1007
// return nearer, beside whatever type that value is expected
1008
// to have; a return written out as the N-ary function the
1009
// marker licenses is the literal's in the shape the formal
1010
// takes.
1011
if function.nested_pack_depth > 0 then
1012
if let body: Trees.Bodies.EXPRESSION = function.body then
1013
body.expression.set_expects_pack(function.nested_pack_depth - 1)
1014
fi
1015
1016
_present_declared_return_as_packed(function, function.nested_pack_depth - 1)
1017
fi
1018
1019
// Implicit tail return, the literal counterpart of the
1020
// setup in `visit_function_definition`: a block body's
1021
// final statement is a tail candidate, terminated or not,
1022
// so the body list is compiled as value-demanding but
1023
// void-tolerant and a type-compatible tail's value flows
1024
// to the literal's return at IL emission.
1025
//
1026
// A literal whose return type was written out is judged
1027
// exactly as a named function's tail is. One that leaves
1028
// the return to be inferred carries the same demand with
1029
// nothing to judge against - as the `=> body` path does
1030
// for an inferred return - and the statement-list visitor
1031
// settles the return from the tail's own type. Either way
1032
// a void tail is the statement it is, so a void body may
1033
// still end on a guard `if`.
1034
if
1035
isa Trees.Bodies.BLOCK(function.body) /\
1036
arguments_resolved
1037
then
1038
let bb = cast Trees.Bodies.BLOCK?(function.body)!
1039
1040
if let tail = bb.statements.last, rt = closure.return_type then
1041
let return_inferred = rt.is_inferred
1042
1043
if
1044
tail.provides_value /\
1045
!isa Trees.Statements.TRY(tail) /\
1046
!isa Trees.Statements.LABELLED(tail) /\
1047
!isa Trees.Statements.THROW(tail) /\
1048
!isa Trees.Statements.RETURN(tail) /\
1049
!Semantic.Symbols.state_machine_for(closure)? /\
1050
(
1051
return_inferred \/
1052
(
1053
!rt.is_sentinel /\
1054
!rt.matches(_innate_symbol_lookup.get_void_type())
1055
)
1056
)
1057
then
1058
bb.statements.compile_expressions_state.want_value = true
1059
bb.statements.compile_expressions_state.void_tolerated = true
1060
bb.statements.function_tail = true
1061
1062
if !return_inferred then
1063
bb.statements.set_expected_type(
1064
rt,
1065
"cannot return value of type {{0}} where {{1}} expected"
1066
)
1067
fi
1068
else
1069
// A literal walked first with nothing to judge
1070
// against, and re-walked once a void slot
1071
// settled its return, carries the tail demand
1072
// the first walk left behind. Clear it: a void
1073
// body has no tail to deliver, and the demand
1074
// would judge the tail against the void it is
1075
// discarded by.
1076
bb.statements.compile_expressions_state.want_value = false
1077
bb.statements.compile_expressions_state.void_tolerated = false
1078
bb.statements.function_tail = false
1079
fi
1080
fi
1081
fi
1082
1083
_logger.commit()
1084
_logger.speculate()
1085
1086
_symbol_use_locations.commit()
1087
_symbol_use_locations.speculate()
1088
1089
// Each body re-walk below must start from the narrowing
1090
// facts in force at the literal, not the ones the previous
1091
// walk recorded: a body ending in `return` leaves the
1092
// environment unreachable (a re-walk from there loses every
1093
// narrow in the body), and a body that unwraps its own
1094
// parameter leaves the recorded presence fact (a re-walk
1095
// over it misreports the unwrap redundant).
1096
let use flow_speculation = _flow.speculate_then_commit()
1097
1098
_walk_literal_body(function, closure)
1099
1100
if _expand_deeper_pack_body(function, closure) then
1101
let use retry_site = RETRY_SITE_STATS.enter("lambdas.carry_nested_pack", RetrySiteKind.REWALK_WITH_INFORMATION)
1102
_logger.roll_back()
1103
_logger.speculate()
1104
1105
_symbol_use_locations.roll_back()
1106
_symbol_use_locations.speculate()
1107
1108
_flow.restore()
1109
1110
CLEAR_STATE_VISITOR(true, true).apply(function.body)
1111
1112
_walk_literal_body(function, closure)
1113
fi
1114
1115
let reported_inference_failure = false
1116
1117
if closure.is_recursive then
1118
let use retry_site = RETRY_SITE_STATS.enter("lambdas.recursive_rewalk", RetrySiteKind.REWALK_WITH_INFORMATION)
1119
_logger.roll_back()
1120
_logger.speculate()
1121
1122
_symbol_use_locations.roll_back()
1123
_symbol_use_locations.speculate()
1124
1125
_flow.restore()
1126
1127
_walk_literal_body(function, closure)
1128
fi
1129
1130
if _build_flags.want_assembler /\ arguments_resolved /\ closure.could_be_delegate then
1131
// The roll_back below is for the re-walk's diagnostics,
1132
// which stand in for the first walk's: converting to a
1133
// delegate changes nothing the body resolves against, so
1134
// the two walks normally agree. Where they don't -
1135
// typically because something enclosing this closure is
1136
// still mid-retry and the second walk runs one step
1137
// behind it - the discarded walk still learned something
1138
// the retry loop needs to see, or it is simply the more
1139
// trustworthy of the two. Keep its progress-and-error
1140
// signal regardless of which walk the caller reads
1141
// diagnostics from.
1142
let use retry_site = RETRY_SITE_STATS.enter("lambdas.convert_to_delegate", RetrySiteKind.ALTERNATIVE)
1143
let first_walk_state = _logger.roll_back()
1144
1145
_logger.speculate()
1146
1147
_symbol_use_locations.roll_back()
1148
_symbol_use_locations.speculate()
1149
1150
_flow.restore()
1151
1152
closure.convert_to_delegate()
1153
1154
_walk_literal_body(function, closure)
1155
1156
_logger.mark_consumed_any_if(first_walk_state.has_consumed_any)
1157
1158
if first_walk_state.has_consumed_error then
1159
_logger.mark_consumed_error()
1160
fi
1161
fi
1162
1163
// Default an unresolved return type to void only when the
1164
// arguments are *fully* resolved — concrete types, not still
1165
// INFERRED_VARIABLE_TYPE placeholders. With placeholder args,
1166
// an unresolved return is the symptom of an identity-shaped
1167
// body (`a => a`) where the body offered no constraint and
1168
// we're depending on the call-site formal-arg-push to
1169
// resolve the args on the next outer iteration. Defaulting
1170
// the return to void here would lock in `*** -> void` and
1171
// poison the overload resolution that follows.
1172
if closure.return_type!.is_inferred /\ closure.arguments |> all(a => a.is_settled) then
1173
// A body whose tail failed to compile says nothing about what
1174
// the literal returns. Settled as void, the literal would
1175
// take a shape that a later walk, once the failure clears,
1176
// could not displace from a variable it was assigned to.
1177
let tail_value =
1178
if let block: Trees.Bodies.BLOCK = function.body then
1179
block.statements.last?.value
1180
elif let expression: Trees.Bodies.EXPRESSION = function.body then
1181
expression.expression.value
1182
else
1183
null
1184
fi
1185
1186
function.returned_only_null_without_slot = false
1187
1188
let null_join = Semantic.ARM_NULL_JOIN()
1189
1190
let tail_is_null =
1191
if let tail_type = tail_value?.type then
1192
null_join.is_genuine_null(tail_type)
1193
else
1194
false
1195
fi
1196
1197
if let tail_type = tail_value?.type /\ Semantic.OPERAND_WAIT.is_held_by(tail_type) then
1198
// The tail is a rule waiting for an operand the call
1199
// site types. Void is the answer for a body that
1200
// produced nothing, and this one has not answered yet:
1201
// the return stays inferred for the walk that settles
1202
// the operand to pin.
1203
elif let tail_type = tail_value?.type /\ tail_type.is_error then
1204
closure.set_return_type(Semantic.Types.ERROR())
1205
elif
1206
let from_slot = _slot_return_type(function) /\
1207
(tail_is_null \/ closure.returned_genuine_null)
1208
then
1209
// Every value the body produced was null, which says
1210
// the return can be absent without saying what it
1211
// holds when present. What it is optional of is the
1212
// slot's to say; void would be an answer the body
1213
// never gave.
1214
closure.set_return_type(from_slot)
1215
elif closure.returned_genuine_null then
1216
// Only null was returned, and with no slot to say
1217
// what the return is optional of there is no type to
1218
// settle it at.
1219
function.returned_only_null_without_slot = true
1220
1221
_logger.error(function.location, "cannot infer type here")
1222
1223
closure.set_return_type(Semantic.Types.ERROR())
1224
else
1225
closure.set_return_type(_innate_symbol_lookup.get_void_type())
1226
1227
// A recursive literal's self-call was compiled during
1228
// the body walks above, against a `$recurse` field
1229
// typed with the then-unresolved function type, and
1230
// the frozen call value keeps that stale composite —
1231
// set_return_type refreshes the field, not the IR
1232
// already recorded against it. With no value-producing
1233
// arm to settle the return mid-walk, this is the only
1234
// point the closure's type becomes final, so walk the
1235
// body once more to re-record the self-call at the
1236
// settled type.
1237
if closure.is_recursive then
1238
let use retry_site = RETRY_SITE_STATS.enter("lambdas.return_defaulted_recursive_rewalk", RetrySiteKind.REWALK_WITH_INFORMATION)
1239
_logger.roll_back()
1240
_logger.speculate()
1241
1242
_symbol_use_locations.roll_back()
1243
_symbol_use_locations.speculate()
1244
1245
_flow.restore()
1246
1247
_walk_literal_body(function, closure)
1248
fi
1249
fi
1250
fi
1251
1252
closure.unmap_type_arguments()
1253
1254
let value mut = closure.load(function.location, _symbol_loader)
1255
1256
// A literal whose body proved store-free surfaces at the
1257
// pure shape of its function type, so it satisfies a pure
1258
// function-typed slot on type alone — freezing to raw IL
1259
// has discarded the closure symbol by the time the slot
1260
// check sees the value. The shape is the literal's own
1261
// property, so it does not depend on the slot it is
1262
// heading for: a store-free literal reads as pure
1263
// wherever its type is shown.
1264
if
1265
!closure.literal_body_impure /\ value.type?
1266
then
1267
let pure_type = Semantic.Types.PURE_FUNCTION_SHAPE.pure_shape_of(value.type, _innate_symbol_lookup)
1268
1269
if pure_type? then
1270
value = IR.Values.TYPE_WRAPPER(pure_type, value)
1271
fi
1272
fi
1273
1274
// The first resolve of a call taking this literal fails on its
1275
// arity, and the retry that follows mints a placeholder for
1276
// each of the callee's type arguments. Later walks resolve
1277
// plainly and never reach the one standing for the formal's
1278
// return, so the literal's own settled return is what it is
1279
// bounded by - once, since a bound offered on every walk
1280
// reads as progress and keeps the body from converging.
1281
if closure.packed_parameters? then
1282
if let expected = function.expected_type /\ expected.is_function /\ !expected.is_action then
1283
if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected.arguments[expected.arguments.count - 1] then
1284
if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin, returned = closure.return_type then
1285
if returned.is_settled /\ !returned.is_void /\ !_is_origin_settled(origin) then
1286
_logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_literal_return", origin, returned))
1287
fi
1288
fi
1289
fi
1290
fi
1291
fi
1292
1293
cast IR.Values.WRAPPER?(function.value)!.value = value
1294
si
1295
1296
// visit_function re-runs on every retry of the enclosing
1297
// function's body (a lambda literal is re-walked along with
1298
// everything else in the body until the retry loop converges),
1299
// so guard on custom_attributes already being populated —
1300
// otherwise the same attribute would be resolved and appended
1301
// again on each retry.
1302
_resolve_argument_attributes(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) is
1303
for expr in function.arguments.expressions do
1304
if let argument: Trees.Expressions.VARIABLE = expr, pragmas = argument.pragmas then
1305
// Trees.Expressions.FUNCTION.pre() suppresses the
1306
// default child walk (so visit_function can walk
1307
// the body up to N times), so nothing else ever
1308
// walks a pragma's own argument expressions.
1309
for pragma in pragmas do
1310
pragma.walk(_visitor)
1311
od
1312
1313
let symbol = closure.find_direct(argument.name.name)
1314
1315
if symbol? /\ !symbol.custom_attributes? then
1316
for pragma in pragmas do
1317
_attribute_resolver.resolve(pragma, symbol)
1318
od
1319
fi
1320
fi
1321
od
1322
si
1323
1324
// Walk a literal's body with a purity frame in force, so the
1325
// flow transfers record whether the body performed anything
1326
// possibly heap-visible. Re-walks (recursion, delegate
1327
// conversion) overwrite the recorded flag — the last walk is
1328
// the one whose compilation stands.
1329
_walk_literal_body(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) is
1330
_flow.push_literal_frame()
1331
1332
closure.enter_literal_body()
1333
function.body.walk(_visitor)
1334
closure.leave_literal_body()
1335
1336
closure.literal_body_impure = _flow.pop_literal_frame()
1337
si
1338
1339
// A nested named function referring to itself, by its own name.
1340
// The name is a local of the enclosing body that nothing assigns
1341
// until the definition statement completes, so the value comes
1342
// from the closure's recurse field, the same place `rec` reads
1343
// it. Returns null for every other reference to the name -
1344
// a call from the enclosing body after the definition, or from a
1345
// sibling function - which the ordinary local load serves.
1346
try_load_self_reference(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol) -> IR.Values.Value? is
1347
let stack = _symbol_table.stack
1348
let index mut = stack.count - 1
1349
1350
while index >= 0 do
1351
let scope = stack[index]
1352
1353
if let target: Semantic.Symbols.Closure = scope then
1354
if target.self_reference_variable? /\ target.self_reference_variable == symbol then
1355
return _load_recurse_from(location, target)
1356
fi
1357
fi
1358
1359
index = index - 1
1360
od
1361
1362
return null
1363
si
1364
1365
// The recurse value for a closure, read from wherever the walk
1366
// currently is. Inside that closure's own body it is its recurse
1367
// field; from a literal written inside it, the field has to be
1368
// threaded down through every frame in between, so each one in
1369
// the chain captures it.
1370
//
1371
// A null target means the nearest recursive ancestor, which is
1372
// what `rec` names. A nested named function names one closure in
1373
// particular, so it passes that one.
1374
_load_recurse_from(location: Source.LOCATION, target: Semantic.Symbols.Closure?) -> IR.Values.Value? is
1375
let function = _symbol_table.current_function
1376
1377
if !function? \/ !function.is_closure then
1378
return null
1379
fi
1380
1381
let closure = cast Semantic.Symbols.Closure?(function)!
1382
1383
let is_target = (candidate: Semantic.Symbols.Closure) -> bool =>
1384
if let wanted = target then
1385
candidate == wanted
1386
else
1387
candidate.is_recursive
1388
fi
1389
1390
if is_target(closure) then
1391
return closure.load_recurse(location, _symbol_loader)
1392
fi
1393
1394
let stack = _symbol_table.stack
1395
let index mut = stack.count - 1
1396
let seen_self mut = false
1397
let intermediates = Collections.LIST[Semantic.Symbols.Closure]()
1398
1399
while index >= 0 do
1400
let scope = stack[index]
1401
1402
if let c: Semantic.Symbols.Closure = scope then
1403
if seen_self then
1404
if is_target(c) then
1405
for intermediate in intermediates do
1406
intermediate.find_or_add_captured_outer_recurse(c)
1407
od
1408
1409
return closure.load_captured_outer_recurse(location, c, _symbol_loader)
1410
fi
1411
1412
intermediates.add(c)
1413
elif c == closure then
1414
seen_self = true
1415
fi
1416
fi
1417
1418
index = index - 1
1419
od
1420
1421
return null
1422
si
1423
1424
visit_recurse(recurse: Trees.Expressions.RECURSE) is
1425
let function = _symbol_table.current_function
1426
1427
if !function? \/ !function.is_closure then
1428
recurse.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), recurse.location)
1429
1430
_logger.error(recurse.location, "rec can only be used in a function literal body")
1431
return
1432
fi
1433
1434
if let value = _load_recurse_from(recurse.location, null) then
1435
recurse.compile_expressions_state.value = value
1436
return
1437
fi
1438
1439
recurse.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), recurse.location)
1440
1441
_logger.error(recurse.location, "rec can only be used in a recursive function")
1442
si
1443
si
1444
si