Skip to content
← Back

src/semantic/symbols/variable.ghul

1
namespace Semantic.Symbols is
2
use IO.Std;
3
4
use System.Text.StringBuilder;
5
6
use IoC;
7
use Logging;
8
use Source;
9
10
use Types.Type;
11
12
use IR.Values.Value;
13
use IR.Values.DUMMY;
14
15
class Variable: Symbol, Types.SettableTyped abstract is
16
type: Type?;
17
set_type(value: Type) is type = value; si
18
19
short_description: string => "{name}: {if type? then type!.short_description else "?" fi}";
20
21
// Concrete Variable / Field describe overrides delegate
22
// straight through to Symbol._describe_typed with the live
23
// declared type — the dual `declared → narrowed` rule lives
24
// there, shared with Property so a narrowed member access
25
// hovers the same shape as a narrowed local.
26
27
symbol_kind: SymbolKind => SymbolKind.VARIABLE;
28
completion_kind: CompletionKind => CompletionKind.VARIABLE;
29
30
is_defined: bool public;
31
is_variable: bool => true;
32
is_assigned: bool public;
33
is_reassigned: bool public;
34
is_mutable_marked: bool public;
35
is_captured: bool public;
36
is_disposed: bool public;
37
38
// Set by the `mark-boxed-locals` analysis pass when a
39
// local is both captured by a closure and reassigned.
40
// Storage becomes `Ghul.BOX[type]`; reads/writes
41
// dispatch through the box's `.value` field; the closure
42
// body and the enclosing scope share one heap cell. A
43
// flag rather than a subclass so symbol identity stays
44
// stable across the analysis-pass marking — IDE caches
45
// (`SYMBOL_DEFINITION_LOCATIONS`, `SymbolUseListener`)
46
// hold direct pointers from declare-symbols time and
47
// mustn't be invalidated. See
48
// `docs/claude/boxed-captured-mutables.md`.
49
is_boxed: bool public;
50
51
// When this variable lives on the synthesised state-machine
52
// frame of a generator function, this points at the matching
53
// `Field` on that class. Load/Store IR for the variable then
54
// routes through `ldarg.0; ldfld/stfld <state_machine_field>`
55
// instead of `ldarg`/`ldloc`/`starg`/`stloc`. Populated by
56
// STATE_MACHINE_FRAME for parameters at declare-time and
57
// for body locals by generate_il during the body walk. Null
58
// for variables in plain (non-generator) functions.
59
state_machine_field: Field? public;
60
61
// The actual IL slot type for this Variable. Defaults to
62
// `type`; switches to `Ghul.BOX[type]` when `is_boxed`.
63
// Queried at IL emission time and by
64
// `closure.find_or_add_capture` when declaring the
65
// frame field. User-visible queries (HOVER, completion,
66
// type-checking) continue to use `type` directly so the
67
// box is invisible above IL level.
68
storage_type: Type? =>
69
if is_boxed /\ type? then
70
IoC.CONTAINER.instance.innate_symbol_lookup.get_box_type(type!)
71
else
72
type
73
fi;
74
75
// While `type` is an INFERRED_VARIABLE_TYPE placeholder,
76
// a Variable holds constraints in three shapes — all
77
// accumulated by the body-retry walk and consulted by
78
// `try_get_inferred_type` when collapsing to a resolved
79
// type.
80
//
81
// `_lub_map` — lower-bound type candidates. Records
82
// "this placeholder IS-A T" from sites that produce a
83
// concrete value typed T to be held in the placeholder
84
// (assignment RHS `v = expr`, lambda call-site actual
85
// passed to a placeholder formal). The LUB-map collapses
86
// these to a single widest-needed candidate type — the
87
// classical least-upper-bound operation.
88
//
89
// `_upper_bounds` — upper-bound type candidates. Records
90
// "this placeholder MUST FIT INTO T" from sites that
91
// consume the placeholder via a concretely-typed slot
92
// (passing the placeholder as an argument to `g(a: T)`).
93
// These are validated against the LUB candidate but
94
// never widen it. Distinct from `_lub_map` so that an
95
// upper-bound `object` (e.g. from `g(v: object)`) does
96
// not dominate the LUB and force v→object when an
97
// assignment said v=bool.
98
//
99
// `_constraints` — operation/structural constraints.
100
// Records "this placeholder is consumed by `.foo`" /
101
// "this placeholder is called with (int)" etc. from
102
// sites that exercise the placeholder without
103
// producing a candidate type. The LUB candidate is
104
// accepted only if every accumulated constraint
105
// discharges against it.
106
//
107
// All three are lazily constructed; null when nothing
108
// has been recorded yet.
109
110
_lub_map: Semantic.LEAST_UPPER_BOUND_MAP?;
111
112
// True when the type-bound LUB has at least one
113
// candidate. Callers gate speculative match propagation (the
114
// call-site-synthesized function-type-shape constraint
115
// used by mutual-recursion inference) on this to avoid
116
// polluting the LUB with a synthesised shape when an
117
// explicit assignment already supplied a candidate —
118
// the synthesised arg types come from the call site and
119
// may not match the assigned shape, leaving the per-
120
// position merge unable to fold the two entries.
121
has_lub_candidate: bool => _lub_map? /\ _lub_map.types.count > 0;
122
123
// Linear list with `matches`-based dedup. A SET would need
124
// Type to override `equals`/`get_hash_code` (it doesn't, and
125
// `matches` isn't an equivalence relation so couldn't back a
126
// SET anyway). In practice this list is tiny (0-2 entries) so
127
// a linear contains-check is cheap.
128
_upper_bounds: Collections.LIST[Type]?;
129
130
// Stored as a SET to deduplicate constraints emitted
131
// from multiple equivalent operation sites (e.g. two
132
// `.foo` accesses on the same placeholder collapse to a
133
// single MEMBER_CONSTRAINT("foo")). Constraint subclasses
134
// override `equals` and `get_hash_code` to make that work.
135
_constraints: Collections.SET[Semantic.Constraint]?;
136
137
init(location: LOCATION, owner: Scope, name: string) is
138
super.init(location, owner, name);
139
si
140
141
// Records a lower-bound type candidate ("placeholder IS-A
142
// this type") into `_lub_map`. Returns true if the bound
143
// was actually added (i.e. the symbol is unresolved AND
144
// the bound carries information). Callers use this to
145
// signal progress to the retry loop via
146
// _logger.mark_consumed_any so the body retry kicks in
147
// even for cases where the body walk itself didn't fire
148
// mark_consumed_any (e.g. member access on placeholder
149
// receiver poisons silently to ERROR without consuming
150
// the receiver).
151
add_lower_bound(bound: Type?) -> bool is
152
// Skip only once the symbol's type is fully settled
153
// (no placeholders, no ERROR). Provisional composites
154
// — e.g. a `Func[List[int], INFERRED_RETURN_TYPE]`
155
// recorded on an early iter before the lambda's return
156
// resolved — still need refining; without further LUB
157
// entries the per-position merge has nothing to fold
158
// the resolved arity into. The earlier `!is_sentinel`
159
// gate stopped accepting refinement constraints in
160
// exactly the case where they were most needed (and
161
// produced the survey §4.24 / fuzz finding 04 IL
162
// placeholder leak).
163
if type? /\ type.is_settled then
164
return false;
165
fi
166
167
if !bound? \/ bound.is_sentinel then
168
return false;
169
fi
170
171
if !_lub_map? then
172
_lub_map = Semantic.LEAST_UPPER_BOUND_MAP();
173
fi
174
175
_lub_map.add(bound);
176
return true;
177
si
178
179
// Re-entrancy latch for try_get_inferred_type. Resolving a
180
// candidate composite recurses into the origins of any
181
// placeholders it carries; two unresolved variables whose
182
// candidates reference each other would recurse forever.
183
// Answering null on re-entry treats the cycle as
184
// still-unresolved, which is what it is.
185
_resolving_inferred_type: bool;
186
187
try_get_inferred_type() -> Type? is
188
if _resolving_inferred_type then
189
return null;
190
fi
191
192
_resolving_inferred_type = true;
193
let result = _try_get_inferred_type();
194
_resolving_inferred_type = false;
195
196
return result;
197
si
198
199
_try_get_inferred_type() -> Type? is
200
let candidate: Type? mut = null;
201
202
if _lub_map? then
203
candidate = _lub_map.get_result();
204
fi
205
206
// No lower-bound candidate — fall back to upper bounds.
207
// Single upper bound: return it (preserves the bare
208
// "only signal is g(v: object)" case as v->object).
209
// Multiple upper bounds: keep deferred — no general
210
// narrowest-of-uppers heuristic yet. Returning null
211
// here leaves the placeholder unresolved and lets the
212
// existing "cannot infer" diagnostic surface if no
213
// further info appears.
214
if !candidate? then
215
if _upper_bounds? /\ _upper_bounds.count == 1 then
216
candidate = _upper_bounds[0];
217
else
218
return null;
219
fi
220
fi
221
222
// The candidate may be a composite that captured other
223
// variables' placeholders before their origins settled
224
// (a lambda type recorded at a call site, a tuple LUB
225
// entry). Nothing rewrites the stored composite when
226
// those origins settle, so collapse the settled slots
227
// here - the chokepoint every consumer reads through -
228
// rather than letting the stale placeholder propagate
229
// into committed types and eventually IL.
230
candidate = SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(candidate!);
231
232
// Upper-bound validation: the chosen candidate must
233
// be assignable to every recorded upper bound. If
234
// not, the placeholder is being asked to be both
235
// wider (assignment / lower bound) and narrower
236
// (passed to a too-narrow slot). Return null so the
237
// placeholder stays unresolved; downstream
238
// assignability errors surface at the offending sites.
239
if _upper_bounds? then
240
for upper in _upper_bounds do
241
if !upper.is_assignable_from(candidate) then
242
return null;
243
fi
244
od
245
fi
246
247
// Operation-side filter: the candidate is only
248
// valid if every accumulated constraint discharges
249
// against it. A rejection here means the LUB picked
250
// a type that doesn't expose an operation the user's
251
// code performs on the placeholder — return null so
252
// the placeholder stays unresolved and the retry
253
// loop has another iteration to accumulate more
254
// information. If no candidate ever discharges, the
255
// slot stays unresolved and the non-convergence sweep
256
// reports it as cannot infer type here rather than
257
// silently producing bad IL.
258
if _constraints? then
259
for c in _constraints do
260
if !c.try_discharge(candidate) then
261
return null;
262
fi
263
od
264
fi
265
266
return candidate;
267
si
268
269
// Record an upper bound on this placeholder's eventual
270
// type. The chosen LUB candidate (from lower bounds)
271
// must be assignable to every upper bound to be accepted
272
// by `try_get_inferred_type`.
273
//
274
// Returns true iff the bound carries new information —
275
// wasn't already recorded by `matches`. The
276
// retry loop uses this signal via `mark_consumed_any`.
277
//
278
// Skipped when the placeholder already has a concrete
279
// resolved type (constraints accumulate only while
280
// unresolved) and when the bound is itself a sentinel
281
// or type variable (no information).
282
add_upper_bound(bound: Type?) -> bool is
283
if type? /\ !type.is_sentinel then
284
return false;
285
fi
286
287
if !bound? \/ bound.is_sentinel \/ bound.is_type_variable then
288
return false;
289
fi
290
291
let upper_bounds mut = _upper_bounds;
292
293
if !upper_bounds? then
294
upper_bounds = Collections.LIST[Type]();
295
_upper_bounds = upper_bounds;
296
else
297
for existing in upper_bounds do
298
if existing.matches(bound) then
299
return false;
300
fi
301
od
302
fi
303
304
upper_bounds.add(bound);
305
return true;
306
si
307
308
// Record an operation/structural constraint against this
309
// placeholder origin. Returns true iff the constraint
310
// carries information that wasn't already recorded — i.e.
311
// wasn't already in the set keyed on its `equals` /
312
// `get_hash_code`. The retry loop uses this signal to
313
// drive `_logger.mark_consumed_any`.
314
//
315
// Like `add_lower_bound`, skipped only when the symbol's
316
// type is fully settled — provisional composites are
317
// still legitimately refining and should keep accumulating
318
// operation evidence too.
319
add_constraint(constraint: Semantic.Constraint?) -> bool is
320
if type? /\ type.is_settled then
321
return false;
322
fi
323
324
if !constraint? then
325
return false;
326
fi
327
328
if !_constraints? then
329
_constraints = Collections.SET[Semantic.Constraint]();
330
elif _constraints.contains(constraint) then
331
return false;
332
fi
333
334
_constraints.add(constraint);
335
return true;
336
si
337
338
specialize(type_map: Collections.Map[string,Type], owner: GENERIC) -> Symbol is
339
let result = cast Variable?(memberwise_clone())!;
340
341
result.specialized_from = self;
342
343
if type? then
344
let specialized_type = type.specialize(type_map);
345
346
result.type = specialized_type;
347
fi
348
349
result.owner = owner;
350
351
return result;
352
si
353
354
gen_reference(buffer: StringBuilder) is
355
gen_name(buffer);
356
si
357
358
gen_definition_header(buffer: StringBuilder) is
359
gen_directive(buffer);
360
361
gen_access(buffer);
362
363
gen_flags(buffer);
364
365
gen_open_paren(buffer);
366
367
storage_type!.gen_type(buffer);
368
369
gen_owner_name(buffer);
370
371
gen_name(buffer);
372
373
gen_close_paren(buffer);
374
si
375
376
gen_directive(buffer: StringBuilder) is si
377
378
gen_access(buffer: StringBuilder) is
379
si
380
381
gen_flags(buffer: StringBuilder) is
382
si
383
384
gen_owner_name(buffer: StringBuilder) is
385
si
386
387
gen_open_paren(buffer: StringBuilder) is
388
si
389
390
gen_close_paren(buffer: StringBuilder) is
391
si
392
si
393
394
// Minimal Variable subclass used as the origin symbol for an
395
// unbound owner type-arg placeholder at a constructor expression.
396
// Carries the inherited `_lub_map` accumulator so overload back-
397
// feed can push concrete types from downstream usage. Never
398
// appears in IL — it's an inference-time-only sentinel that
399
// identifies "the T slot of this specific construction".
400
class INFERRED_TYPE_ARG_ORIGIN: Variable is
401
init(location: LOCATION, owner: Scope, name: string) is
402
super.init(location, owner, name);
403
si
404
405
gen_directive(buffer: System.Text.StringBuilder) is
406
si
407
si
408
409
// FIXME: pull up common code into a local + argument superclass:
410
class LOCAL_VARIABLE: Variable, Types.SettableTyped is
411
is_local: bool => true;
412
413
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
414
_describe_typed(context, PARTS.literal(name), type);
415
416
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
417
_local_kind();
418
419
_local_kind() -> string =>
420
if is_boxed then "captured variable"
421
elif is_captured then "captured value"
422
elif is_disposed then "scoped disposal value"
423
elif is_reassigned then "local variable"
424
else "local value"
425
fi;
426
427
init(location: LOCATION, owner: Scope, name: string) is
428
super.init(location, owner, name);
429
430
il_name_override = IoC.CONTAINER.instance.local_id_generator.get_unique_il_name_for(name);
431
si
432
433
define() is
434
is_defined = true;
435
si
436
437
check_is_defined(location: LOCATION) is
438
if !is_defined then
439
IoC.CONTAINER.instance.logger.error(location, "variable is not defined here");
440
fi
441
si
442
443
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
444
assert !from?;
445
446
check_is_defined(location);
447
448
return loader.load_local_variable(location, self);
449
si
450
451
load_outer(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
452
assert !from?;
453
454
// A closure capturing this variable can only see a meaningful
455
// value if the let-binding has already completed by the time
456
// the closure is created. If is_defined is false the closure
457
// is being constructed inside the variable's own initializer
458
// (or before it), so the slot it captures is null. Without
459
// this check, the silent ERROR-typed reference escapes all
460
// the way to IL emission and crashes Type.gen_type.
461
check_is_defined(location);
462
463
return loader.load_outer_local_variable(location, self);
464
si
465
466
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value is
467
assert !from?;
468
469
check_is_defined(location);
470
471
is_assigned = true;
472
473
if !is_initialize then
474
is_reassigned = true;
475
fi
476
477
return loader.store_local_variable(location, self, value, is_initialize);
478
si
479
480
gen_directive(buffer: StringBuilder) is
481
buffer.append(".locals ");
482
si
483
484
gen_access(buffer: StringBuilder) is
485
si
486
487
gen_flags(buffer: StringBuilder) is
488
buffer.append("init ");
489
si
490
491
gen_open_paren(buffer: StringBuilder) is
492
buffer.append("(");
493
si
494
495
gen_close_paren(buffer: StringBuilder) is
496
buffer.append(")");
497
si
498
si
499
500
// FIXME: pull up common code into a local + argument superclass:
501
class LOCAL_ARGUMENT: Variable, Types.SettableTyped is
502
is_argument: bool => true;
503
is_local: bool => true;
504
505
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
506
_describe_typed(context, PARTS.literal(name), type);
507
508
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
509
_argument_kind();
510
511
_argument_kind() -> string =>
512
if is_captured then "captured value"
513
elif is_reassigned then "local variable"
514
else "local argument"
515
fi;
516
517
init(location: LOCATION, owner: Scope, name: string) is
518
super.init(location, owner, name);
519
si
520
521
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
522
assert !from?;
523
return loader.load_local_argument(location, self);
524
si
525
526
load_outer(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
527
assert !from?;
528
return loader.load_outer_local_argument(location, self);
529
si
530
531
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value is
532
assert !from?;
533
534
is_assigned = true;
535
536
if !is_initialize then
537
is_reassigned = true;
538
fi
539
540
return loader.store_local_argument(location, self, value, is_initialize);
541
si
542
543
gen_definition_header(buffer: StringBuilder) is
544
si
545
si
546
547
class Field: Variable, Types.SettableTyped abstract is
548
unspecialized_type: Type? public;
549
550
symbol_kind: SymbolKind => SymbolKind.FIELD;
551
completion_kind: CompletionKind => CompletionKind.FIELD;
552
553
is_private: bool;
554
is_field: bool => true;
555
is_public_readable: bool => !is_private;
556
is_workspace_visible: bool => !is_private;
557
558
is_accessible_to(accessor: Classy?) -> bool is
559
if !is_private then
560
return true;
561
fi
562
563
let policy = IoC.CONTAINER.instance.build_flags.underscore_access;
564
let o = cast Classy?(owner);
565
566
if policy == Compiler.UnderscoreAccess.PRIVATE then
567
return accessor? /\ o? /\ o == accessor;
568
elif policy == Compiler.UnderscoreAccess.PROTECTED then
569
return accessor? /\ o? /\ o.type? /\ accessor.type? /\ o.type.is_assignable_from(accessor.type);
570
fi
571
572
// LEGACY: the pre-existing is_public_readable rule remains the gate.
573
return true;
574
si
575
576
access_prefix: string =>
577
if !is_private then
578
""
579
elif IoC.CONTAINER.instance.build_flags.underscore_access == Compiler.UnderscoreAccess.PRIVATE then
580
"private "
581
elif IoC.CONTAINER.instance.build_flags.underscore_access == Compiler.UnderscoreAccess.PROTECTED then
582
"protected "
583
else
584
""
585
fi;
586
587
// Shared body for the concrete Field kinds. Delegates to
588
// `_describe_typed` so the narrowed / declared dual display
589
// rule stays in one place — a hover on a field whose observed
590
// type differs from its declared shape shows both.
591
_describe_field(context: DESCRIBE_CONTEXT) -> SignaturePart =>
592
_describe_typed(context, PARTS.name(self), type);
593
594
init(location: LOCATION, owner: Scope, name: string) is
595
super.init(location, owner, name);
596
597
self.is_private = name.starts_with('_');
598
si
599
600
specialize(type_map: Collections.Map[string,Type], owner: GENERIC) -> Symbol is
601
let result = cast Field?(super.specialize(type_map, owner))!;
602
603
result.unspecialized_type = type!;
604
605
return result;
606
si
607
608
gen_reference(buffer: StringBuilder) is
609
let t mut = unspecialized_type;
610
611
if !t? then
612
t = type!;
613
fi
614
615
t.gen_type(buffer);
616
owner!.gen_reference(buffer);
617
gen_dot(buffer);
618
gen_name(buffer);
619
si
620
621
gen_access(buffer: StringBuilder) is
622
if is_private then
623
buffer.append("assembly ");
624
else
625
buffer.append("public ");
626
fi
627
si
628
629
gen_directive(buffer: StringBuilder) is
630
buffer.append(".field ");
631
si
632
633
gen_dot(buffer: StringBuilder) is
634
buffer.append("::");
635
si
636
si
637
638
class GLOBAL_VARIABLE: Field, Types.SettableTyped is
639
// Set by the .NET importer when the symbol is read back from a referenced
640
// assembly's $globals class so field references get an [asm] prefix.
641
il_assembly_name: string? public;
642
643
// Globals live on the synthetic $globals class; declaring-class-private
644
// is meaningless for them. An underscore global variable is
645
// assembly-internal (emitted assembly, hidden from other assemblies)
646
// and freely reachable within the assembly.
647
is_accessible_to(accessor: Classy?) -> bool => true;
648
access_prefix: string => "";
649
650
init(location: LOCATION, owner: Scope, name: string) is
651
super.init(location, owner, name);
652
si
653
654
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value is
655
assert !from? else "load global variable from instance context";
656
return loader.load_global_variable(self);
657
si
658
659
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value is
660
assert !from? else "load global variable from instance context";
661
return loader.store_global_variable(self, value);
662
si
663
664
gen_flags(buffer: StringBuilder) is
665
buffer.append("static ");
666
si
667
668
// Field definition lives inside `.class 'NS'.'$globals' { ... }` block.
669
gen_owner_name(buffer: StringBuilder) is
670
si
671
672
gen_reference(buffer: StringBuilder) is
673
let t mut = unspecialized_type;
674
675
if !t? then
676
t = type!;
677
fi
678
679
t.gen_type(buffer);
680
681
cast Symbols.NAMESPACE?(owner)!.gen_globals_class_reference(buffer, il_assembly_name);
682
683
buffer.append("::");
684
685
gen_name(buffer);
686
si
687
si
688
689
class INSTANCE_FIELD: Field is
690
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
691
_describe_field(context);
692
693
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "{access_prefix}field";
694
695
is_instance: bool => true;
696
697
init(location: LOCATION, owner: Scope, name: string) is
698
super.init(location, owner, name);
699
si
700
701
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value =>
702
loader.load_instance_variable(location, from, self);
703
704
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value =>
705
loader.store_instance_variable(location, from, self, value);
706
si
707
708
class VARIANT_FIELD: Field is
709
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
710
_describe_field(context);
711
712
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "variant field";
713
714
is_instance: bool => true;
715
716
// it's OK for variant fields to hide symbols in the base union
717
can_hide_inherited: bool => true;
718
719
init(location: LOCATION, owner: Scope, name: string) is
720
super.init(location, owner, name);
721
si
722
723
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value =>
724
loader.load_instance_variable(location, from, self);
725
726
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value =>
727
loader.store_instance_variable(location, from, self, value);
728
si
729
730
class STRUCT_FIELD: Field is
731
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
732
_describe_field(context);
733
734
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "{access_prefix}field";
735
736
is_instance: bool => true;
737
738
init(location: LOCATION, owner: Scope, name: string) is
739
super.init(location, owner, name);
740
si
741
742
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value =>
743
loader.load_struct_variable(location, from, self);
744
745
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value =>
746
loader.store_struct_variable(location, from, self, value);
747
si
748
749
class STATIC_FIELD: Field is
750
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
751
_describe_field(context);
752
753
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "{access_prefix}class field";
754
755
init(location: LOCATION, owner: Scope, name: string) is
756
super.init(location, owner, name);
757
si
758
759
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value =>
760
loader.load_static_field(self);
761
762
store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value =>
763
loader.store_static_field(self, value);
764
765
gen_flags(buffer: StringBuilder) is
766
buffer.append("static ");
767
si
768
si
769
si
770