Skip to content
← Back

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

1
namespace Syntax.Process is
2
use System.Exception
3
use Ghul.Disposable
4
5
use IO.Std
6
7
use Logging
8
use Source
9
10
use IR.Values
11
use IR.VALUE_CONVERTER
12
use IR.VALUE_BOXER
13
14
use Semantic.LEAST_UPPER_BOUND_MAP
15
use Semantic.Types.Type
16
17
use Syntax.Trees.Definitions.PRAGMA
18
19
use Ghul.Pipes
20
21
22
// Expression walks: function literals, tuples, sequences, self, super, spill, await, cast,
23
// isa, typeof, operators, indexing, member access, generic applications and literals.
24
partial COMPILE_EXPRESSIONS is
25
pre(function: Trees.Expressions.FUNCTION) -> bool is
26
// Push a function-literal boundary marker on the val-
27
// block stack. A `return` inside this lambda's body
28
// looks up the innermost val-block via the top of the
29
// stack; the null marker reports "no val-block target"
30
// and the return falls through to the function-return
31
// path — exiting the lambda, not the enclosing val-
32
// block.
33
_val_block_stack.add(null)
34
35
return true
36
si
37
38
visit(function: Trees.Expressions.FUNCTION) is
39
let mark = _logger.mark()
40
let use uses_guard = _symbol_use_locations.mark_then_release()
41
42
// The lambda body walks under the enclosing method's
43
// environment (a closure may soundly observe a narrow
44
// in force at its construction point), but its own ifs /
45
// assignments / divergence must not leak back out — so
46
// the enclosing environment is saved and restored.
47
//
48
// The tracked deferred-init locals are deliberately NOT
49
// swapped out. Closures capture by value at construction
50
// time, so the closure body walking under `saved_env`
51
// observes exactly the definite-assignment facts in
52
// force where the closure is built — reading a captured
53
// local that is unassigned there is a genuine
54
// use-before-assignment (the closure captured a
55
// not-yet-assigned value), not a false positive.
56
let saved_env = _flow.current_env.copy()
57
58
try
59
RETRY_SITE_STATS.note("expressions.function_literal")
60
_logger.speculate()
61
_symbol_use_locations.speculate()
62
63
super.pre(function)
64
65
_lambdas.visit_function(function)
66
67
// The lambda's signature is settled by the line above,
68
// so this is the first point at which an async one is
69
// known to have a state machine — and the last before
70
// its body walks. A named async function's frame is
71
// realised at the equivalent point in
72
// visit(Definitions.FUNCTION); without the same here,
73
// the frame's constructor is first declared while the
74
// body is emitted, long after its row would have been
75
// numbered.
76
_declare_lambda_state_machine_frame(function)
77
78
super.visit(function)
79
80
_logger.commit()
81
_symbol_use_locations.commit()
82
catch e: Exception
83
function.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), function.location)
84
_logger.release(mark)
85
86
_logger.exception(function.location, e, "exception compiling function literal")
87
yrt
88
89
_flow.set_env(saved_env)
90
91
// Pop the function-literal boundary marker pushed by
92
// pre(FUNCTION). After this point an outer val-block
93
// (if any) is once again the innermost return target.
94
assert _val_block_stack.count > 0 else "val_block_stack underflow at function literal exit"
95
assert !_val_block_stack[_val_block_stack.count - 1]? else "val_block_stack head is not the function-literal marker"
96
_val_block_stack.remove_at(_val_block_stack.count - 1)
97
si
98
99
// See COMPILE_LAMBDAS.try_load_self_reference. Reached from the
100
// identifier load, which cannot see the lambda machinery itself.
101
try_load_self_reference(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol) -> IR.Values.Value? =>
102
_lambdas.try_load_self_reference(location, symbol)
103
104
visit(recurse: Trees.Expressions.RECURSE) is
105
_lambdas.visit_recurse(recurse)
106
si
107
108
pre(tuple: Trees.Expressions.TUPLE) -> bool =>
109
_tuples.pre_tuple(tuple)
110
111
visit(tuple: Trees.Expressions.TUPLE) is
112
_tuples.visit_tuple(tuple)
113
si
114
115
pre(sequence: Trees.Expressions.SEQUENCE) -> bool => true
116
visit(sequence: Trees.Expressions.SEQUENCE) is
117
let mark = _logger.mark()
118
119
try
120
RETRY_SITE_STATS.note("expressions.sequence")
121
_logger.speculate()
122
123
super.pre(sequence)
124
125
sequence.type_expression.walk(self)
126
127
// If the sequence is going to compile against a known
128
// list/array type — either an inline type annotation
129
// (`[1, 2, 3]: int[]`) or a constraint pushed by the
130
// surrounding context (typed initializer / list-of-
131
// lambdas) — push the corresponding element type down
132
// to each element as its own constraint. Constraint-
133
// aware element types (notably function literals) use
134
// it to infer their argument types; element types that
135
// ignore constraint (most literals) are unaffected.
136
let element_constraint: Type? mut = _
137
138
if let sequence.type_expression? /\ !isa Trees.TypeExpressions.INFER(type_expression), type_expression.type? then
139
element_constraint = type.get_element_type()
140
elif let sequence.expected_type? then
141
element_constraint = expected_type.get_element_type()
142
fi
143
144
for e in sequence.elements do
145
if element_constraint? then
146
e.set_expected_type(element_constraint, "element type {{0}} not compatible with inferred list type {{1}}")
147
else
148
e.clear_expected_type()
149
fi
150
od
151
152
sequence.elements.walk(self)
153
154
_tuples.visit_sequence(sequence)
155
156
_logger.commit()
157
catch e: Exception
158
sequence.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), sequence.location)
159
_logger.release(mark)
160
161
_logger.exception(sequence.location, e, "exception compiling call")
162
yrt
163
si
164
165
visit(`self: Trees.Expressions.SELF) is
166
let s = current_instance_context
167
168
let type: Type? mut = null
169
170
if s? then
171
let f = current_function
172
173
if !f? \/ !f.is_instance then
174
_logger.error(`self.location, "cannot access self from non-instance context")
175
fi
176
177
// A closure body that reads `self` is self-dependent even
178
// if it captures no values (e.g. `() => self`), so its
179
// delegate must not be memoized and shared across receivers.
180
if let closure: Semantic.Symbols.Closure = f then
181
closure.note_delegate_body_loads_self()
182
fi
183
184
if s.argument_names.count > 0 then
185
let arguments = Collections.LIST[Type]()
186
187
for n in s.argument_names do
188
let argument = s.find_member(n)
189
let argument_type = if argument? then argument.type else null fi
190
191
if argument? /\ argument.is_type_variable /\ argument_type? then
192
arguments.add(argument_type)
193
fi
194
od
195
196
if arguments.count == s.argument_names.count then
197
type = Semantic.Types.GENERIC(
198
`self.location,
199
cast Semantic.Symbols.Classy(s),
200
arguments)
201
fi
202
fi
203
204
// A flow narrowing on `self` (keyed on its instance
205
// context) presents `self` at the narrowed type, so
206
// `isa`/destructure and member access see the variant.
207
// A bare variant narrow (`CONS`) is specialised against
208
// `self`'s closed type (`List[T]`) so it resolves to its
209
// closed-generic form (`CONS[T]`) for a loadable reference.
210
if let narrowed = _flow.current_env.narrowed_type_of(s) then
211
if type? then
212
type = _condition_analyzer.specialize_variant_for_receiver(type, narrowed)
213
else
214
type = narrowed
215
fi
216
fi
217
218
// Generator instance methods read `self` from the
219
// frame's _outer_self field — the state-machine's
220
// ldarg.0 is the state machine itself, not the
221
// user instance.
222
let state_machine = Semantic.Symbols.state_machine_for(current_function)
223
224
if state_machine? /\ state_machine.frame? /\ !s.is_value_type then
225
if let frame = state_machine.frame then
226
frame.declare()
227
228
if frame.outer_self_field? then
229
`self.compile_expressions_state.value = Load.OUTER_SELF(s, type, frame.outer_self_field)
230
fi
231
fi
232
fi
233
234
if !`self.value? then
235
if s.is_value_type then
236
`self.compile_expressions_state.value =
237
Load.VALUE_SELF(
238
s, type
239
)
240
else
241
`self.compile_expressions_state.value =
242
Load.REFERENCE_SELF(
243
s, type
244
)
245
fi
246
fi
247
248
// FIXME: this breaks VSCode rename symbol:
249
// _symbol_use_locations.add_symbol_use(`self.location, s);
250
else
251
_logger.error(`self.location, "cannot access self from non-instance context")
252
fi
253
si
254
255
visit(`super: Trees.Expressions.SUPER) is
256
// FIXME:
257
let s = _symbol_table.current_instance_context
258
259
if s? then
260
if s.is_trait then
261
_logger.error(`super.location, "{s.short_description} does not have a super class")
262
263
return
264
fi
265
266
let `classy = cast Semantic.Symbols.Classy(s)
267
let super_type mut = `classy.ancestors[0]
268
269
// If the enclosing method overrides exactly one trait method,
270
// prefer that trait as the super type so super.foo() resolves
271
// to the trait's default body and emits as a non-virtual
272
// `call` (.NET DIM). Class-chain super stays on `ancestors[0]`
273
// because that already specialises generic base types — using
274
// the overridee's owner type would lose the specialisation.
275
let current = current_function
276
if current? /\ current.overridees? then
277
let overridee_count = current.overridees |> count()
278
if overridee_count == 1 then
279
let overridee = current.overridees |> first()
280
if overridee? /\ isa Semantic.Symbols.Classy(overridee.owner) then
281
let owner = cast Semantic.Symbols.Classy(overridee.owner)
282
let owner_type = owner.type
283
284
if owner.is_trait /\ owner_type? then
285
super_type = owner_type
286
fi
287
fi
288
fi
289
fi
290
291
`super.compile_expressions_state.value = Load.SUPER(s, super_type)
292
293
// FIXME: breaks VSCode rename symbol:
294
// _symbol_use_locations.add_symbol_use(`super.location, s);
295
fi
296
si
297
298
// SPILL is synthesised by the SPILL_AWAITS pass, in the
299
// rewrite-syntax-trees phase, so one is already in the tree by
300
// the time this runs. It types as a transparent wrapper over
301
// its operand; generate-il emits the operand eagerly and stores
302
// the result in the frame field allocated here.
303
visit(spill: Trees.Expressions.SPILL) is
304
spill.compile_expressions_state.value = null
305
306
let operand_value = spill.operand.value
307
308
if !operand_value? \/ !operand_value.type? then
309
spill.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), spill.location)
310
return
311
fi
312
313
// The receiver of a static call names a type rather than
314
// holding a value, so there is nothing on the stack for the
315
// suspend to lose and nothing a frame field could hold.
316
// Pass it through untouched.
317
if operand_value.is_type_expression then
318
spill.compile_expressions_state.value = operand_value
319
return
320
fi
321
322
_declare_spill_field(spill, operand_value.type)
323
324
spill.compile_expressions_state.value = IR.Values.WRAPPER(DUMMY(operand_value.type!, spill.location))
325
si
326
327
visit(`await: Trees.Expressions.AWAIT) is
328
`await.compile_expressions_state.value = null
329
330
let operand_value = `await.operand.value
331
332
if !operand_value? \/ !operand_value.type? then
333
`await.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `await.location)
334
return
335
fi
336
337
let operand_type = operand_value.type
338
339
let awaitable = _awaitable_resolver.resolve(`await.location, operand_type)
340
341
if !awaitable? then
342
`await.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `await.location)
343
return
344
fi
345
346
`await.awaitable = awaitable
347
348
let element_type = awaitable.result_type
349
350
if !element_type.is_void then
351
_declare_await_result_field(`await, element_type)
352
fi
353
354
_declare_awaiter_field(`await, awaitable.awaiter_type)
355
356
// Generate-il fills the wrapper with IR.Values.AWAIT_SUSPEND
357
// when emitting the SM body. The wrapper carries the result
358
// type so surrounding expressions / let-bindings see the
359
// right type at compile-expressions time.
360
`await.compile_expressions_state.value = IR.Values.WRAPPER(DUMMY(element_type, `await.location))
361
si
362
363
// The `cast` keyword's own span. A CAST's location runs to the
364
// closing parenthesis, and the node keeps no separate span for
365
// the keyword, so it is derived: the location starts at the
366
// keyword, which is four characters wide, and a span's end
367
// column is inclusive.
368
_cast_keyword_location(`cast: Trees.Expressions.CAST) -> Source.LOCATION =>
369
Source.LOCATION(
370
`cast.location.file_name,
371
`cast.location.start_line,
372
`cast.location.start_column,
373
`cast.location.start_line,
374
`cast.location.start_column + 3
375
)
376
377
visit(`cast: Trees.Expressions.CAST) is
378
`cast.compile_expressions_state.value = null
379
380
// `cast (X)(args)` settled as a call of the cast value: the
381
// written-out reading was walked as this node's only child,
382
// so its value is this node's value.
383
if `cast.reading == Trees.Expressions.CastReading.CALLED then
384
`cast.compile_expressions_state.value = `cast.called_form!.value
385
386
return
387
fi
388
389
// `cast(v)` writes no target type and takes the one its
390
// context supplies, the way a bare `_` does. Nothing has
391
// pushed one in on the first walk of a call argument or an
392
// operator operand, so the error here is what tells the
393
// consumer this node is still waiting; the consumer rolls
394
// it back and re-walks once resolution has settled on a
395
// formal type.
396
let type mut =
397
if `cast.type_expression? then
398
`cast.type_expression.type
399
else
400
`cast.expected_type
401
fi
402
403
if !type? then
404
`cast.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `cast.location)
405
406
if `cast.type_expression? then
407
_logger.error(`cast.type_expression.location, "cast has no type")
408
else
409
_logger.error(`cast.location, "cannot infer the type to cast to here")
410
fi
411
412
return
413
fi
414
415
// The slot a typeless cast takes its target from can still
416
// hold an inference placeholder - the element type of a
417
// `LIST()` that a sibling `add` settles, say. A placeholder
418
// cannot be named in an instruction, so it is no more of a
419
// target than a missing one: report, and flag the walk as
420
// having consumed an unresolved type so the body-retry loop
421
// walks again once the placeholder has settled.
422
if !`cast.type_expression? /\ type.contains_inferred then
423
_logger.mark_consumed_any()
424
_logger.error(`cast.location, "cannot infer the type to cast to here")
425
426
`cast.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `cast.location)
427
428
return
429
fi
430
431
if `cast.type_expression? then
432
`cast.type_expression.check_is_not_reference(_logger, "cannot cast to a reference type")
433
else
434
// The target type is written nowhere, so hover over the
435
// keyword is where the reader sees what it resolved to.
436
// Recorded over the keyword alone rather than the whole
437
// expression, so hovering the value being converted
438
// still describes the value.
439
_symbol_use_locations.add_inferred_type_hover(_cast_keyword_location(`cast), type)
440
fi
441
442
let right_value = `cast.right.value
443
444
if !right_value? \/ !right_value.type? then
445
_logger.poison(`cast.right.location, "cast has no value")
446
447
return
448
fi
449
450
let specialized = _condition_analyzer.specialize_variant_for_receiver(
451
right_value.type,
452
type
453
)
454
455
if specialized? then
456
type = specialized
457
fi
458
459
// just check the cast is possible at this stage
460
_type_caster.check_cast_is_valid(`cast.location, right_value.type!, type)
461
462
// Warn when the cast can never succeed at runtime: the source's
463
// statically-known type is sealed enough that we can rule out
464
// any subtype that satisfies the target. The conservative form
465
// is a value-type source against a *reference* target that
466
// isn't one of its boxed-form ancestors — a value type's
467
// runtime type is its declared type, so `cast string(42)` and
468
// similar are unconditionally a null result. Value→value
469
// casts go through the numeric-conversion path in TYPE_CASTER
470
// and are left to that check; reference-source casts stay
471
// unwarned because the runtime value may be a subtype
472
// unrelated to the declared source.
473
//
474
// Skip the warning when the source is optional — `T?` to
475
// a reference target lowers to boxing the Nullable<T>
476
// (null when absent, the boxed T when present), which the
477
// CLR supports unconditionally. The strict non-nullable-
478
// by-default rule rejects `T? → T` at slot assignment, but
479
// an explicit cast expressing the boxing is sound and the
480
// warning would be a false positive.
481
let source_type = right_value.type
482
483
let is_impossible_cast =
484
source_type? /\
485
source_type.is_settled /\ !source_type.is_type_variable /\
486
!source_type.is_sentinel /\ !source_type.is_error /\
487
type.is_settled /\ !type.is_type_variable /\
488
!type.is_sentinel /\ !type.is_error /\
489
source_type.is_value_type /\ !type.is_value_type /\
490
!source_type.is_optional /\
491
!type.is_assignable_from(source_type) /\
492
!source_type.is_assignable_from(type) /\
493
!_type_caster.find_user_defined_conversion(source_type, type)?
494
495
if !_build_flags.no_warn_impossible_cast /\ is_impossible_cast then
496
_logger.warn(
497
`cast.location,
498
"impossible-cast",
499
"cast from {source_type} to {type} can never succeed"
500
)
501
fi
502
503
// A cast to a non-optional reference target throws when it
504
// fails, so a site that means "null on failure" wants
505
// `cast T?(...)`, which says so at the type level and lets the
506
// strict-optional slot check catch misuses where the value is
507
// stored. Skipped when the target is not a non-optional
508
// reference - `cast T?(...)` is the fix rather than a target of
509
// the warning, and a value-type or type-variable target does
510
// not throw - when the source is statically assignable to the
511
// target, so the cast is provably safe, and when the
512
// impossible-cast form already reported the site, since that
513
// message subsumes this one. A cast at an internal location was
514
// written by the compiler rather than by the user, who has
515
// nowhere to apply the advice.
516
if
517
!_build_flags.no_warn_cast_may_throw /\
518
!`cast.location.is_internal /\
519
!is_impossible_cast /\
520
source_type? /\
521
source_type.is_settled /\ !source_type.is_type_variable /\
522
!source_type.is_sentinel /\ !source_type.is_error /\
523
_is_non_optional_reference(type) /\
524
!_cast_target_covers_source(type, source_type)
525
then
526
let target = type
527
_logger.warn(
528
`cast.location,
529
"cast-may-throw",
530
"cast to non-optional {target} may throw",
531
`cast.location,
532
"help: use cast {target}? for null on failure"
533
)
534
fi
535
536
// we will fill this wrapper with the actual code to cast in the generate IL pass:
537
`cast.compile_expressions_state.value =
538
IR.Values.WRAPPER(DUMMY(type, `cast.location))
539
si
540
541
visit(`isa: Trees.Expressions.ISA) is
542
// Stamp the log position the test is walked at, so facts
543
// formed from it skip the calls that ran before it.
544
_flow.note_test_site(`isa)
545
546
`isa.compile_expressions_state.value = null
547
548
let isa_type mut = `isa.type_expression.type
549
550
if isa_type == null then
551
_logger.error(`isa.type_expression.location, "isa has no type")
552
`isa.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `isa.location)
553
return
554
fi
555
556
if let `isa.right?, right.value?, value.type? then
557
let specialized = _condition_analyzer.specialize_variant_for_receiver(
558
type,
559
isa_type
560
)
561
562
if specialized? then
563
isa_type = specialized
564
fi
565
fi
566
567
let bool_type = _innate_symbol_lookup.get_bool_type()
568
569
`isa.compile_expressions_state.value =
570
ISA(
571
bool_type,
572
isa_type,
573
`isa.right.value!
574
)
575
si
576
577
visit(`typeof: Trees.Expressions.TYPEOF) is
578
`typeof.compile_expressions_state.value = null
579
580
let typeof_type = `typeof.type_expression.type
581
582
if !typeof_type? then
583
_logger.error(`typeof.type_expression.location, "typeof has no type")
584
`typeof.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), `typeof.location)
585
return
586
fi
587
588
let type_type = _innate_symbol_lookup.get_type_type()
589
590
`typeof.compile_expressions_state.value =
591
TYPEOF(
592
type_type,
593
typeof_type
594
)
595
si
596
597
visit(construct: Trees.Expressions.CONSTRUCT) is
598
_calls.visit_construct(construct)
599
_check_pure_slots(construct.location, construct.value, construct.arguments)
600
_note_call(construct.location, construct.value)
601
si
602
603
visit(unary: Trees.Expressions.UNARY) is
604
_operators.visit_unary(unary)
605
_check_pure_slots(unary.location, unary.value, null)
606
_note_call(unary.location, unary.value)
607
si
608
609
pre(binary: Trees.Expressions.BINARY) -> bool is
610
return _operators.pre_binary(binary)
611
si
612
613
visit(binary: Trees.Expressions.BINARY) is
614
try
615
_operators.visit_binary(binary)
616
_check_pure_slots(binary.location, binary.value, null)
617
_note_call(binary.location, binary.value)
618
catch ex: Exception
619
_logger.exception(binary.location, ex, "exception compiling binary operator (called from {System.Diagnostics.StackTrace().to_string().replace_line_endings(" ")})")
620
yrt
621
si
622
623
visit(field_equals: Trees.Expressions.FIELD_EQUALS) is
624
try
625
_operators.visit_field_equals(field_equals)
626
_note_call(field_equals.location, field_equals.value)
627
catch ex: Exception
628
_logger.exception(field_equals.location, ex, "exception compiling field comparison (called from {System.Diagnostics.StackTrace().to_string().replace_line_endings(" ")})")
629
yrt
630
si
631
632
visit(memberwise_equals: Trees.Expressions.MEMBERWISE_EQUALS) is
633
try
634
_operators.visit_memberwise_equals(memberwise_equals)
635
_note_call(memberwise_equals.location, memberwise_equals.value)
636
catch ex: Exception
637
_logger.exception(memberwise_equals.location, ex, "exception compiling synthesized equality")
638
yrt
639
si
640
641
visit(memberwise_hash: Trees.Expressions.MEMBERWISE_HASH) is
642
try
643
_operators.visit_memberwise_hash(memberwise_hash)
644
_note_call(memberwise_hash.location, memberwise_hash.value)
645
catch ex: Exception
646
_logger.exception(memberwise_hash.location, ex, "exception compiling synthesized hash")
647
yrt
648
si
649
650
visit(hash_operand: Trees.Expressions.HASH_OPERAND) is
651
try
652
_operators.visit_hash_operand(hash_operand)
653
_note_call(hash_operand.location, hash_operand.value)
654
catch ex: Exception
655
_logger.exception(hash_operand.location, ex, "exception compiling hash operand (called from {System.Diagnostics.StackTrace().to_string().replace_line_endings(" ")})")
656
yrt
657
si
658
659
// Build a value-equality test Value for a `case` `when` label,
660
// the way `=~` (or `<>`, compared to zero) would. Forwards to
661
// the shared operator machinery so `case` reuses the same
662
// null-safe lowering and resolution as the `=~` operator. See
663
// COMPILE_OPERATORS._try_equality_test.
664
//
665
// No source token in either caller names the operator, so the
666
// operator use is recorded at whatever location the caller
667
// hands in: the whole `case` arm for a label, the leaf itself
668
// for a literal destructure, colouring that span as a method
669
// call. Suppress symbol-use recording for the whole build. A
670
// written `=~` is unaffected because the suppression is scoped
671
// to this call frame: the binary-operator visitor records its
672
// use outside it, whichever lowering it takes (including
673
// _build_null_safe_equality, which this builder also reaches).
674
build_equality_test(
675
left_value: IR.Values.Value,
676
right_value: IR.Values.Value,
677
op_name: string,
678
location: Source.LOCATION
679
) -> IR.Values.Value? is
680
_symbol_use_locations.begin_suppress()
681
682
try
683
return _operators._try_equality_test(left_value, right_value, op_name, location)
684
finally
685
_symbol_use_locations.end_suppress()
686
yrt
687
si
688
689
pre(index: Trees.Expressions.INDEX) -> bool =>
690
_operators.pre_index(index)
691
692
visit(index: Trees.Expressions.INDEX) is
693
try
694
_operators.visit_index(index)
695
check_receiver_present(index.left)
696
_check_pure_slots(index.location, index.value, null)
697
_note_call(index.location, index.value)
698
catch e: Exception
699
index.compile_expressions_state.value = null
700
701
_logger.exception(index.location, e, "exception compiling index")
702
yrt
703
si
704
705
visit(member: Trees.Expressions.MEMBER) is
706
_access.visit_member(member)
707
_note_call(member.location, member.value)
708
si
709
710
pre(ambiguous_expression: Trees.Expressions.AMBIGUOUS_EXPRESSION) -> bool =>
711
_generic_application.pre_ambiguous_expression(ambiguous_expression)
712
713
visit(ambiguous_expression: Trees.Expressions.AMBIGUOUS_EXPRESSION) is
714
si
715
716
pre(generic_application: Trees.Expressions.GENERIC_APPLICATION) -> bool =>
717
_generic_application.pre_generic_application(generic_application)
718
719
visit(generic_application: Trees.Expressions.GENERIC_APPLICATION) is
720
si
721
722
visit(integer: Trees.Expressions.Literals.INTEGER) is
723
_literals.visit_integer(integer)
724
si
725
726
visit(float: Trees.Expressions.Literals.FLOAT) is
727
_literals.visit_float(float)
728
si
729
730
visit(interpolation: Trees.Expressions.STRING_INTERPOLATION) is
731
_literals.visit_interpolation(interpolation)
732
733
// An alignment clause is handed to the interpolation
734
// handler's int parameter as-is, so a non-int alignment
735
// has to be rejected here rather than reach emission.
736
let int_type = _innate_symbol_lookup.get_int_type()
737
738
for fragment in interpolation.values do
739
if !fragment.is_expression then
740
continue
741
fi
742
743
if let alignment = fragment.alignment then
744
if let alignment_type = alignment.value?.type then
745
if !alignment_type.is_error /\ !alignment_type.is_inferred /\
746
alignment_type.compare(int_type) != Semantic.Types.MATCH.SAME then
747
_logger.error(
748
alignment.location,
749
"interpolation alignment must be int, not {alignment_type}")
750
fi
751
fi
752
fi
753
od
754
755
// Interpolation formats each fragment through to_string at
756
// run time, but those calls are synthesised at emission and
757
// never surface as call values here, so the call transfer
758
// has to fire for them. Each fragment is recorded against
759
// the to_string it will dispatch to, so the judge can
760
// discharge it like any other call; a fragment whose target
761
// cannot be named records an unbounded crossing instead.
762
_note_interpolation_calls(interpolation)
763
si
764
765
_note_interpolation_calls(interpolation: Trees.Expressions.STRING_INTERPOLATION) is
766
for fragment in interpolation.values do
767
if !fragment.is_expression then
768
continue
769
fi
770
771
// a format specifier selects a different, culture-aware
772
// formatting path
773
if fragment.format? then
774
_flow.on_call(interpolation.location)
775
return
776
fi
777
778
let fragment_type = fragment.expression.value?.type
779
780
if !fragment_type? then
781
_flow.on_call(interpolation.location)
782
return
783
fi
784
785
let to_string = _zero_argument_to_string(fragment_type.find_member("to_string"))
786
787
if !to_string? then
788
_flow.on_call(interpolation.location)
789
return
790
fi
791
792
// same structural gate as _note_call
793
if to_string.is_store_free then
794
continue
795
fi
796
797
_flow.on_call_of(interpolation.location, to_string)
798
od
799
si
800
801
// The zero-argument to_string a fragment formats through.
802
_zero_argument_to_string(member: Semantic.Symbols.Symbol?) -> Semantic.Symbols.Function? is
803
if let group: Semantic.Symbols.FUNCTION_GROUP = member then
804
for function in group.functions do
805
if !function.are_arguments_declared \/ function.arguments.count == 0 then
806
return function
807
fi
808
od
809
810
return null
811
fi
812
813
if let function: Semantic.Symbols.Function = member then
814
if !function.are_arguments_declared \/ function.arguments.count == 0 then
815
return function
816
fi
817
fi
818
819
return null
820
si
821
822
visit(`string: Trees.Expressions.Literals.STRING) is
823
_literals.visit_string(`string)
824
si
825
826
visit(character: Trees.Expressions.Literals.CHARACTER) is
827
_literals.visit_character(character)
828
si
829
830
visit(boolean: Trees.Expressions.Literals.BOOLEAN) is
831
_literals.visit_boolean(boolean)
832
si
833
834
si
835
si