Skip to content
← Back

src/semantic/function_reference_resolver.ghul

1
namespace Semantic is
2
use Ghul.Pipes
3
use Source.LOCATION
4
5
use Types.Type
6
7
use IR.Values
8
9
// Converts a global function, static/instance/struct method, or
10
// the single member of an overloaded group into a function/
11
// delegate value directly - `ldftn` on the method plus whatever
12
// receiver an instance method needs, no closure frame, since a
13
// named function has nothing to capture.
14
class FUNCTION_REFERENCE_RESOLVER(
15
_logger: Logging.Logger,
16
_symbol_table: SYMBOL_TABLE,
17
_symbol_loader: SYMBOL_LOADER,
18
_innate_symbol_lookup: Lookups.InnateSymbolLookup,
19
_overload_resolver: OVERLOAD_RESOLVER
20
) is
21
_delegate_shape: DELEGATE_SHAPE
22
23
super()
24
25
init(..) is
26
_delegate_shape = DELEGATE_SHAPE()
27
si
28
29
// Returns null when `symbol` isn't a function reference in
30
// value position, or is an overloaded group with no target
31
// shape available yet to pick a member by - the caller then
32
// falls back to its ordinary `symbol.load` path.
33
try_load(
34
location: LOCATION,
35
symbol: Symbols.Symbol,
36
from: Value?,
37
expected_type: Type?,
38
is_call_target: bool
39
) -> Value? is
40
if is_call_target \/ isa Symbols.Closure(symbol) then
41
return null
42
fi
43
44
let single: Symbols.Function? mut = cast Symbols.Function?(symbol)
45
46
if !single? then
47
let group = cast Symbols.FUNCTION_GROUP?(symbol)
48
49
if !group? \/ group.count == 0 then
50
return null
51
fi
52
53
if group.count == 1 then
54
single = group.functions[0]
55
else
56
let target_shape = get_target_call_shape(expected_type)
57
58
if !target_shape? then
59
return null
60
fi
61
62
single = _resolve_group_member(location, group, from, target_shape)
63
64
if !single? then
65
return DUMMY(Types.ERROR(), location)
66
fi
67
fi
68
fi
69
70
// An open generic can't be checked against a target shape
71
// until it's instantiated: bind its own type arguments
72
// from the shape the slot expects, the same way a call
73
// site binds them from its actual arguments.
74
if single.is_generic then
75
let target_shape = get_target_call_shape(expected_type)
76
77
let specialized =
78
if target_shape? then
79
_try_specialize_from_target_shape(location, single, target_shape)
80
else
81
single
82
fi
83
84
// Nothing here pins the function's own type arguments:
85
// there is no slot at all, or the slot is one the
86
// enclosing call has still to infer. Building the value
87
// at the function's own shape would put its free type
88
// variables into the argument types that resolution
89
// binds from, and a variable the sibling actuals pin
90
// concretely then joins with one of those to `object`.
91
// Leave the reference unresolved instead - the state a
92
// bare overloaded group is left in - so the caller's
93
// deferred re-walk pushes the settled formal and
94
// instantiates against that. With no such re-walk to
95
// come, the load reports itself as unusable.
96
if specialized == single /\ symbol.is_function_group /\ _slot_pins_nothing(target_shape) then
97
return null
98
fi
99
100
single = specialized
101
fi
102
103
// An innate operator is an IL instruction declared as a
104
// static member, with no method behind it, so a reference
105
// to one emits a call to a method the runtime cannot find.
106
// Calling it is what it is for.
107
if single.is_innate then
108
_logger.error(
109
location,
110
"cannot take the value of built-in operator '{single.name}'")
111
112
return DUMMY(Types.ERROR(), location)
113
fi
114
115
return _build_value(location, single, from, expected_type)
116
si
117
118
// A slot that cannot instantiate an open generic function:
119
// absent, still carrying an inference placeholder, or written
120
// in type variables belonging to the call being resolved
121
// rather than to the function this reference sits in.
122
_slot_pins_nothing(target_shape: Type?) -> bool =>
123
!target_shape? \/
124
target_shape.contains_inferred \/
125
target_shape.has_function_generic_argument_foreign_to(_symbol_table.current_function)
126
127
// The function-type shape a value must present to be usable
128
// as `expected_type`: `expected_type` itself when it's already
129
// a ghūl function type, or the call shape of its `invoke` when
130
// it's a named .NET delegate. Null when `expected_type` is
131
// absent, or present but not callable at all.
132
get_target_call_shape(expected_type: Type?) -> Type? is
133
if !expected_type? then
134
return null
135
fi
136
137
if expected_type.is_function then
138
return expected_type
139
fi
140
141
return _delegate_shape.try_get_function_type(expected_type, _innate_symbol_lookup)
142
si
143
144
// Instantiates an open generic function against a target
145
// shape. The shape's parameter types and its return slot both
146
// contribute to the function's own type arguments, so a
147
// variable split between the two positions still binds.
148
// Returns the function unchanged when the shape pins nothing,
149
// pins it incompletely, or contradicts it - the ordinary
150
// assignability check at the use site then accepts or rejects
151
// the uninstantiated form.
152
_try_specialize_from_target_shape(
153
location: LOCATION,
154
function: Symbols.Function,
155
target_shape: Type
156
) -> Symbols.Function is
157
let shape_arguments = target_shape.arguments
158
let parameter_count = shape_arguments.count - 1
159
160
if function.arguments.count != parameter_count then
161
return function
162
fi
163
164
let parameter_types = Collections.LIST[Type](parameter_count)
165
166
for i in 0..parameter_count do
167
parameter_types.add(shape_arguments[i])
168
od
169
170
let results = Types.GENERIC_ARGUMENT_BIND_RESULTS(function.generic_arguments)
171
172
// Parameter-driven binding can pin something only when a
173
// formal mentions a type variable, and an unsettled slot
174
// carries no information to bind with - leave the attempt
175
// out in either case rather than binding a type argument
176
// to a placeholder. A pair that cannot agree under any
177
// instantiation voids the whole attempt.
178
let parameters_bound mut = false
179
180
if
181
function.arguments |> any(a => a.is_wild) /\
182
parameter_types |> all(t => !t.is_error /\ !t.contains_inferred)
183
then
184
let parameters_ok mut = true
185
186
for i in 0..parameter_count do
187
if !function.arguments[i].bind_type_variables(parameter_types[i], results) then
188
parameters_ok = false
189
break
190
fi
191
od
192
193
if parameters_ok then
194
results.check_complete(location, function.generic_arguments)
195
parameters_bound = results.is_bound
196
fi
197
fi
198
199
// The return slot binds what the parameters left open -
200
// including variables that appear only there. Skipped when
201
// the parameters already pinned everything: an open return
202
// slot carries no information then, and a contradictory
203
// one is the assignability check's to report.
204
if !parameters_bound then
205
let return_slot = shape_arguments[parameter_count]
206
207
if let return_type = function.return_type /\ !return_slot.is_error /\ !return_slot.contains_inferred then
208
return_type.bind_type_variables(return_slot, results)
209
fi
210
fi
211
212
results.check_complete(location, function.generic_arguments)
213
214
if !results.is_bound \/ !function.check_lub_conformance(results, parameter_types) then
215
return function
216
fi
217
218
// A slot shape carrying another function's method-level
219
// type parameter carries an index that is meaningless
220
// here; only the caller's own type parameters may appear.
221
let caller = IoC.CONTAINER.instance.symbol_table.current_function
222
223
if results.contains_function_generic_argument_foreign_to(caller) then
224
return function
225
fi
226
227
return function.specialize_function(results.map, null)
228
si
229
230
// Picks the group member whose formal parameters accept
231
// `target_shape`'s parameter types, via the same
232
// OVERLOAD_RESOLVER a call site uses: those parameter types
233
// stand in for the actual argument types (the direction a
234
// value of this shape would be invoked with), and its return
235
// type is the tie-break constraint.
236
_resolve_group_member(
237
location: LOCATION,
238
group: Symbols.FUNCTION_GROUP,
239
from: Value?,
240
target_shape: Type
241
) -> Symbols.Function? is
242
let shape_arguments = target_shape.arguments
243
let parameter_count = shape_arguments.count - 1
244
245
let parameter_types = Collections.LIST[Type](parameter_count)
246
247
for i in 0..parameter_count do
248
parameter_types.add(shape_arguments[i])
249
od
250
251
let return_constraint = shape_arguments[parameter_count]
252
253
let want_instance =
254
if from? then
255
from.is_consumable
256
else
257
_symbol_table.current_instance_context?
258
fi
259
260
let result = _overload_resolver.resolve(location, group, parameter_types, false, want_instance, false, null, return_constraint)
261
262
if !result? then
263
return null
264
fi
265
266
return result.function
267
si
268
269
// Checked against `expected_type` when it resolves to a
270
// callable shape via get_target_call_shape; a non-callable
271
// (or absent) `expected_type` yields a null shape here, and
272
// the function's own native call shape is used instead,
273
// leaving the ordinary assignability check at the use site
274
// to accept or reject it against the real target.
275
_build_value(
276
location: LOCATION,
277
function: Symbols.Function,
278
from: Value?,
279
expected_type: Type?
280
) -> Value is
281
let source_shape = function.get_full_type(_innate_symbol_lookup)
282
let target_shape = get_target_call_shape(expected_type)
283
284
// A target with a slot still open - an inference
285
// placeholder, or a free type variable of the enclosing
286
// generic callee - can't be checked by assignability: the
287
// function's own type is what should flow into that slot,
288
// not be tested against it. Build at the source shape and
289
// let the ordinary assignability check at the use site
290
// accept or reject the value, the same way an absent
291
// expected type does.
292
//
293
// Every position counts, not only the return, and a slot
294
// that names nothing counts as open as much as a wild one
295
// does. `NONE` compares different from everything, so a
296
// parameter the callee has not settled refuses a function
297
// the settled target would take.
298
let open_slot =
299
target_shape? /\
300
target_shape.arguments |> any(a => a.is_wild \/ a.is_none)
301
302
if
303
target_shape? /\
304
!target_shape.contains_inferred /\
305
!open_slot /\
306
!target_shape.is_assignable_from(source_shape)
307
then
308
_logger.error(location, "{function} is not compatible with {expected_type!}")
309
return DUMMY(Types.ERROR(), location)
310
fi
311
312
// `target_shape` is the invoke *shape* used for the
313
// assignability check above - when `expected_type` is a
314
// real named delegate rather than a ghūl function type,
315
// that shape is only the delegate's call signature, not
316
// the delegate type itself. The built value has to carry
317
// the delegate type so `Load.DELEGATE.gen` constructs it
318
// with `newobj` against the right `.ctor`.
319
let result_type =
320
if target_shape? /\ !target_shape.contains_inferred /\ !open_slot then
321
expected_type!
322
else
323
source_shape
324
fi
325
326
let target: Value =
327
if !function.is_instance then
328
NULL(Types.NULL())
329
elif from? then
330
from
331
else
332
_symbol_loader.load_self(location)
333
fi
334
335
// `super.method` binds to the base implementation, the
336
// same as an ordinary `super.method()` call site - never
337
// virtual, whatever the method's own is_virtual says.
338
let is_virtual = function.is_instance /\ function.is_virtual /\ !target.is_super
339
340
let function_pointer = Load.FUNCTION_POINTER(function, is_virtual)
341
342
return Load.DELEGATE(result_type, function_pointer, target)
343
si
344
si
345
si