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
_arguments: Collections.List[Type];
22
23
_declaring_arguments: bool;
24
_override_class: METHOD_OVERRIDE_CLASS?;
25
26
override_class: METHOD_OVERRIDE_CLASS is
27
if !_override_class? then
28
// arguments is empty when resolve-explicit-variable-types
29
// never visited this function (e.g. a partially-recovered
30
// parse left the symbol orphaned from current_function),
31
// giving that case a zero-arg override class — partial
32
// symbols don't meaningfully participate in override
33
// resolution anyway.
34
let count = generic_arguments.count;
35
_override_class = METHOD_OVERRIDE_CLASS(arguments, count);
36
fi
37
38
return _override_class;
39
si
40
41
_overriders: Collections.MutableList[Symbol]?;
42
_overridees: Collections.MutableList[Symbol]?;
43
44
// Set by infer-store-free: a call to this function provably
45
// cannot store to any pre-existing heap location — no field,
46
// property, global, indexer or array-element assignment,
47
// directly or through anything the call could dispatch to,
48
// including every override. False means "not proven", not
49
// "known to store". The bit is read and written through the
50
// unspecialized function so specializations created at any
51
// point see it, and stored in STORE_FREE_BITS keyed by the
52
// function's id so it survives an incremental edit re-creating
53
// the symbol when the replacement adopts the predecessor's id.
54
is_store_free: bool is
55
let rsf = root_specialized_from;
56
57
if rsf != self then
58
return (cast Function?(rsf)!).is_store_free;
59
fi
60
61
// declared `pure` is trusted without proof — including on
62
// body-less trait members, which the analysis never sees
63
return STORE_FREE_BITS.is_store_free(id) \/ _is_declared_pure \/ _is_trusted_import;
64
si
65
66
// A curated store-free import is trusted at query time, not
67
// only when a named body's fixpoint happens to reach it as a
68
// callee edge. A call in a function-literal body or a
69
// string-interpolation fragment never becomes such an edge, so
70
// without this an otherwise store-free import reads as
71
// state-changing purely by where it was called from — the same
72
// import trusted in a named body goes untrusted in a lambda.
73
// Gated on has_no_overriders so a virtual entry with an
74
// in-assembly override still falls to the fixpoint's
75
// dispatch-shadow check rather than being trusted blind.
76
_is_trusted_import: bool =>
77
has_no_overriders /\ _is_whitelisted_import;
78
79
// Whitelist membership is fixed at import from the function's
80
// own name and owner, so it is derived once and cached.
81
_whitelisted_import_cache: bool?;
82
83
_is_whitelisted_import: bool is
84
if !_whitelisted_import_cache? then
85
_whitelisted_import_cache = is_reflected /\ STORE_FREE_IMPORTS.is_store_free(self);
86
fi
87
88
return _whitelisted_import_cache!;
89
si
90
91
set_store_free(value: bool) is
92
let rsf = root_specialized_from;
93
94
if rsf != self then
95
(cast Function?(rsf)!).set_store_free(value);
96
return;
97
fi
98
99
STORE_FREE_BITS.set_store_free(id, value);
100
si
101
102
// Whether this function is a constructor. Overridden on the
103
// method that carries the `.ctor` IL name; false everywhere
104
// else, so callers can ask any function without a cast.
105
is_constructor: bool => false;
106
107
// A constructor is trusted to write no pre-existing heap slot
108
// *given its receiver is fresh* — the case a `NEW` presents.
109
// Store-free constructors qualify directly; a constructor that
110
// only writes its own instance fields qualifies through the
111
// fixpoint's construction pass. The strict store-free bit stays
112
// the answer for every non-construction call site.
113
constructs_store_free: bool is
114
let rsf = root_specialized_from;
115
116
if rsf != self then
117
return (cast Function?(rsf)!).constructs_store_free;
118
fi
119
120
return is_store_free \/ STORE_FREE_BITS.constructs_store_free(id);
121
si
122
123
set_constructs_store_free(value: bool) is
124
let rsf = root_specialized_from;
125
126
if rsf != self then
127
(cast Function?(rsf)!).set_constructs_store_free(value);
128
return;
129
fi
130
131
STORE_FREE_BITS.set_constructs_store_free(id, value);
132
si
133
134
// Declared `pure` in source: the function is trusted
135
// effectively store-free without its body being provable.
136
// Feeds the store-free bit unconditionally after the
137
// fixpoint, and obliges every override or trait
138
// implementation to be pure itself — declared or proven.
139
_is_declared_pure: bool;
140
141
is_declared_pure: bool is
142
let rsf = root_specialized_from;
143
144
if rsf != self then
145
return (cast Function?(rsf)!).is_declared_pure;
146
fi
147
148
return _is_declared_pure;
149
si
150
151
mark_declared_pure() is
152
let rsf = root_specialized_from;
153
154
if rsf != self then
155
(cast Function?(rsf)!).mark_declared_pure();
156
return;
157
fi
158
159
_is_declared_pure = true;
160
si
161
162
// Recorded while compile-expressions walks a function
163
// literal's body: true when the body performed a possibly
164
// heap-visible operation — a possibly-storing call, a heap
165
// store, or any local reassignment (a reassigned local can be
166
// a captured one, which is a frame-field store; own-local
167
// reassignment is conservatively included). Consulted where
168
// the literal meets a pure function-typed slot. Meaningless
169
// for named functions — infer-store-free covers those.
170
literal_body_impure: bool public;
171
172
// The operation named by an `INTRINSIC_ATTRIBUTE` on this
173
// declaration, or null. Set for a source declaration only: the
174
// declaration is emitted so consumers can reflect it, and a
175
// separate innate is registered from it once signatures resolve.
176
intrinsic_operation: string? public;
177
178
// No more-derived override exists. In a closed-by-default,
179
// wholly-compiled assembly this means the method is effectively
180
// final — the only body a call can reach is this one.
181
has_no_overriders: bool => !_overriders? \/ _overriders.count == 0;
182
183
span: LOCATION;
184
185
// Incremental body re-walk override: also shift the declaration
186
// span when the retained interface symbol is relocated.
187
set_span(span_location: LOCATION) is
188
span = span_location;
189
si
190
191
type: Type? public;
192
return_type: Type? public;
193
194
// True when this function was declared without an explicit
195
// return-type annotation (so the return type starts as
196
// INFERRED_RETURN_TYPE and is set by walking return statements
197
// / expression bodies). Used by the compile pass to drive LUB
198
// widening across multiple return statements: when a later
199
// return produces a type that's neither assignable to nor
200
// from the current binding, widening to the LUB is the right
201
// answer for an inferred return type, but a declared return
202
// type with the same shape is a genuine type error.
203
return_type_was_inferred: bool public;
204
205
// Set by compile-lambdas when the AST FUNCTION had
206
// `contains_let_await` set by declare-symbols. When settling
207
// an inferred return type from the body's value, wrap a
208
// bare-T value as `Tasks.TASK[T]` so the closure's signature
209
// matches its async-state-machine emission shape. Body
210
// values already typed Task[?] are left untouched.
211
wrap_inferred_return_as_task: bool public;
212
213
// Set by compile-lambdas when the AST FUNCTION had
214
// `is_void_async` set by declare-symbols — i.e., body
215
// contains `await` but no value-returning `return X;`
216
// statements. Read by the async state machine setup to pick
217
// the non-generic Tasks.TASK over Tasks.TASK[T].
218
is_void_async: bool public;
219
220
// True once the argument list has been supplied — by
221
// resolve-explicit-variable-types for source functions, at import
222
// for reflected ones, or at synthesis. Distinguishes a
223
// not-yet-declared function from a declared zero-argument one:
224
// both have an empty arguments list, but only the declared one
225
// may participate in arity-based overload filtering.
226
_are_arguments_declared: bool;
227
228
are_arguments_declared: bool => _are_arguments_declared;
229
230
arguments: Collections.List[Type] public => _arguments,
231
= value is
232
assert value |> all(a => a?) else "setting an argument to null for {name}";
233
234
_arguments = value;
235
_are_arguments_declared = true;
236
si
237
238
generic_arguments: Collections.List[Type] public;
239
generic_argument_names: Collections.List[string] public;
240
unspecialized_arguments: Collections.List[Type]? public;
241
unspecialized_return_type: Type? public;
242
243
// Parallel to generic_argument_names: kind / `new()` / type-bound
244
// constraints per method-level type parameter. Populated at
245
// import for .NET methods, whose parameter symbols are not
246
// declared into the function's scope and so can't be reached
247
// via find_direct. ghūl-declared methods leave these empty and
248
// carry the same information on the parameter symbol.
249
generic_argument_constraint_kinds: Collections.List[TypeParameterConstraintKind] public;
250
generic_argument_has_constructor_constraint: Collections.List[bool] public;
251
generic_argument_type_bounds: Collections.List[Type?] public;
252
253
argument_names: Collections.List[string] public;
254
255
// Parallel to `argument_names`: the declared default of each
256
// parameter, or null when the parameter has no default and so
257
// cannot be omitted from a named call. A ghūl-source `= _`
258
// parameter is stored as "default"; a literal default
259
// (reflected methods only) is stored as its text.
260
argument_defaults: Collections.List[string?] public;
261
262
// Parallel to `argument_names`: per-parameter by-ref direction,
263
// derived from reflected `IsIn`/`IsOut` and populated only for
264
// reflected methods that have a non-plain by-ref slot. Null
265
// elsewhere, where a by-ref parameter defaults to plain `ref`
266
// — both read and written. `reads` gates the must-be-assigned-
267
// before check; `writes` gates definite assignment of the
268
// argument. Held on the unspecialized function so specializations
269
// observe them through `root_specialized_from`.
270
_argument_reads: Collections.List[bool]?;
271
_argument_writes: Collections.List[bool]?;
272
273
set_argument_directions(reads: Collections.List[bool], writes: Collections.List[bool]) is
274
let rsf = root_specialized_from;
275
276
if rsf != self then
277
(cast Function?(rsf)!).set_argument_directions(reads, writes);
278
return;
279
fi
280
281
_argument_reads = reads;
282
_argument_writes = writes;
283
si
284
285
// Whether the callee reads the incoming value of argument `i`.
286
// True for every by-ref slot except a pure `out`, and the
287
// conservative default when no reflected direction is recorded.
288
argument_reads(i: int) -> bool is
289
let rsf = root_specialized_from;
290
291
if rsf != self then
292
return (cast Function?(rsf)!).argument_reads(i);
293
fi
294
295
if _argument_reads? /\ i < _argument_reads.count then
296
return _argument_reads[i];
297
fi
298
299
return true;
300
si
301
302
// Whether the callee writes argument `i`, so passing it by `ref`
303
// definitely assigns the target. True for every by-ref slot
304
// except a pure `in`, and the conservative default.
305
argument_writes(i: int) -> bool is
306
let rsf = root_specialized_from;
307
308
if rsf != self then
309
return (cast Function?(rsf)!).argument_writes(i);
310
fi
311
312
if _argument_writes? /\ i < _argument_writes.count then
313
return _argument_writes[i];
314
fi
315
316
return true;
317
si
318
319
symbol_kind: SymbolKind => SymbolKind.FUNCTION;
320
completion_kind: CompletionKind => CompletionKind.FUNCTION;
321
322
is_function: bool => true;
323
is_generic: bool public;
324
is_abstract: bool => false;
325
is_virtual: bool => false;
326
is_default_trait_method: bool => false;
327
is_capture_context: bool => true;
328
is_workspace_visible: bool => !name.starts_with('_');
329
is_recursive: bool => false; // only applicable if a closure
330
331
short_description: string => "{name}{generic_argument_descriptions}({short_argument_descriptions}) -> {return_type!.short_description}";
332
search_description: string => short_description;
333
334
// Prefixes the description's trailing kind comment when the
335
// function is proven store-free — diagnostic surfacing only,
336
// deliberately inside the comment so it does not read as
337
// source syntax.
338
pure_prefix: string => if is_store_free then "pure " else "" fi;
339
340
argument_descriptions: string =>
341
(0..arguments.count) |> map(i => get_argument_description(i)) |> join() ?? "";
342
343
short_argument_descriptions: string =>
344
(0..arguments.count) |> map(i => get_short_argument_description(i)) |> join() ?? "";
345
346
generic_argument_descriptions: string is
347
if generic_arguments.count == 0 then
348
return "";
349
fi
350
351
let result = System.Text.StringBuilder();
352
353
result.append('[');
354
355
generic_arguments |> append_to(result, ",");
356
357
result.append(']');
358
359
return result.to_string();
360
si
361
362
// Shared body for the concrete Function kinds. Reproduces the
363
// signature shape `{qname}{[gen,args]}({name}: {type}, …)` +
364
// optional ` -> {return_type}` — no trailing classifier; that
365
// lives on `describe_kind`. The `(...)` argument list is a
366
// WRAPPABLE so the DOC hover renderer can break it across
367
// lines; the generic `[]` bracket is not wrappable.
368
_describe_function(
369
context: DESCRIBE_CONTEXT,
370
include_return_type: bool
371
) -> SignaturePart is
372
let parts = Collections.LIST[SignaturePart]();
373
parts.add(PARTS.name(self));
374
parts.add(_describe_generic_arguments());
375
parts.add(_describe_arguments(context));
376
if include_return_type /\ return_type? then
377
parts.add(PARTS.literal(" -> "));
378
parts.add(PARTS.type_ref(return_type!));
379
fi
380
return SignaturePart.SEQUENCE(parts);
381
si
382
383
_describe_generic_arguments() -> SignaturePart is
384
if generic_arguments.count == 0 then
385
return PARTS.nil();
386
fi
387
let items = Collections.LIST[SignaturePart]();
388
for t in generic_arguments do
389
items.add(PARTS.type_ref(t));
390
od
391
return SignaturePart.WRAPPABLE("[", ",", true, "]", items);
392
si
393
394
_describe_arguments(context: DESCRIBE_CONTEXT) -> SignaturePart is
395
let items = Collections.LIST[SignaturePart]();
396
for i in 0..arguments.count do
397
items.add(PARTS.sequence([
398
PARTS.literal("{argument_names[i]}: "),
399
PARTS.type_ref(arguments[i])
400
]));
401
od
402
return SignaturePart.WRAPPABLE("(", ",", false, ")", items);
403
si
404
405
overriders: Collections.Iterable[Symbol]? => _overriders;
406
overridees: Collections.Iterable[Symbol]? => _overridees;
407
408
has_overridees: bool => _overridees? /\ _overridees.count > 0;
409
410
// Attribute pragmas resolved onto a parameter (`@Foo() name: T`).
411
// A parameter's own symbol is a member of its owning function's
412
// scope regardless of function kind, so this reaches it the
413
// same way for a named function, a delegate/anon-func closure,
414
// or a frame-boxed capturing closure.
415
gen_argument_custom_attributes(context: IR.CONTEXT) is
416
let i mut = 0;
417
418
for name in argument_names do
419
let argument_symbol = find_direct(name);
420
421
if let attributes = argument_symbol?.custom_attributes then
422
context.write_line(".param [{i + 1}]");
423
424
for attribute in attributes do
425
context.write_line(attribute.gen_il_line());
426
od
427
fi
428
429
i = i + 1;
430
od
431
si
432
433
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
434
super.init(location, owner, name, enclosing_scope);
435
436
self.span = span;
437
438
_arguments = Collections.LIST[Type](0);
439
argument_names = Collections.LIST[string](0);
440
generic_arguments = Collections.LIST[Type](0);
441
generic_argument_names = Collections.LIST[string](0);
442
generic_argument_constraint_kinds = Collections.LIST[TypeParameterConstraintKind](0);
443
generic_argument_has_constructor_constraint = Collections.LIST[bool](0);
444
generic_argument_type_bounds = Collections.LIST[Type?](0);
445
446
if name =~ "init" then
447
il_name_override = "'.ctor'";
448
elif name =~ "=~" /\ isa Classy(owner) then
449
// A type's `=~` maps to .NET `Equals` for interop. A global
450
// `=~` operator keeps its own name, or it comes back from
451
// reflection as `equals` and no longer resolves.
452
il_name_override = "Equals";
453
fi
454
455
type = Types.NAMED(self);
456
si
457
458
set_arguments(argument_names: Collections.List[string], argument_types: Collections.List[Type]) is
459
self.arguments = argument_types;
460
461
assert argument_names |> all(a => a?) else "setting an argument name to null for {name} (B)";
462
463
self.argument_names = argument_names;
464
si
465
466
add_overrider(overrider: Symbol mut) is
467
let rsf = root_specialized_from;
468
if rsf != self then
469
rsf.add_overrider(overrider);
470
return;
471
fi
472
473
let overriders mut = _overriders;
474
475
if !overriders? then
476
overriders = Collections.LIST[Symbol]();
477
_overriders = overriders;
478
fi
479
480
overrider = overrider.root_specialized_from;
481
482
if overriders.contains(overrider) then
483
return;
484
fi
485
486
overriders.add(overrider);
487
488
if let journal = INHERITANCE_JOURNAL.current then
489
journal.record(InheritanceOp.FUNCTION_OVERRIDER_ADDED(self, overrider));
490
fi
491
si
492
493
remove_overrider(overrider: Symbol) is
494
let rsf = root_specialized_from;
495
if rsf != self then
496
rsf.remove_overrider(overrider);
497
return;
498
fi
499
500
let overriders = _overriders;
501
502
if overriders? then
503
overriders.remove(overrider.root_specialized_from);
504
fi
505
si
506
507
add_overridee(overridee: Symbol mut) is
508
let rsf = root_specialized_from;
509
if rsf != self then
510
rsf.add_overridee(overridee);
511
return;
512
fi
513
514
let overridees mut = _overridees;
515
516
if !overridees? then
517
overridees = Collections.LIST[Symbol]();
518
_overridees = overridees;
519
fi
520
521
overridee = overridee.root_specialized_from;
522
523
if overridees.contains(overridee) then
524
return;
525
fi
526
527
overridees.add(overridee);
528
529
if let journal = INHERITANCE_JOURNAL.current then
530
journal.record(InheritanceOp.FUNCTION_OVERRIDEE_ADDED(self, overridee));
531
fi
532
si
533
534
remove_overridee(overridee: Symbol) is
535
let rsf = root_specialized_from;
536
if rsf != self then
537
rsf.remove_overridee(overridee);
538
return;
539
fi
540
541
let overridees = _overridees;
542
543
if overridees? then
544
overridees.remove(overridee.root_specialized_from);
545
fi
546
si
547
548
load_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value is
549
IoC.CONTAINER.instance.logger.error(location, "cannot access instance member from non-instance context");
550
551
return IR.Values.DUMMY(Types.ERROR(), location);
552
si
553
554
load_outer_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value? is
555
IoC.CONTAINER.instance.logger.error(location, "cannot access instance member from non-instance context");
556
557
return IR.Values.DUMMY(Types.ERROR(), location);
558
si
559
560
load_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value => throw NotImplementedException("{get_type()} cannot load captured value: {symbol} from: {location}");
561
load_outer_captured_value(location: LOCATION, symbol: Variable, loader: SYMBOL_LOADER) -> Value? => throw NotImplementedException("{get_type()} cannot load outer captured value: {symbol} from: {location}");
562
store_captured_value(location: LOCATION, symbol: Variable, value: Value, loader: SYMBOL_LOADER) -> Value => throw NotImplementedException("{get_type()} cannot store captured value: {symbol} from: {location}");
563
start_declaring_arguments() is
564
_declaring_arguments = true;
565
si
566
567
end_declaring_arguments() is
568
_declaring_arguments = false;
569
si
570
571
/*
572
given a set of actual function argument types, try to infer actual generic argument types by pattern matching formal
573
argument types (which may contain formal generic argument types) against correspinding actual arguments. Arguments
574
could be unknown (!!! or ***), which match anything and do not contradict any type inferences we make.
575
576
map[T,U](from: Iterable[T], mapper: T -> U) -> Iterable[U]
577
map([1, 2, 3, 4, 5], x => x + 1)
578
579
- the type of [1, 2, ... ] is known to be int[]
580
- prior type inference should figure out the return type of x => x + 1 must be int (because the only overload
581
resolution possible for !!! + 1 is int + int -> int) so we'll be called with actual argument types of int[]
582
and !!! -> int that need to be matched against Iterable[T] and T -> U
583
584
- int[] implements Iterable[int] which pattern matches Iterable[T], allowing us to infer that T should be int
585
- !!! -> int pattern matches T -> U. !!! doesn't contradict a type of int for T, and int implies a type of int for U
586
587
so we can return a type map of T = int, U = int
588
*/
589
// When LUB widening fired during bind (siblings case), the bound
590
// type may be wider than any individual arg-derived candidate.
591
// Re-verify each actual arg still conforms to its parameter type
592
// with the bound type-args substituted in. Without this check a
593
// call like structured[T](T, Iterable[T]) with (int, string)
594
// (or the constructor analogue Box[T] with init(item: T, bag:
595
// Iterable[T]) called as Box(1, "hello")) would bind
596
// T = LUB(int, char) = ValueType and silently accept, even
597
// though `string` is Iterable[char] which (without ghūl's
598
// variance handling marking Iterable covariant) is not
599
// Iterable[ValueType] — yielding an InvalidProgramException
600
// at JIT for the constructor path, or a runtime cast failure.
601
//
602
// Only run when LUB actually fired — pairwise widening is
603
// monotonic in the wider direction and doesn't need re-checking,
604
// and skipping the check on the happy path avoids triggering
605
// premature type evaluation on args that aren't yet ready
606
// (e.g. function literals being passed to higher-order calls).
607
check_lub_conformance(results: Types.GENERIC_ARGUMENT_BIND_RESULTS, args: Collections.List[Type]) -> bool is
608
if !results.is_bound \/ !results.used_lub then
609
return true;
610
fi
611
612
let type_map = results.map;
613
for i in 0..args.count do
614
let specialized_param = arguments[i].specialize(type_map);
615
if !specialized_param.is_assignable_from(args[i]) then
616
return false;
617
fi
618
od
619
620
return true;
621
si
622
623
try_bind_generic_arguments(location: Source.LOCATION, args: Collections.List[Type]) -> Types.GENERIC_ARGUMENT_BIND_RESULTS? is
624
// This method binds the *function's* own generic args
625
// (use try_bind_owner_generic_arguments for the owning
626
// class's). When the function isn't generic there is
627
// nothing here to bind — return null. Without this guard
628
// a non-generic instance method on a generic class
629
// (e.g. `Box[T].set(value: T)` called on `Box[?]`) would
630
// proceed to call check_complete with a null
631
// generic_arguments and NRE inside check_complete.
632
if !is_generic then
633
return null;
634
fi
635
636
assert args.count == arguments.count else "expected to bind {arguments.count} arguments in {self} but only {args} supplied";
637
638
let results = Types.GENERIC_ARGUMENT_BIND_RESULTS();
639
640
let all_ok = true;
641
642
for i in 0..args.count do
643
if !arguments[i].bind_type_variables(args[i], results) then
644
return null;
645
fi
646
od
647
648
results.check_complete(location, generic_arguments);
649
650
if !results.is_bound then
651
// A wild optional parameter (`T?`) matched a bare null
652
// actual, which accepts without pinning the type variable.
653
// Default any such never-pinned variable to object so the
654
// selected overload is fully specialized; otherwise it
655
// would emit with a free type parameter (`!!N`) and fail to
656
// load at run time.
657
results.default_null_only_unbound(
658
generic_arguments,
659
IoC.CONTAINER.instance.innate_symbol_lookup.get_object_type()
660
);
661
662
results.check_complete(location, generic_arguments);
663
fi
664
665
if !check_lub_conformance(results, args) then
666
return null;
667
fi
668
669
return results;
670
si
671
672
try_bind_owner_generic_arguments(location: Source.LOCATION, args: Collections.List[Type]) -> Types.GENERIC_ARGUMENT_BIND_RESULTS? is
673
let owner_classy = cast Classy?(owner);
674
675
if !owner_classy? \/ !owner_classy.is_generic then
676
return null;
677
fi
678
679
let results = Types.GENERIC_ARGUMENT_BIND_RESULTS();
680
681
for i in 0..args.count do
682
if !arguments[i].bind_type_variables(args[i], results) then
683
return null;
684
fi
685
od
686
687
results.check_complete(location, owner_classy.arguments);
688
689
if !check_lub_conformance(results, args) then
690
return null;
691
fi
692
693
return results;
694
si
695
696
specialize_function(type_map: Collections.Map[string,Type], owner: GENERIC) -> Function is
697
let result = cast Function?(memberwise_clone())!;
698
699
result.specialized_from = self;
700
result._override_class = null;
701
702
if !return_type? then
703
IoC.CONTAINER.instance.logger.poison(self.location, "specialized with null return type");
704
else
705
result.return_type = return_type.specialize(type_map);
706
fi
707
708
if unspecialized_arguments? then
709
result.unspecialized_arguments = unspecialized_arguments;
710
else
711
result.unspecialized_arguments = arguments;
712
fi
713
714
if unspecialized_return_type? then
715
result.unspecialized_return_type = unspecialized_return_type;
716
else
717
result.unspecialized_return_type = return_type!;
718
fi
719
720
// Pre-sized empty, filled by add: a LIST(arguments) copy would
721
// duplicate every element only for the loop to replace them.
722
let ra = Collections.LIST[Type](arguments.count);
723
724
result.arguments = ra;
725
726
for a in arguments do
727
ra.add(a.specialize(type_map));
728
od
729
730
if generic_arguments.count > 0 then
731
let specialized_arguments = Collections.LIST[Type](generic_arguments.count);
732
733
for ga in generic_arguments do
734
specialized_arguments.add(ga.specialize(type_map));
735
od
736
737
result.generic_arguments = specialized_arguments;
738
fi
739
740
// owner is absent for owner-less functions
741
@suppress("presence-test-non-optional")
742
if owner? then
743
if result.owner == owner.unspecialized_symbol then
744
result.owner = owner;
745
elif result.owner != owner then
746
result.owner = result.owner!.type!.specialize(owner.type_map).symbol;
747
else
748
Std.error.write_line("{result} is already owned by {owner}");
749
fi
750
fi
751
752
return result;
753
si
754
755
specialize(type_map: Collections.Map[string,Type], owner: GENERIC) -> Symbol =>
756
specialize_function(type_map, owner);
757
758
get_argument_constraint_kind(index: int) -> TypeParameterConstraintKind is
759
if index >= 0 /\ index < generic_argument_constraint_kinds.count then
760
return generic_argument_constraint_kinds[index];
761
fi
762
763
if index >= 0 /\ index < generic_argument_names.count then
764
let argument = find_direct(generic_argument_names[index]);
765
766
if argument? then
767
return argument.constraint_kind;
768
fi
769
fi
770
771
return TypeParameterConstraintKind.NONE;
772
si
773
774
get_argument_has_constructor_constraint(index: int) -> bool is
775
if index >= 0 /\ index < generic_argument_has_constructor_constraint.count then
776
return generic_argument_has_constructor_constraint[index];
777
fi
778
779
if index >= 0 /\ index < generic_argument_names.count then
780
let argument = find_direct(generic_argument_names[index]);
781
782
if argument? then
783
return argument.has_constructor_constraint;
784
fi
785
fi
786
787
return false;
788
si
789
790
// The type bound (`[T: SomeBase]`) of the method-level type
791
// parameter at `index`, or null when unbounded. Imported
792
// methods carry it in `generic_argument_type_bounds`; ghūl-
793
// declared methods carry it on the parameter symbol as its
794
// first ancestor.
795
get_argument_type_bound(index: int) -> Type? is
796
if index >= 0 /\ index < generic_argument_type_bounds.count then
797
return generic_argument_type_bounds[index];
798
fi
799
800
if index >= 0 /\ index < generic_argument_names.count then
801
let argument = find_direct(generic_argument_names[index]);
802
803
if argument? /\ argument.is_type_variable then
804
let ancestors = argument.ancestors;
805
806
if ancestors.count > 0 /\ !ancestors[0].is_object then
807
return ancestors[0];
808
fi
809
fi
810
fi
811
812
return null;
813
si
814
815
try_specialize(
816
location: LOCATION,
817
logger: Logger,
818
actual_type_arguments: Collections.List[Type]
819
) -> Symbol? is
820
if !is_generic then
821
logger.error(location, "cannot explicitly specialize non-generic type");
822
return null;
823
elif actual_type_arguments.count != generic_argument_names.count then
824
logger.error(location, "expected {generic_argument_names.count} explicit generic type arguments");
825
return null;
826
fi
827
828
GENERIC_CONSTRAINT_CHECKER().check_arguments(
829
location,
830
logger,
831
self,
832
generic_argument_names,
833
actual_type_arguments
834
);
835
836
return specialize(actual_type_arguments);
837
si
838
839
specialize(actual_type_arguments: Collections.List[Type]) -> Symbol is
840
assert is_generic else "trying to specialize non generic function {qualified_name}";
841
842
let type_map = Collections.MAP[string,Type]();
843
844
for (index, value) in actual_type_arguments |> index() do
845
type_map[generic_argument_names[index]] = value;
846
od
847
848
let result = specialize_function(type_map, null);
849
850
if result.is_generic then
851
result.is_generic = false;
852
fi
853
854
return result;
855
si
856
857
set_void_return_type() is
858
return_type = IoC.CONTAINER.instance.innate_symbol_lookup.get_void_type();
859
si
860
861
set_return_type(rt: Type?) is
862
return_type = rt;
863
864
if rt? /\ are_arguments_declared then
865
type = IoC.CONTAINER.instance.innate_symbol_lookup.get_function_type(
866
arguments |> cat([rt]) |> collect_list()
867
);
868
else
869
type = Types.ERROR();
870
fi
871
872
type_updated(type!);
873
si
874
875
type_updated(type: Type) is
876
// override me
877
si
878
879
get_full_type(innate_symbol_lookup: Lookups.InnateSymbolLookup) -> Types.Type is
880
let types = Collections.LIST[Type](arguments.count + 1);
881
882
types.add_range(arguments);
883
types.add(return_type!);
884
885
// A store-free function referred to as a value is a value
886
// of the pure shape of its type — the property belongs to
887
// the function, not to the slot it is being read into.
888
return innate_symbol_lookup.get_function_type(types, is_store_free);
889
si
890
891
try_override(into: Classy, function: Function, logger: Logger) is
892
logger.error(location, "cannot override {function}");
893
si
894
895
try_instance_override_me(into: Classy, function: Function, logger: Logger) is
896
logger.error(function.location, "cannot be overridden by {function}");
897
si
898
899
try_struct_override_me(into: Classy, function: Function, logger: Logger) is
900
logger.error(function.location, "cannot be overridden by {function}");
901
si
902
903
try_abstract_override_me(into: Classy, function: Function, logger: Logger) is
904
logger.error(function.location, "cannot be overridden by {function}");
905
si
906
907
inheritance_warn(logger: Logger, into: Classy, code: string, message: string) is
908
if owner == into then
909
logger.warn(location, code, message);
910
else
911
logger.warn(into.location, code, "{self} {message}");
912
fi
913
si
914
915
inheritance_error(logger: Logger, into: Classy, message: string) is
916
if owner == into then
917
logger.error(location, message);
918
else
919
logger.error(into.location, "{self} {message}");
920
fi
921
si
922
923
ensure_return_type_matches(into: Classy, overridee: Function, want_override: bool, logger: Logger) -> bool is
924
if !into.is_reflected then
925
if !return_type!.matches(overridee.return_type!) then
926
if want_override then
927
inheritance_warn(logger, into, "override-mismatch-return-type", "does not override {overridee} due to different return type {return_type}");
928
else
929
inheritance_error(logger, into, "does not implement {overridee} due to different return type {return_type}");
930
fi
931
return false;
932
fi
933
934
// Optionality is not part of the emitted signature, so a
935
// method whose return type differs from its overridee's
936
// only in optionality overrides it at run time regardless.
937
// Widening the return to optional would let null reach
938
// callers typed by the overridee. Internal functions are
939
// property accessors, reported at the property level;
940
// reflected overriders are imported declarations the user
941
// cannot change, so they are not reported at all.
942
if !is_internal /\ !is_reflected /\ return_type!.is_optional /\ !overridee.return_type!.is_optional then
943
inheritance_error(logger, into, "cannot {override_verb(want_override)} {overridee} with optional return type {return_type}");
944
fi
945
fi
946
947
return true;
948
si
949
950
// Arguments compare optionality-blind for override matching, so an
951
// overriding method can redeclare an optional argument as
952
// non-optional - but it still receives callers' optional values
953
// through the overridden signature, so that narrowing is unsound.
954
ensure_arguments_accept_optionals(into: Classy, overridee: Function, want_override: bool, logger: Logger) is
955
if into.is_reflected \/ is_reflected \/ is_internal \/ arguments.count != overridee.arguments.count then
956
return;
957
fi
958
959
for i in 0..arguments.count do
960
// An optional type variable is exempt: an unconstrained
961
// type parameter cannot be spelled optional in source, so
962
// the signature this would demand is unwritable. Reflected
963
// generic interfaces declare such arguments routinely
964
// (IComparer, IEqualityComparer).
965
if
966
overridee.arguments[i].is_optional /\
967
!overridee.arguments[i].is_type_variable /\
968
!arguments[i].is_optional
969
then
970
inheritance_error(logger, into, "cannot {override_verb(want_override)} {overridee}: argument {i + 1} must be optional");
971
fi
972
od
973
si
974
975
override_verb(want_override: bool) -> string static =>
976
if want_override then "override" else "implement" fi;
977
978
ensure_il_name_matches(into: Classy, overridee: Function, override_type: string, logger: Logger) -> bool is
979
if il_name !~ overridee.il_name then
980
if il_name_override? then
981
logger.warn(location, "override-mismatch-il-name", "does not {override_type} {overridee} due to inconsistent IL names ({il_name} vs {overridee.il_name})");
982
return false;
983
else
984
il_name_override = overridee.il_name;
985
986
if let journal = INHERITANCE_JOURNAL.current then
987
journal.record(InheritanceOp.IL_NAME_SET(self));
988
fi
989
fi
990
fi
991
992
return true;
993
si
994
995
declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
996
let result = FUNCTION_GENERIC_ARGUMENT(location, self, name, index);
997
998
declare(location, result, symbol_definition_listener);
999
1000
return result;
1001
si
1002
1003
declare_closure_symbol(location: LOCATION, result: Closure) -> Symbol is
1004
declare(location, result, null);
1005
1006
return result;
1007
si
1008
1009
declare_variable(location: LOCATION, name: string, is_static: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1010
let result: Variable =
1011
if _declaring_arguments then
1012
Symbols.LOCAL_ARGUMENT(location, self, name);
1013
else
1014
Symbols.LOCAL_VARIABLE(location, self, name);
1015
fi;
1016
1017
declare(location, result, symbol_definition_listener);
1018
1019
return result;
1020
si
1021
1022
declare_function(location: LOCATION, span: LOCATION, name: string, is_static: bool, is_private: bool, has_body: bool, enclosing: Scope, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is
1023
let result = Symbols.GLOBAL_FUNCTION(location, span, self, name, enclosing);
1024
1025
declare_function_group(location, result, symbol_definition_listener);
1026
1027
return result;
1028
si
1029
1030
get_argument_description(index: int) -> string is
1031
let result = System.Text.StringBuilder();
1032
1033
result
1034
.append(argument_names[index])
1035
.append(": ")
1036
.append(arguments[index]);
1037
1038
return result.to_string();
1039
si
1040
1041
get_short_argument_description(index: int) -> string is
1042
let result = System.Text.StringBuilder();
1043
1044
result
1045
.append(argument_names[index])
1046
.append(": ");
1047
1048
result.append(arguments[index].short_description);
1049
1050
return result.to_string();
1051
si
1052
1053
_display_owner_name: string is
1054
let o = owner;
1055
1056
if isa Symbol(o) then
1057
return IoC.CONTAINER.instance.name_display.name_for(o);
1058
fi
1059
1060
return o!.qualified_name;
1061
si
1062
1063
to_string() -> string is
1064
let result = System.Text.StringBuilder();
1065
1066
try
1067
if name.starts_with("$get_") then
1068
result
1069
.append(_display_owner_name)
1070
.append(".")
1071
.append(name.substring(5))
1072
.append(": ")
1073
.append(return_type);
1074
elif name.starts_with("$set_") then
1075
result
1076
.append(_display_owner_name)
1077
.append(".")
1078
.append(name.substring(5))
1079
.append(": ")
1080
.append(return_type)
1081
.append(" = ")
1082
.append(argument_names[0]);
1083
elif name =~ "get_Item" then
1084
result
1085
.append(_display_owner_name)
1086
.append("[")
1087
.append(argument_names[0])
1088
.append(": ")
1089
.append(arguments[0])
1090
.append("]: ")
1091
1092
.append(return_type);
1093
elif name =~ "set_Item" then
1094
result
1095
.append(_display_owner_name)
1096
.append("[")
1097
.append(argument_names[0])
1098
.append(": ")
1099
.append(arguments[0])
1100
.append("]: ")
1101
1102
.append(return_type)
1103
.append(" = ")
1104
.append(argument_names[1]);
1105
else
1106
result
1107
.append(IoC.CONTAINER.instance.name_display.name_for(self))
1108
.append(generic_argument_descriptions)
1109
.append("(")
1110
.append(short_argument_descriptions)
1111
.append(") -> ")
1112
.append(return_type);
1113
fi
1114
1115
return result.to_string();
1116
catch ex: Exception
1117
return "[garbled function: {result}]";
1118
yrt
1119
si
1120
1121
gen_entrypoint(context: IR.CONTEXT) is
1122
if name !~ context.entry_point_name \/ arguments.count > 1 \/ !return_type? then
1123
return;
1124
fi
1125
1126
if arguments.count == 1 then
1127
let lookup = IoC.CONTAINER.instance.innate_symbol_lookup;
1128
1129
if !return_type!.matches(lookup.get_int_type()) /\ !return_type!.matches(lookup.get_void_type()) then
1130
IoC.CONTAINER.instance.logger.warn(location, "non-entrypoint", "not an entrypoint because return type is not int or void");
1131
return;
1132
fi
1133
1134
let array_type = lookup.get_array_type(lookup.get_string_type());
1135
1136
if !arguments[0].matches(array_type) then
1137
IoC.CONTAINER.instance.logger.warn(location, "non-entrypoint", "not an entrypoint because argument type is not string[]");
1138
return;
1139
fi
1140
fi
1141
1142
if context.seen_entrypoint then
1143
IoC.CONTAINER.instance.logger.error(location, "duplicate entrypoint");
1144
return;
1145
fi
1146
1147
context.seen_entrypoint = true;
1148
1149
context.write_line(".entrypoint");
1150
si
1151
1152
gen_owner_reference(buffer: StringBuilder) is
1153
owner!.gen_reference(buffer);
1154
si
1155
1156
gen_reference(buffer: StringBuilder) is
1157
gen_calling_convention(buffer);
1158
1159
let rt mut = unspecialized_return_type;
1160
1161
if !rt? then
1162
rt = return_type!;
1163
fi
1164
1165
rt.gen_type(buffer);
1166
1167
gen_owner_reference(buffer);
1168
1169
gen_dot(buffer);
1170
1171
gen_name(buffer);
1172
1173
if generic_arguments.count > 0 then
1174
buffer.append('<');
1175
1176
gen_generic_arguments_list(buffer);
1177
1178
buffer.append('>');
1179
fi
1180
1181
buffer.append('(');
1182
1183
gen_actual_arguments_list(buffer);
1184
1185
buffer.append(')');
1186
si
1187
1188
gen_dot(buffer: StringBuilder) is
1189
buffer.append("::");
1190
si
1191
1192
gen_reference_for_property(buffer: StringBuilder) is
1193
gen_calling_convention(buffer);
1194
1195
let rt mut = unspecialized_return_type;
1196
1197
if !rt? then
1198
rt = return_type!;
1199
fi
1200
1201
rt.gen_type(buffer);
1202
1203
owner!.gen_dotted_name(buffer, self);
1204
1205
gen_name(buffer);
1206
1207
buffer.append('(');
1208
1209
gen_actual_arguments_list(buffer);
1210
1211
buffer.append(')');
1212
si
1213
1214
gen_definition_header(buffer: StringBuilder) is
1215
buffer.append(".method ");
1216
1217
gen_access(buffer);
1218
1219
gen_flags(buffer);
1220
1221
gen_calling_convention(buffer);
1222
1223
buffer.append(" default ");
1224
1225
return_type!.gen_type(buffer);
1226
1227
gen_owner_name(buffer);
1228
1229
gen_name(buffer);
1230
1231
if generic_arguments.count > 0 then
1232
buffer.append('<');
1233
1234
gen_generic_arguments_names(buffer);
1235
1236
buffer.append('>');
1237
fi
1238
1239
buffer.append('(');
1240
1241
gen_formal_arguments_list(buffer);
1242
1243
buffer.append(") cil managed");
1244
si
1245
1246
gen_body_header(context: IR.CONTEXT) is
1247
si
1248
1249
gen_access(buffer: StringBuilder) is
1250
buffer.append("public ");
1251
si
1252
1253
gen_flags(buffer: StringBuilder) is
1254
si
1255
1256
gen_calling_convention(buffer: StringBuilder) is
1257
si
1258
1259
gen_owner_name(buffer: StringBuilder) is
1260
si
1261
1262
gen_formal_arguments_list(buffer: StringBuilder) is
1263
let seen_any mut = false;
1264
1265
for i in 0..argument_names.count do
1266
if seen_any then
1267
buffer.append(',');
1268
fi
1269
1270
arguments[i].gen_type(buffer);
1271
1272
buffer
1273
.append('\'')
1274
.append(argument_names[i])
1275
.append('\'');
1276
1277
seen_any = true;
1278
od
1279
si
1280
1281
gen_actual_arguments_list(buffer: StringBuilder) is
1282
let seen_any mut = false;
1283
let args mut = unspecialized_arguments;
1284
1285
if !args? then
1286
args = arguments;
1287
fi
1288
1289
for argument in args do
1290
if seen_any then
1291
buffer.append(',');
1292
fi
1293
1294
argument.gen_type(buffer);
1295
1296
seen_any = true;
1297
od
1298
si
1299
1300
gen_generic_arguments_list(buffer: StringBuilder) is
1301
let seen_any mut = false;
1302
1303
for argument in generic_arguments do
1304
if seen_any then
1305
buffer.append(',');
1306
fi
1307
1308
argument.gen_type(buffer);
1309
1310
seen_any = true;
1311
od
1312
si
1313
1314
gen_generic_arguments_names(buffer: StringBuilder) is
1315
let seen_any mut = false;
1316
1317
for (index, argument) in generic_arguments |> index() do
1318
if seen_any then
1319
buffer.append(',');
1320
fi
1321
1322
// ILAsm generic-parameter constraint order: [class |
1323
// valuetype] [.ctor] (bound-type-list) name - flags
1324
// first, the parenthesized interface/base-type bound
1325
// last, right before the name.
1326
let kind = get_argument_constraint_kind(index);
1327
1328
if kind == TypeParameterConstraintKind.REFERENCE then
1329
buffer.append("class ");
1330
elif kind == TypeParameterConstraintKind.VALUE then
1331
buffer.append("valuetype ");
1332
fi
1333
1334
if get_argument_has_constructor_constraint(index) then
1335
buffer.append(".ctor ");
1336
fi
1337
1338
// A bound (`[T: SomeInterface]`) needs a CLR-visible
1339
// constraint clause here, not only at each call site's
1340
// substitution - shared generic code is verified
1341
// against the declared parameter.
1342
let bound = get_argument_type_bound(index);
1343
1344
if bound? then
1345
buffer.append('(');
1346
bound.gen_type(buffer);
1347
buffer.append(')');
1348
fi
1349
1350
buffer.append(argument.name);
1351
1352
seen_any = true;
1353
od
1354
si
1355
si
1356
1357
class GLOBAL_FUNCTION: Function is
1358
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
1359
_describe_function(context, true);
1360
1361
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
1362
"{pure_prefix}global function";
1363
1364
// Set by the .NET importer when the symbol is read back from a referenced
1365
// assembly's $globals class so call sites get an [asm] prefix.
1366
il_assembly_name: string? public;
1367
1368
// Set for an underscore-prefixed global (or the accessor of an
1369
// underscore-prefixed global property) under the private/protected
1370
// policy: emit assembly rather than public so it is hidden from other
1371
// assemblies while staying reachable within this one. Globals live on
1372
// the synthetic $globals class, so declaring-class-private is
1373
// meaningless for them; assembly-internal is the whole effect.
1374
emit_assembly: bool public;
1375
1376
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
1377
super.init(location, span, owner, name, enclosing_scope);
1378
si
1379
1380
gen_access(buffer: StringBuilder) is
1381
if emit_assembly then
1382
buffer.append("assembly ");
1383
else
1384
buffer.append("public ");
1385
fi
1386
si
1387
1388
declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
1389
declare_closure_symbol(location, Symbols.GLOBAL_CLOSURE(location, owner, name, enclosing, is_recursive));
1390
1391
declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
1392
declare_closure_symbol(location, Symbols.GLOBAL_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive));
1393
1394
load(location: LOCATION, from: IR.Values.Value?, loader: SYMBOL_LOADER) -> IR.Values.Value is
1395
if from? /\ from.is_consumable then
1396
IoC.CONTAINER.instance.logger.poison(location, "global function load shouldn't have a left expression");
1397
fi
1398
1399
return loader.load_global_function(self);
1400
si
1401
1402
call(location: Source.LOCATION, from: IR.Values.Value?, arguments: Collections.List[IR.Values.Value], type: Type?, caller: FUNCTION_CALLER) -> IR.Values.Value is
1403
if from? /\ from.is_consumable then
1404
IoC.CONTAINER.instance.logger.poison(location, "global function call shouldn't have a left expression");
1405
fi
1406
1407
return caller.call_global_function(self, arguments, self.arguments, type);
1408
si
1409
1410
// Method definition lives inside `.class 'NS'.'$globals' { ... }` block,
1411
// so the .method header has no qualifier — base (empty) gen_owner_name
1412
// is what we want.
1413
gen_owner_name(buffer: StringBuilder) is
1414
si
1415
1416
gen_owner_reference(buffer: StringBuilder) is
1417
cast Symbols.NAMESPACE?(owner)!.gen_globals_class_reference(buffer, il_assembly_name);
1418
si
1419
1420
gen_reference_for_property(buffer: StringBuilder) is
1421
gen_calling_convention(buffer);
1422
1423
let rt mut = unspecialized_return_type;
1424
1425
if !rt? then
1426
rt = return_type!;
1427
fi
1428
1429
rt.gen_type(buffer);
1430
1431
cast Symbols.NAMESPACE?(owner)!.gen_globals_class_reference(buffer, il_assembly_name);
1432
1433
buffer.append("::");
1434
1435
gen_name(buffer);
1436
1437
buffer.append('(');
1438
1439
gen_actual_arguments_list(buffer);
1440
1441
buffer.append(')');
1442
si
1443
1444
gen_dot(buffer: StringBuilder) is
1445
buffer.append("::");
1446
si
1447
1448
// FIXME: should storage class be split out of here:
1449
gen_flags(buffer: StringBuilder) is
1450
buffer
1451
.append("hidebysig static ");
1452
si
1453
1454
gen_body_header(context: IR.CONTEXT) is
1455
gen_entrypoint(context);
1456
si
1457
si
1458
si