Appearance
| 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 |