Skip to content
← Back

src/semantic/symbols/function.ghul

1
namespace Semantic.Symbols is
2
use IO.Std
3
4
use System.Exception
5
use System.NotImplementedException
6
use System.Text.StringBuilder
7
8
use Collections.Iterable
9
10
use IoC
11
use Logging
12
use Source
13
14
use IR.Values.Value
15
16
use Types.Type
17
18
use Ghul.Pipes
19
20
class Function: ScopedWithEnclosingScope, Types.Typed abstract is
21
// Whether the method emitted for this function takes a receiver.
22
// Usually the same question as `is_instance`, but a closure
23
// answers the two differently: it is not an instance member of
24
// anything the language can see, while the method emitted for it
25
// does take the frame holding its captures. Everything about the
26
// emitted method — its flags, its signature's calling
27
// convention, and the slot each argument occupies — has to agree
28
// on this, and disagreeing produces a static method whose body
29
// reads argument 0 as a receiver.
30
is_emitted_with_receiver: bool => is_instance
31
32
_arguments: Collections.List[Type]
33
34
_declaring_arguments: bool
35
_override_class: METHOD_OVERRIDE_CLASS?
36
37
override_class: METHOD_OVERRIDE_CLASS is
38
if !_override_class? then
39
// arguments is empty when resolve-explicit-variable-types
40
// never visited this function (e.g. a partially-recovered
41
// parse left the symbol orphaned from current_function),
42
// giving that case a zero-arg override class — partial
43
// symbols don't meaningfully participate in override
44
// resolution anyway.
45
_override_class = METHOD_OVERRIDE_CLASS(arguments, generic_arguments)
46
fi
47
48
return _override_class
49
si
50
51
_overriders: Collections.MutableList[Symbol]?
52
_overridees: Collections.MutableList[Symbol]?
53
54
// Whether a call to this function is trusted not to store to
55
// any pre-existing heap location, without the body being seen:
56
// declared `pure` — including on a body-less trait member the
57
// analysis never walks — a curated store-free import, or a
58
// synthesized backing-field read. Answerable at any point in
59
// the build, and never stale, because every contributor is
60
// settled by declaration shape rather than inferred from a
61
// body. What was actually proven is EFFECTS.is_store_free,
62
// which is only answerable once expressions are compiled, and
63
// which takes the union with this.
64
is_store_free: bool is
65
let rsf = root_specialized_from
66
67
if rsf != self then
68
return (cast Function?(rsf)!).is_store_free
69
fi
70
71
return _is_declared_pure \/ _is_trusted_import \/ _is_trusted_backing_read \/ _is_unreaching_static_import
72
si
73
74
// Set when this function was synthesized as the read accessor
75
// of an auto property: its body is a read of the backing
76
// field, by construction, so it stores nothing without any
77
// analysis being needed.
78
_is_backing_read: bool
79
80
mark_backing_read() is
81
let rsf = root_specialized_from
82
83
if rsf != self then
84
(cast Function?(rsf)!).mark_backing_read()
85
return
86
fi
87
88
_is_backing_read = true
89
si
90
91
// A backing read is only trusted at a call site when the call
92
// is bound to reach it: an in-assembly overrider, or a
93
// possible override outside the assembly behind an open
94
// class, could stand behind the call and store.
95
_is_trusted_backing_read: bool =>
96
_is_backing_read /\ has_no_overriders /\ !is_openly_dispatchable
97
98
// Whether an override outside this compilation could stand
99
// behind a call to this function: an instance method of
100
// anything but a closed class. Mirrors the dispatch-shadow
101
// rule the store-free solvers apply.
102
is_openly_dispatchable: bool is
103
if isa STRUCT_METHOD(self) then
104
return false
105
fi
106
107
if !isa INSTANCE_METHOD(self) then
108
return false
109
fi
110
111
let owner = self.owner
112
113
if !owner? \/ !isa Classy(owner) then
114
return true
115
fi
116
117
return (cast Classy(owner)).is_open
118
si
119
120
// Written back by the store-free solve once expressions have
121
// compiled: the body, and everything it can reach, was proven
122
// to store nothing. Read where the answer is surfaced rather
123
// than relied on — hover's pure prefix and the pure
124
// function-type shape — so a stale answer in analysis mode
125
// costs a momentarily wrong display, never a wrong judgement;
126
// the crossing discharge and the pure-slot check read EFFECTS instead,
127
// inside the round that solved it. Kept in the id-keyed
128
// STORE_FREE_BITS so it survives an incremental edit that
129
// replaces the symbol object under an adopted id.
130
is_proven_store_free: bool is
131
let rsf = root_specialized_from
132
133
if rsf != self then
134
return (cast Function?(rsf)!).is_proven_store_free
135
fi
136
137
return is_store_free \/ STORE_FREE_BITS.is_proven_store_free(id)
138
si
139
140
set_proven_store_free(value: bool) is
141
let rsf = root_specialized_from
142
143
if rsf != self then
144
(cast Function?(rsf)!).set_proven_store_free(value)
145
return
146
fi
147
148
STORE_FREE_BITS.set_proven_store_free(id, value)
149
si
150
151
// Set while a literal's body compiles if it performed any
152
// heap-visible operation — a crossing-recording call, a heap
153
// store, or any local reassignment (a reassigned local can be
154
// a captured one, which is a frame-field store; own-local
155
// reassignment is conservatively included). Consulted where
156
// the compiled literal takes its value's type: a clean body
157
// surfaces at the pure shape. Meaningless for named
158
// functions — the store-free solve covers those.
159
literal_body_impure: bool public
160
161
// A curated store-free import is trusted at query time, not
162
// only when a named body's fixpoint happens to reach it as a
163
// callee edge. A call in a function-literal body or a
164
// string-interpolation fragment never becomes such an edge, so
165
// without this an otherwise store-free import reads as
166
// state-changing purely by where it was called from — the same
167
// import trusted in a named body goes untrusted in a lambda.
168
// Gated on has_no_overriders so a virtual entry with an
169
// in-assembly override still falls to the fixpoint's
170
// dispatch-shadow check rather than being trusted blind.
171
_is_trusted_import: bool =>
172
has_no_overriders /\ _is_whitelisted_import
173
174
// Whitelist membership is fixed at import from the function's
175
// own name and owner, so it is derived once and cached.
176
_whitelisted_import_cache: bool?
177
178
_is_whitelisted_import: bool is
179
if !_whitelisted_import_cache? then
180
_whitelisted_import_cache = is_reflected /\ STORE_FREE_IMPORTS.is_store_free(self)
181
fi
182
183
return _whitelisted_import_cache
184
si
185
186
// Weaker than store-free: a call to this function can write
187
// its own receiver's internal state, but nothing else, and can
188
// reach no user code on the way. The call transfer applies the
189
// heap-store rule instead of the full kill for one of these,
190
// so field facts survive it and property facts do not.
191
//
192
// Store-free implies it, so a caller can ask this one question
193
// and get the weaker answer whenever the stronger one holds.
194
// Gated on has_no_overriders for the same reason the trusted
195
// store-free imports are: a virtual entry with an in-assembly
196
// override could dispatch to a body that stores anything.
197
writes_only_receiver_interior: bool is
198
let rsf = root_specialized_from
199
200
if rsf != self then
201
return (cast Function?(rsf)!).writes_only_receiver_interior
202
fi
203
204
return is_store_free \/ (has_no_overriders /\ _is_receiver_interior_import) \/ _is_unreaching_instance_import
205
si
206
207
// Fixed at import from the function's own name, owner and
208
// parameter types, so it is derived once and cached.
209
_receiver_interior_import_cache: bool?
210
211
_is_receiver_interior_import: bool is
212
if !_receiver_interior_import_cache? then
213
_receiver_interior_import_cache =
214
is_reflected /\ RECEIVER_INTERIOR_IMPORTS.writes_only_receiver_interior(self)
215
fi
216
217
return _receiver_interior_import_cache
218
si
219
220
// A member of a generic owner declines alongside a generic
221
// method: the owner's type parameters can carry constraints,
222
// and the body can dispatch through one into code declared
223
// outside the import, which neither the parameters nor the
224
// dispatch stamp vouch for. `LIST[T].sort` runs the element
225
// type's comparer this way.
226
_owner_is_generic: bool is
227
if let o: Classy = owner?.unspecialized_symbol then
228
return o.is_generic
229
fi
230
231
return false
232
si
233
234
// An imported BCL static whose parameters hand it no way to
235
// name code declared here or to reach storage that existed
236
// before the call. It has no receiver and no overridable
237
// parameter types, so whatever it writes lands only in its
238
// own fresh storage or in state no ghūl member can address,
239
// and a call to one is trusted store-free on the same footing
240
// as the curated import lists. Generic methods and members of
241
// generic owners decline: a body can dispatch through such a
242
// type parameter, which a parameter-only reading cannot see.
243
//
244
// Restricted to `STATIC_METHOD` - a global function imported
245
// from another ghūl assembly is arbitrary ghūl source, not a
246
// BCL surface: it can write its own assembly's globals and
247
// dispatch into this assembly through an object stored there,
248
// which a parameter-only reading cannot see either. `pure` is
249
// the way such a function earns this trust.
250
//
251
// A BCL static can still route through mutable ambient state
252
// invisible to its parameters - `Console.write_line(s)`
253
// dispatches through whatever `TextWriter` `Console.set_out`
254
// last installed, which can be a ghūl-implemented override
255
// that stores. This tier accepts that gap deliberately rather
256
// than declining every string-taking static or curating one
257
// away: redirecting a stream this pervasive into something
258
// that mutates state a live narrowing depends on is a
259
// vanishingly unrealistic thing for real code to do, and
260
// guarding against it would cost the tier its main value -
261
// trusting BCL statics without a curated list - for a
262
// hazard no program is likely to hit.
263
264
_unreaching_static_import_cache: bool?
265
266
_is_unreaching_static_import: bool is
267
if !_unreaching_static_import_cache? then
268
_unreaching_static_import_cache =
269
is_reflected /\
270
!is_generic /\
271
!_owner_is_generic /\
272
IMPORT_ARGUMENTS.all_arguments_scalar(self) /\
273
!isa STATIC_CONSTRUCTOR(self) /\
274
isa STATIC_METHOD(self) /\
275
!(cast STATIC_METHOD?(self)!).is_static_interface_virtual
276
fi
277
278
return _unreaching_static_import_cache
279
si
280
281
// The instance counterpart: an imported method the CLR binds
282
// statically (`cannot_be_overridden`), so that no override in
283
// any assembly can stand behind the call, with parameters that
284
// reach nothing pre-existing or user code. Everything such a
285
// method can write is therefore its own receiver's interior,
286
// which makes it receiver-interior by construction rather than
287
// by curation. Generic methods and members of generic owners
288
// decline, as they do for the static tier.
289
// A delegate's members decline however their parameters read.
290
// `Invoke` takes whatever the delegate's own shape takes and
291
// runs arbitrary code, so a shape-only reading of it - sealed
292
// owner, scalar parameters, bound statically - vouches for
293
// nothing. Recognised by walking to `System.MulticastDelegate`
294
// by symbol identity rather than by matching a member name.
295
_owner_is_delegate: bool is
296
if let owner_classy: Classy = owner?.unspecialized_symbol then
297
return owner_classy.is_delegate
298
fi
299
300
return false
301
si
302
303
_unreaching_instance_import_cache: bool?
304
305
_is_unreaching_instance_import: bool is
306
if !_unreaching_instance_import_cache? then
307
_unreaching_instance_import_cache =
308
is_reflected /\
309
!is_generic /\
310
!_owner_is_generic /\
311
!_owner_is_delegate /\
312
IMPORT_ARGUMENTS.all_arguments_scalar(self) /\
313
isa Method(self) /\
314
(cast Method?(self)!).cannot_be_overridden
315
fi
316
317
return _unreaching_instance_import_cache
318
si
319
320
// Whether this function is a constructor. Overridden on the
321
// method that carries the `.ctor` IL name; false everywhere
322
// else, so callers can ask any function without a cast.
323
is_constructor: bool => false
324
325
// Whether this is an imported .NET member that only its declaring
326
// type and that type's subclasses can use. The import leaves access
327
// to the runtime; completion reads this to keep such a member off
328
// the list after an ordinary dot.
329
is_imported_protected: bool => _is_imported_protected
330
331
_is_imported_protected: bool
332
333
mark_imported_protected() is
334
_is_imported_protected = true
335
si
336
337
// A constructor is trusted to write no pre-existing heap slot
338
// *given its receiver is fresh* — the case a `NEW` presents.
339
// Only the structural tiers answer here; a constructor that
340
// writes its own instance fields is proven harmless by the
341
// solve instead, and the crossing its construction records is
342
// discharged against EFFECTS.constructs_store_free.
343
constructs_store_free: bool is
344
let rsf = root_specialized_from
345
346
if rsf != self then
347
return (cast Function?(rsf)!).constructs_store_free
348
fi
349
350
return is_store_free \/ _is_unreaching_import_construction
351
si
352
353
// An imported constructor whose parameters hand it no way to
354
// name code declared here. Its receiver did not exist before
355
// the call, so nothing pre-existing is reachable through it
356
// either, and the two routes together are the whole of what
357
// the constructor can address. That leaves construction of an
358
// imported type harmless without any per-member curation,
359
// which is what keeps a `Collections.MAP()` from ending every
360
// fact live around it.
361
//
362
// A write reached through a static field an earlier call
363
// populated is outside the argument, and is accepted on the
364
// same footing as the equals-and-hash contract the curated
365
// import lists already rest on.
366
_unreaching_import_construction_cache: bool?
367
368
_is_unreaching_import_construction: bool is
369
if !_unreaching_import_construction_cache? then
370
_unreaching_import_construction_cache =
371
is_reflected /\ is_constructor /\ IMPORT_ARGUMENTS.all_arguments_scalar(self)
372
fi
373
374
return _unreaching_import_construction_cache
375
si
376
377
// Declared `pure` in source: the function is trusted
378
// effectively store-free without its body being provable.
379
// Feeds the store-free bit unconditionally after the
380
// fixpoint, and obliges every override or trait
381
// implementation to be pure itself — declared or proven.
382
_is_declared_pure: bool
383
384
is_declared_pure: bool is
385
let rsf = root_specialized_from
386
387
if rsf != self then
388
return (cast Function?(rsf)!).is_declared_pure
389
fi
390
391
return _is_declared_pure
392
si
393
394
mark_declared_pure() is
395
let rsf = root_specialized_from
396
397
if rsf != self then
398
(cast Function?(rsf)!).mark_declared_pure()
399
return
400
fi
401
402
_is_declared_pure = true
403
si
404
405
// The read accessor of a property declared `stable`: two
406
// adjacent reads with nothing between them agree on presence
407
// and runtime type. Trusted, not verified — the same standing
408
// as `pure` — and orthogonal to it: a memoiser is impure and
409
// stable. A fact narrowed through the property counts as
410
// backed even when the getter's body is not provably
411
// self-stable, and every override must honour the contract.
412
// Carried across assemblies by STABLE_ATTRIBUTE.
413
_is_declared_stable: bool
414
415
is_declared_stable: bool is
416
let rsf = root_specialized_from
417
418
if rsf != self then
419
return (cast Function?(rsf)!).is_declared_stable
420
fi
421
422
return _is_declared_stable
423
si
424
425
mark_declared_stable() is
426
let rsf = root_specialized_from
427
428
if rsf != self then
429
(cast Function?(rsf)!).mark_declared_stable()
430
return
431
fi
432
433
_is_declared_stable = true
434
si
435
436
// The operation named by an `INTRINSIC_ATTRIBUTE` on this
437
// declaration, or null. Set for a source declaration only: the
438
// declaration is emitted so consumers can reflect it, and a
439
// separate innate is registered from it once signatures resolve.
440
intrinsic_operation: string? public
441
442
// Set on the entry point synthesised from a file's top-level
443
// statements. Only this function's statements run in textual
444
// order, so TOP_LEVEL_VARIABLE checks it to report a use above
445
// the variable's `let`, and analysis mode routes edits to files
446
// carrying it to the full rebuild.
447
is_top_level_entry: bool public
448
449
// Set by select-entry-point on the one function this assembly
450
// enters at. Emission reads it rather than re-deriving the choice
451
// from the name, so every candidate is ranked against the others
452
// before any IL is written.
453
is_entry_point: bool public
454
455
// No more-derived override exists. In a closed-by-default,
456
// wholly-compiled assembly this means the method is effectively
457
// final — the only body a call can reach is this one.
458
has_no_overriders: bool => !_overriders? \/ _overriders.count == 0
459
460
span: LOCATION
461
462
// Incremental body re-walk override: also shift the declaration
463
// span when the retained interface symbol is relocated.
464
set_span(span_location: LOCATION) is
465
span = span_location
466
si
467
468
type: Type? public
469
return_type: Type? public
470
471
// True when this function was declared without an explicit
472
// return-type annotation (so the return type starts as
473
// INFERRED_RETURN_TYPE and is set by walking return statements
474
// / expression bodies). Used by the compile pass to drive LUB
475
// widening across multiple return statements: when a later
476
// return produces a type that's neither assignable to nor
477
// from the current binding, widening to the LUB is the right
478
// answer for an inferred return type, but a declared return
479
// type with the same shape is a genuine type error.
480
return_type_was_inferred: bool public
481
482
// Set by compile-expressions when a `return null` is reached
483
// while the return type is still inferred. A null says a value
484
// can be absent without saying what it holds when present, so it
485
// settles nothing on its own: what it records is that whatever
486
// the return settles at has to be optional, and that a body
487
// whose every return is null takes its type from the slot the
488
// literal goes into rather than from itself.
489
returned_genuine_null: bool public
490
491
// Set by compile-lambdas when the AST FUNCTION had
492
// `contains_let_await` set by declare-symbols. When settling
493
// an inferred return type from the body's value, wrap a
494
// bare-T value as `Tasks.TASK[T]` so the closure's signature
495
// matches its async-state-machine emission shape. Body
496
// values already typed Task[?] are left untouched.
497
wrap_inferred_return_as_task: bool public
498
499
// Set by compile-lambdas when the literal's slot returns `U?` over
500
// an unconstrained U. An inferred return settles as `MAYBE[T]`
501
// over what the body produced, so the literal's delegate has the
502
// shape the slot binds against.
503
wrap_inferred_return_as_maybe: bool public
504
505
// Set on the closure of a literal synthesised to adapt a named
506
// function reference to a formal it differs from only in an
507
// optional position's carrier. Such a literal exists to present
508
// the formal's own shape, so a settled slot return is adopted
509
// rather than inferred from the body it wraps.
510
is_carrier_adapter: bool public
511
512
// Set by compile-lambdas when the AST FUNCTION had
513
// `is_void_async` set by declare-symbols — i.e., body
514
// contains `await` but no value-returning `return X;`
515
// statements. Read by the async state machine setup to pick
516
// the non-generic Tasks.TASK over Tasks.TASK[T].
517
is_void_async: bool public
518
519
// Set by compile-lambdas when the slot an async closure goes
520
// into names a generic task-like other than Task, with the
521
// result argument still to be inferred from the body. The
522
// inferred return type is then built from this symbol rather
523
// than from Task, so `spawn[T](body: () -> COROUTINE[T])`
524
// infers T from the closure's returns.
525
async_task_like_template: Classy? public
526
527
// True once the argument list has been supplied — by
528
// resolve-explicit-variable-types for source functions, at import
529
// for reflected ones, or at synthesis. Distinguishes a
530
// not-yet-declared function from a declared zero-argument one:
531
// both have an empty arguments list, but only the declared one
532
// may participate in arity-based overload filtering.
533
_are_arguments_declared: bool
534
535
are_arguments_declared: bool => _are_arguments_declared
536
537
arguments: Collections.List[Type] public => _arguments,
538
= value is
539
assert value |> all(a => a?) else "setting an argument to null for {name}"
540
541
_arguments = value
542
_are_arguments_declared = true
543
si
544
545
generic_arguments: Collections.List[Type] public
546
generic_argument_names: Collections.List[string] public
547
unspecialized_arguments: Collections.List[Type]? public
548
549
// Parallel to `arguments`: whether each formal was declared to
550
// take an argument pack spread out - `f: T.. -> U` - rather than
551
// as the tuple the pack binds to. Empty for the great majority
552
// of functions, which mention no pack at all.
553
argument_is_pack: Collections.List[bool] public
554
555
// Parallel to `argument_is_pack`: how many returns into the
556
// formal's own type the marked function type sits. Zero is the
557
// formal's own type - `f: T.. -> U` - and one is the function
558
// its own return names, as `f: X -> T.. -> U` does.
559
argument_pack_depth: Collections.List[int] public
560
561
// Index of the formal declared to absorb the call's remaining
562
// arguments into the pack's tuple - `v: T..` - and -1 for the
563
// great majority of functions, which declare no such formal.
564
spread_argument_index: int public
565
566
// How many returns into the declared return type the marked
567
// function type sits - `-> T.. -> U` is zero, `-> X -> T.. -> U`
568
// is one - and -1 for the great majority of functions, whose
569
// return type carries no pack marker. The declared return type
570
// itself still names the tuple-in shape; a call that binds the
571
// pack to a concrete tuple presents its result as the
572
// corresponding N-ary function instead.
573
return_pack_depth: int public
574
unspecialized_return_type: Type? public
575
576
// Parallel to generic_argument_names: kind / `init` / type-bound
577
// constraints per method-level type parameter. Populated at
578
// import for .NET methods, whose parameter symbols are not
579
// declared into the function's scope and so can't be reached
580
// via find_direct. ghūl-declared methods leave these empty and
581
// carry the same information on the parameter symbol.
582
generic_argument_constraint_kinds: Collections.List[TypeParameterConstraintKind] public
583
generic_argument_has_constructor_constraint: Collections.List[bool] public
584
generic_argument_type_bounds: Collections.List[Collections.List[Type]] public
585
586
argument_names: Collections.List[string] public
587
588
// Parallel to `argument_names`: the declared default of each
589
// parameter, or null when the parameter has no default and so
590
// cannot be omitted from a named call. A ghūl-source `= _`
591
// parameter is stored as "default"; a literal default
592
// (reflected methods only) is stored as its text.
593
argument_defaults: Collections.List[string?] public
594
595
// Parallel to `argument_names`: per-parameter by-ref direction,
596
// derived from reflected `IsIn`/`IsOut` and populated only for
597
// reflected methods that have a non-plain by-ref slot. Null
598
// elsewhere, where a by-ref parameter defaults to plain `ref`
599
// — both read and written. `reads` gates the must-be-assigned-
600
// before check; `writes` gates definite assignment of the
601
// argument. Held on the unspecialized function so specializations
602
// observe them through `root_specialized_from`.
603
_argument_reads: Collections.List[bool]?
604
_argument_writes: Collections.List[bool]?
605
606
set_argument_directions(reads: Collections.List[bool], writes: Collections.List[bool]) is
607
let rsf = root_specialized_from
608
609
if rsf != self then
610
(cast Function?(rsf)!).set_argument_directions(reads, writes)
611
return
612
fi
613
614
_argument_reads = reads
615
_argument_writes = writes
616
si
617
618
// Whether the callee reads the incoming value of argument `i`.
619
// True for every by-ref slot except a pure `out`, and the
620
// conservative default when no reflected direction is recorded.
621
argument_reads(i: int) -> bool is
622
let rsf = root_specialized_from
623
624
if rsf != self then
625
return (cast Function?(rsf)!).argument_reads(i)
626
fi
627
628
if _argument_reads? /\ i < _argument_reads.count then
629
return _argument_reads[i]
630
fi
631
632
return true
633
si
634
635
// Whether the callee writes argument `i`, so passing it by `ref`
636
// definitely assigns the target. True for every by-ref slot
637
// except a pure `in`, and the conservative default.
638
argument_writes(i: int) -> bool is
639
let rsf = root_specialized_from
640
641
if rsf != self then
642
return (cast Function?(rsf)!).argument_writes(i)
643
fi
644
645
if _argument_writes? /\ i < _argument_writes.count then
646
return _argument_writes[i]
647
fi
648
649
return true
650
si
651
652
symbol_kind: SymbolKind => SymbolKind.FUNCTION
653
completion_kind: CompletionKind => CompletionKind.FUNCTION
654
655
is_function: bool => true
656
is_generic: bool public
657
658
// Excluded as a candidate when a binary operator expression
659
// resolves. Set on a reflected operator-named member of a type
660
// whose operator is innate — `int`'s `<>` from
661
// `IComparable[int].CompareTo` — so `a < b` keeps lowering to
662
// the comparison opcode while the member remains reachable
663
// every other way: it satisfies its trait, resolves by name,
664
// and converts to a delegate.
665
is_hidden_from_operator_resolution: bool public
666
is_abstract: bool => false
667
668
// Whether the source declared this method without a body. A
669
// `DllImport` needs one that was: the call it stands for is the
670
// library's, so a body of its own would be dead code.
671
is_declared_without_body: bool public
672
673
// What this method's `DllImport` says, for a method declared
674
// with no body that calls into a shared library. Absent on
675
// every ordinary method.
676
pinvoke: Semantic.PINVOKE_IMPORT? public
677
678
// Only a body-less class method that overrides an implemented
679
// one carries a throwing body; every other function has one of
680
// its own, so this asks nothing of them.
681
throws_unimplemented: bool => false
682
683
mark_throws_unimplemented() is si
684
685
// A synthesized `reset` a type never declared: its body is a
686
// throw rather than anything the source asked for.
687
throws_not_supported: bool => false
688
689
mark_throws_not_supported() is si
690
is_virtual: bool => false
691
is_default_trait_method: bool => false
692
is_capture_context: bool => true
693
is_workspace_visible: bool => !name.starts_with('_')
694
is_recursive: bool => false // only applicable if a closure
695
696
// An indexer's accessors carry the CLR-required names `get_Item`
697
// and `set_Item`, which are not spellable in ghūl source. Rendered
698
// as a plain call they read as a member the language does not
699
// have, so they take the declaration's own shape instead - the
700
// same shape `to_string` gives them, with short type descriptions.
701
short_description: string =>
702
if is_indexer_accessor then
703
render_indexer_shape(
704
get_short_argument_description(0),
705
indexer_value_type!.short_description
706
)
707
else
708
"{name}{generic_argument_descriptions}({short_argument_descriptions}) -> {_return_type_description(true)}"
709
fi
710
711
search_description: string => short_description
712
713
// Prefixes the description's trailing kind comment when the
714
// function is proven store-free — diagnostic surfacing only,
715
// deliberately inside the comment so it does not read as
716
// source syntax.
717
pure_prefix: string => if is_proven_store_free then "pure " else "" fi
718
719
argument_descriptions: string =>
720
(0..arguments.count) |> map(i => get_argument_description(i)) |> join() ?? ""
721
722
short_argument_descriptions: string =>
723
(0..arguments.count) |> map(i => get_short_argument_description(i)) |> join() ?? ""
724
725
generic_argument_descriptions: string is
726
if generic_arguments.count == 0 then
727
return ""
728
fi
729
730
let result = System.Text.StringBuilder()
731
732
result.append('[')
733
734
let seen_any mut = false
735
736
for i in 0..generic_arguments.count do
737
if seen_any then
738
result.append(',')
739
fi
740
741
result.append(generic_arguments[i])
742
743
// The `..` bound belongs to the declaration, so it is
744
// written here rather than by the type's own rendering,
745
// which also answers wherever the parameter is used.
746
if generic_arguments[i].symbol.is_argument_pack then
747
result.append("..")
748
fi
749
750
seen_any = true
751
od
752
753
result.append(']')
754
755
return result.to_string()
756
si
757
758
// Sets the `..` on each type parameter a pack marker names. A
759
// reflected function carries its markers on formals and return
760
// only; the declaration's own `[T..]` is what they name, rebuilt
761
// here from them.
762
mark_pack_type_parameters() is
763
for i in 0..arguments.count do
764
if i < argument_is_pack.count /\ argument_is_pack[i] then
765
let depth = if i < argument_pack_depth.count then argument_pack_depth[i] else 0 fi
766
767
_mark_pack_slot(Semantic.ARGUMENT_PACK.marked_slot(arguments[i], depth))
768
elif i == spread_argument_index then
769
_mark_pack_parameter(arguments[i])
770
fi
771
od
772
773
if return_pack_depth >= 0 then
774
_mark_pack_slot(Semantic.ARGUMENT_PACK.marked_slot(return_type, return_pack_depth))
775
fi
776
si
777
778
_mark_pack_slot(slot: Type?) is
779
if slot? then
780
_mark_pack_parameter(slot.arguments[0])
781
fi
782
si
783
784
_mark_pack_parameter(type: Type?) is
785
if type? /\ type.is_function_generic_argument then
786
type.symbol.set_is_argument_pack(true)
787
fi
788
si
789
790
// Shared body for the concrete Function kinds. Reproduces the
791
// signature shape `{qname}{[gen,args]}({name}: {type}, …)` +
792
// optional ` -> {return_type}` — no trailing classifier; that
793
// lives on `describe_kind`. The `(...)` argument list is a
794
// WRAPPABLE so the DOC hover renderer can break it across
795
// lines; the generic `[]` bracket is not wrappable.
796
_describe_function(
797
context: DESCRIBE_CONTEXT,
798
include_return_type: bool
799
) -> SignaturePart is
800
let parts = Collections.LIST[SignaturePart]()
801
parts.add(PARTS.name(self))
802
parts.add(_describe_generic_arguments())
803
parts.add(_describe_arguments(context))
804
if include_return_type /\ return_type? then
805
parts.add(PARTS.literal(" -> "))
806
parts.add(_describe_return_type())
807
fi
808
return SignaturePart.SEQUENCE(parts)
809
si
810
811
_describe_generic_arguments() -> SignaturePart is
812
if generic_arguments.count == 0 then
813
return PARTS.nil()
814
fi
815
let items = Collections.LIST[SignaturePart]()
816
for t in generic_arguments do
817
// The `..` marker belongs to the declaration, so it is
818
// written here rather than by the type's own rendering,
819
// which also answers wherever the parameter is used.
820
if t.symbol.is_argument_pack then
821
items.add(PARTS.sequence([PARTS.type_ref(t), PARTS.literal("..")]))
822
else
823
items.add(PARTS.type_ref(t))
824
fi
825
od
826
return SignaturePart.WRAPPABLE("[", ",", true, "]", items)
827
si
828
829
_describe_arguments(context: DESCRIBE_CONTEXT) -> SignaturePart is
830
let items = Collections.LIST[SignaturePart]()
831
for i in 0..arguments.count do
832
items.add(PARTS.sequence([
833
PARTS.literal("{argument_names[i]}: "),
834
_describe_argument_type(i)
835
]))
836
od
837
return SignaturePart.WRAPPABLE("(", ",", false, ")", items)
838
si
839
840
// A formal declared to take an argument pack spread out is
841
// written `f: T.. -> U`, and the marker sits on the parameter of
842
// its own function type - which the type's own rendering knows
843
// nothing about, so the two halves are written out here.
844
_describe_argument_type(index: int) -> SignaturePart is
845
if !get_argument_is_pack(index) then
846
return PARTS.type_ref(arguments[index])
847
fi
848
849
return _describe_pack_marked_type(arguments[index], get_argument_pack_depth(index))
850
si
851
852
// A return type that carries the marker reads the same way.
853
_describe_return_type() -> SignaturePart is
854
if return_pack_depth < 0 then
855
return PARTS.type_ref(return_type!)
856
fi
857
858
return _describe_pack_marked_type(return_type!, return_pack_depth)
859
si
860
861
_describe_pack_marked_type(type: Type, depth: int) -> SignaturePart is
862
let slot = Semantic.ARGUMENT_PACK.marked_slot(type, depth)
863
864
if !slot? then
865
return PARTS.type_ref(type)
866
fi
867
868
let parts = Collections.LIST[SignaturePart]()
869
870
// The hops the marker sits behind read as they always do;
871
// only the one it was written on carries the marker.
872
let hop mut = type
873
874
for _ in 0..depth do
875
parts.add(_describe_function_parameters(hop))
876
parts.add(PARTS.literal(" -> "))
877
878
hop = hop.arguments[hop.arguments.count - 1]
879
od
880
881
// The pack is the last parameter; any before it are the
882
// function type's own, and the list is parenthesised as it is
883
// written.
884
let fixed = Semantic.ARGUMENT_PACK.fixed_count(slot)
885
886
if fixed > 0 then
887
parts.add(PARTS.literal("("))
888
889
for i in 0..fixed do
890
parts.add(PARTS.type_ref(slot.arguments[i]))
891
parts.add(PARTS.literal(", "))
892
od
893
fi
894
895
parts.add(PARTS.type_ref(slot.arguments[fixed]))
896
parts.add(PARTS.literal(if fixed > 0 then "..) -> " else ".. -> " fi))
897
898
if slot.is_action then
899
parts.add(PARTS.literal("void"))
900
else
901
parts.add(PARTS.type_ref(slot.arguments[fixed + 1]))
902
fi
903
904
if slot.is_pure_function then
905
parts.add(PARTS.literal(" pure"))
906
fi
907
908
return SignaturePart.SEQUENCE(parts)
909
si
910
911
// The parameter half of a function type, parenthesised wherever
912
// it is not the single parameter that needs no parentheses.
913
_describe_function_parameters(type: Type) -> SignaturePart is
914
let count =
915
if type.is_action then
916
type.arguments.count
917
else
918
type.arguments.count - 1
919
fi
920
921
let items = Collections.LIST[SignaturePart]()
922
923
for i in 0..count do
924
items.add(PARTS.type_ref(type.arguments[i]))
925
od
926
927
if count == 1 then
928
return items[0]
929
fi
930
931
return SignaturePart.WRAPPABLE("(", ",", false, ")", items)
932
si
933
934
overriders: Collections.Iterable[Symbol]? => _overriders
935
overridees: Collections.Iterable[Symbol]? => _overridees
936
937
has_overridees: bool => _overridees? /\ _overridees.count > 0
938
939
// Attribute pragmas resolved onto a parameter (`@Foo() name: T`).
940
// A parameter's own symbol is a member of its owning function's
941
// scope regardless of function kind, so this reaches it the
942
// same way for a named function, a delegate/anon-func closure,
943
// or a frame-boxed capturing closure.
944
// argument_defaults is supplied by whichever route declared the
945
// function - reflection for an imported one, resolve-explicit-
946
// types for one written in source.
947
@suppress("field-definite-assignment")
948
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
949
super.init(location, owner, name, enclosing_scope)
950
951
self.span = span
952
953
_arguments = Collections.LIST[Type](0)
954
argument_names = Collections.LIST[string](0)
955
generic_arguments = Collections.LIST[Type](0)
956
generic_argument_names = Collections.LIST[string](0)
957
generic_argument_constraint_kinds = Collections.LIST[TypeParameterConstraintKind](0)
958
generic_argument_has_constructor_constraint = Collections.LIST[bool](0)
959
argument_is_pack = Collections.LIST[bool](0)
960
argument_pack_depth = Collections.LIST[int](0)
961
spread_argument_index = -1
962
return_pack_depth = -1
963
generic_argument_type_bounds = Collections.LIST[Collections.LIST[Type]](0)
964
965
if name =~ "init" then
966
il_name_override = ".ctor"
967
elif name =~ "=~" /\ isa Classy(owner) then
968
// A type's `=~` maps to .NET `Equals` for interop. A global
969
// `=~` operator keeps its own name, or it comes back from
970
// reflection as `equals` and no longer resolves.
971
il_name_override = "Equals"
972
fi
973
974
type = Types.NAMED(self)
975
si
976
977
set_arguments(argument_names: Collections.List[string], argument_types: Collections.List[Type]) is
978
self.arguments = argument_types
979
980
assert argument_names |> all(a => a?) else "setting an argument name to null for {name} (B)"
981
982
self.argument_names = argument_names
983
si
984
985
add_overrider(overrider: Symbol mut) is
986
let rsf = root_specialized_from
987
if rsf != self then
988
rsf.add_overrider(overrider)
989
return
990
fi
991
992
let overriders mut = _overriders
993
994
if !overriders? then
995
overriders = Collections.LIST[Symbol]()
996
_overriders = overriders
997
fi
998
999
overrider = overrider.root_specialized_from
1000
1001
if overriders.contains(overrider) then
1002
return
1003
fi
1004
1005
overriders.add(overrider)
1006
1007
if let journal = INHERITANCE_JOURNAL.current then
1008
journal.record(InheritanceOp.FUNCTION_OVERRIDER_ADDED(self, overrider))
1009
fi
1010
si
1011
1012
remove_overrider(overrider: Symbol) is
1013
let rsf = root_specialized_from
1014
if rsf != self then
1015
rsf.remove_overrider(overrider)
1016
return
1017
fi
1018
1019
let overriders = _overriders
1020
1021
if overriders? then
1022
overriders.remove(overrider.root_specialized_from)
1023
fi
1024
si
1025
1026
add_overridee(overridee: Symbol mut) is
1027
let rsf = root_specialized_from
1028
if rsf != self then
1029
rsf.add_overridee(overridee)
1030
return
1031
fi
1032
1033
let overridees mut = _overridees
1034
1035
if !overridees? then
1036
overridees = Collections.LIST[Symbol]()
1037
_overridees = overridees
1038
fi
1039
1040
overridee = overridee.root_specialized_from
1041
1042
if overridees.contains(overridee) then
1043
return
1044
fi
1045
1046
overridees.add(overridee)
1047
1048
if let journal = INHERITANCE_JOURNAL.current then
1049
journal.record(InheritanceOp.FUNCTION_OVERRIDEE_ADDED(self, overridee))
1050
fi
1051
si
1052
1053
remove_overridee(overridee: Symbol) is
1054
let rsf = root_specialized_from
1055
if rsf != self then
1056
rsf.remove_overridee(overridee)
1057
return
1058
fi
1059
1060
let overridees = _overridees
1061
1062
if overridees? then
1063
overridees.remove(overridee.root_specialized_from)
1064
fi
1065
si
1066
1067
load_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value is
1068
IoC.CONTAINER.instance.logger.error(location, "cannot access instance member from non-instance context")
1069
1070
return IR.Values.DUMMY(Types.ERROR(), location)
1071
si
1072
1073
load_outer_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value? is
1074
IoC.CONTAINER.instance.logger.error(location, "cannot access instance member from non-instance context")
1075
1076
return IR.Values.DUMMY(Types.ERROR(), location)
1077
si
1078
1079
load_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value => throw NotImplementedException("{get_type()} cannot load captured value: {symbol} from: {location}")
1080
load_outer_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value? => throw NotImplementedException("{get_type()} cannot load outer captured value: {symbol} from: {location}")
1081
store_captured_value(location: LOCATION, symbol: Variable, value: Value, loader: SYMBOL_LOADER) -> Value => throw NotImplementedException("{get_type()} cannot store captured value: {symbol} from: {location}")
1082
start_declaring_arguments() is
1083
_declaring_arguments = true
1084
si
1085
1086
end_declaring_arguments() is
1087
_declaring_arguments = false
1088
si
1089
1090
/*
1091
given a set of actual function argument types, try to infer actual generic argument types by pattern matching formal
1092
argument types (which may contain formal generic argument types) against correspinding actual arguments. Arguments
1093
could be unknown (!!! or ***), which match anything and do not contradict any type inferences we make.
1094
1095
map[T,U](from: Iterable[T], mapper: T -> U) -> Iterable[U]
1096
map([1, 2, 3, 4, 5], x => x + 1)
1097
1098
- the type of [1, 2, ... ] is known to be int[]
1099
- prior type inference should figure out the return type of x => x + 1 must be int (because the only overload
1100
resolution possible for !!! + 1 is int + int -> int) so we'll be called with actual argument types of int[]
1101
and !!! -> int that need to be matched against Iterable[T] and T -> U
1102
1103
- int[] implements Iterable[int] which pattern matches Iterable[T], allowing us to infer that T should be int
1104
- !!! -> int pattern matches T -> U. !!! doesn't contradict a type of int for T, and int implies a type of int for U
1105
1106
so we can return a type map of T = int, U = int
1107
*/
1108
// When LUB widening fired during bind (siblings case), the bound
1109
// type may be wider than any individual arg-derived candidate.
1110
// Re-verify each actual arg still conforms to its parameter type
1111
// with the bound type-args substituted in. Without this check a
1112
// call like structured[T](T, Iterable[T]) with (int, string)
1113
// (or the constructor analogue Box[T] with init(item: T, bag:
1114
// Iterable[T]) called as Box(1, "hello")) would bind
1115
// T = LUB(int, char) = ValueType and silently accept, even
1116
// though `string` is Iterable[char] which (without ghūl's
1117
// variance handling marking Iterable covariant) is not
1118
// Iterable[ValueType] — yielding an InvalidProgramException
1119
// at JIT for the constructor path, or a runtime cast failure.
1120
//
1121
// Only run when LUB actually fired — pairwise widening is
1122
// monotonic in the wider direction and doesn't need re-checking,
1123
// and skipping the check on the happy path avoids triggering
1124
// premature type evaluation on args that aren't yet ready
1125
// (e.g. function literals being passed to higher-order calls).
1126
check_lub_conformance(results: Types.GENERIC_ARGUMENT_BIND_RESULTS, args: Collections.List[Type]) -> bool is
1127
if !results.is_bound \/ !results.used_lub then
1128
return true
1129
fi
1130
1131
let type_map = results.map
1132
for i in 0..args.count do
1133
let specialized_param = arguments[i].specialize(type_map)
1134
if !specialized_param.is_assignable_from(args[i]) then
1135
return false
1136
fi
1137
od
1138
1139
return true
1140
si
1141
1142
try_bind_generic_arguments(location: Source.LOCATION, args: Collections.List[Type]) -> Types.GENERIC_ARGUMENT_BIND_RESULTS? is
1143
// This method binds the *function's* own generic args
1144
// (use try_bind_owner_generic_arguments for the owning
1145
// class's). When the function isn't generic there is
1146
// nothing here to bind — return null. Without this guard
1147
// a non-generic instance method on a generic class
1148
// (e.g. `Box[T].set(value: T)` called on `Box[?]`) would
1149
// proceed to call check_complete with a null
1150
// generic_arguments and NRE inside check_complete.
1151
if !is_generic then
1152
return null
1153
fi
1154
1155
assert args.count == arguments.count else "expected to bind {arguments.count} arguments in {self} but only {args} supplied"
1156
1157
let results = Types.GENERIC_ARGUMENT_BIND_RESULTS(_bindable_type_arguments())
1158
1159
let all_ok = true
1160
1161
for i in 0..args.count do
1162
if !arguments[i].bind_type_variables(args[i], results) then
1163
return null
1164
fi
1165
od
1166
1167
results.check_complete(location, generic_arguments)
1168
1169
if !results.is_bound then
1170
// A wild optional parameter (`T?`) matched a bare null
1171
// actual, which accepts without pinning the type variable.
1172
// Default any such never-pinned variable to object so the
1173
// selected overload is fully specialized; otherwise it
1174
// would emit with a free type parameter (`!!N`) and fail to
1175
// load at run time.
1176
results.default_null_only_unbound(
1177
generic_arguments,
1178
IoC.CONTAINER.instance.innate_symbol_lookup.get_object_type()
1179
)
1180
1181
results.check_complete(location, generic_arguments)
1182
fi
1183
1184
if !check_lub_conformance(results, args) then
1185
return null
1186
fi
1187
1188
// Bound actuals must not carry a method-level type
1189
// parameter that belongs to a different function: its
1190
// `!!N` index is only meaningful inside that function,
1191
// and emitting it at this call site produces an
1192
// unloadable assembly. The caller's own type parameters
1193
// are allowed — their indices are valid in the enclosing
1194
// method.
1195
let caller = IoC.CONTAINER.instance.symbol_table.current_function
1196
1197
if results.contains_function_generic_argument_foreign_to(caller) then
1198
return null
1199
fi
1200
1201
return results
1202
si
1203
1204
// The type arguments a call to this function may pin: its own,
1205
// plus the declaring type's when those are still open. A static
1206
// generic method reached through its declaring class can have
1207
// both inferred from one argument list; reached through a
1208
// constructed type the declaring half is already supplied, and
1209
// the only type variables left in the formals belong to whoever
1210
// wrote the call.
1211
_bindable_type_arguments() -> Collections.List[Types.Type] is
1212
let result = Collections.LIST[Types.Type](generic_arguments)
1213
1214
if let owner_classy = cast Classy?(owner) then
1215
for name in owner_classy.argument_names do
1216
if let argument = owner_classy.find_direct(name) /\ argument.type? then
1217
result.add(argument.type!)
1218
fi
1219
od
1220
fi
1221
1222
return result
1223
si
1224
1225
try_bind_owner_generic_arguments(location: Source.LOCATION, args: Collections.List[Type]) -> Types.GENERIC_ARGUMENT_BIND_RESULTS? is
1226
let owner_classy = cast Classy?(owner)
1227
1228
if !owner_classy? \/ !owner_classy.is_generic then
1229
return null
1230
fi
1231
1232
let results = Types.GENERIC_ARGUMENT_BIND_RESULTS()
1233
1234
for i in 0..args.count do
1235
if !arguments[i].bind_type_variables(args[i], results) then
1236
return null
1237
fi
1238
od
1239
1240
// An owner type argument that no formal mentions cannot be
1241
// bound by pairing formals with actuals, but an actual whose
1242
// bound instantiates the owner has already pinned it.
1243
OWNER_INSTANTIATION_BINDER.bind_unbound_from_actual_instantiations(owner_classy, args, results)
1244
1245
results.check_complete(location, owner_classy.arguments)
1246
1247
if !check_lub_conformance(results, args) then
1248
return null
1249
fi
1250
1251
let caller = IoC.CONTAINER.instance.symbol_table.current_function
1252
1253
if results.contains_function_generic_argument_foreign_to(caller) then
1254
return null
1255
fi
1256
1257
return results
1258
si
1259
1260
specialize_function(type_map: Collections.Map[Symbol,Type], owner: GENERIC?) -> Function is
1261
let result = cast Function?(memberwise_clone())!
1262
1263
result.specialized_from = self
1264
result._override_class = null
1265
1266
if !return_type? then
1267
IoC.CONTAINER.instance.logger.poison(self.location, "specialized with null return type")
1268
else
1269
result.return_type = return_type.specialize(type_map)
1270
fi
1271
1272
if unspecialized_arguments? then
1273
result.unspecialized_arguments = unspecialized_arguments
1274
else
1275
result.unspecialized_arguments = arguments
1276
fi
1277
1278
// Which formals take a pack spread out is a property of the
1279
// declaration, so it survives specialisation - by which point
1280
// the parameter itself has become the tuple it bound to.
1281
result.argument_is_pack = argument_is_pack
1282
result.argument_pack_depth = argument_pack_depth
1283
result.spread_argument_index = spread_argument_index
1284
result.return_pack_depth = return_pack_depth
1285
1286
if unspecialized_return_type? then
1287
result.unspecialized_return_type = unspecialized_return_type
1288
else
1289
result.unspecialized_return_type = return_type
1290
fi
1291
1292
// Pre-sized empty, filled by add: a LIST(arguments) copy would
1293
// duplicate every element only for the loop to replace them.
1294
let ra = Collections.LIST[Type](arguments.count)
1295
1296
result.arguments = ra
1297
1298
for a in arguments do
1299
ra.add(a.specialize(type_map))
1300
od
1301
1302
if generic_arguments.count > 0 then
1303
let specialized_arguments = Collections.LIST[Type](generic_arguments.count)
1304
1305
for ga in generic_arguments do
1306
specialized_arguments.add(ga.specialize(type_map))
1307
od
1308
1309
result.generic_arguments = specialized_arguments
1310
fi
1311
1312
// owner is absent for owner-less functions
1313
@suppress("presence-test-non-optional")
1314
if owner? then
1315
if result.owner == owner.unspecialized_symbol then
1316
result.owner = owner
1317
elif result.owner != owner then
1318
result.owner = result.owner!.type!.specialize(owner.type_map).symbol
1319
else
1320
Std.error.write_line("{result} is already owned by {owner}")
1321
fi
1322
fi
1323
1324
return result
1325
si
1326
1327
specialize(type_map: Collections.Map[Symbol,Type], owner: GENERIC) -> Symbol =>
1328
specialize_function(type_map, owner)
1329
1330
get_argument_constraint_kind(index: int) -> TypeParameterConstraintKind is
1331
if index >= 0 /\ index < generic_argument_constraint_kinds.count then
1332
return generic_argument_constraint_kinds[index]
1333
fi
1334
1335
if index >= 0 /\ index < generic_argument_names.count then
1336
let argument = find_direct(generic_argument_names[index])
1337
1338
if argument? then
1339
return argument.constraint_kind
1340
fi
1341
fi
1342
1343
return TypeParameterConstraintKind.NONE
1344
si
1345
1346
// Whether the formal at `index` takes an argument pack spread
1347
// out. False for every function that declares no pack.
1348
get_argument_is_pack(index: int) -> bool =>
1349
index >= 0 /\ index < argument_is_pack.count /\ argument_is_pack[index]
1350
1351
// How many returns into the formal at `index` the pack marker
1352
// sits. Zero wherever the depth was never recorded, which is
1353
// the formal's own type and what every pack meant before the
1354
// marker could be written deeper.
1355
get_argument_pack_depth(index: int) -> int =>
1356
if index >= 0 /\ index < argument_pack_depth.count then
1357
argument_pack_depth[index]
1358
else
1359
0
1360
fi
1361
1362
// Whether this function absorbs a call's remaining arguments
1363
// into a pack's tuple.
1364
has_spread_argument: bool => spread_argument_index >= 0
1365
1366
get_argument_has_constructor_constraint(index: int) -> bool is
1367
if index >= 0 /\ index < generic_argument_has_constructor_constraint.count then
1368
return generic_argument_has_constructor_constraint[index]
1369
fi
1370
1371
if index >= 0 /\ index < generic_argument_names.count then
1372
let argument = find_direct(generic_argument_names[index])
1373
1374
if argument? then
1375
return argument.has_constructor_constraint
1376
fi
1377
fi
1378
1379
return false
1380
si
1381
1382
// The bounds (`[T: A /\ B]`) of the method-level type parameter at
1383
// `index`, empty when unbounded. Imported methods carry them in
1384
// `generic_argument_type_bounds`; ghūl-declared methods carry them
1385
// on the parameter symbol as its ancestors, with the meaningless
1386
// `object` default bound dropped.
1387
get_argument_type_bounds(index: int) -> Collections.List[Type] is
1388
if index >= 0 /\ index < generic_argument_type_bounds.count then
1389
return generic_argument_type_bounds[index]
1390
fi
1391
1392
if index >= 0 /\ index < generic_argument_names.count then
1393
let argument = find_direct(generic_argument_names[index])
1394
1395
if argument? /\ argument.is_type_variable then
1396
let result = Collections.LIST[Type](0)
1397
1398
for ancestor in argument.ancestors do
1399
if !ancestor.is_object then
1400
result.add(ancestor)
1401
fi
1402
od
1403
1404
return result
1405
fi
1406
fi
1407
1408
return Collections.LIST[Type](0)
1409
si
1410
1411
try_specialize(
1412
location: LOCATION,
1413
logger: Logger,
1414
actual_type_arguments: Collections.List[Type]
1415
) -> Symbol? is
1416
if !is_generic then
1417
logger.error(location, "cannot explicitly specialize non-generic type")
1418
return null
1419
elif actual_type_arguments.count != generic_argument_names.count then
1420
logger.error(location, "expected {generic_argument_names.count} explicit generic type arguments")
1421
return null
1422
fi
1423
1424
GENERIC_CONSTRAINT_CHECKER().check_arguments(
1425
location,
1426
logger,
1427
self,
1428
generic_argument_names,
1429
actual_type_arguments
1430
)
1431
1432
return specialize(actual_type_arguments)
1433
si
1434
1435
// The declared type parameter at `index`. A function's own
1436
// formals are written in terms of these symbols, so a
1437
// substitution map has to be keyed on them. A reflected generic
1438
// method declares none into its scope and carries them
1439
// positionally instead, where the mapped type's symbol is the
1440
// same one its formals mention.
1441
_type_parameter_at(index: int) -> GenericArgument? is
1442
if index < 0 \/ index >= generic_argument_names.count then
1443
return null
1444
fi
1445
1446
if let declared = find_direct(generic_argument_names[index]) then
1447
return cast GenericArgument?(declared)
1448
fi
1449
1450
if index < generic_arguments.count then
1451
return cast GenericArgument?(generic_arguments[index].symbol)
1452
fi
1453
1454
return null
1455
si
1456
1457
specialize(actual_type_arguments: Collections.List[Type]) -> Symbol is
1458
assert is_generic else "trying to specialize non generic function {qualified_name}"
1459
1460
let type_map = Collections.MAP[Symbol,Type]()
1461
1462
for (index, value) in actual_type_arguments |> index() do
1463
let parameter = _type_parameter_at(index)
1464
1465
assert parameter? else
1466
"function '{qualified_name}' has no type parameter at {index}"
1467
1468
type_map[parameter] = value
1469
od
1470
1471
let result = specialize_function(type_map, null)
1472
1473
if result.is_generic then
1474
result.is_generic = false
1475
fi
1476
1477
return result
1478
si
1479
1480
set_void_return_type() is
1481
return_type = IoC.CONTAINER.instance.innate_symbol_lookup.get_void_type()
1482
si
1483
1484
set_return_type(rt: Type?) is
1485
return_type = rt
1486
1487
if rt? /\ are_arguments_declared then
1488
if arguments.count > Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS then
1489
IoC.CONTAINER.instance.logger.error(
1490
location,
1491
"a function literal cannot have more than {Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS} parameters")
1492
1493
type = Types.ERROR()
1494
else
1495
type = IoC.CONTAINER.instance.innate_symbol_lookup.get_function_type(
1496
arguments |> cat([rt]) |> collect_list()
1497
)
1498
fi
1499
else
1500
type = Types.ERROR()
1501
fi
1502
1503
type_updated(type!)
1504
si
1505
1506
type_updated(type: Type) is
1507
// override me
1508
si
1509
1510
get_full_type(innate_symbol_lookup: Lookups.InnateSymbolLookup) -> Types.Type is
1511
if arguments.count > Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS then
1512
IoC.CONTAINER.instance.logger.error(
1513
location,
1514
"a function with more than {Lookups.INNATE_TYPE_LIMITS.MAX_FUNCTION_PARAMETERS} parameters cannot be used as a value")
1515
1516
return Types.ERROR()
1517
fi
1518
1519
let types = Collections.LIST[Type](arguments.count + 1)
1520
1521
types.add_range(arguments)
1522
types.add(return_type!)
1523
1524
// A store-free function referred to as a value is a value
1525
// of the pure shape of its type — the property belongs to
1526
// the function, not to the slot it is being read into.
1527
return innate_symbol_lookup.get_function_type(types, is_proven_store_free)
1528
si
1529
1530
try_override(into: Classy, function: Function, logger: Logger) is
1531
logger.error(location, "cannot override {function}", function.location, "declared here")
1532
si
1533
1534
try_instance_override_me(into: Classy, function: Function, logger: Logger) is
1535
logger.error(function.location, "cannot be overridden by {function}", location, "overridden declaration")
1536
si
1537
1538
try_struct_override_me(into: Classy, function: Function, logger: Logger) is
1539
logger.error(function.location, "cannot be overridden by {function}", location, "overridden declaration")
1540
si
1541
1542
try_abstract_override_me(into: Classy, function: Function, logger: Logger) is
1543
logger.error(function.location, "cannot be overridden by {function}", location, "overridden declaration")
1544
si
1545
1546
// What every cell does once it has decided the declaration in
1547
// front of it really is an override of this member: check what
1548
// an implementation is held to, and record the relation both
1549
// ways so everything downstream - the contracts, the editor,
1550
// the covariant-return slot - can see it.
1551
record_implementing_override(into: Classy, overrider: Function, logger: Logger) is
1552
let return_type_matches = overrider.ensure_return_type_matches(into, self, false, logger)
1553
1554
overrider.ensure_arguments_accept_optionals(into, self, false, logger)
1555
1556
let il_name_matches = overrider.ensure_il_name_matches(into, self, "implement", logger)
1557
1558
overrider.add_overridee(self)
1559
self.add_overrider(overrider)
1560
si
1561
1562
inheritance_warn(logger: Logger, into: Classy, code: string, message: string) is
1563
if owner == into then
1564
logger.warn(location, code, message)
1565
else
1566
logger.warn(into.location, code, "{self} {message}")
1567
fi
1568
si
1569
1570
inheritance_error(logger: Logger, into: Classy, message: string) is
1571
if owner == into then
1572
logger.error(location, message)
1573
else
1574
logger.error(into.location, "{self} {message}")
1575
fi
1576
si
1577
1578
// Whether this function's return type is a narrower reference type
1579
// than the one it overrides or implements. Such a member takes the
1580
// overridden slot even though its emitted signature differs, so a
1581
// caller holding the declaring type reaches it. Only references
1582
// qualify: a value type differs in representation from the type it
1583
// narrows, so no one method can answer both signatures.
1584
has_covariant_return_over(overridee: Function) -> bool is
1585
let own = return_type
1586
let overridden = _return_type_of(overridee)
1587
1588
if !own? \/ !overridden? then
1589
return false
1590
fi
1591
1592
if own.matches(overridden) then
1593
return false
1594
fi
1595
1596
if
1597
own.is_value_type \/ overridden.is_value_type \/
1598
own.is_type_variable \/ overridden.is_type_variable
1599
then
1600
return false
1601
fi
1602
1603
return overridden.is_assignable_from(own)
1604
si
1605
1606
// What `overridee` returns, read in this function's own type
1607
// parameters: two declarations of one generic method name the
1608
// same position by different symbols.
1609
_return_type_of(overridee: Function) -> Types.Type? is
1610
if let overridden = overridee.return_type then
1611
return
1612
GENERIC_PARAMETER_ALIGNMENT.rewrite(
1613
overridden, generic_arguments, overridee.generic_arguments)
1614
fi
1615
1616
return null
1617
si
1618
1619
ensure_return_type_matches(into: Classy, overridee: Function, want_override: bool, logger: Logger) -> bool is
1620
if !into.is_reflected then
1621
if
1622
!return_type!.matches(_return_type_of(overridee)!) /\
1623
!has_covariant_return_over(overridee)
1624
then
1625
inheritance_error(logger, into, "does not {override_verb(want_override)} {overridee} due to different return type {return_type}")
1626
1627
return false
1628
fi
1629
1630
// Optionality is not part of the emitted signature, so a
1631
// method whose return type differs from its overridee's
1632
// only in optionality overrides it at run time regardless.
1633
// Widening the return to optional would let null reach
1634
// callers typed by the overridee. Internal functions are
1635
// property accessors, reported at the property level;
1636
// reflected overriders are imported declarations the user
1637
// cannot change, so they are not reported at all.
1638
if !is_internal /\ !is_reflected /\ return_type!.is_optional /\ !overridee.return_type!.is_optional then
1639
inheritance_error(logger, into, "cannot {override_verb(want_override)} {overridee} with optional return type {return_type}")
1640
fi
1641
fi
1642
1643
return true
1644
si
1645
1646
// Arguments compare optionality-blind for override matching, so an
1647
// overriding method can redeclare an optional argument as
1648
// non-optional - but it still receives callers' optional values
1649
// through the overridden signature, so that narrowing is unsound.
1650
ensure_arguments_accept_optionals(into: Classy, overridee: Function, want_override: bool, logger: Logger) is
1651
if into.is_reflected \/ is_reflected \/ is_internal \/ arguments.count != overridee.arguments.count then
1652
return
1653
fi
1654
1655
// The equality and order operators are exempt: an absent
1656
// operand is answered by the null checks the operator's
1657
// own lowering writes around the call, so a body declared
1658
// non-optional is only handed present values however the
1659
// overridden member spells its parameter. That makes the
1660
// non-optional spelling honest for an implementation, and
1661
// lets one implementation shape satisfy Ghul.Equatable
1662
// and Ghul.Comparable however their type argument renders.
1663
if name =~ "=~" \/ name =~ "<>" then
1664
return
1665
fi
1666
1667
for i in 0..arguments.count do
1668
// An optional type variable is exempt: an unconstrained
1669
// type parameter cannot be spelled optional in source, so
1670
// the signature this would demand is unwritable. Reflected
1671
// generic interfaces declare such arguments routinely
1672
// (IComparer, IEqualityComparer).
1673
if
1674
overridee.arguments[i].is_optional /\
1675
!overridee.arguments[i].is_type_variable /\
1676
!arguments[i].is_optional
1677
then
1678
inheritance_error(logger, into, "cannot {override_verb(want_override)} {overridee}: argument {i + 1} must be optional")
1679
fi
1680
od
1681
si
1682
1683
override_verb(want_override: bool) -> string static =>
1684
if want_override then "override" else "implement" fi
1685
1686
ensure_il_name_matches(into: Classy, overridee: Function, override_type: string, logger: Logger) -> bool is
1687
if il_name !~ overridee.il_name then
1688
if il_name_override? then
1689
logger.warn(
1690
location,
1691
"override-mismatch-il-name",
1692
"does not {override_type} {overridee} due to inconsistent IL names ({il_name} vs {overridee.il_name})",
1693
overridee.location,
1694
"overridden member declared here")
1695
return false
1696
else
1697
il_name_override = overridee.il_name
1698
1699
if let journal = INHERITANCE_JOURNAL.current then
1700
journal.record(InheritanceOp.IL_NAME_SET(self))
1701
fi
1702
fi
1703
fi
1704
1705
return true
1706
si
1707
1708
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1709
let result = FUNCTION_GENERIC_ARGUMENT(location, self, name, index)
1710
1711
declare(location, result, symbol_definition_listener)
1712
1713
return result
1714
si
1715
1716
declare_closure_symbol(location: LOCATION, result: Closure) -> Symbol is
1717
declare(location, result, null)
1718
1719
return result
1720
si
1721
1722
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1723
let result: Variable =
1724
if _declaring_arguments then
1725
Symbols.LOCAL_ARGUMENT(location, self, name)
1726
else
1727
Symbols.LOCAL_VARIABLE(location, self, name)
1728
fi
1729
1730
declare(location, result, symbol_definition_listener)
1731
1732
return result
1733
si
1734
1735
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, is_property_accessor: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1736
let result = Symbols.GLOBAL_FUNCTION(location, span, self, name, enclosing)
1737
1738
declare_function_group(location, result, symbol_definition_listener)
1739
1740
return result
1741
si
1742
1743
get_argument_description(index: int) -> string is
1744
let result = System.Text.StringBuilder()
1745
1746
result
1747
.append(argument_names[index])
1748
.append(": ")
1749
.append(_argument_type_description(index, false))
1750
1751
return result.to_string()
1752
si
1753
1754
// A formal declared to take an argument pack spread out is
1755
// written `f: T.. -> U`, and the marker sits on the parameter of
1756
// its own function type - which the type's own rendering knows
1757
// nothing about, so the two halves are written out here.
1758
_argument_type_description(index: int, short: bool) -> string is
1759
let type = arguments[index]
1760
1761
if !get_argument_is_pack(index) then
1762
return if short then type.short_description else "{type}" fi
1763
fi
1764
1765
return _pack_marked_type_description(type, get_argument_pack_depth(index), short)
1766
si
1767
1768
_return_type_description(short: bool) -> string is
1769
let type = return_type!
1770
1771
if return_pack_depth < 0 then
1772
return if short then type.short_description else "{type}" fi
1773
fi
1774
1775
return _pack_marked_type_description(type, return_pack_depth, short)
1776
si
1777
1778
_pack_marked_type_description(type: Type, depth: int, short: bool) -> string is
1779
let slot = Semantic.ARGUMENT_PACK.marked_slot(type, depth)
1780
1781
if !slot? then
1782
return if short then type.short_description else "{type}" fi
1783
fi
1784
1785
let result = System.Text.StringBuilder()
1786
1787
let hop mut = type
1788
1789
for _ in 0..depth do
1790
result.append(_function_parameters_description(hop, short)).append(" -> ")
1791
1792
hop = hop.arguments[hop.arguments.count - 1]
1793
od
1794
1795
// The pack is the last parameter; any before it are the
1796
// formal's own, and the list is parenthesised as it is written.
1797
let fixed = Semantic.ARGUMENT_PACK.fixed_count(slot)
1798
1799
let parameter = slot.arguments[fixed]
1800
1801
let returns =
1802
if slot.is_action then
1803
"void"
1804
elif short then
1805
slot.arguments[fixed + 1].short_description
1806
else
1807
"{slot.arguments[fixed + 1]}"
1808
fi
1809
1810
let purity = if slot.is_pure_function then " pure" else "" fi
1811
1812
if fixed > 0 then
1813
result.append("(")
1814
1815
for i in 0..fixed do
1816
let leading = slot.arguments[i]
1817
1818
result.append(if short then leading.short_description else "{leading}" fi).append(", ")
1819
od
1820
fi
1821
1822
result.append(if short then parameter.short_description else "{parameter}" fi)
1823
result.append("..")
1824
1825
if fixed > 0 then
1826
result.append(")")
1827
fi
1828
1829
result.append(" -> ").append(returns).append(purity)
1830
1831
return result.to_string()
1832
si
1833
1834
_function_parameters_description(type: Type, short: bool) -> string is
1835
let count =
1836
if type.is_action then
1837
type.arguments.count
1838
else
1839
type.arguments.count - 1
1840
fi
1841
1842
let result = System.Text.StringBuilder()
1843
1844
if count != 1 then
1845
result.append("(")
1846
fi
1847
1848
for i in 0..count do
1849
if i > 0 then
1850
result.append(", ")
1851
fi
1852
1853
let argument = type.arguments[i]
1854
1855
result.append(if short then argument.short_description else "{argument}" fi)
1856
od
1857
1858
if count != 1 then
1859
result.append(")")
1860
fi
1861
1862
return result.to_string()
1863
si
1864
1865
get_short_argument_description(index: int) -> string is
1866
let result = System.Text.StringBuilder()
1867
1868
result
1869
.append(argument_names[index])
1870
.append(": ")
1871
.append(_argument_type_description(index, true))
1872
1873
return result.to_string()
1874
si
1875
1876
is_indexer_accessor: bool => INDEXER_NAMES.is_canonical(name)
1877
1878
// The element type an indexer reads or writes: the return type of
1879
// the read accessor, and the value parameter of the write one,
1880
// whose own return type is void.
1881
indexer_value_type: Type? =>
1882
if name =~ INDEXER_NAMES.assign then
1883
if arguments.count > 1 then arguments[1] else null fi
1884
else
1885
return_type
1886
fi
1887
1888
// `OWNER[index: I]: E`, with `= value` on the write accessor. The
1889
// caller supplies both renderings so the long and short forms
1890
// differ only in how their types are described.
1891
render_indexer_shape(index_description: string, value_description: string) -> string is
1892
let result = "{_display_owner_name}[{index_description}]: {value_description}"
1893
1894
if name =~ INDEXER_NAMES.assign /\ argument_names.count > 1 then
1895
return "{result} = {argument_names[1]}"
1896
fi
1897
1898
return result
1899
si
1900
1901
_display_owner_name: string is
1902
let o = owner
1903
1904
if isa Symbol(o) then
1905
return IoC.CONTAINER.instance.name_display.name_for(o)
1906
fi
1907
1908
return o!.qualified_name
1909
si
1910
1911
to_string() -> string is
1912
let result = System.Text.StringBuilder()
1913
1914
try
1915
if name.starts_with("$get_") then
1916
result
1917
.append(_display_owner_name)
1918
.append(".")
1919
.append(name.substring(5))
1920
.append(": ")
1921
.append(return_type)
1922
elif name.starts_with("$set_") then
1923
result
1924
.append(_display_owner_name)
1925
.append(".")
1926
.append(name.substring(5))
1927
.append(": ")
1928
.append(return_type)
1929
.append(" = ")
1930
.append(argument_names[0])
1931
elif is_indexer_accessor then
1932
result
1933
.append(
1934
render_indexer_shape(
1935
"{argument_names[0]}: {arguments[0]}",
1936
"{indexer_value_type}"
1937
)
1938
)
1939
else
1940
result
1941
.append(IoC.CONTAINER.instance.name_display.name_for(self))
1942
.append(generic_argument_descriptions)
1943
.append("(")
1944
.append(short_argument_descriptions)
1945
.append(") -> ")
1946
.append(_return_type_description(false))
1947
fi
1948
1949
return result.to_string()
1950
catch ex: Exception
1951
return "[garbled function: {result}]"
1952
yrt
1953
si
1954
1955
gen_entrypoint(context: IR.CONTEXT) is
1956
if !is_entry_point then
1957
return
1958
fi
1959
1960
context.seen_entrypoint = true
1961
1962
// The entry point is marked by handle once the method's row
1963
// is written, so this records the function rather than
1964
// emitting anything here.
1965
context.srm_assembly_emitter.entry_point_function = self
1966
si
1967
1968
gen_body_header(context: IR.CONTEXT) is
1969
si
1970
1971
si
1972
1973
class GLOBAL_FUNCTION: Function is
1974
is_public_readable: bool => !emit_assembly
1975
1976
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
1977
_describe_function(context, true)
1978
1979
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
1980
"{pure_prefix}global function"
1981
1982
// Set by the .NET importer when the symbol is read back from a
1983
// referenced assembly: the carrier class the method is a static
1984
// member of, which a call site's methodref hangs off. A namespace
1985
// can have several carriers, so the carrier is recorded rather
1986
// than derived from the namespace.
1987
il_carrier: Classy? public
1988
1989
// Set for an underscore-prefixed global (or the accessor of an
1990
// underscore-prefixed global property) under the private/protected
1991
// policy: emit assembly rather than public so it is hidden from other
1992
// assemblies while staying reachable within this one. Globals live on
1993
// the synthetic $globals class, so declaring-class-private is
1994
// meaningless for them; assembly-internal is the whole effect.
1995
emit_assembly: bool public
1996
1997
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
1998
super.init(location, span, owner, name, enclosing_scope)
1999
si
2000
2001
declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
2002
declare_closure_symbol(location, Symbols.GLOBAL_CLOSURE(location, owner, name, enclosing, is_recursive))
2003
2004
declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
2005
declare_closure_symbol(location, Symbols.GLOBAL_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive))
2006
2007
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
2008
if from? /\ from.is_consumable then
2009
IoC.CONTAINER.instance.logger.poison(location, "global function load shouldn't have a left expression")
2010
fi
2011
2012
return loader.load_global_function(self)
2013
si
2014
2015
call(location: Source.LOCATION, from: IR.Values.Value?, arguments: Collections.List[IR.Values.Value], type: Type?, caller: FUNCTION_CALLER) -> IR.Values.Value is
2016
if from? /\ from.is_consumable then
2017
IoC.CONTAINER.instance.logger.poison(location, "global function call shouldn't have a left expression")
2018
fi
2019
2020
return caller.call_global_function(self, arguments, self.arguments, type)
2021
si
2022
2023
// Method definition lives inside `.class 'NS'.'$globals' { ... }` block,
2024
// so the .method header has no qualifier — base (empty) gen_owner_name
2025
// is what we want.
2026
// FIXME: should storage class be split out of here:
2027
gen_body_header(context: IR.CONTEXT) is
2028
gen_entrypoint(context)
2029
si
2030
si
2031
si