Skip to content
← Back

src/syntax/process/declare_members.ghul

1
namespace Syntax.Process is
2
use Logging;
3
use Source;
4
use Trees;
5
6
// Declares everything below type level: functions, properties, fields,
7
// enum members, and the block scopes, locals and closures inside
8
// bodies. Runs after resolve-uses - the declare-symbols pass declares
9
// only the type-level skeleton (namespaces, types, variants, type
10
// parameters), so by the time members are declared every import is
11
// bound and an impl/partial block's target name can be reached through
12
// a use import and declared anywhere.
13
//
14
// The inherited ScopedVisitor handlers enter the scopes declare-symbols
15
// associated with the type-level nodes; the overrides here declare the
16
// member-level symbols into them. impl and partial blocks are handled
17
// in place: the target resolves against the block's write site, and the
18
// block's members are declared into it through an injection scope.
19
class DECLARE_MEMBERS: ScopedVisitor is
20
_logger: Logger;
21
_symbol_definition_listener: Semantic.SymbolDefinitionListener;
22
_symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS;
23
_local_id_generator: IR.LOCAL_ID_GENERATOR;
24
25
_anon_index: int;
26
_pragma_scope_stack: PRAGMA_SCOPE_STACK;
27
_generic_argument_declarer: GENERIC_ARGUMENT_DECLARER;
28
29
init(
30
logger: Logger,
31
symbol_table: Semantic.SYMBOL_TABLE,
32
namespaces: Semantic.NAMESPACES,
33
symbol_definition_listener: Semantic.SymbolDefinitionListener,
34
symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS,
35
local_id_generator: IR.LOCAL_ID_GENERATOR
36
) is
37
super.init(logger, symbol_table, namespaces);
38
39
_logger = logger;
40
_symbol_definition_listener = symbol_definition_listener;
41
_symbol_use_locations = symbol_use_locations;
42
_local_id_generator = local_id_generator;
43
44
_pragma_scope_stack = PRAGMA_SCOPE_STACK();
45
_generic_argument_declarer = GENERIC_ARGUMENT_DECLARER(logger, symbol_table, symbol_definition_listener);
46
si
47
48
apply(node: Node) is
49
assert _pragma_scope_stack.is_balanced;
50
51
node.walk(self);
52
53
assert _pragma_scope_stack.is_balanced;
54
si
55
56
next_anon_name() -> string is
57
let result = "$anon_{_anon_index}";
58
_anon_index = _anon_index + 1;
59
return result;
60
si
61
62
// `_` is a discard placeholder: every occurrence
63
// gets its own unique slot so the redefinition check doesn't
64
// fire and there's no shared name for code to read from. Used
65
// in `let _ = expr`, tuple destructure (`let (_, _, z) = ...`),
66
// and lambda parameters.
67
next_discard_name() -> string is
68
let result = "$discard_{_anon_index}";
69
_anon_index = _anon_index + 1;
70
return result;
71
si
72
73
// Name of the single physical parameter slot backing a
74
// destructured formal argument - the parameter itself has no
75
// user-written name, only its leaves do.
76
next_argument_group_name() -> string is
77
let result = "$arg_{_anon_index}";
78
_anon_index = _anon_index + 1;
79
return result;
80
si
81
82
pre(pragma: Definitions.PRAGMA) -> bool is
83
_pragma_scope_stack.enter(pragma.pragma);
84
85
return false;
86
si
87
88
visit(pragma: Definitions.PRAGMA) is
89
let p = pragma.pragma;
90
91
let name = p.name.to_string();
92
93
let is_primitive = name =~ "IL.built_in_type";
94
95
if
96
is_primitive \/
97
name =~ "IL.name" \/
98
name =~ "IL.name.read" \/
99
name =~ "IL.name.assign"
100
then
101
if p.arguments.expressions.count != 1 then
102
_logger.error(p.arguments.location, "expected one argument");
103
return;
104
fi
105
106
let argument = p.arguments.expressions[0];
107
108
if !isa Expressions.Literals.STRING(argument) then
109
_logger.error(p.arguments.location, "expected a string literal argument");
110
return;
111
fi
112
113
let il_name = argument.value_string;
114
115
let definition mut = pragma.definition;
116
117
while isa Definitions.PRAGMA(definition) do
118
definition = cast Definitions.PRAGMA(definition).definition;
119
od
120
121
let symbol = symbol_for(definition);
122
123
if symbol? then
124
if isa Semantic.Symbols.Property(symbol) then
125
let property = symbol;
126
127
if name =~ "IL.name.read" then
128
property.read_function_il_name_override = il_name;
129
elif name =~ "IL.name.assign" then
130
property.assign_function_il_name_override = il_name;
131
elif name =~ "IL.name" then
132
property.il_name_override = il_name;
133
134
if !property.read_function_il_name_override? then
135
property.read_function_il_name_override = "get_{il_name}";
136
fi
137
138
if !property.assign_function_il_name_override? then
139
property.assign_function_il_name_override = "set_{il_name}";
140
fi
141
fi
142
143
return;
144
fi
145
146
if is_primitive then
147
symbol.il_is_primitive_type = true;
148
fi
149
150
symbol.il_name_override = il_name;
151
fi
152
else
153
_pragma_scope_stack.leave(p);
154
fi
155
si
156
157
visit(`union: Definitions.UNION) is
158
// Pick the default variant now that every variant's fields
159
// have been declared: prefer one with the explicit-default
160
// flag; otherwise fall back to a sole variant whose own
161
// (non-inherited) field count is positive.
162
// Cross-assembly unions don't pass through here; they
163
// get `default_variant` set by
164
// `SYMBOL_FACTORY.materialize_variant` when it sees
165
// the `DEFAULT_VARIANT_ATTRIBUTE` marker on a reflected
166
// variant.
167
let union_symbol: Semantic.Symbols.UNION? mut = null;
168
if isa Semantic.Symbols.UNION(current_scope) then
169
union_symbol = cast Semantic.Symbols.UNION(current_scope);
170
fi
171
172
if union_symbol? then
173
let explicit: Semantic.Symbols.VARIANT? mut = null;
174
let explicit_count mut = 0;
175
let sole_with_own_fields: Semantic.Symbols.VARIANT? mut = null;
176
let with_own_fields_count mut = 0;
177
178
for s in union_symbol.symbols do
179
if isa Semantic.Symbols.VARIANT(s) then
180
let v = cast Semantic.Symbols.VARIANT(s);
181
182
if v.is_default then
183
explicit = v;
184
explicit_count = explicit_count + 1;
185
fi
186
187
if v.own_field_count > 0 then
188
sole_with_own_fields = v;
189
with_own_fields_count = with_own_fields_count + 1;
190
fi
191
fi
192
od
193
194
if explicit_count == 1 then
195
union_symbol.default_variant = explicit;
196
elif explicit_count == 0 /\ with_own_fields_count == 1 then
197
union_symbol.default_variant = sole_with_own_fields;
198
fi
199
fi
200
201
leave_scope(`union);
202
si
203
204
pre(variant: Definitions.VARIANT) -> bool is
205
enter_scope(variant);
206
207
// Take charge of the walk so inherited-primary names and
208
// own-field declarations register on the variant scope
209
// interleaved in source position — positional destructure
210
// and field-description rendering both consult
211
// `_field_names` by index, so the order must match the
212
// synthesised init's argument order (which is taken from
213
// `variant.fields` in source order). Variables.VARIABLE.walk
214
// still skips inherited entries, so own fields go through
215
// the normal visit(VARIABLE) → declare_variable path and
216
// inherited entries are registered here directly.
217
let variant_scope: Semantic.Symbols.VARIANT? mut = null;
218
if isa Semantic.Symbols.VARIANT(current_declaration_context) then
219
variant_scope = cast Semantic.Symbols.VARIANT?(current_declaration_context)!;
220
fi
221
222
for f in variant.fields do
223
if f.is_inherited_primary then
224
if variant_scope? then
225
if let f.name?, field_name = name.name then
226
variant_scope.register_inherited_primary_field_name(field_name);
227
fi
228
fi
229
else
230
f.walk(self);
231
fi
232
od
233
234
variant.body.walk(self);
235
236
return true;
237
si
238
239
// An impl/partial block declares its members into an
240
// already-declared target type. The target resolves here, at the
241
// block's write site - after resolve-uses, so the name can come
242
// through a use import and the target can be declared anywhere.
243
// The block gets an injection scope rather than the target's
244
// scope directly, so that names its members reference resolve at
245
// the write site while the target's members and type parameters
246
// stay visible first; the members are then declared by this
247
// visitor's ordinary member handlers.
248
pre(`partial: Definitions.PARTIAL) -> bool is
249
_enter_injection(
250
`partial,
251
"cannot find type {`partial.name.name} to add members to",
252
"cannot add members to imported type"
253
);
254
255
`partial.body.walk(self);
256
257
return true;
258
si
259
260
pre(`impl: Definitions.IMPL) -> bool is
261
_enter_injection(
262
`impl,
263
"cannot find type {`impl.name.name} to implement an interface for",
264
"cannot implement an interface for imported type"
265
);
266
267
`impl.body.walk(self);
268
269
return true;
270
si
271
272
_enter_injection(block: Definitions.Classy, cannot_find_message: string, imported_target_message: string) is
273
let target = cast Semantic.Symbols.Classy?(find_enclosing(block.name));
274
275
if !target? then
276
_logger.error(block.name.location, cannot_find_message);
277
associate_and_enter_scope(block, _rejecting_scope());
278
elif target.is_reflected then
279
// The CLR fixes a compiled type's members and interfaces at
280
// its definition, so only a type declared in this compilation
281
// can be reopened.
282
_logger.error(block.name.location, "{imported_target_message} {target.name}");
283
associate_and_enter_scope(block, _rejecting_scope());
284
else
285
// The target name is a reference to the target type, so
286
// record it: hover, rename and find-references all read
287
// these recorded uses.
288
_symbol_use_locations.add_symbol_use(block.name.right_location, cast Semantic.Symbols.Symbol(target));
289
290
if let block.name.qualifier? /\ isa Semantic.Symbols.Classy(target.owner) then
291
_symbol_use_locations.add_symbol_use(
292
qualifier.right_location,
293
cast Semantic.Symbols.Symbol(target.owner)
294
);
295
fi
296
297
associate_and_enter_scope(block, Semantic.INJECTION_SCOPE(target, current_scope));
298
fi
299
si
300
301
// When a block's target cannot be resolved to a same-assembly type,
302
// its members have nowhere valid to live. Route them into a block
303
// scope so each member is cleanly rejected ("cannot declare … here")
304
// rather than cascading to "no scope found" downstream or being
305
// silently declared as globals in the enclosing scope. A block scope
306
// still chains name lookups to the enclosing scope, so the block's
307
// own header references - an impl's interface name - resolve
308
// normally, as do the type names in each rejected member's own
309
// header.
310
_rejecting_scope() -> Semantic.Scope =>
311
Semantic.BLOCK_SCOPE(current_scope);
312
313
pre(enum_member: Definitions.ENUM_MEMBER) -> bool is
314
let value: string? mut = null;
315
316
if enum_member.initializer? then
317
let i = enum_member.initializer;
318
319
if isa Trees.Expressions.Literals.Literal(i) then
320
value = i.value_string;
321
else
322
_logger.error(i.location, "enum member initializer must be an integer literal");
323
fi
324
fi
325
326
current_declaration_context.declare_enum_member(
327
enum_member.name.location,
328
enum_member.name.name,
329
value,
330
_symbol_definition_listener
331
);
332
return false;
333
si
334
335
pre(function: Definitions.FUNCTION) -> bool is
336
// parse recovery can leave the declaration nameless;
337
// there is nothing to declare for it
338
let name = function.name;
339
340
if !name? then
341
return true;
342
fi
343
344
let is_innate = function.body? /\ isa Trees.Bodies.INNATE(function.body);
345
let is_static = function.modifiers.is_static;
346
347
if is_static /\ name.name =~ "init" /\ function.arguments.count > 0 then
348
_logger.error(function.location, "a static constructor cannot take parameters");
349
fi
350
351
let is_private = function.modifiers.is_private;
352
353
// An underscore-prefixed method, or the accessor of an underscore-
354
// prefixed property (whose own $get_/$set_ name is not underscore-
355
// prefixed), is subject to the underscore access policy.
356
let is_underscore_method = name.name.starts_with('_') \/ function.is_underscore_scoped;
357
358
let property: Semantic.Symbols.Property? mut = null;
359
360
_local_id_generator.enter_function();
361
362
if function.for_property? then
363
let symbol = symbol_for(function.for_property);
364
365
assert symbol? else "function is accessor for property but no property found: {function.location}";
366
assert isa Semantic.Symbols.Property(symbol) else "function is accessor for property but associated symbol is not a property: {function.location}";
367
368
property = cast Semantic.Symbols.Property(symbol);
369
fi
370
371
if is_innate then
372
let `innate = cast Trees.Bodies.INNATE?(function.body)!;
373
374
associate_and_enter_scope(
375
function,
376
current_declaration_context.declare_innate(
377
function.location,
378
name.name,
379
`innate.name.to_string(),
380
current_scope,_symbol_definition_listener
381
)
382
);
383
else
384
// Generator vs async detection. A body with `yield`
385
// (not inside a nested lambda) becomes a generator;
386
// a body with `await` (in this body, not in a nested
387
// lambda) becomes an async function.
388
//
389
// Either-or only — a body with both is diagnosed
390
// and falls back to generator classification.
391
let has_body = function.body? /\ !function.body.is_null;
392
393
let body_has_yield =
394
has_body /\ YIELD_SCANNER().body_has_yield(function.body!);
395
396
let await_scanner = AWAIT_SCANNER();
397
if has_body then
398
await_scanner.scan(function.body!);
399
fi
400
401
let body_has_await = await_scanner.found;
402
403
function.contains_let_await = body_has_await;
404
function.is_void_async = body_has_await /\ !await_scanner.found_value_return;
405
406
if body_has_yield /\ body_has_await then
407
_logger.error(
408
function.location,
409
"function cannot be both a generator and async"
410
);
411
fi
412
413
let is_generator = body_has_yield;
414
let is_async = body_has_await /\ !is_generator;
415
416
let symbol: Semantic.Symbols.Symbol mut;
417
418
if is_generator then
419
symbol = current_declaration_context.declare_generator_function(
420
name.location,
421
function.location,
422
name.name,
423
is_static,
424
is_private,
425
has_body,
426
current_scope,
427
_symbol_definition_listener);
428
elif is_async then
429
symbol = current_declaration_context.declare_async_function(
430
name.location,
431
function.location,
432
name.name,
433
is_static,
434
is_private,
435
has_body,
436
current_scope,
437
_symbol_definition_listener);
438
else
439
symbol = current_declaration_context.declare_function(
440
name.location,
441
function.location,
442
name.name,
443
is_static,
444
is_underscore_method,
445
has_body,
446
current_scope,
447
_symbol_definition_listener);
448
fi
449
450
// A rejected declaration has no function symbol to scope
451
// its arguments and body against. Entering it anyway makes
452
// every name in the header and body report as not found on
453
// top of the rejection; a rejecting scope keeps them
454
// resolvable.
455
if isa Semantic.Symbols.UNDEFINED(symbol) then
456
associate_and_enter_scope(function, _rejecting_scope());
457
else
458
associate_and_enter_scope(function, symbol);
459
fi
460
fi
461
462
let symbol = symbol_for(function);
463
464
if symbol? /\ isa Semantic.Symbols.Function(symbol) then
465
let function_symbol = symbol;
466
467
if function.modifiers.is_pure then
468
function_symbol.mark_declared_pure();
469
fi
470
471
if let operation = _pragma_scope_stack.intrinsic_operation then
472
function_symbol.intrinsic_operation = operation;
473
fi
474
475
// A member declared under an operator name means an
476
// operand of that type could reach this operator, which
477
// could store. The store-free walk reads this to decide
478
// whether an operator on an operand it cannot type has to
479
// be treated conservatively.
480
if
481
Lexical.TOKENIZER.is_operator_name(name.name) /\
482
isa Semantic.Symbols.Classy(function_symbol.owner)
483
then
484
Semantic.Symbols.MEMBER_OPERATOR_NAMES.add(name.name);
485
fi
486
487
// Record the primary constructor on its owning type so a
488
// hover on the declaration can show the primary parameters.
489
if
490
function.is_primary_constructor /\
491
isa Semantic.Symbols.Classy(function_symbol.owner)
492
then
493
(cast Semantic.Symbols.Classy?(function_symbol.owner)!).primary_constructor = function_symbol;
494
fi
495
496
// Record on the owning type that it has its own
497
// zero-argument constructor — needed early (before
498
// constructor signatures are resolved) to check a
499
// `new()` type-parameter constraint.
500
if
501
name.name =~ "init" /\
502
function.arguments.variables.count == 0 /\
503
isa Semantic.Symbols.Classy(function_symbol.owner)
504
then
505
(cast Semantic.Symbols.Classy?(function_symbol.owner)!).has_parameterless_constructor = true;
506
fi
507
508
// A user-written body-less instance method on a class
509
// makes that class implicitly abstract — the user
510
// meant the method as a contract for subclasses to
511
// implement, and a bare instance would throw if the
512
// method were ever invoked. Skip property accessors,
513
// since a write-only property leaves the synthesised
514
// getter body-less without the user intending the
515
// class to be abstract; skip `init` (that's a
516
// separate concern handled by primary-ctor rewriting)
517
// and static methods (statics don't make instances
518
// abstract).
519
let body_is_null =
520
!function.body? \/ function.body.is_null;
521
522
if
523
body_is_null /\
524
!function.for_property? /\
525
!is_static /\
526
name.name !~ "init" /\
527
isa Semantic.Symbols.CLASS(function_symbol.owner)
528
then
529
(cast Semantic.Symbols.CLASS(function_symbol.owner)).mark_has_bodyless_method();
530
fi
531
532
if property? then
533
if function.arguments.variables.count == 0 then
534
property.read_function = function_symbol;
535
536
if property.read_function_il_name_override? then
537
function_symbol.il_name_override = property.read_function_il_name_override;
538
fi
539
else
540
property.assign_function = function_symbol;
541
542
if property.assign_function_il_name_override? then
543
function_symbol.il_name_override = property.assign_function_il_name_override;
544
fi
545
fi
546
fi
547
548
if function.generic_arguments.count > 0 then
549
let generic_arguments = _generic_argument_declarer.declare_generic_arguments(function.generic_arguments);
550
551
function_symbol.generic_argument_names = generic_arguments.names;
552
function_symbol.generic_arguments = generic_arguments.types;
553
function_symbol.is_generic = true;
554
fi
555
556
function_symbol.start_declaring_arguments();
557
function.arguments.walk(self);
558
function_symbol.end_declaring_arguments();
559
elif isa Semantic.BLOCK_SCOPE(current_declaration_context) then
560
// The declaration was rejected above, so there is no
561
// function symbol to open a declaring-arguments window
562
// against — but the parameters still need somewhere to
563
// resolve, or every reference downstream reports as
564
// missing on top of the rejection. Declare them into the
565
// rejecting scope entered above instead.
566
function.arguments.walk(self);
567
fi
568
569
if function.body? then
570
function.body.walk(self);
571
fi
572
573
return true ;
574
si
575
576
visit(function: Definitions.FUNCTION) is
577
_local_id_generator.leave_function();
578
579
leave_scope(function);
580
si
581
582
// Declare just a function's body — its block scopes, locals and
583
// closures — reusing the body-handling visit methods. The caller
584
// must already have the cursor positioned at the function's
585
// (retained) scope. Used by the incremental body re-walk, which
586
// keeps the interface symbols and re-declares only the edited
587
// bodies; the interface is never re-walked here, so the pass's
588
// non-idempotency on declarations is not exercised.
589
declare_body(function: Definitions.FUNCTION) is
590
if !function.body? then
591
return;
592
fi
593
594
_local_id_generator.enter_function();
595
596
function.body!.walk(self);
597
598
_local_id_generator.leave_function();
599
si
600
601
pre(property: Definitions.PROPERTY) -> bool is
602
// parse recovery can leave the declaration nameless;
603
// there is nothing to declare for it
604
let name = property.name;
605
606
if !name? then
607
return true;
608
fi
609
610
let is_static = property.modifiers.is_static;
611
let instance_context = current_instance_context;
612
613
if property.modifiers.is_field then
614
// is_field implies the storage class modifier is present
615
if !instance_context? \/ instance_context.is_trait then
616
_logger.error(property.modifiers.storage_class!.location, "field is not valid here");
617
property.modifiers.clear_storage_class();
618
elif property.read_body? \/ property.assign_body? \/ property.assign_argument? then
619
_logger.error(property.modifiers.storage_class!.location, "field cannot have a body");
620
fi
621
fi
622
623
if
624
property.modifiers.is_field \/ (
625
name.name.starts_with('_') /\
626
!property.read_body? /\
627
!property.assign_body?
628
)
629
then
630
let symbol = current_declaration_context.declare_variable(name.location, name.name, is_static, _symbol_definition_listener);
631
632
associate_node_with_scope(property, symbol);
633
634
else
635
let owner_is_trait = instance_context? /\ instance_context.is_trait;
636
637
let is_assignable = !property.read_body? \/ property.assign_argument?;
638
let is_private = !property.modifiers.is_public /\ !owner_is_trait;
639
640
let symbol =
641
current_declaration_context
642
.declare_property(
643
name.location,
644
property.location,
645
name.name,
646
is_static,
647
is_private,
648
is_assignable,
649
_symbol_definition_listener
650
);
651
652
if property.read_body == null /\ property.assign_body == null then
653
current_declaration_context.declare_variable(
654
name.location,
655
"${name.name}",
656
is_static,
657
_symbol_definition_listener);
658
fi
659
660
associate_node_with_scope(property, symbol);
661
fi
662
663
return true;
664
si
665
666
pre(indexer: Definitions.INDEXER) -> bool is
667
// ???
668
669
return true;
670
si
671
672
visit(variable: Variables.VARIABLE) is
673
// A destructured formal argument is one physical parameter
674
// at the aggregate (tuple) type, unpacked into its leaf
675
// names at method entry - not one parameter per leaf. The
676
// leaves are ordinary body-scoped locals, declared here
677
// even though we're inside the function's `_declaring_
678
// arguments` window, so declare_variable doesn't turn them
679
// into LOCAL_ARGUMENTs.
680
if variable.is_argument /\ !variable.left.is_simple_name then
681
let function = cast Semantic.Symbols.Function?(current_declaration_context);
682
683
// Declaring into the enclosing function's rejecting scope
684
// (see pre(FUNCTION) above) reaches here too, with no
685
// function symbol to open a declaring-arguments window
686
// against — there is nothing to distinguish an argument
687
// from any other local in a block scope, so the window
688
// toggle is simply skipped.
689
assert function? \/ isa Semantic.BLOCK_SCOPE(current_declaration_context) else "destructured formal argument declared outside a function scope";
690
691
let group_symbol =
692
current_declaration_context.declare_variable(
693
variable.location,
694
next_argument_group_name(),
695
variable.is_static,
696
_symbol_definition_listener
697
);
698
699
associate_node_with_scope(variable, group_symbol);
700
701
if function? then
702
function.end_declaring_arguments();
703
fi
704
705
for name in variable.names do
706
if name.name =~ "_" then
707
name.name = next_discard_name();
708
fi
709
710
current_declaration_context.declare_variable(name.location, name.name, variable.is_static, _symbol_definition_listener);
711
od
712
713
if function? then
714
function.start_declaring_arguments();
715
fi
716
717
if variable.pragmas? then
718
_logger.error(variable.location, "attribute is not allowed on a destructured parameter");
719
fi
720
721
return;
722
fi
723
724
let declared_symbol: Semantic.Symbols.Symbol? mut = null;
725
726
for name in variable.names do
727
728
if name.name =~ "_" then
729
name.name = next_discard_name();
730
fi
731
732
let declared = current_declaration_context.declare_variable(name.location, name.name, variable.is_static, _symbol_definition_listener);
733
734
if variable.is_mutable_marked then
735
if let v: Semantic.Symbols.Variable = declared then
736
v.is_mutable_marked = true;
737
fi
738
fi
739
740
declared_symbol = declared;
741
od
742
743
// Only a formal-argument VARIABLE can carry attribute
744
// pragmas (parsed only inside CONTEXT.in_formal_arguments);
745
// associate it with its declared symbol so compile-expressions
746
// and generate-il can find it again via symbol_for. A
747
// destructured parameter declares more than one name, so
748
// there is no single symbol an attribute could sensibly
749
// attach to.
750
if variable.pragmas? then
751
if declared_symbol? /\ variable.left.is_simple_name then
752
associate_node_with_scope(variable, declared_symbol);
753
else
754
_logger.error(variable.location, "attribute is not allowed on a destructured parameter");
755
fi
756
fi
757
si
758
759
// Controlled walk: per clause, walk the clause's pieces and
760
// THEN declare its pattern names — so later clauses'
761
// scrutinees see earlier clauses' bindings during
762
// name-resolution. Mirrors what plain `let a = …; let b = …;`
763
// gets for free across separate statements (visit(VARIABLE) on
764
// the first runs before the second is walked).
765
pre(rb: Statements.REFUTABLE_BINDING) -> bool is
766
for c in rb.clauses do
767
if let c.narrow_type_expression? then
768
narrow_type_expression.walk(self);
769
fi
770
771
c.scrutinee.walk(self);
772
c.pattern.walk(self);
773
774
if let c.guard? then
775
guard.walk(self);
776
fi
777
778
for name in c.pattern.names! do
779
if name.name =~ "_" then
780
name.name = next_discard_name();
781
fi
782
783
current_declaration_context.declare_variable(
784
name.location,
785
name.name,
786
false,
787
_symbol_definition_listener
788
);
789
od
790
od
791
792
return true;
793
si
794
795
visit(rb: Statements.REFUTABLE_BINDING) is
796
si
797
798
visit(variable: Expressions.VARIABLE) is
799
si
800
801
pre(if_branch: Statements.IF_BRANCH) -> bool is
802
create_and_enter_block_scope(if_branch);
803
return false;
804
si
805
806
visit(if_branch: Statements.IF_BRANCH) is
807
leave_scope(if_branch);
808
si
809
810
pre(`case: Statements.CASE) -> bool is
811
create_and_enter_block_scope(`case);
812
return false;
813
si
814
815
visit(`case: Statements.CASE) is
816
leave_scope(`case);
817
si
818
819
pre(case_match: Statements.CASE_MATCH) -> bool is
820
create_and_enter_block_scope(case_match);
821
return false;
822
si
823
824
visit(case_match: Statements.CASE_MATCH) is
825
leave_scope(case_match);
826
si
827
828
pre(`try: Statements.TRY) -> bool is
829
create_and_enter_block_scope(`try);
830
return false;
831
si
832
833
visit(`try: Statements.TRY) is
834
leave_scope(`try);
835
si
836
837
pre(`catch: Statements.CATCH) -> bool is
838
create_and_enter_block_scope(`catch);
839
return false;
840
si
841
842
visit(`catch: Statements.CATCH) is
843
leave_scope(`catch);
844
si
845
846
pre(`do: Statements.DO) -> bool is
847
create_and_enter_block_scope(`do);
848
return false;
849
si
850
851
visit(`do: Statements.DO) is
852
leave_scope(`do);
853
si
854
855
pre(`for: Statements.FOR) -> bool is
856
create_and_enter_block_scope(`for);
857
return false;
858
si
859
860
visit(`for: Statements.FOR) is
861
leave_scope(`for);
862
si
863
864
pre(labelled: Statements.LABELLED) -> bool is
865
current_declaration_context.declare_label(labelled.label.location, labelled.label.name, _symbol_definition_listener);
866
return false;
867
si
868
869
visit(labelled: Statements.LABELLED) is
870
si
871
872
pre(variable: Expressions.VARIABLE) -> bool is
873
if variable.name.name =~ "_" then
874
variable.name.name = next_discard_name();
875
fi
876
877
// A destructured lambda parameter is one physical argument
878
// under a synthesised name, unpacked into its leaves at
879
// entry - the same shape declare-members gives a
880
// destructured formal argument of a named function. The
881
// leaves are ordinary body locals, so they are declared
882
// outside the function's declaring-arguments window.
883
if let variable.left? then
884
variable.name.name = next_argument_group_name();
885
886
current_declaration_context.declare_variable(variable.name.location, variable.name.name, false, _symbol_definition_listener);
887
888
let function = cast Semantic.Symbols.Function?(current_declaration_context);
889
890
if function? then
891
function.end_declaring_arguments();
892
fi
893
894
for name in left.names! do
895
if name.name =~ "_" then
896
name.name = next_discard_name();
897
fi
898
899
current_declaration_context.declare_variable(name.location, name.name, false, _symbol_definition_listener);
900
od
901
902
if function? then
903
function.start_declaring_arguments();
904
fi
905
906
return false;
907
fi
908
909
current_declaration_context.declare_variable(variable.name.location, variable.name.name, false, _symbol_definition_listener);
910
return false;
911
si
912
913
pre(function: Expressions.FUNCTION) -> bool is
914
// A lambda whose body contains `await` (not inside another
915
// nested lambda) is classified as `*_ASYNC_CLOSURE` so
916
// `async_state_machine_for` picks it up for state-machine
917
// IL emission. `contains_let_await` and `is_void_async`
918
// are propagated to the AST node so compile-lambdas can
919
// settle the inferred return type to `Tasks.TASK` /
920
// `Tasks.TASK[T]` shape.
921
let await_scanner = AWAIT_SCANNER();
922
if !function.body.is_null then
923
await_scanner.scan(function.body);
924
fi
925
926
let body_has_await = await_scanner.found;
927
function.contains_let_await = body_has_await;
928
function.is_void_async = body_has_await /\ !await_scanner.found_value_return;
929
930
// An async literal's body compiles into a state machine
931
// whose locals live as frame fields, which the names a
932
// destructure pattern binds are not set up as. Reject the
933
// combination rather than emit a body that refers to slots
934
// that were never declared.
935
if body_has_await then
936
for a in function.arguments.expressions do
937
let argument = cast Trees.Expressions.VARIABLE?(a);
938
939
if argument? /\ argument.is_destructuring then
940
_logger.error(
941
argument.location,
942
"a destructuring parameter is not supported on an asynchronous function literal"
943
);
944
fi
945
od
946
fi
947
948
// a lambda expression always sits inside a function
949
let current_function = self.current_function!;
950
951
let closure_symbol: Semantic.Symbols.Symbol mut;
952
953
if body_has_await then
954
closure_symbol = current_function.declare_async_closure(
955
function.location,
956
next_anon_name(),
957
// FIXME:
958
cast Semantic.Scope?(current_closure_context)!,
959
current_scope,
960
function.is_recursive,
961
_symbol_definition_listener
962
);
963
else
964
closure_symbol = current_function.declare_closure(
965
function.location,
966
next_anon_name(),
967
// FIXME:
968
cast Semantic.Scope?(current_closure_context)!,
969
current_scope,
970
function.is_recursive,
971
_symbol_definition_listener
972
);
973
fi
974
975
associate_and_enter_scope(
976
function,
977
closure_symbol
978
);
979
980
return true;
981
si
982
983
visit(function: Expressions.FUNCTION) is
984
let symbol = symbol_for(function);
985
986
if symbol? /\ isa Semantic.Symbols.Function(symbol) then
987
let function_symbol = symbol;
988
989
let arguments = function.arguments.expressions;
990
991
// we don't know if identifier expressions in a tuple are actually untyped
992
// anonymous function formal arguments until we know the context, so re-write
993
// them now to be variables:
994
for index in 0..arguments.count do
995
let a mut = arguments[index];
996
997
if isa Trees.Expressions.IDENTIFIER(a) then
998
let infer = Trees.TypeExpressions.INFER(a.location);
999
1000
a = Trees.Expressions.VARIABLE(a.location, cast Syntax.Trees.Expressions.IDENTIFIER(a).identifier, infer, null);
1001
1002
arguments[index] = a;
1003
elif isa Trees.Expressions.DEFAULT(a) /\ a.could_be_formal_argument then
1004
// A bare `_` formal (`_ => ...`) is parsed as a
1005
// default-value expression and re-written here to
1006
// an untyped discard parameter. Multi-arg and
1007
// destructure formals reach this via
1008
// rewrite_as_variables instead.
1009
a = Trees.Expressions.VARIABLE(
1010
a.location,
1011
Trees.Identifiers.Identifier(a.location, "_"),
1012
Trees.TypeExpressions.INFER(a.location),
1013
null
1014
);
1015
1016
arguments[index] = a;
1017
fi
1018
od
1019
1020
function_symbol.start_declaring_arguments();
1021
1022
function.arguments.walk(self);
1023
1024
function_symbol.end_declaring_arguments();
1025
fi
1026
1027
function.body.walk(self);
1028
1029
leave_scope(function);
1030
si
1031
1032
pre(let_in: Expressions.LET_IN) -> bool is
1033
create_and_enter_block_scope(let_in);
1034
return false;
1035
si
1036
1037
visit(let_in: Expressions.LET_IN) is
1038
leave_scope(let_in);
1039
si
1040
1041
pre(expression: Bodies.EXPRESSION) -> bool is
1042
create_and_enter_block_scope(expression);
1043
return false;
1044
si
1045
1046
visit(expression: Bodies.EXPRESSION) is
1047
leave_scope(expression);
1048
si
1049
1050
pre(block: Bodies.BLOCK) -> bool is
1051
create_and_enter_block_scope(block);
1052
return false;
1053
si
1054
1055
visit(block: Bodies.BLOCK) is
1056
leave_scope(block);
1057
si si
1058
si