Skip to content
← Back

src/semantic/symbols/method.ghul

1
namespace Semantic.Symbols is
2
use IO.Std
3
4
use System.Text.StringBuilder
5
6
use Collections.Iterable
7
use Collections.LIST
8
9
use IoC
10
use Logging
11
use Source
12
13
use IR.Values.Value
14
15
use Types.Type
16
17
class Method: Function abstract is
18
_throws_not_supported: bool
19
20
throws_not_supported: bool => _throws_not_supported
21
22
mark_throws_not_supported() is
23
_throws_not_supported = true
24
si
25
26
is_constructor: bool => self.il_name_override =~ ".ctor"
27
28
// Set at import for a reflected method that a call can never
29
// dispatch away from: a static that is not a static-virtual
30
// interface slot, or an instance member the CLR binds
31
// statically (non-virtual, final, declared on a struct, or on
32
// a sealed owner). No override in any assembly can stand
33
// behind a call to such a method, which is what lets the
34
// reachability tiers in IMPORT_ARGUMENTS trust one from its
35
// signature alone.
36
cannot_be_overridden: bool public
37
38
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
39
super.init(location, span, owner, name, enclosing_scope)
40
si
41
42
// Underscore access policy for the state-machine method kinds
43
// (generator / async). Those are already distinct method kinds and so
44
// cannot be the dedicated PRIVATE_/PROTECTED_ classes; they consult the
45
// name and policy here instead. Regular methods use the dedicated kinds
46
// chosen in Classy._make_instance_method / _make_static_method.
47
_is_underscore_non_public: bool =>
48
name.starts_with('_') /\
49
IoC.CONTAINER.instance.build_flags.underscore_access != Compiler.UnderscoreAccess.LEGACY
50
51
_gen_underscore_access(buffer: StringBuilder) is
52
if _is_underscore_non_public then
53
buffer.append("assembly ")
54
else
55
buffer.append("public ")
56
fi
57
si
58
59
// Shared by every default-trait-method kind: the plain one and the
60
// generator / async ones, which extend the state-machine method
61
// classes instead and so cannot inherit it.
62
_check_ineffective_trait_override(into: Classy, overrider: Function, logger: Logger) is
63
// Property accessors flow through handle_property_overridee, which
64
// raises this diagnostic at the property level. Skip the accessor
65
// here so we don't double-fire with the mangled `$get_*`/`$set_*`
66
// name.
67
if name.starts_with('$') then
68
return
69
fi
70
71
if let owner_classy: Classy = owner then
72
INEFFECTIVE_TRAIT_OVERRIDE_CHECKER()
73
.check(into, overrider.location, overrider.to_string(), self, name, owner_classy, logger)
74
fi
75
si
76
77
_underscore_is_accessible_to(accessor: Classy?) -> bool is
78
if !_is_underscore_non_public then
79
return true
80
fi
81
82
let o = cast Classy?(owner?.unspecialized_symbol)
83
84
if IoC.CONTAINER.instance.build_flags.underscore_access == Compiler.UnderscoreAccess.PRIVATE then
85
return is_accessible_to_declaring_type(accessor)
86
fi
87
88
// PROTECTED: a member reached through a specialization is the
89
// declaring type under a distinct symbol, so normalise before
90
// the assignability test - same specialisation-identity case
91
// as the private branch above.
92
let owning_type = o?.type
93
94
return accessor? /\ owning_type? /\ accessor.type? /\ owning_type.is_assignable_from(accessor.type)
95
si
96
si
97
98
class INSTANCE_METHOD: Method is
99
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
100
_describe_function(context, !is_constructor)
101
102
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
103
if is_constructor then "constructor" else "{pure_prefix}{access_prefix}method" fi
104
105
symbol_kind: SymbolKind => SymbolKind.METHOD
106
completion_kind: CompletionKind => CompletionKind.METHOD
107
108
is_instance: bool => true
109
is_virtual: bool => true
110
111
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
112
super.init(location, span, owner, name, enclosing_scope)
113
si
114
115
declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
116
declare_closure_symbol(location, Symbols.INSTANCE_CLOSURE(location, owner, name, enclosing, is_recursive))
117
118
declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
119
declare_closure_symbol(location, Symbols.INSTANCE_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive))
120
121
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_instance_method(location, from, self)
122
123
load_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value is
124
let context = IoC.CONTAINER.instance.symbol_table.current_instance_context
125
126
return IR.Values.Load.REFERENCE_SELF(context!, context.own_instantiation)
127
si
128
129
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value is
130
return caller.call_instance_method(location, from, self, arguments, self.arguments, type)
131
si
132
133
try_override(into: Classy, overridee: Function, logger: Logging.Logger) is
134
overridee.try_instance_override_me(into, self, logger)
135
si
136
137
try_instance_override_me(into: Classy, overrider: Function, logger: Logger) is
138
let return_type_matches = overrider.ensure_return_type_matches(into, self, true, logger)
139
140
overrider.ensure_arguments_accept_optionals(into, self, true, logger)
141
142
let il_name_matches = overrider.ensure_il_name_matches(into, self, "override", logger)
143
144
overrider.add_overridee(self)
145
self.add_overrider(overrider)
146
si
147
148
try_struct_override_me(into: Classy, overrider: Function, logger: Logger) is
149
let return_type_matches = overrider.ensure_return_type_matches(into, self, true, logger)
150
151
overrider.ensure_arguments_accept_optionals(into, self, true, logger)
152
153
let il_name_matches = overrider.ensure_il_name_matches(into, self, "override", logger)
154
155
overrider.add_overridee(self)
156
self.add_overrider(overrider)
157
si
158
159
try_abstract_override_me(into: Classy, overrider: Function, logger: Logger) is
160
// A trait restating a member it inherits leaves the
161
// obligation where it was, and an imported type settled its
162
// own hierarchy in the assembly it came from, where nobody
163
// compiling against it can change anything - so a
164
// diagnostic there would be unactionable.
165
if into.is_trait \/ overrider.is_reflected then
166
logger.info(overrider.location, "hides {self}")
167
168
return
169
fi
170
171
// A trait's default is withdrawn by a class that writes the
172
// member again with no body: the class is abstract and its
173
// subclasses owe an implementation, which is what the
174
// declaration says. A class member with a body is the case
175
// that cannot go back to an abstract row - a caller holding
176
// the base type would still reach the override - so that
177
// one is given a body that throws, saying at the call what
178
// the declaration says at the class.
179
if !is_default_trait_method then
180
overrider.mark_throws_unimplemented()
181
fi
182
183
record_implementing_override(into, overrider, logger)
184
si
185
186
si
187
188
// An underscore-prefixed instance method under the PROTECTED policy: a
189
// normal virtual method that a subclass in the same assembly can override,
190
// but nothing outside the assembly can see.
191
class PROTECTED_METHOD: INSTANCE_METHOD is
192
is_public_readable: bool => false
193
194
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
195
super.init(location, span, owner, name, enclosing_scope)
196
si
197
198
is_accessible_to(accessor: Classy?) -> bool =>
199
accessor? /\
200
let o = cast Classy?(owner) in
201
o? /\ o.type? /\ accessor.type? /\ o.type.is_assignable_from(accessor.type)
202
203
access_prefix: string => "protected "
204
si
205
206
// An underscore-prefixed instance method under the PRIVATE policy: an
207
// implementation detail of its declaring type. Not virtual, so a same-named
208
// method in a subclass is a distinct method rather than an override, and
209
// calls resolve statically.
210
class PRIVATE_METHOD: INSTANCE_METHOD is
211
is_virtual: bool => false
212
213
is_public_readable: bool => false
214
215
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
216
super.init(location, span, owner, name, enclosing_scope)
217
si
218
219
try_override(into: Classy, overridee: Function, logger: Logging.Logger) is
220
si
221
222
is_accessible_to(accessor: Classy?) -> bool =>
223
is_accessible_to_declaring_type(accessor)
224
225
access_prefix: string => "private "
226
si
227
228
class STRUCT_METHOD: INSTANCE_METHOD is
229
// STRUCT_METHOD inherits describe / describe_kind from
230
// INSTANCE_METHOD unchanged.
231
symbol_kind: SymbolKind => SymbolKind.METHOD
232
completion_kind: CompletionKind => CompletionKind.METHOD
233
234
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
235
super.init(location, span, owner, name, enclosing_scope)
236
si
237
238
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_struct_method(location, from, self)
239
240
load_self(location: LOCATION, loader: SYMBOL_LOADER) -> Value is
241
let context = IoC.CONTAINER.instance.symbol_table.current_instance_context
242
243
return IR.Values.Load.REFERENCE_SELF(context!, context.own_instantiation)
244
si
245
246
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value =>
247
caller.call_struct_method(location, from, self, arguments, self.arguments, type)
248
249
try_override(into: Classy, overridee: Function, logger: Logging.Logger) =>
250
overridee.try_struct_override_me(into, self, logger)
251
252
try_struct_override_me(into: Classy, overrider: Function, logger: Logger) =>
253
logger.error(overrider.location, "cannot override struct method {self}", self.location, "declared here")
254
255
try_instance_override_me(into: Classy, overrider: Function, logger: Logger) =>
256
logger.error(overrider.location, "cannot override struct method {self}", self.location, "declared here")
257
258
try_abstract_override_me(into: Classy, overrider: Function, logger: Logger) =>
259
logger.error(overrider.location, "cannot override struct method {self}", self.location, "declared here")
260
261
si
262
263
class ABSTRACT_METHOD: INSTANCE_METHOD is
264
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
265
_describe_function(context, true)
266
267
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
268
"{pure_prefix}abstract method"
269
270
// Set when this declaration overrides a member that has a body:
271
// the slot is already implemented, so the row carries a
272
// throwing body rather than being abstract.
273
_throws_unimplemented: bool
274
275
throws_unimplemented: bool => _throws_unimplemented
276
277
278
mark_throws_unimplemented() is
279
if _throws_unimplemented then
280
return
281
fi
282
283
_throws_unimplemented = true
284
285
// The member has a body after all, so it is not what makes
286
// the class abstract.
287
if let owner_class: CLASS = owner then
288
owner_class.unmark_has_bodyless_method()
289
fi
290
si
291
292
is_abstract: bool => !_throws_unimplemented
293
294
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
295
super.init(location, span, owner, name, enclosing_scope)
296
si
297
298
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value => caller.call_abstract_method(location, from, self, arguments, self.arguments, type)
299
300
try_pull_down_into(
301
into: Classy,
302
other_overridee_symbols: Collections.Iterable[Symbol],
303
logger: Logging.Logger
304
) is
305
// An abstract class is entitled to leave it, and a trait
306
// carries it onward; a reflected type answered for itself
307
// in the assembly it came from.
308
if !into.is_trait /\ !into.is_reflected /\ !into.is_abstract /\ !_throws_unimplemented then
309
logger.error(into.location, "must implement {self}", self.location, "member declared here")
310
fi
311
312
into.add_member(self)
313
si
314
315
try_override(into: Classy, overridee: Function, logger: Logging.Logger) =>
316
overridee.try_abstract_override_me(into, self, logger)
317
318
try_instance_override_me(into: Classy, overrider: Function, logger: Logger) =>
319
record_implementing_override(into, overrider, logger)
320
321
try_struct_override_me(into: Classy, overrider: Function, logger: Logger) =>
322
record_implementing_override(into, overrider, logger)
323
324
try_abstract_override_me(into: Classy, overrider: Function, logger: Logger) is
325
// A trait redeclaring a member it inherits states the
326
// contract again for its own readers and leaves the
327
// obligation where it was, and an imported type answered
328
// for itself in the assembly it came from. A class
329
// redeclaring one is overriding it: the member it declares
330
// is what its own subclasses have to satisfy, and the
331
// contracts the trait member carries have to reach them
332
// through it.
333
if into.is_trait \/ overrider.is_reflected then
334
logger.info(overrider.location, "hides {self}")
335
336
return
337
fi
338
339
record_implementing_override(into, overrider, logger)
340
si
341
342
si
343
344
class DEFAULT_TRAIT_METHOD: INSTANCE_METHOD is
345
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
346
"{pure_prefix}default trait method"
347
348
is_default_trait_method: bool => true
349
350
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
351
super.init(location, span, owner, name, enclosing_scope)
352
si
353
354
try_instance_override_me(into: Classy, overrider: Function, logger: Logger) is
355
super.try_instance_override_me(into, overrider, logger)
356
357
_check_ineffective_trait_override(into, overrider, logger)
358
si
359
si
360
361
class STATIC_METHOD: Method is
362
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
363
_describe_function(context, true)
364
365
describe_kind(context: DESCRIBE_CONTEXT) -> string? =>
366
"{pure_prefix}{access_prefix}class method"
367
symbol_kind: SymbolKind => SymbolKind.METHOD
368
completion_kind: CompletionKind => CompletionKind.METHOD
369
370
// Set for a reflected static virtual/abstract interface member -
371
// the only shape of static method the CLR allows to be
372
// dispatched through an as-yet-unresolved type parameter.
373
is_static_interface_virtual: bool public
374
is_virtual: bool => is_static_interface_virtual
375
376
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
377
super.init(location, span, owner, name, enclosing_scope)
378
si
379
380
declare_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
381
declare_closure_symbol(location, Symbols.STATIC_CLOSURE(location, owner, name, enclosing, is_recursive))
382
383
declare_async_closure(location: LOCATION, name: string, owner: Scope, enclosing: Scope, is_recursive: bool, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol =>
384
declare_closure_symbol(location, Symbols.STATIC_ASYNC_CLOSURE(location, owner, name, enclosing, is_recursive))
385
386
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_static_method(self)
387
388
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> Value is
389
if is_static_interface_virtual then
390
let dispatch_type = _static_interface_dispatch_type(from)
391
392
if dispatch_type? then
393
return caller.call_static_interface_method(self, dispatch_type, arguments, self.arguments, type)
394
fi
395
396
// A static virtual member has no body on its declaring
397
// interface - implementations are found through the type
398
// argument the call dispatches through. Without one there
399
// is nothing to call, and emitting a memberref against the
400
// open interface writes its own type parameter into code
401
// that has no generic scope to resolve it.
402
IoC.CONTAINER.instance.logger.error(location, "cannot infer type here")
403
404
return IR.Values.DUMMY(Types.ERROR(), location)
405
fi
406
407
return caller.call_static_method(self, arguments, self.arguments, type)
408
si
409
410
// The type to dispatch through. Written as `T.member(...)` the
411
// receiver names it. Reached any other way - an operator, or the
412
// member imported into scope by name - there is no receiver, and
413
// the self type of the interface carries it instead: every static
414
// virtual interface member is declared on an interface whose first
415
// type argument is the implementing type. That type is a type
416
// parameter where the call is generic and a concrete type where
417
// the interface is instantiated at one; `constrained.` takes
418
// either.
419
_static_interface_dispatch_type(from: Value?) -> Types.Type? is
420
if from? /\ from.type? then
421
return from.type
422
fi
423
424
if let owner_generic = cast GENERIC?(owner) /\ owner_generic.arguments.count > 0 then
425
return owner_generic.arguments[0]
426
fi
427
428
return null
429
si
430
431
try_override(into: Classy, overridee: Function, logger: Logging.Logger) is
432
// This is arguably not an issue as the hidden instance remains available via super.method()
433
if !is_internal /\ overridee.is_instance then
434
logger.warn(self.location, "hides-inherited", "static method hides {overridee}", overridee.location, "hidden method declared here")
435
fi
436
si
437
438
// Don't believe it makes sense to report an instance methods hiding a static method
439
// as the static method remains available via CLASS.method()
440
try_instance_override_me(into: Classy, overrider: Function, logger: Logger) is
441
si
442
443
try_struct_override_me(into: Classy, overrider: Function, logger: Logger) is
444
si
445
446
try_abstract_override_me(into: Classy, overrider: Function, logger: Logger) is
447
si
448
449
gen_body_header(context: IR.CONTEXT) is
450
gen_entrypoint(context)
451
si
452
si
453
454
// Underscore-prefixed static methods under the PROTECTED / PRIVATE
455
// policies. Static methods are already non-virtual, so only the emitted
456
// accessibility differs from STATIC_METHOD.
457
class PROTECTED_STATIC_METHOD: STATIC_METHOD is
458
is_public_readable: bool => false
459
460
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
461
super.init(location, span, owner, name, enclosing_scope)
462
si
463
464
is_accessible_to(accessor: Classy?) -> bool =>
465
accessor? /\
466
let o = cast Classy?(owner) in
467
o? /\ o.type? /\ accessor.type? /\ o.type.is_assignable_from(accessor.type)
468
469
access_prefix: string => "protected "
470
si
471
472
class PRIVATE_STATIC_METHOD: STATIC_METHOD is
473
is_public_readable: bool => false
474
475
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
476
super.init(location, span, owner, name, enclosing_scope)
477
si
478
479
is_accessible_to(accessor: Classy?) -> bool =>
480
is_accessible_to_declaring_type(accessor)
481
482
access_prefix: string => "private "
483
si
484
485
// A static constructor: `init() static`. Emitted as the owning
486
// type's `.cctor`, which the CLR runs once before the type is first
487
// used. It takes no parameters and no receiver; a parameterised
488
// static init is rejected during declare-symbols.
489
class STATIC_CONSTRUCTOR: STATIC_METHOD is
490
is_static_constructor: bool => true
491
492
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
493
_describe_function(context, false)
494
495
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "static constructor"
496
497
init(location: LOCATION, span: LOCATION, owner: Scope, name: string, enclosing_scope: Scope) is
498
super.init(location, span, owner, name, enclosing_scope)
499
500
// Function.init overrode il_name to '.ctor' for the "init"
501
// name; the static constructor is the CLR's '.cctor'.
502
il_name_override = ".cctor"
503
si
504
505
gen_body_header(context: IR.CONTEXT) is
506
si
507
si
508
si