Skip to content
← Back

src/semantic/symbols/classy.ghul

1
namespace Semantic.Symbols is
2
use IO.Std;
3
4
use System.Text.StringBuilder;
5
6
use Collections.SET;
7
8
use Ghul.Pipes;
9
10
use IoC;
11
use Logging;
12
use Source;
13
14
use IR.Values.Value;
15
16
use Types.Type;
17
18
class Classy: ScopedWithEnclosingScope, ClosureContext is
19
_ancestors: Collections.LIST[Type];
20
_implementors: Collections.LIST[Symbol]?;
21
_enclosing_symbols: Collections.MAP[string,Symbol];
22
_closures: Collections.SET[Closure]?;
23
24
_are_overrides_resolved: bool;
25
26
// The reversible record of what this class's pull-down did, so
27
// reset_pulled_down_symbols can undo it exactly. Null until the
28
// class resolves its overrides, and for classes marked resolved
29
// without a pull-down (reflected imports).
30
_inheritance_journal: INHERITANCE_JOURNAL?;
31
32
type: Type?;
33
set_type(value: Type) is type = value; si
34
35
span: LOCATION;
36
37
// Incremental body re-walk override: also shift the declaration
38
// span when the retained interface symbol is relocated.
39
set_span(span_location: LOCATION) is
40
span = span_location;
41
si
42
43
_depth: int;
44
depth: int is
45
if _depth > 0 then
46
return _depth;
47
fi
48
49
_depth = _calc_depth();
50
return _depth;
51
si
52
53
argument_names: Collections.List[string];
54
argument_variances: Collections.List[Types.TypeVariance]? public;
55
argument_constraint_kinds: Collections.List[TypeParameterConstraintKind] public;
56
argument_has_constructor_constraint: Collections.List[bool] public;
57
// Parallel to argument_names: the type bound (`where T : SomeBase`)
58
// for each type parameter, or null when unbounded. Populated at
59
// import for .NET-defined generics whose parameter symbols don't
60
// live in the symbol's own scope; ghūl-declared generics keep the
61
// bound on the parameter symbol itself.
62
argument_type_bounds: Collections.List[Type?] public;
63
64
// True when this type has its own accessible parameterless
65
// constructor — a zero-argument `init` for a ghūl-declared type,
66
// a public parameterless `.ctor` for an imported one. Used to
67
// check a `new()` type-parameter constraint. Set when the type
68
// is declared / imported, since a ghūl constructor's signature
69
// is not resolved early enough to inspect at constraint-check
70
// time.
71
has_parameterless_constructor: bool public;
72
73
// The constructor synthesised from this type's primary-constructor
74
// header, when it has one. Recorded by declare-symbols so a hover
75
// on the declaration can show the primary parameters; null for a
76
// type without a primary header (secondary constructors are not
77
// recorded here).
78
primary_constructor: Function? public;
79
80
// Set by TYPE_GROUP when the type joins a group of same-named
81
// sibling types distinguished by generic-argument count.
82
// Triggers `\`N` suffixing in IL emission so .NET sees distinct
83
// names — lone types (no siblings) emit unchanged so the
84
// universal compiler-source path is byte-identical.
85
has_argument_count_siblings: bool public;
86
87
is_generic: bool => argument_names.count > 0;
88
89
get_argument_variance(index: int) -> Types.TypeVariance =>
90
if !argument_variances? \/ index < 0 \/ index >= argument_variances.count then
91
Types.TypeVariance.INVARIANT
92
else
93
argument_variances[index]
94
fi;
95
96
// FIXME: not safe to expose unspecialized ancestors
97
ancestors: Collections.List[Type] => _ancestors;
98
99
implementors: Collections.Iterable[Symbol]? => _implementors;
100
101
il_assembly_name: string? public;
102
103
is_workspace_visible: bool => true;
104
is_capture_context: bool => true;
105
is_type: bool => true;
106
is_classy: bool => true;
107
is_instance_context: bool => false;
108
109
// True when extension across assembly boundaries is permitted.
110
// The base default is true — most things are conceptually open
111
// (traits exist to be implemented; structs are open by CLR
112
// semantics; imported types are out of our jurisdiction). Only
113
// ghūl-declared `class` declarations are closed by default;
114
// `Symbols.CLASS` overrides this with a settable field, set
115
// from the `open` modifier during declare-symbols.
116
is_open: bool => true;
117
118
// True when this Classy itself cannot appear as a runtime type
119
// (only its subclasses can). Default false — traits/structs/
120
// unions/variants are never "abstract" in this sense for
121
// narrowing purposes (unions enumerate via variants; trait
122
// implementors aren't enumerable to begin with). `Symbols.CLASS`
123
// overrides this with a settable field, set from the `abstract`
124
// modifier during declare-symbols and from
125
// `TypeAttributes.Abstract` on import.
126
is_abstract: bool => false;
127
128
// The set of direct subclasses declared in the same assembly as
129
// this Classy. Used by the variant-complement narrowing path to
130
// enumerate a closed root's possible dynamic types. Returns an
131
// empty list when the root is open — callers gate on `is_open`
132
// before consulting this. Built from `implementors`, filtered
133
// to ghūl-declared CLASS subclasses (trait implementors and
134
// imported subclasses don't count for closure).
135
closed_subclasses: Collections.Iterable[Classy] is
136
let result = Collections.LIST[Classy]();
137
138
if !_implementors? then
139
return result;
140
fi
141
142
for s in _implementors do
143
if isa CLASS(s) then
144
let sub = cast Classy(s);
145
if !sub.is_reflected then
146
result.add(sub);
147
fi
148
fi
149
od
150
151
return result;
152
si
153
154
// True when this Classy is the root of a closed set of subtypes
155
// narrowing can complement against. Two shapes qualify: a union
156
// (variants are the closed set), and a ghūl-declared closed
157
// class (`closed_subclasses` is the closed set). Open classes,
158
// traits, structs, enums and imported types do not.
159
is_closed_root: bool =>
160
is_union \/ (is_class /\ !is_open);
161
162
// The subtypes that make up this closed root's in-set. Returns
163
// the variants for a union, the direct in-assembly subclasses
164
// for a closed class, an empty list otherwise. Callers gate on
165
// `is_closed_root` first; the empty fallback is a safety net.
166
closed_alternatives: Collections.Iterable[Classy] is
167
let result = Collections.LIST[Classy]();
168
169
if is_union then
170
for s in symbols do
171
if s.is_variant then
172
result.add(cast Classy?(s)!);
173
fi
174
od
175
176
return result;
177
fi
178
179
if is_class /\ !is_open then
180
for s in closed_subclasses do
181
result.add(s);
182
od
183
fi
184
185
return result;
186
si
187
188
is_derived_from_iterable_trait: bool
189
=> find_ancestor(IoC.CONTAINER.instance.innate_symbol_lookup.get_unspecialized_iterable_type())?;
190
191
is_derived_from_iterator_trait: bool
192
=> find_ancestor(IoC.CONTAINER.instance.innate_symbol_lookup.get_unspecialized_iterator_type())?;
193
194
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, argument_names: Collections.List[string], enclosing_scope: Scope) is
195
super.init(location, owner, name, enclosing_scope);
196
197
_ancestors = Collections.LIST[Type]();
198
_enclosing_symbols = Collections.MAP[string,Symbol]();
199
argument_constraint_kinds = Collections.LIST[TypeParameterConstraintKind](0);
200
argument_has_constructor_constraint = Collections.LIST[bool](0);
201
argument_type_bounds = Collections.LIST[Type?](0);
202
203
self.span = span;
204
self.argument_names = argument_names;
205
206
type = Types.NAMED(self);
207
si
208
209
get_ancestor(i: int) -> Type
210
=> ancestors[i].specialize(Collections.MAP[string,Type]());
211
212
add_ancestor(ancestor: Type) is
213
assert ancestor? else "adding null ancestor to {name}";
214
215
_ancestors.add(ancestor);
216
si
217
218
_calc_depth() -> int;
219
220
add_implementor(symbol: Symbol) is
221
let implementors mut = _implementors;
222
223
if !implementors? then
224
implementors = Collections.LIST[Symbol]();
225
_implementors = implementors;
226
elif implementors.contains(symbol) then
227
return;
228
fi
229
230
implementors.add(symbol);
231
232
if let journal = INHERITANCE_JOURNAL.current then
233
journal.record(InheritanceOp.IMPLEMENTOR_ADDED(self, symbol));
234
fi
235
si
236
237
remove_implementor(symbol: Symbol) is
238
let implementors = _implementors;
239
240
if implementors? then
241
implementors.remove(symbol);
242
fi
243
si
244
245
push_ancestor(ancestor: Type) is
246
let na = Collections.LIST[Type]();
247
248
na.add(ancestor);
249
na.add_range(_ancestors);
250
251
_ancestors = na;
252
si
253
254
add_closure(closure: Closure) is
255
if !_closures? then
256
_closures = Collections.SET[Closure]();
257
fi
258
259
if !_closures.contains(closure) then
260
_closures.add(closure);
261
fi
262
si
263
264
get_closures() -> Collections.Iterable[Closure] =>
265
if _closures? then _closures else Collections.LIST[Closure](0) fi;
266
267
find_member(name: string) -> Symbol? => find_direct(name);
268
269
// The synthetic `$globals` class hosts namespace-level functions and
270
// fields in IL but is not user-spellable. Hide it from qualified
271
// names so HOVER and diagnostics show `NS.member` rather than
272
// `NS.$globals.member`.
273
qualified_name: string =>
274
if name =~ "$globals" /\ owner? then
275
owner.qualified_name;
276
elif owner? then
277
owner.qualify(name);
278
else
279
name;
280
fi;
281
282
qualify(name: string) -> string =>
283
if self.name =~ "$globals" /\ owner? then
284
owner.qualify(name);
285
else
286
"{qualified_name}.{name}";
287
fi;
288
289
// The member store backs the find_enclosing memo below; any
290
// mutation invalidates it. Batch builds never mutate a class
291
// after its expressions compile, but an analysis-mode
292
// incremental edit replaces members on a retained class — a
293
// memoized name would keep resolving to the outgoing symbol's
294
// (emptied) function group, so calls through it stop resolving.
295
declare(location: LOCATION, symbol: Symbol, symbol_definition_listener: SymbolDefinitionListener?) is
296
_enclosing_symbols.clear();
297
super.declare(location, symbol, symbol_definition_listener);
298
si
299
300
remove_direct(name: string) is
301
_enclosing_symbols.clear();
302
super.remove_direct(name);
303
si
304
305
put_direct(name: string, symbol: Symbol) is
306
_enclosing_symbols.clear();
307
super.put_direct(name, symbol);
308
si
309
310
find_enclosing(name: string) -> Symbol? is
311
if _enclosing_symbols.contains_key(name) then
312
return _enclosing_symbols[name];
313
fi
314
315
let result = find_direct(name);
316
317
if result? then
318
if !isa FUNCTION_GROUP(result) then
319
_enclosing_symbols[name] = result;
320
321
return result;
322
fi
323
324
let outer = find_enclosing_only(name);
325
326
if !outer? \/ !isa FUNCTION_GROUP(outer) then
327
_enclosing_symbols[name] = result;
328
329
return result;
330
fi
331
332
let combined = result.merged_over(outer);
333
334
_enclosing_symbols[name] = combined;
335
336
return combined;
337
fi
338
339
return find_enclosing_only(name);
340
si
341
342
find_ancestor_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
343
assert _are_overrides_resolved;
344
345
for a in ancestors do
346
if let a.scope? then
347
scope.find_member_matches(prefix, matches);
348
fi
349
od
350
si
351
352
find_member_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
353
assert _are_overrides_resolved;
354
355
find_direct_matches(prefix, matches);
356
si
357
358
find_enclosing_matches(prefix: string, matches: Collections.MutableMap[string, Symbols.Symbol]) is
359
assert _are_overrides_resolved;
360
361
find_member_matches(prefix, matches);
362
find_enclosing_only_matches(prefix, matches);
363
si
364
365
assert_symbols_pulled_down() is
366
if !_are_overrides_resolved then
367
pull_down_super_symbols();
368
fi
369
si
370
371
mark_overrides_resolved() is
372
_are_overrides_resolved = true;
373
si
374
375
pull_down_super_symbols() is
376
if _are_overrides_resolved then
377
return;
378
fi
379
380
_are_overrides_resolved = true;
381
382
let journal = INHERITANCE_JOURNAL(self);
383
384
// A reflected class is import-lifetime and never reset, so its
385
// journal is discarded after the pull-down. It is still pushed
386
// while the pull-down runs: a recursive ancestor resolution
387
// must never record its own mutations into the journal of the
388
// class that happened to trigger it.
389
if !is_reflected then
390
_inheritance_journal = journal;
391
fi
392
393
INHERITANCE_JOURNAL.push(journal);
394
395
try
396
for i in 0..ancestors.count do
397
let symbol = get_ancestor(i).symbol;
398
399
symbol.pull_down_super_symbols();
400
symbol.add_implementor(self);
401
od
402
403
let resolver = SYMBOL_INHERITANCE_RESOLVER(self);
404
405
resolver.pull_down_super_symbols_into();
406
finally
407
INHERITANCE_JOURNAL.pop();
408
yrt
409
si
410
411
// Reverse this class's pull_down_super_symbols exactly: remove the
412
// pulled-down members, override links, implementor registrations
413
// and inherited IL-name / assign-accessor state it recorded, and
414
// clear the resolved flag so resolve-overrides can run again for
415
// this class against a retained symbol table.
416
reset_pulled_down_symbols() is
417
if !_are_overrides_resolved then
418
return;
419
fi
420
421
_are_overrides_resolved = false;
422
423
if let journal = _inheritance_journal then
424
journal.undo();
425
426
_inheritance_journal = null;
427
fi
428
si
429
430
try_specialize(
431
location: LOCATION,
432
logger: Logger,
433
actual_type_arguments: Collections.List[Type]
434
) -> Symbol? is
435
if !is_generic then
436
logger.error(location, "cannot explicitly specialize non-generic type");
437
return null;
438
elif actual_type_arguments.count != argument_names.count then
439
logger.error(location, "expected {argument_names.count} explicit generic type arguments");
440
return null;
441
fi
442
443
check_argument_constraints(location, logger, actual_type_arguments);
444
445
return GENERIC(location, self, actual_type_arguments);
446
si
447
448
// The kind constraint of the type parameter at `index`. Imported
449
// generics carry it in the `argument_constraint_kinds` list (the
450
// type-parameter symbols are not declared in scope); ghūl-declared
451
// generics carry it on the type-parameter symbol itself.
452
get_argument_constraint_kind(index: int) -> TypeParameterConstraintKind is
453
if index >= 0 /\ index < argument_constraint_kinds.count then
454
return argument_constraint_kinds[index];
455
fi
456
457
if index >= 0 /\ index < argument_names.count then
458
let argument = find_direct(argument_names[index]);
459
460
if argument? then
461
return argument.constraint_kind;
462
fi
463
fi
464
465
return TypeParameterConstraintKind.NONE;
466
si
467
468
// Whether the type parameter at `index` carries a parameterless-
469
// constructor (`new()`) constraint. Imported .NET generics carry
470
// it in `argument_has_constructor_constraint` (populated by
471
// symbol_factory at import time); ghūl-declared generics carry it
472
// on the type-parameter symbol itself (set by declare_symbols
473
// from the parsed `[T: …, new()]` NTE flag).
474
get_argument_has_constructor_constraint(index: int) -> bool is
475
if index >= 0 /\ index < argument_has_constructor_constraint.count then
476
return argument_has_constructor_constraint[index];
477
fi
478
479
if index >= 0 /\ index < argument_names.count then
480
let argument = find_direct(argument_names[index]);
481
482
if argument? then
483
return argument.has_constructor_constraint;
484
fi
485
fi
486
487
return false;
488
si
489
490
// The type bound (`[T: SomeBase]`) of the type parameter at
491
// `index`, or null when unbounded. Imported generics carry it
492
// in `argument_type_bounds`; ghūl-declared generics carry it on
493
// the type-parameter symbol as its first ancestor.
494
get_argument_type_bound(index: int) -> Type? is
495
if index >= 0 /\ index < argument_type_bounds.count then
496
return argument_type_bounds[index];
497
fi
498
499
if index >= 0 /\ index < argument_names.count then
500
let argument = find_direct(argument_names[index]);
501
502
if argument? /\ argument.is_type_variable then
503
let ancestors = argument.ancestors;
504
505
if ancestors.count > 0 /\ !ancestors[0].is_object then
506
return ancestors[0];
507
fi
508
fi
509
fi
510
511
return null;
512
si
513
514
check_argument_constraints(
515
location: LOCATION,
516
logger: Logger,
517
actual_type_arguments: Collections.List[Type]
518
) is
519
GENERIC_CONSTRAINT_CHECKER().check_arguments(
520
location,
521
logger,
522
self,
523
argument_names,
524
actual_type_arguments
525
);
526
si
527
528
check_argument_type_bounds(
529
location: LOCATION,
530
logger: Logger,
531
actual_type_arguments: Collections.List[Type]
532
) is
533
GENERIC_CONSTRAINT_CHECKER().check_argument_type_bounds(
534
location,
535
logger,
536
self,
537
argument_names,
538
actual_type_arguments
539
);
540
si
541
542
check_argument_kinds(
543
location: LOCATION,
544
logger: Logger,
545
actual_type_arguments: Collections.List[Type]
546
) is
547
GENERIC_CONSTRAINT_CHECKER().check_argument_kinds(
548
location,
549
logger,
550
self,
551
argument_names,
552
actual_type_arguments
553
);
554
si
555
556
gen_reference(buffer: StringBuilder) is
557
gen_type(buffer);
558
559
if is_generic then
560
buffer.append('<');
561
gen_actual_type_arguments(buffer);
562
buffer.append("> ");
563
fi
564
si
565
566
gen_class_name(buffer: StringBuilder) is
567
if il_is_primitive_type then
568
buffer
569
.append(il_name_override)
570
.append(' ');
571
572
return;
573
fi
574
575
gen_assembly_reference(buffer);
576
gen_dotted_name(buffer, null);
577
si
578
579
gen_type(buffer: StringBuilder) is
580
if il_is_primitive_type then
581
buffer
582
.append(il_name_override)
583
.append(' ');
584
585
return;
586
fi
587
588
gen_type_prefix(buffer);
589
gen_class_name(buffer);
590
si
591
592
gen_definition_header(buffer: StringBuilder) is
593
gen_directive(buffer);
594
595
gen_access(buffer);
596
597
gen_flags(buffer);
598
599
owner!.gen_dotted_name(buffer, self);
600
601
gen_name(buffer);
602
603
if is_generic then
604
buffer.append('<');
605
gen_formal_type_arguments(buffer);
606
buffer.append("> ");
607
fi
608
609
gen_extends(buffer);
610
611
gen_implements(buffer);
612
si
613
614
gen_directive(buffer: StringBuilder) is
615
buffer.append(".class ");
616
si
617
618
gen_access(buffer: StringBuilder) is
619
let policy = IoC.CONTAINER.instance.build_flags.underscore_access;
620
621
if name.starts_with('_') /\ (policy == Compiler.UnderscoreAccess.PRIVATE \/ policy == Compiler.UnderscoreAccess.PROTECTED) then
622
buffer.append("private ");
623
else
624
buffer.append("public ");
625
fi
626
si
627
628
gen_flags(buffer: StringBuilder) is
629
buffer.append("auto ansi ");
630
gen_before_field_init(buffer);
631
si
632
633
// True when this type declares an explicit static constructor
634
// (`init() static`). Such a type must not be emitted with
635
// `beforefieldinit`, which would let the CLR run the `.cctor`
636
// at an unspecified point before first use rather than
637
// precisely before it.
638
has_static_constructor: bool is
639
if let group: Symbols.FUNCTION_GROUP = find_direct("init") then
640
for f in group.functions do
641
if f.is_static_constructor then
642
return true;
643
fi
644
od
645
fi
646
647
return false;
648
si
649
650
gen_before_field_init(buffer: StringBuilder) is
651
if !has_static_constructor then
652
buffer.append("beforefieldinit ");
653
fi
654
si
655
656
gen_formal_type_arguments(buffer: StringBuilder) is
657
let seen_any mut = false;
658
659
for (index, argument) in argument_names |> index() do
660
if seen_any then
661
buffer.append(',');
662
fi
663
664
let variance = get_argument_variance(index);
665
666
if variance == Types.TypeVariance.COVARIANT then
667
buffer.append('+');
668
elif variance == Types.TypeVariance.CONTRAVARIANT then
669
buffer.append('-');
670
fi
671
672
let kind = get_argument_constraint_kind(index);
673
674
if kind == TypeParameterConstraintKind.REFERENCE then
675
buffer.append("class ");
676
elif kind == TypeParameterConstraintKind.VALUE then
677
buffer.append("valuetype ");
678
fi
679
680
buffer
681
.append('\'')
682
.append(argument)
683
.append('\'');
684
685
seen_any = true;
686
od
687
si
688
689
gen_actual_type_arguments(buffer: StringBuilder) is
690
let seen_any mut = false;
691
692
for index in 0..argument_names.count do
693
if seen_any then
694
buffer.append(',');
695
fi
696
697
buffer
698
.append('!')
699
.append(index);
700
701
seen_any = true;
702
od
703
si
704
705
gen_extends(buffer: StringBuilder) is
706
for ancestor in ancestors do
707
assert isa Types.NAMED(ancestor);
708
709
if ancestor.is_trait then
710
continue;
711
fi
712
713
buffer
714
.append(" extends ");
715
716
ancestor
717
.gen_class_name(buffer);
718
719
break;
720
od
721
si
722
723
gen_implements(buffer: StringBuilder) is
724
let seen_any mut = false;
725
726
for ancestor in ancestors do
727
assert isa Types.NAMED(ancestor);
728
729
if !ancestor.is_trait then
730
continue;
731
fi
732
733
if seen_any then
734
buffer
735
.append(',');
736
else
737
buffer
738
.append("implements ");
739
fi
740
741
ancestor
742
.gen_class_name(buffer);
743
744
seen_any = true;
745
od
746
si
747
748
gen_assembly_reference(buffer: StringBuilder) is
749
if il_assembly_name? then
750
buffer
751
.append("['")
752
.append(il_assembly_name)
753
.append("']");
754
elif il_name_override? then
755
let parts = il_name_override.split(['[',']']);
756
757
if parts.count == 3 then
758
buffer
759
.append('[')
760
.append(parts[1])
761
.append(']');
762
fi
763
fi
764
si
765
766
gen_dot(buffer: System.Text.StringBuilder) is
767
buffer.append(".");
768
si
769
770
gen_dotted_name(buffer: System.Text.StringBuilder, qualifying: Scope?) is
771
let iln = il_name_override;
772
773
if iln? then
774
let parts = iln.split(['[',']']);
775
776
if parts.count == 3 then
777
buffer
778
.append(parts[2]);
779
else
780
if owner? /\ !iln.contains('.') then
781
owner.gen_dotted_name(buffer, self);
782
fi
783
784
buffer.append(iln);
785
fi
786
else
787
if owner? then
788
owner.gen_dotted_name(buffer, self);
789
fi
790
791
buffer
792
.append('\'')
793
.append(name);
794
795
if has_argument_count_siblings /\ is_generic then
796
buffer
797
.append('`')
798
.append(argument_names.count);
799
fi
800
801
buffer.append('\'');
802
fi
803
804
if !qualifying? then
805
buffer.append(' ');
806
else
807
qualifying.gen_dot(buffer);
808
fi
809
si
810
811
gen_name(buffer: System.Text.StringBuilder) is
812
if has_argument_count_siblings /\ is_generic /\ !il_name_override? then
813
buffer
814
.append('\'')
815
.append(name)
816
.append('`')
817
.append(argument_names.count)
818
.append('\'');
819
else
820
super.gen_name(buffer);
821
fi
822
si
823
824
gen_type_prefix(buffer: StringBuilder) is
825
throw System.NotImplementedException("not implemented by {get_type()}");
826
si
827
828
// Shared head rendering for the classy kinds. Produces
829
// `<keyword> <name>[<type params>]`, optionally followed by the
830
// primary constructor arguments, so a hover on a declaration shows
831
// the shape you would write. The concrete kinds supply their
832
// keyword and whether a constructor applies.
833
// The name part already carries the type parameters through
834
// `render_name` (`render_type_argument_suffix`), so the head is just
835
// keyword + name + optional primary constructor arguments.
836
_describe_classy_head(keyword: string, include_constructor: bool) -> SignaturePart is
837
let parts = Collections.LIST[SignaturePart]();
838
parts.add(PARTS.literal(keyword));
839
parts.add(PARTS.name(self));
840
if include_constructor then
841
parts.add(_describe_constructor_arguments());
842
fi
843
return SignaturePart.SEQUENCE(parts);
844
si
845
846
// A generic classy always renders its formal type parameters.
847
render_type_argument_suffix() -> string is
848
if argument_names.count == 0 then
849
return "";
850
fi
851
let result = System.Text.StringBuilder();
852
result.append('[');
853
let first mut = true;
854
for name in argument_names do
855
if !first then
856
result.append(',');
857
fi
858
first = false;
859
result.append(name);
860
od
861
result.append(']');
862
return result.to_string();
863
si
864
865
_describe_constructor_arguments() -> SignaturePart is
866
let constructor = primary_constructor;
867
if !constructor? \/ constructor.arguments.count == 0 then
868
return PARTS.nil();
869
fi
870
let items = Collections.LIST[SignaturePart]();
871
for i in 0..constructor.arguments.count do
872
items.add(PARTS.sequence([
873
PARTS.literal("{constructor.argument_names[i]}: "),
874
PARTS.type_ref(constructor.arguments[i])
875
]));
876
od
877
return SignaturePart.WRAPPABLE("(", ",", false, ")", items);
878
si
879
880
_make_instance_method(location: LOCATION, span: LOCATION, name: string, is_underscore: bool, enclosing: Scope) -> Function is
881
if is_underscore then
882
let policy = IoC.CONTAINER.instance.build_flags.underscore_access;
883
884
if policy == Compiler.UnderscoreAccess.PRIVATE then
885
return Symbols.PRIVATE_METHOD(location, span, self, name, enclosing);
886
elif policy == Compiler.UnderscoreAccess.PROTECTED then
887
return Symbols.PROTECTED_METHOD(location, span, self, name, enclosing);
888
fi
889
fi
890
891
return Symbols.INSTANCE_METHOD(location, span, self, name, enclosing);
892
si
893
894
_make_static_method(location: LOCATION, span: LOCATION, name: string, is_underscore: bool, enclosing: Scope) -> Function is
895
if name =~ "init" then
896
return Symbols.STATIC_CONSTRUCTOR(location, span, self, name, enclosing);
897
fi
898
899
if is_underscore then
900
let policy = IoC.CONTAINER.instance.build_flags.underscore_access;
901
902
if policy == Compiler.UnderscoreAccess.PRIVATE then
903
return Symbols.PRIVATE_STATIC_METHOD(location, span, self, name, enclosing);
904
elif policy == Compiler.UnderscoreAccess.PROTECTED then
905
return Symbols.PROTECTED_STATIC_METHOD(location, span, self, name, enclosing);
906
fi
907
fi
908
909
return Symbols.STATIC_METHOD(location, span, self, name, enclosing);
910
si
911
si
912
913
class CLASS: Classy, Types.Typed is
914
short_description: string => "class {name}";
915
916
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
917
_describe_classy_head("class ", true);
918
919
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "class";
920
921
symbol_kind: SymbolKind => SymbolKind.CLASS;
922
completion_kind: CompletionKind => CompletionKind.CLASS;
923
924
925
is_inheritable: bool => true;
926
is_class: bool => true;
927
is_object: bool;
928
is_root_value_type: bool;
929
930
il_name_prefix: string => "class ";
931
932
is_instance_context: bool => true;
933
934
// Open/closed state for the class. Resolved explicitly at
935
// declare-symbols time (from the `open` modifier) for ghūl-
936
// declared classes, and at import time (from the presence of
937
// the `[Ghul.Internal.CLOSED_ATTRIBUTE]` marker) for imported
938
// classes. When neither path has set the state, the fallback
939
// is `is_reflected` — an unmarked imported class is treated as
940
// open since it was built by a compiler that doesn't yet emit
941
// the marker.
942
_is_open: bool;
943
_is_open_set: bool;
944
945
is_open: bool =>
946
if _is_open_set then _is_open
947
else is_reflected
948
fi;
949
950
mark_open() is
951
_is_open = true;
952
_is_open_set = true;
953
si
954
955
mark_closed() is
956
_is_open = false;
957
_is_open_set = true;
958
si
959
960
// Set from the `abstract` modifier during declare-symbols for
961
// ghūl-declared classes, and from `TypeAttributes.Abstract` at
962
// import time for reflected classes. An abstract class cannot
963
// be instantiated directly (constructor calls are rejected),
964
// and the closed-narrowing path excludes it from the
965
// complement universe so the narrow can reach subtype-only
966
// members.
967
//
968
// Beyond the explicit mark, a class is implicitly abstract
969
// when it carries any user-written body-less method — the
970
// user wrote a method without a body, clearly meaning it as
971
// a contract for subclasses to satisfy, and a bare instance
972
// of this class would throw on calling it. Today's ghūl
973
// synthesises a throw body for body-less ghūl-class methods
974
// rather than emitting them as real `ABSTRACT_METHOD`
975
// symbols, so the user-intent signal has to be captured
976
// explicitly via `mark_has_bodyless_method` during
977
// declare-symbols. (Inherited-but-unimplemented abstract
978
// methods aren't covered here — for those, the user should
979
// either override or mark the class explicitly `abstract`.)
980
_is_abstract: bool;
981
_has_bodyless_method: bool;
982
983
is_abstract: bool =>
984
_is_abstract \/ _has_bodyless_method;
985
986
mark_has_bodyless_method() is
987
_has_bodyless_method = true;
988
si
989
990
mark_abstract() is
991
_is_abstract = true;
992
si
993
994
gen_flags(buffer: StringBuilder) is
995
if is_abstract then
996
buffer.append("abstract ");
997
fi
998
buffer.append("auto ansi ");
999
gen_before_field_init(buffer);
1000
si
1001
1002
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1003
super.init(location, span, owner, name, arguments, enclosing_scope);
1004
1005
self.span = span;
1006
si
1007
1008
mark_is_object() is
1009
is_object = true;
1010
si
1011
1012
mark_is_root_value_type() is
1013
is_root_value_type = true;
1014
si
1015
1016
_calc_depth() -> int =>
1017
if is_object then
1018
0
1019
else
1020
ancestors[0].depth + 1
1021
fi;
1022
1023
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_class(self);
1024
1025
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1026
let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index);
1027
1028
declare(location, result, symbol_definition_listener);
1029
1030
return result;
1031
si
1032
1033
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1034
let result: Function mut;
1035
1036
if is_static then
1037
result = _make_static_method(location, span, name, is_private, enclosing);
1038
else
1039
result = _make_instance_method(location, span, name, is_private, enclosing);
1040
fi
1041
1042
declare_function_group(location, result, symbol_definition_listener);
1043
1044
return result;
1045
si
1046
1047
declare_generator_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1048
let result: Function mut;
1049
1050
if is_static then
1051
result = Symbols.STATIC_GENERATOR_METHOD(location, span, self, name, enclosing);
1052
else
1053
result = Symbols.INSTANCE_GENERATOR_METHOD(location, span, self, name, enclosing);
1054
fi
1055
1056
declare_function_group(location, result, symbol_definition_listener);
1057
1058
return result;
1059
si
1060
1061
declare_async_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1062
let result: Function mut;
1063
1064
if is_static then
1065
result = Symbols.STATIC_ASYNC_METHOD(location, span, self, name, enclosing);
1066
else
1067
result = Symbols.INSTANCE_ASYNC_METHOD(location, span, self, name, enclosing);
1068
fi
1069
1070
declare_function_group(location, result, symbol_definition_listener);
1071
1072
return result;
1073
si
1074
1075
declare_innate(location: LOCATION, name: string, innate_name: string, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1076
let result = Symbols.INNATE_METHOD(location, self, name, enclosing, innate_name);
1077
1078
declare_function_group(location, result, symbol_definition_listener);
1079
1080
return result;
1081
si
1082
1083
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1084
let result: Variable mut;
1085
1086
if is_static then
1087
result = Symbols.STATIC_FIELD(location, self, name);
1088
else
1089
result = Symbols.INSTANCE_FIELD(location, self, name);
1090
fi
1091
1092
declare(location, result, symbol_definition_listener);
1093
1094
return result;
1095
si
1096
1097
declare_property(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, is_assignable: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1098
let result: Property mut;
1099
1100
if is_static then
1101
result = Symbols.STATIC_PROPERTY(location, span, self, name, is_assignable, is_private);
1102
else
1103
result = Symbols.INSTANCE_PROPERTY(location, span, self, name, is_assignable, is_private);
1104
fi
1105
1106
declare(location, result, symbol_definition_listener);
1107
1108
return result;
1109
si
1110
1111
gen_type_prefix(buffer: StringBuilder) is
1112
buffer.append("class ");
1113
si
1114
si
1115
1116
class TRAIT: Classy, Types.Typed is
1117
short_description: string => "trait {name}";
1118
1119
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
1120
_describe_classy_head("trait ", false);
1121
1122
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "trait";
1123
1124
symbol_kind: SymbolKind => SymbolKind.INTERFACE;
1125
completion_kind: CompletionKind => CompletionKind.INTERFACE;
1126
1127
1128
is_inheritable: bool => true;
1129
is_trait: bool => true;
1130
1131
il_name_prefix: string => "class ";
1132
1133
is_instance_context: bool => true;
1134
1135
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1136
super.init(location, span, owner, name, arguments, enclosing_scope);
1137
si
1138
1139
_calc_depth() -> int =>
1140
ancestors |> map(a => a.depth) |> reduce(0, (max, n) => if n > max then n else max fi) + 1;
1141
1142
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1143
let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index);
1144
1145
declare(location, result, symbol_definition_listener);
1146
1147
return result;
1148
si
1149
1150
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
1151
return loader.load_trait(self);
1152
si
1153
1154
declare_innate(location: LOCATION, name: string, innate_name: string, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1155
let result = Symbols.INNATE_FUNCTION(location, self, name, enclosing, innate_name);
1156
1157
declare_function_group(location, result, symbol_definition_listener);
1158
1159
return result;
1160
si
1161
1162
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1163
let result: Function mut;
1164
1165
if is_static then
1166
IoC.CONTAINER.instance.logger.error(location, "cannot declare static method in trait");
1167
result = _make_static_method(location, span, name, is_private, enclosing);
1168
elif has_body then
1169
result = Symbols.DEFAULT_TRAIT_METHOD(location, span, self, name, enclosing);
1170
else
1171
result = Symbols.ABSTRACT_METHOD(location, span, self, name, enclosing);
1172
fi
1173
1174
declare_function_group(location, result, symbol_definition_listener);
1175
1176
return result;
1177
si
1178
1179
declare_generator_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1180
let result: Function mut;
1181
1182
if is_static then
1183
IoC.CONTAINER.instance.logger.error(location, "cannot declare static method in trait");
1184
result = Symbols.STATIC_GENERATOR_METHOD(location, span, self, name, enclosing);
1185
else
1186
result = Symbols.DEFAULT_TRAIT_GENERATOR_METHOD(location, span, self, name, enclosing);
1187
fi
1188
1189
declare_function_group(location, result, symbol_definition_listener);
1190
1191
return result;
1192
si
1193
1194
declare_async_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1195
let result: Function mut;
1196
1197
if is_static then
1198
IoC.CONTAINER.instance.logger.error(location, "cannot declare static method in trait");
1199
result = Symbols.STATIC_ASYNC_METHOD(location, span, self, name, enclosing);
1200
else
1201
result = Symbols.DEFAULT_TRAIT_ASYNC_METHOD(location, span, self, name, enclosing);
1202
fi
1203
1204
declare_function_group(location, result, symbol_definition_listener);
1205
1206
return result;
1207
si
1208
1209
declare_property(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, is_assignable: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1210
let result: Property mut;
1211
1212
if is_static then
1213
IoC.CONTAINER.instance.logger.error(location, "cannot declare static property in trait");
1214
result = Symbols.STATIC_PROPERTY(location, span, self, name, is_assignable, is_private);
1215
else
1216
result = Symbols.INSTANCE_PROPERTY(location, span, self, name, is_assignable, is_private);
1217
fi
1218
1219
declare(location, result, symbol_definition_listener);
1220
1221
return result;
1222
si
1223
1224
gen_flags(buffer: StringBuilder) is
1225
buffer.append("interface auto ansi ");
1226
gen_before_field_init(buffer);
1227
si
1228
1229
gen_type_prefix(buffer: StringBuilder) is
1230
buffer.append("class ");
1231
si
1232
1233
gen_extends(buffer: StringBuilder) is
1234
// do nothing
1235
si
1236
si
1237
1238
class STRUCT: Classy, Types.Typed is
1239
short_description: string => "struct {name}";
1240
1241
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
1242
_describe_classy_head("struct ", true);
1243
1244
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "struct";
1245
1246
symbol_kind: SymbolKind => SymbolKind.STRUCT;
1247
completion_kind: CompletionKind => CompletionKind.STRUCT;
1248
1249
1250
is_value_type: bool => true;
1251
1252
il_name_prefix: string => "valuetype ";
1253
1254
is_instance_context: bool => true;
1255
1256
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1257
super.init(location, span, owner, name, arguments, enclosing_scope);
1258
si
1259
1260
_calc_depth() -> int => 2; // object -> value type -> struct
1261
1262
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
1263
return loader.load_struct(self);
1264
si
1265
1266
// FIXME: most of these can be folded into Classy:
1267
1268
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1269
let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index);
1270
1271
declare(location, result, symbol_definition_listener);
1272
1273
return result;
1274
si
1275
1276
declare_innate(location: LOCATION, name: string, innate_name: string, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1277
let result = Symbols.INNATE_METHOD(location, self, name, enclosing, innate_name);
1278
1279
declare_function_group(location, result, symbol_definition_listener);
1280
1281
return result;
1282
si
1283
1284
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1285
let result: Function mut;
1286
1287
if is_static then
1288
result = _make_static_method(location, span, name, is_private, enclosing);
1289
else
1290
result = Symbols.STRUCT_METHOD(location, span, self, name, enclosing);
1291
fi
1292
1293
declare_function_group(location, result, symbol_definition_listener);
1294
1295
return result;
1296
si
1297
1298
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1299
let result: Variable mut;
1300
1301
if is_static then
1302
result = Symbols.STATIC_FIELD(location, self, name);
1303
else
1304
result = Symbols.STRUCT_FIELD(location, self, name);
1305
fi
1306
1307
declare(location, result, symbol_definition_listener);
1308
1309
return result;
1310
si
1311
1312
declare_property(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, is_assignable: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1313
let result: Property mut;
1314
1315
if is_static then
1316
result = Symbols.STATIC_PROPERTY(location, span, self, name, is_assignable, is_private);
1317
else
1318
result = Symbols.INSTANCE_PROPERTY(location, span, self, name, is_assignable, is_private);
1319
fi
1320
1321
declare(location, result, symbol_definition_listener);
1322
1323
return result;
1324
si
1325
1326
gen_type_prefix(buffer: StringBuilder) is
1327
buffer.append("valuetype ");
1328
si
1329
1330
gen_flags(buffer: StringBuilder) is
1331
// Sequential layout — C#'s default for structs — keeps
1332
// the in-memory field order the same as the declaration
1333
// order, so the layout of a ghūl struct matches a C# one
1334
// declared field-for-field the same way.
1335
buffer.append("sealed sequential ansi ");
1336
gen_before_field_init(buffer);
1337
si
1338
si
1339
1340
class UNION: Classy, Types.Typed is
1341
short_description: string => "union {name}";
1342
1343
describe(context: DESCRIBE_CONTEXT) -> SignaturePart is
1344
let parts = Collections.LIST[SignaturePart]();
1345
parts.add(_describe_classy_head("union ", false));
1346
1347
// A union's traits are not visible from its body - variants
1348
// only - and an impl block can add one from another file
1349
// entirely, so the hover lists them.
1350
let first mut = true;
1351
for a in ancestors do
1352
if !a.is_trait then
1353
continue;
1354
fi
1355
1356
parts.add(PARTS.literal(if first then ": " else ", " fi));
1357
parts.add(PARTS.type_ref(a));
1358
first = false;
1359
od
1360
1361
return SignaturePart.SEQUENCE(parts);
1362
si
1363
1364
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "union";
1365
1366
symbol_kind: SymbolKind => SymbolKind.CLASS;
1367
completion_kind: CompletionKind => CompletionKind.CLASS;
1368
1369
1370
il_name_prefix: string => "class ";
1371
1372
is_union: bool => true;
1373
is_instance_context: bool => true;
1374
1375
// The variant `?` and `!` target. `compile_access` reads
1376
// this to lower `u?` to `isa Default(u)` and `u!` to a cast
1377
// (plus single-field projection). Source unions get this
1378
// set during declare_members; cross-assembly unions get it
1379
// via the `DEFAULT_VARIANT_ATTRIBUTE` marker read in
1380
// `SYMBOL_FACTORY.materialize_variant`. When null — a
1381
// source union with no default, or a cross-asm union from
1382
// an older compiler that predates the marker — `?` short-
1383
// circuits to a bare null check and `!` to a plain
1384
// non-null assert.
1385
default_variant: VARIANT? public;
1386
1387
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1388
super.init(location, span, owner, name, arguments, enclosing_scope);
1389
si
1390
1391
_calc_depth() -> int => 1; // object -> union
1392
1393
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value =>
1394
loader.load_union(self);
1395
1396
// FIXME: most of these can be folded into Classy:
1397
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1398
let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index);
1399
1400
declare(location, result, symbol_definition_listener);
1401
1402
return result;
1403
si
1404
1405
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1406
let result: Function mut;
1407
1408
if is_static then
1409
result = _make_static_method(location, span, name, is_private, enclosing);
1410
else
1411
result = _make_instance_method(location, span, name, is_private, enclosing);
1412
fi
1413
1414
declare_function_group(location, result, symbol_definition_listener);
1415
1416
return result;
1417
si
1418
1419
declare_generator_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1420
let result: Function mut;
1421
1422
if is_static then
1423
result = Symbols.STATIC_GENERATOR_METHOD(location, span, self, name, enclosing);
1424
else
1425
result = Symbols.INSTANCE_GENERATOR_METHOD(location, span, self, name, enclosing);
1426
fi
1427
1428
declare_function_group(location, result, symbol_definition_listener);
1429
1430
return result;
1431
si
1432
1433
declare_async_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1434
let result: Function mut;
1435
1436
if is_static then
1437
result = Symbols.STATIC_ASYNC_METHOD(location, span, self, name, enclosing);
1438
else
1439
result = Symbols.INSTANCE_ASYNC_METHOD(location, span, self, name, enclosing);
1440
fi
1441
1442
declare_function_group(location, result, symbol_definition_listener);
1443
1444
return result;
1445
si
1446
1447
declare_property(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, is_assignable: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1448
let result: Property mut;
1449
1450
if is_static then
1451
result = Symbols.STATIC_PROPERTY(location, span, self, name, is_assignable, is_private);
1452
else
1453
result = Symbols.INSTANCE_PROPERTY(location, span, self, name, is_assignable, is_private);
1454
fi
1455
1456
declare(location, result, symbol_definition_listener);
1457
1458
return result;
1459
si
1460
1461
// Supports the backing fields the auto-property lowering
1462
// synthesises for primary-constructor parameters. User-written
1463
// fields inside a union body aren't reachable from the parser,
1464
// so this is exercised only for synthesised members.
1465
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1466
let result: Variable mut;
1467
1468
if is_static then
1469
result = Symbols.STATIC_FIELD(location, self, name);
1470
else
1471
result = Symbols.INSTANCE_FIELD(location, self, name);
1472
fi
1473
1474
declare(location, result, symbol_definition_listener);
1475
1476
return result;
1477
si
1478
1479
declare_variant(location: LOCATION, span: LOCATION, name: string, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1480
let result = Symbols.VARIANT(location, span, self, name, argument_names, enclosing);
1481
1482
declare(location, result, symbol_definition_listener);
1483
1484
return result;
1485
si
1486
1487
gen_type_prefix(buffer: StringBuilder) is
1488
buffer.append("class ");
1489
si
1490
1491
gen_flags(buffer: StringBuilder) is
1492
buffer.append("auto ansi ");
1493
gen_before_field_init(buffer);
1494
si
1495
si
1496
1497
class VARIANT: Classy, Types.Typed is
1498
_field_names: Collections.LIST[string];
1499
1500
short_description: string => "variant {name}";
1501
1502
// No `variant` keyword: a variant has no standalone declaration
1503
// syntax outside its union, so the head is just the union-qualified
1504
// name plus any fields, and the kind is carried by `describe_kind`.
1505
describe(context: DESCRIBE_CONTEXT) -> SignaturePart is
1506
let parts = Collections.LIST[SignaturePart]();
1507
parts.add(PARTS.name(self));
1508
if _field_names.count > 0 then
1509
let items = Collections.LIST[SignaturePart]();
1510
for name in _field_names do
1511
let member = find_member(name);
1512
if member? then
1513
items.add(PARTS.sequence([
1514
PARTS.literal("{member.name}: "),
1515
PARTS.type_ref(member.type!)
1516
]));
1517
fi
1518
od
1519
parts.add(SignaturePart.WRAPPABLE("(", ",", false, ")", items));
1520
fi
1521
return SignaturePart.SEQUENCE(parts);
1522
si
1523
1524
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "variant";
1525
1526
symbol_kind: SymbolKind => SymbolKind.CLASS;
1527
completion_kind: CompletionKind => CompletionKind.CLASS;
1528
1529
1530
il_name_prefix: string => "class ";
1531
1532
is_variant: bool => true;
1533
is_unit_variant: bool => _field_names.count == 0;
1534
is_instance_context: bool => true;
1535
can_accept_actual_type_arguments: bool => true;
1536
1537
// Total field count (own + inherited). `own_field_count`
1538
// excludes inherited primary fields; this property includes
1539
// them so the single-field unwrap projection considers the
1540
// variant's full surface — a `BOX(payload: T, ..)` against
1541
// a union with primary params is multi-field overall and
1542
// unwraps to the variant itself, not the lone own field.
1543
field_count: int => _field_names.count;
1544
1545
// True for the variant the union nominated as its default —
1546
// either via the `default` modifier, or as the lone non-unit
1547
// variant fallback. Set by declare_symbols from the AST flag.
1548
is_default: bool public;
1549
1550
// Own-field count (own + inherited-primary kept in
1551
// `_field_names`; `own_field_count` excludes the inherited
1552
// ones so the implicit-default rule "exactly one non-unit
1553
// variant" measures variants by what they declare themselves
1554
// — a variant whose only fields come from the union's
1555
// primary-constructor splice is still a unit variant for
1556
// that rule.
1557
own_field_count: int public;
1558
1559
field_descriptions: string =>
1560
if _field_names.count == 0 then
1561
"";
1562
else
1563
"({_field_names |> map(name => let member = find_member(name)! in "{member.name}: {member.type}") |> join(", ")})";
1564
fi;
1565
1566
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1567
super.init(location, span, owner, name, arguments, enclosing_scope);
1568
1569
_field_names = Collections.LIST[string]();
1570
si
1571
1572
_calc_depth() -> int => 2; // object -> union -> variant
1573
1574
get_destructure_member_name(index: int) -> string? =>
1575
if index < _field_names.count then
1576
_field_names[index];
1577
else
1578
null
1579
fi;
1580
1581
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value =>
1582
loader.load_variant(self);
1583
1584
// FIXME: most of these can be folded into Classy:
1585
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1586
let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index);
1587
1588
declare(location, result, symbol_definition_listener);
1589
1590
return result;
1591
si
1592
1593
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1594
let result: Function mut;
1595
1596
if is_static then
1597
result = _make_static_method(location, span, name, is_private, enclosing);
1598
else
1599
result = _make_instance_method(location, span, name, is_private, enclosing);
1600
fi
1601
1602
declare_function_group(location, result, symbol_definition_listener);
1603
1604
return result;
1605
si
1606
1607
declare_generator_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1608
let result: Function mut;
1609
1610
if is_static then
1611
result = Symbols.STATIC_GENERATOR_METHOD(location, span, self, name, enclosing);
1612
else
1613
result = Symbols.INSTANCE_GENERATOR_METHOD(location, span, self, name, enclosing);
1614
fi
1615
1616
declare_function_group(location, result, symbol_definition_listener);
1617
1618
return result;
1619
si
1620
1621
declare_async_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1622
let result: Function mut;
1623
1624
if is_static then
1625
result = Symbols.STATIC_ASYNC_METHOD(location, span, self, name, enclosing);
1626
else
1627
result = Symbols.INSTANCE_ASYNC_METHOD(location, span, self, name, enclosing);
1628
fi
1629
1630
declare_function_group(location, result, symbol_definition_listener);
1631
1632
return result;
1633
si
1634
1635
declare_innate(location: LOCATION, name: string, innate_name: string, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1636
let result = Symbols.INNATE_METHOD(location, self, name, enclosing, innate_name);
1637
1638
declare_function_group(location, result, symbol_definition_listener);
1639
1640
return result;
1641
si
1642
1643
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1644
let result = Symbols.VARIANT_FIELD(location, self, name);
1645
1646
_field_names.add(name);
1647
own_field_count = own_field_count + 1;
1648
1649
declare(location, result, symbol_definition_listener);
1650
1651
return result;
1652
si
1653
1654
// Used by the reflection layer: when a cross-assembly
1655
// variant's symbol is materialized, its fields are added
1656
// via `add_member` (which doesn't touch `_field_names`).
1657
// Positional destructure (`let (v, r) = step`) consults
1658
// `_field_names` via `get_destructure_member_name(index)`,
1659
// so reflected variants need this list populated in source
1660
// order. The reflection caller iterates the variant's
1661
// instance fields in their .NET-metadata declaration order
1662
// (which matches source order in practice) and calls this
1663
// for each.
1664
register_reflected_field_name(name: string) is
1665
_field_names.add(name);
1666
own_field_count = own_field_count + 1;
1667
si
1668
1669
// Called by declare_members for variant fields produced by
1670
// expanding a `..` splice against the enclosing union's
1671
// primary-constructor parameters. No VARIANT_FIELD is created
1672
// — the union base owns the storage — but the name still
1673
// contributes to the variant's arity (`is_unit_variant`,
1674
// positional destructure, field-description rendering).
1675
register_inherited_primary_field_name(name: string) is
1676
_field_names.add(name);
1677
si
1678
1679
declare_property(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, is_assignable: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1680
let result: Property mut;
1681
1682
if is_static then
1683
result = Symbols.STATIC_PROPERTY(location, span, self, name, is_assignable, is_private);
1684
else
1685
result = Symbols.INSTANCE_PROPERTY(location, span, self, name, is_assignable, is_private);
1686
fi
1687
1688
declare(location, result, symbol_definition_listener);
1689
1690
return result;
1691
si
1692
1693
specialize(arguments: Collections.List[Type]) -> Symbol is
1694
return GENERIC(location, self, arguments);
1695
si
1696
1697
gen_dot(buffer: System.Text.StringBuilder) is
1698
buffer.append(".");
1699
si
1700
1701
gen_type_prefix(buffer: StringBuilder) is
1702
buffer.append("class ");
1703
si
1704
1705
gen_flags(buffer: StringBuilder) is
1706
buffer.append("sealed auto ansi ");
1707
gen_before_field_init(buffer);
1708
si
1709
si
1710
1711
class ENUM_STRUCT: STRUCT is
1712
_next_value: int;
1713
1714
next_value: int is
1715
let result = _next_value;
1716
1717
_next_value = _next_value + 1;
1718
1719
return result;
1720
si
1721
1722
short_description: string => "enum {name}";
1723
1724
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
1725
PARTS.sequence([PARTS.literal("enum "), PARTS.name(self)]);
1726
1727
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "enum";
1728
1729
symbol_kind: SymbolKind => SymbolKind.ENUM;
1730
completion_kind: CompletionKind => CompletionKind.ENUM;
1731
1732
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
1733
super.init(location, span, owner, name, Collections.LIST[string](), enclosing_scope);
1734
si
1735
1736
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
1737
return loader.load_struct(self);
1738
si
1739
1740
declare_enum_member(location: LOCATION, name: string, value: string? mut, symbol_definition_listener: SymbolDefinitionListener?) is
1741
if !value? then
1742
value = "{next_value}";
1743
fi
1744
1745
let result = Symbols.ENUM_STRUCT_MEMBER(location, self, name, value);
1746
1747
declare(location, result, symbol_definition_listener);
1748
si
1749
1750
gen_flags(buffer: StringBuilder) is
1751
// Enums use auto layout — the runtime treats them as
1752
// their underlying scalar type and the explicit-value
1753
// `value__` field carries the storage.
1754
buffer.append("sealed auto ansi ");
1755
gen_before_field_init(buffer);
1756
si
1757
si
1758
1759
class VOID_STRUCT: STRUCT is
1760
is_void: bool => true;
1761
1762
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, arguments: Collections.List[string], enclosing_scope: Scope) is
1763
super.init(location, span, owner, name, arguments, enclosing_scope);
1764
si
1765
1766
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
1767
IoC.CONTAINER.instance.logger.error(location, "cannot use void value here");
1768
1769
return loader.load_struct(self);
1770
si
1771
si
1772
1773
class FRAME: Classy is
1774
_next_id: int static;
1775
1776
_closure: Closure;
1777
_constructor: Method?;
1778
_captures: Collections.LIST[Field];
1779
1780
next_id: int static is
1781
let result = _next_id;
1782
1783
_next_id = _next_id + 1;
1784
1785
return result;
1786
si
1787
1788
init(owner: Scope, closure: Closure) is
1789
let owner_owner: Scope mut;
1790
1791
if isa Symbol(owner) then
1792
let owner_symbol = owner;
1793
1794
owner_owner = owner_symbol.owner!;
1795
else
1796
owner_owner = owner;
1797
fi
1798
1799
super.init(LOCATION.internal, LOCATION.internal, owner_owner, "$frame_{next_id}", System.Array.empty[string](), owner);
1800
1801
assert closure.captured_values?;
1802
1803
_closure = closure;
1804
_captures = Collections.LIST[Field](closure.captured_values!.count);
1805
1806
set_type(Types.NAMED(self));
1807
si
1808
1809
declare() is
1810
let symbol_definition_listener = IoC.CONTAINER.instance.symbol_definition_locations;
1811
1812
if !_constructor? then
1813
declare_constructor(symbol_definition_listener);
1814
1815
type = Types.NAMED(self);
1816
else
1817
// Iterative-inference body retry: a field's type may
1818
// have been refreshed by Closure.find_or_add_capture
1819
// when the source variable's type resolved between
1820
// iterations. The constructor's argument types are a
1821
// snapshot from the first declare() call — refresh
1822
// them so the frame ctor's IL signature matches the
1823
// resolved field types instead of the iter-1
1824
// placeholder.
1825
refresh_constructor_argument_types();
1826
fi
1827
si
1828
1829
declare_constructor(symbol_definition_listener: SymbolDefinitionListener?) is
1830
let constructor = Symbols.INSTANCE_METHOD(LOCATION.internal, LOCATION.internal, self, "init", self);
1831
1832
let argument_names = Collections.LIST[string]();
1833
let arguments = Collections.LIST[Type]();
1834
1835
for `field in symbols |> filter(s => s.is_variable /\ s.name !~ "$recurse") |> map(s => cast Variable?(s)!) do
1836
argument_names.add(`field.name);
1837
// Defensive: a frame field captured during a closure-load
1838
// for a forward-referenced variable (e.g. mutual recursion
1839
// between two let-bound lambdas) may not yet have its
1840
// type set. set_arguments asserts no null entries, so
1841
// default to ERROR. The upstream "variable is not
1842
// defined here" diagnostic is already emitted; the IL
1843
// signature emission stage produces a `/* error type */`
1844
// comment harmlessly.
1845
arguments.add(if `field.type? then `field.type else Types.ERROR() fi);
1846
od
1847
1848
constructor.set_arguments(argument_names, arguments);
1849
1850
constructor.set_void_return_type();
1851
1852
declare(LOCATION.internal, constructor, symbol_definition_listener);
1853
1854
_constructor = constructor;
1855
si
1856
1857
refresh_constructor_argument_types() is
1858
let argument_names = Collections.LIST[string]();
1859
let arguments = Collections.LIST[Type]();
1860
1861
for `field in symbols |> filter(s => s.is_variable /\ s.name !~ "$recurse") |> map(s => cast Variable?(s)!) do
1862
argument_names.add(`field.name);
1863
arguments.add(if `field.type? then `field.type else Types.ERROR() fi);
1864
od
1865
1866
_constructor!.set_arguments(argument_names, arguments);
1867
si
1868
1869
get_captured(name: string) -> Field? is
1870
for c in _captures do
1871
if c.name =~ name then
1872
return c;
1873
fi
1874
od
1875
return null;
1876
si
1877
1878
declare_captured(name: string, type: Type?, symbol_definition_listener: SymbolDefinitionListener?) -> Field is
1879
// type may be null during early inference iterations — the
1880
// body-retry loop walks again once the source's type resolves,
1881
// and the field's type is set on the later walk. Mirrors the
1882
// pre-strict-mode behaviour where Type was passed through
1883
// unchecked.
1884
let `field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, name);
1885
1886
declare(location, `field, symbol_definition_listener);
1887
1888
if type? then
1889
`field.set_type(type);
1890
fi
1891
1892
_captures.add(`field);
1893
1894
return `field;
1895
si
1896
1897
declare_recurse(symbol_definition_listener: SymbolDefinitionListener?) -> Field is
1898
let `field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$recurse");
1899
1900
declare(location, `field, symbol_definition_listener);
1901
1902
`field.set_type(_closure.type!);
1903
1904
_captures.add(`field);
1905
1906
return `field;
1907
si
1908
1909
try_update_recurse_type(type: Type) is
1910
let `field = get_captured("$recurse");
1911
1912
if `field? then
1913
`field.set_type(type);
1914
fi
1915
si
1916
1917
set_type_arguments(arguments: Collections.Iterable[Symbol]) is
1918
// self.arguments = arguments |> map(a => a.type) |> collect();
1919
self.argument_names = arguments |> map(a => a.name) |> collect();
1920
si
1921
1922
gen_all(context: IR.CONTEXT, symbol_loader: SYMBOL_LOADER) is
1923
gen_definition_header(context);
1924
1925
context.write_line("{{");
1926
1927
context.indent();
1928
1929
for c in _captures do
1930
c.gen_definition_header(context);
1931
od
1932
1933
gen_constructor(context, symbol_loader);
1934
1935
gen_closure(context);
1936
1937
context.outdent();
1938
1939
context.write_line("}}");
1940
si
1941
1942
gen_constructor(context: IR.CONTEXT, symbol_loader: SYMBOL_LOADER) is
1943
let internal = LOCATION.internal;
1944
1945
_constructor!.gen_definition_header(context);
1946
1947
context.write_line("{{");
1948
1949
context.indent();
1950
1951
try
1952
for c in _captures |> filter(c => c.name !~ "$recurse") do
1953
let argument = LOCAL_ARGUMENT(internal, _constructor!, c.name);
1954
argument.set_type(c.type!);
1955
1956
c.store(
1957
internal,
1958
IR.Values.Load.REFERENCE_SELF(self),
1959
argument.load(LOCATION.internal, null, symbol_loader),
1960
symbol_loader,
1961
true
1962
).gen(context);
1963
od
1964
catch ex: System.Exception
1965
IoC.CONTAINER.instance.logger.exception(location, ex, "error generating closure frame constructor");
1966
yrt
1967
1968
context.write_line("ret");
1969
1970
context.outdent();
1971
context.write_line("}}");
1972
si
1973
1974
gen_closure(context: IR.CONTEXT) is
1975
_closure.gen_definition_header(context);
1976
1977
context.write_line("{{");
1978
1979
context.indent();
1980
1981
_closure.gen_argument_custom_attributes(context);
1982
1983
context.write_line(_closure.il_body);
1984
1985
context.outdent();
1986
context.write_line("}}");
1987
si
1988
1989
get_create_instance(
1990
actual_arguments: Collections.List[Value],
1991
type_arguments: Collections.List[Type]?
1992
) -> IR.Values.Value? is
1993
declare();
1994
1995
try
1996
return
1997
if type_arguments? then
1998
let specialized_self = GENERIC(location, self, type_arguments);
1999
let ctor = cast Function?(specialized_self.find_member("init"))!;
2000
2001
IR.Values.NEW(specialized_self.type, ctor, actual_arguments)
2002
else
2003
IR.Values.NEW(type!, _constructor!, actual_arguments)
2004
fi
2005
.freeze();
2006
catch ex: System.Exception
2007
CONTAINER.instance.logger.exception(self.location, ex, "trying to generate frame instance");
2008
yrt
2009
return null;
2010
si
2011
2012
gen_access(buffer: StringBuilder) is
2013
buffer.append("private ");
2014
si
2015
2016
gen_type_prefix(buffer: StringBuilder) is
2017
buffer.append("class ");
2018
si
2019
si
2020
2021
class ENUM_STRUCT_MEMBER: Symbol, Types.Typed is
2022
_enum: ENUM_STRUCT => cast ENUM_STRUCT?(owner)!;
2023
2024
type: Type => _enum.type!;
2025
2026
value: string;
2027
2028
short_description: string => name;
2029
2030
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
2031
PARTS.sequence([
2032
PARTS.name(self),
2033
PARTS.literal(" = {value}")
2034
]);
2035
2036
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "enum member";
2037
2038
symbol_kind: SymbolKind => SymbolKind.ENUM_MEMBER;
2039
completion_kind: CompletionKind => CompletionKind.ENUM_MEMBER;
2040
2041
init(location: LOCATION, owner: ENUM_STRUCT, name: string, value: string) is
2042
super.init(location, owner, name);
2043
2044
self.value = value;
2045
si
2046
2047
specialize(type_map: Collections.Map[string,Symbols.Symbol], owner: GENERIC) -> Symbol
2048
=> self;
2049
2050
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
2051
let result = loader.load_enum_struct_member(self);
2052
2053
return result;
2054
si
2055
2056
gen_definition_header(buffer: StringBuilder) is
2057
buffer
2058
.append(".field public static literal ");
2059
2060
type.gen_type(buffer);
2061
2062
gen_name(buffer);
2063
2064
buffer
2065
.append(" = int32(")
2066
.append(value)
2067
.append(')');
2068
si
2069
si
2070
si