Appearance
| 1 | namespace Semantic is | |
| 2 | use Logging | |
| 3 | use Types.Type | |
| 4 | use Ghul.Pipes | |
| 5 | ||
| 6 | // Resolve closure argument types from the lambda's AST argument | |
| 7 | // expressions, mutating each argument symbol's `.type` and | |
| 8 | // recording any captured type-variables on the closure. Picks | |
| 9 | // among four resolution branches in priority order: | |
| 10 | // | |
| 11 | // 1. Symbol already carries a usable (non-inferred / non- | |
| 12 | // error) type — keep it. This is set by a previous walk | |
| 13 | // (overload resolution's second pass set the symbol's | |
| 14 | // type from the chosen formal, or a function-level retry | |
| 15 | // is re-walking the body). | |
| 16 | // | |
| 17 | // 2. Argument has a written type expression that isn't INFER | |
| 18 | // — use it directly. | |
| 19 | // | |
| 20 | // 3. An implied type from the enclosing context | |
| 21 | // (function.constraint.arguments) is available and | |
| 22 | // "usable" — install it on the symbol. "Usable" means the | |
| 23 | // type is concrete OR an in-scope type-variable. Foreign | |
| 24 | // type-variables (carried over from an overload-resolution | |
| 25 | // constraint where the candidate is a different generic | |
| 26 | // function) are rejected — see #1210 commentary. Any | |
| 27 | // in-scope type-variables embedded in the implied type are | |
| 28 | // recorded via `closure.add_type_argument_reference` so IL | |
| 29 | // emission generates a generic closure method with | |
| 30 | // matching `!!N` slots. | |
| 31 | // | |
| 32 | // 4. Fall back to the iterative-inference path: try the | |
| 33 | // argument variable's accumulated LUB. On success install | |
| 34 | // that as the resolved type. On failure (still inferred / | |
| 35 | // error) emit "cannot infer type here" and install a | |
| 36 | // fresh INFERRED_VARIABLE_TYPE placeholder, leaving the | |
| 37 | // outer body-retry loop to resolve from body operations. | |
| 38 | // | |
| 39 | // `resolve(...)` returns true when the loop completed and the | |
| 40 | // closure's `arguments` / `argument_names` were populated. | |
| 41 | // Returns false on an unexpected argument shape (anything other | |
| 42 | // than a `Syntax.Trees.Expressions.VARIABLE`) without writing | |
| 43 | // anything back to the closure. | |
| 44 | // | |
| 45 | // A parameter written as a destructure pattern carries its pattern | |
| 46 | // on that node's `left`. It stays one physical argument here — the | |
| 47 | // resolution above settles the aggregate type, and the pattern's | |
| 48 | // leaves take their types from it. | |
| 49 | class CLOSURE_ARG_RESOLVER(_logger: Logger) is | |
| 50 | super() | |
| 51 | ||
| 52 | resolve( | |
| 53 | arguments: Collections.List[Syntax.Trees.Expressions.Expression], | |
| 54 | closure: Symbols.Closure, | |
| 55 | implied_argument_types: Collections.List[Type]? | |
| 56 | ) -> bool is | |
| 57 | let argument_names = Collections.LIST[string]() | |
| 58 | let argument_types = Collections.LIST[Type]() | |
| 59 | ||
| 60 | if !_resolve_all(arguments, closure, implied_argument_types, argument_names, argument_types, null) then | |
| 61 | return false | |
| 62 | fi | |
| 63 | ||
| 64 | closure.packed_parameters = null | |
| 65 | closure.arguments = Collections.LIST[Type](argument_types) | |
| 66 | closure.argument_names = argument_names | |
| 67 | ||
| 68 | return true | |
| 69 | si | |
| 70 | ||
| 71 | // The same resolution for a literal written with an argument pack | |
| 72 | // spread out, going into a formal that takes the pack as one | |
| 73 | // tuple. The parameters stay the ones the literal declared, typed | |
| 74 | // from the tuple's elements where it has settled and as any other | |
| 75 | // parameter is where it has not. The closure is recorded taking | |
| 76 | // the tuple, so the type it has is the formal's own shape. | |
| 77 | resolve_packed( | |
| 78 | arguments: Collections.List[Syntax.Trees.Expressions.Expression], | |
| 79 | closure: Symbols.Closure, | |
| 80 | expected_tuple: Type?, | |
| 81 | fixed_types: Collections.List[Type] | |
| 82 | ) -> bool is | |
| 83 | let fixed = fixed_types.count | |
| 84 | let pack_count = arguments.count - fixed | |
| 85 | ||
| 86 | let group = closure.pack_group ?? Symbols.LOCAL_ARGUMENT(closure.location, closure, "$pack") | |
| 87 | ||
| 88 | group.is_defined = true | |
| 89 | ||
| 90 | closure.pack_group = group | |
| 91 | ||
| 92 | // What the formal says the tuple is, where it says something a | |
| 93 | // parameter can take. Where it does not - the tuple is another | |
| 94 | // function's own type parameters, or a guess that does not | |
| 95 | // destructure - the tuple is whatever resolving the call has | |
| 96 | // bound the literal's one physical parameter to so far. | |
| 97 | let implied = | |
| 98 | _elements_of(if expected_tuple? then SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(expected_tuple) else null fi, pack_count, closure) ?? | |
| 99 | _elements_of(group.try_get_inferred_type(), pack_count, closure) | |
| 100 | ||
| 101 | let argument_names = Collections.LIST[string]() | |
| 102 | let argument_types = Collections.LIST[Type]() | |
| 103 | let symbols = Collections.LIST[Symbols.Variable]() | |
| 104 | ||
| 105 | // By position: the formal's own parameters first, then the | |
| 106 | // pack's elements where they are known. | |
| 107 | let implied_types = Collections.LIST[Type]() | |
| 108 | ||
| 109 | for fixed_type in fixed_types do | |
| 110 | // A parameter of the formal's own that nothing has settled | |
| 111 | // yet is not a type a parameter can take. An error type in | |
| 112 | // its place is one no parameter takes, which leaves that | |
| 113 | // parameter to be inferred from the body. | |
| 114 | implied_types.add(if fixed_type.is_settled then fixed_type else Types.ERROR() fi) | |
| 115 | od | |
| 116 | ||
| 117 | if let known = implied then | |
| 118 | implied_types.add_range(known.elements) | |
| 119 | fi | |
| 120 | ||
| 121 | if !_resolve_all(arguments, closure, implied_types, argument_names, argument_types, symbols) then | |
| 122 | return false | |
| 123 | fi | |
| 124 | ||
| 125 | let element_types = Collections.LIST[Type]() | |
| 126 | let packed = Collections.LIST[Symbols.Variable]() | |
| 127 | ||
| 128 | for i in fixed..arguments.count do | |
| 129 | element_types.add(argument_types[i]) | |
| 130 | packed.add(symbols[i]) | |
| 131 | od | |
| 132 | ||
| 133 | // A parameter written with a type is filled from the element | |
| 134 | // at its position, so that element has to be one it accepts. | |
| 135 | if let known = implied then | |
| 136 | for i in 0..pack_count do | |
| 137 | let written = element_types[i] | |
| 138 | ||
| 139 | if written.is_settled /\ !written.is_assignable_from(known.elements[i]) then | |
| 140 | _logger.error( | |
| 141 | arguments[fixed + i].location, | |
| 142 | "expected argument of type {written} but {known.elements[i]} supplied" | |
| 143 | ) | |
| 144 | fi | |
| 145 | od | |
| 146 | fi | |
| 147 | ||
| 148 | let group_type: Type mut | |
| 149 | ||
| 150 | if let known = implied then | |
| 151 | group_type = known.tuple | |
| 152 | elif element_types |> all(t => t.is_settled) then | |
| 153 | // Nothing else says what the tuple is, so the parameters do. | |
| 154 | group_type = IoC.CONTAINER.instance.innate_symbol_lookup.get_tuple_type(element_types, null) | |
| 155 | else | |
| 156 | // Still open: the one physical parameter stands for it, so | |
| 157 | // that resolving the call against the literal can bind it. | |
| 158 | let placeholder = Types.INFERRED_VARIABLE_TYPE(group) | |
| 159 | ||
| 160 | OBLIGATIONS.defer("parameter", placeholder, null) | |
| 161 | ||
| 162 | group_type = placeholder | |
| 163 | fi | |
| 164 | ||
| 165 | group.set_type(group_type) | |
| 166 | ||
| 167 | let physical_types = Collections.LIST[Type]() | |
| 168 | let physical_names = Collections.LIST[string]() | |
| 169 | ||
| 170 | for i in 0..fixed do | |
| 171 | physical_types.add(argument_types[i]) | |
| 172 | physical_names.add(argument_names[i]) | |
| 173 | od | |
| 174 | ||
| 175 | physical_types.add(group_type) | |
| 176 | physical_names.add("$pack") | |
| 177 | ||
| 178 | closure.packed_parameters = packed | |
| 179 | closure.arguments = physical_types | |
| 180 | closure.argument_names = physical_names | |
| 181 | ||
| 182 | return true | |
| 183 | si | |
| 184 | ||
| 185 | // The types `tuple` destructures into by position, where it is | |
| 186 | // settled, names nothing out of the literal's scope, and has | |
| 187 | // `count` elements. Absent otherwise. | |
| 188 | _elements_of( | |
| 189 | tuple: Type?, | |
| 190 | count: int, | |
| 191 | closure: Symbols.Closure | |
| 192 | ) -> (tuple: Type, elements: Collections.LIST[Type])? is | |
| 193 | if !tuple? \/ !tuple.is_settled \/ !_is_implied_type_usable(tuple, closure) then | |
| 194 | return null | |
| 195 | fi | |
| 196 | ||
| 197 | let strategy = Syntax.Process.DESTRUCTURE_RESOLVER.resolve_strategy(tuple, count) | |
| 198 | ||
| 199 | let elements = Collections.LIST[Type]() | |
| 200 | ||
| 201 | for i in 0..count do | |
| 202 | if strategy.is_deconstruct then | |
| 203 | if let element_type = strategy.deconstruct_function!.arguments[i].get_element_type() then | |
| 204 | elements.add(element_type) | |
| 205 | fi | |
| 206 | elif i < strategy.members.count then | |
| 207 | if let member = strategy.members[i], member_type = member.type then | |
| 208 | elements.add(member_type) | |
| 209 | fi | |
| 210 | fi | |
| 211 | od | |
| 212 | ||
| 213 | if elements.count != count then | |
| 214 | return null | |
| 215 | fi | |
| 216 | ||
| 217 | return (tuple = tuple, elements = elements) | |
| 218 | si | |
| 219 | ||
| 220 | _resolve_all( | |
| 221 | arguments: Collections.List[Syntax.Trees.Expressions.Expression], | |
| 222 | closure: Symbols.Closure, | |
| 223 | implied_argument_types: Collections.List[Type]?, | |
| 224 | argument_names: Collections.LIST[string], | |
| 225 | argument_types: Collections.LIST[Type], | |
| 226 | symbols: Collections.LIST[Symbols.Variable]? | |
| 227 | ) -> bool is | |
| 228 | for index in 0..arguments.count do | |
| 229 | let a = arguments[index] | |
| 230 | ||
| 231 | if !isa Syntax.Trees.Expressions.VARIABLE(a) then | |
| 232 | // A lambda parameter group is speculated as a tuple | |
| 233 | // expression and only then converted to a pattern, | |
| 234 | // so a `~` leaf arrives here as a unary operator | |
| 235 | // the conversion could not take, rather than as a | |
| 236 | // marked leaf. Name it, since the generic message | |
| 237 | // below says nothing about what is wrong. | |
| 238 | if let marker_location = _find_match_marker(a) then | |
| 239 | _logger.error( | |
| 240 | marker_location, | |
| 241 | "a match marker is only allowed in a refutable pattern (if let, while let or case-when arm)" | |
| 242 | ) | |
| 243 | ||
| 244 | return false | |
| 245 | fi | |
| 246 | ||
| 247 | _logger.error(a.location, "unexpected kind of argument ({a.get_type()})") | |
| 248 | return false | |
| 249 | fi | |
| 250 | ||
| 251 | let argument = a | |
| 252 | ||
| 253 | argument_names.add(argument.name.name) | |
| 254 | ||
| 255 | let symbol = cast Symbols.Variable?(closure.find_direct(argument.name.name))! | |
| 256 | ||
| 257 | // A parameter holds a value from the moment its literal is | |
| 258 | // entered, whatever pass this is and however many retries | |
| 259 | // its type takes to settle. Without this, `is_defined` | |
| 260 | // stays false for a plain (non-destructured) parameter | |
| 261 | // forever, and a reference to it from within its own body | |
| 262 | // reads as the self-referencing-`let`-initializer case to | |
| 263 | // `SHADOWED_CALLABLE_FINDER.find` — which | |
| 264 | // skips that call's sentinel-type guard and, when an | |
| 265 | // enclosing scope happens to declare a same-named | |
| 266 | // callable, spuriously falls back and captures it. | |
| 267 | symbol.is_defined = true | |
| 268 | ||
| 269 | let argument_type = _resolve_one(a, argument, symbol, index, implied_argument_types, closure) | |
| 270 | ||
| 271 | argument_types.add(argument_type) | |
| 272 | ||
| 273 | if symbols? then | |
| 274 | symbols.add(symbol) | |
| 275 | fi | |
| 276 | ||
| 277 | // The physical argument's type is what the pattern | |
| 278 | // unpacks; push it through the leaves so the body sees | |
| 279 | // each bound name at its element type. | |
| 280 | if let argument.left? then | |
| 281 | _assign_destructure_element_types(left, argument_type, closure) | |
| 282 | fi | |
| 283 | od | |
| 284 | ||
| 285 | return true | |
| 286 | si | |
| 287 | ||
| 288 | // Marks every name a pattern binds as holding a value, for a walk | |
| 289 | // on which the aggregate has no members to type them from yet. | |
| 290 | _define_leaves(left: Syntax.Trees.Variables.VariableLeft, closure: Symbols.Closure) is | |
| 291 | for element in left.elements! do | |
| 292 | if element.is_simple_name then | |
| 293 | if let symbol = cast Symbols.Variable?(closure.find_direct(element.name!.name)) then | |
| 294 | symbol.define() | |
| 295 | fi | |
| 296 | else | |
| 297 | _define_leaves(element, closure) | |
| 298 | fi | |
| 299 | od | |
| 300 | si | |
| 301 | ||
| 302 | // Push a destructured parameter's aggregate type down onto the | |
| 303 | // names its pattern binds, so the body sees each leaf at its | |
| 304 | // element type. Shares DESTRUCTURE_RESOLVER with `let` | |
| 305 | // destructuring and with a named function's destructured | |
| 306 | // formal argument, so a value tuple, a `deconstruct(...)` | |
| 307 | // source and positional members all resolve the same way. | |
| 308 | _assign_destructure_element_types( | |
| 309 | left: Syntax.Trees.Variables.VariableLeft, | |
| 310 | from_type: Type?, | |
| 311 | closure: Symbols.Closure | |
| 312 | ) is | |
| 313 | // The aggregate may be a placeholder whose origin has since | |
| 314 | // settled - a pack slot pinned by a later call, say - and the | |
| 315 | // members to destructure are the settled tuple's. | |
| 316 | let aggregate = if from_type? then SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(from_type) else null fi | |
| 317 | ||
| 318 | // One still being inferred has no members to type the leaves | |
| 319 | // from yet: an obligation of this walk, with the leaves defined | |
| 320 | // so the body can name them, and their types left to a walk on | |
| 321 | // which the aggregate has settled. | |
| 322 | if aggregate? /\ aggregate.is_inferred then | |
| 323 | OBLIGATIONS.defer("destructure", aggregate, left.location) | |
| 324 | _define_leaves(left, closure) | |
| 325 | ||
| 326 | return | |
| 327 | fi | |
| 328 | ||
| 329 | let elements = left.elements! | |
| 330 | ||
| 331 | let strategy = | |
| 332 | Syntax.Process.DESTRUCTURE_RESOLVER.resolve_strategy_reporting( | |
| 333 | _logger, left.location, aggregate, elements.count, null | |
| 334 | ) | |
| 335 | ||
| 336 | for i in 0..elements.count do | |
| 337 | let element = elements[i] | |
| 338 | ||
| 339 | let element_type = | |
| 340 | if strategy.is_deconstruct then | |
| 341 | strategy.deconstruct_function!.arguments[i].get_element_type() | |
| 342 | else | |
| 343 | let member = strategy.members[i] in | |
| 344 | if member? then member.type else null fi | |
| 345 | fi | |
| 346 | ||
| 347 | if element.is_simple_name then | |
| 348 | let symbol = cast Symbols.Variable?(closure.find_direct(element.name!.name)) | |
| 349 | ||
| 350 | if let typed_symbol = cast Types.SettableTyped?(symbol) then | |
| 351 | // The cast above only yields present when `symbol` | |
| 352 | // itself was, so `symbol` is present here too. | |
| 353 | symbol!.define() | |
| 354 | typed_symbol.set_type(if element_type? then element_type else Types.ERROR() fi) | |
| 355 | fi | |
| 356 | else | |
| 357 | _assign_destructure_element_types(element, element_type, closure) | |
| 358 | fi | |
| 359 | od | |
| 360 | si | |
| 361 | ||
| 362 | // The location of a `~` match marker anywhere in a parameter | |
| 363 | // group, or absent when there is none. | |
| 364 | _find_match_marker(expression: Syntax.Trees.Expressions.Expression) -> Source.LOCATION? is | |
| 365 | if let unary: Syntax.Trees.Expressions.UNARY = expression then | |
| 366 | if unary.operation.name =~ "~" then | |
| 367 | return unary.location | |
| 368 | fi | |
| 369 | ||
| 370 | return _find_match_marker(unary.right) | |
| 371 | fi | |
| 372 | ||
| 373 | if let tuple: Syntax.Trees.Expressions.TUPLE = expression then | |
| 374 | for element in tuple.elements.expressions do | |
| 375 | if let found = _find_match_marker(element) then | |
| 376 | return found | |
| 377 | fi | |
| 378 | od | |
| 379 | fi | |
| 380 | ||
| 381 | return null | |
| 382 | si | |
| 383 | ||
| 384 | _resolve_one( | |
| 385 | a: Syntax.Trees.Expressions.Expression, | |
| 386 | argument: Syntax.Trees.Expressions.VARIABLE, | |
| 387 | symbol: Symbols.Variable, | |
| 388 | index: int, | |
| 389 | implied_argument_types: Collections.List[Type]?, | |
| 390 | closure: Symbols.Closure | |
| 391 | ) -> Type is | |
| 392 | if symbol.type? /\ symbol.type.is_settled then | |
| 393 | return symbol.type! | |
| 394 | fi | |
| 395 | ||
| 396 | // A type holding a placeholder whose origin has since settled | |
| 397 | // - a pack slot pinned by a later call, an argument bounded by | |
| 398 | // a call in the body - collapses to what it settled to, so the | |
| 399 | // closure's signature names the answer rather than the | |
| 400 | // placeholder that stood for it. | |
| 401 | if let existing = symbol.type then | |
| 402 | let collapsed = SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(existing) | |
| 403 | ||
| 404 | if collapsed != existing /\ collapsed.is_settled then | |
| 405 | symbol.set_type(collapsed) | |
| 406 | _record_method_level_type_arguments(collapsed, symbol) | |
| 407 | ||
| 408 | return collapsed | |
| 409 | fi | |
| 410 | fi | |
| 411 | ||
| 412 | if !isa Syntax.Trees.TypeExpressions.INFER(argument.type_expression) then | |
| 413 | let te_type = argument.type_expression.type | |
| 414 | assert te_type? else "argument type-expression has no resolved type" | |
| 415 | return te_type | |
| 416 | fi | |
| 417 | ||
| 418 | // The implied types come from the formal the call pushed, | |
| 419 | // so a literal of a different arity has nothing at this | |
| 420 | // index. That is a call the resolver will reject; falling | |
| 421 | // through to inference here keeps this walk from reading | |
| 422 | // off the end of the list first. | |
| 423 | if implied_argument_types? /\ index < implied_argument_types.count then | |
| 424 | let implied_argument_type = implied_argument_types[index] | |
| 425 | ||
| 426 | if _is_implied_type_usable(implied_argument_type, closure) then | |
| 427 | symbol.set_type(implied_argument_type) | |
| 428 | _record_method_level_type_arguments(implied_argument_type, symbol) | |
| 429 | return implied_argument_type | |
| 430 | fi | |
| 431 | fi | |
| 432 | ||
| 433 | return _resolve_from_inference_or_placeholder(a, symbol) | |
| 434 | si | |
| 435 | ||
| 436 | _resolve_from_inference_or_placeholder( | |
| 437 | a: Syntax.Trees.Expressions.Expression, | |
| 438 | symbol: Symbols.Variable | |
| 439 | ) -> Type is | |
| 440 | let inferred = symbol.try_get_inferred_type() | |
| 441 | ||
| 442 | if inferred? /\ !inferred.is_sentinel then | |
| 443 | symbol.set_type(inferred) | |
| 444 | _record_method_level_type_arguments(inferred, symbol) | |
| 445 | ||
| 446 | // A shape whose parts are still to be inferred - the | |
| 447 | // return of a function only ever called - leaves the | |
| 448 | // parameter as unsettled as no type at all. | |
| 449 | if !inferred.is_settled then | |
| 450 | OBLIGATIONS.defer("parameter", Types.INFERRED_VARIABLE_TYPE(symbol), null) | |
| 451 | fi | |
| 452 | ||
| 453 | return inferred | |
| 454 | fi | |
| 455 | ||
| 456 | // Nothing has typed the parameter yet: an obligation of this | |
| 457 | // walk on its placeholder, reported at the parameter by the | |
| 458 | // fixing step if no later walk settles it. | |
| 459 | let placeholder = Types.INFERRED_VARIABLE_TYPE(symbol) | |
| 460 | symbol.set_type(placeholder) | |
| 461 | ||
| 462 | OBLIGATIONS.defer("parameter", placeholder, null) | |
| 463 | ||
| 464 | return placeholder | |
| 465 | si | |
| 466 | ||
| 467 | // Same intent as the implied-type-path walk: when a closure | |
| 468 | // arg's type contains method-level type variables (T from an | |
| 469 | // enclosing generic method, not class-level T from a Box[T]'s | |
| 470 | // members) the closure has to capture them so IL emission | |
| 471 | // generates a generic closure method with matching `!!N` | |
| 472 | // slots. For the inference path the type carries no AST node, | |
| 473 | // so the explicit walk-and-record is the only way the | |
| 474 | // RECORD_TYPE_ARGUMENT_USES pass — which keys off written | |
| 475 | // type expressions — would otherwise miss them. | |
| 476 | _record_method_level_type_arguments(t: Type, symbol: Symbols.Variable) is | |
| 477 | if !isa Symbols.Closure(symbol.owner) then | |
| 478 | return | |
| 479 | fi | |
| 480 | ||
| 481 | let closure = cast Symbols.Closure(symbol.owner) | |
| 482 | ||
| 483 | let collected = Collections.LIST[Symbols.Symbol]() | |
| 484 | INFERENCE_HELPERS.collect_method_level_type_variables(t, collected) | |
| 485 | ||
| 486 | for u in collected do | |
| 487 | closure.add_type_argument_reference(u) | |
| 488 | od | |
| 489 | si | |
| 490 | ||
| 491 | // True when the implied type for a closure argument is safe | |
| 492 | // to install as the symbol's type. Concrete types are always | |
| 493 | // usable. Type-variable-containing types are usable only when | |
| 494 | // every embedded type-variable is declared by a lexical | |
| 495 | // ancestor of the closure — i.e. it's in scope. Foreign type | |
| 496 | // variables (from overload-resolution constraints carrying | |
| 497 | // the *candidate* function's type vars) are rejected so the | |
| 498 | // iterative-inference fallback runs and resolves the arg | |
| 499 | // from body operations. | |
| 500 | // | |
| 501 | // ERROR-bearing types are also rejected. The call-site retry | |
| 502 | // walks tuple actuals under the candidate's still-generic | |
| 503 | // formal, and partial-binding can produce an `(ERROR, ERROR)` | |
| 504 | // tuple substitution when an earlier walk left ERROR fragments | |
| 505 | // around. Installing that as the closure arg's type silently | |
| 506 | // turns the destructure-on-arg path into a tuple-with-ERRORs | |
| 507 | // destructure, which the existing path accepts without an | |
| 508 | // error — `g2` ends up with ERROR type, IL gen runs (no errors | |
| 509 | // logged), and ICEs in Type.gen_type. Rejecting the implied | |
| 510 | // pushes us into the placeholder-or-LUB path, which emits | |
| 511 | // "cannot infer type here" so IL gen short-circuits cleanly. | |
| 512 | _is_implied_type_usable(t: Type, closure: Symbols.Closure) -> bool is | |
| 513 | // ghūl closures capture locals by value, so the inner | |
| 514 | // lambda can't assign to a primitive local in this | |
| 515 | // scope. BOX[bool] gives us a mutable holder the lambda | |
| 516 | // can write to via property assignment. | |
| 517 | let any_foreign = Ghul.BOX(false) | |
| 518 | let any_error = Ghul.BOX(false) | |
| 519 | ||
| 520 | t.walk((u: Type) is | |
| 521 | if u.is_error then | |
| 522 | any_error.value = true | |
| 523 | fi | |
| 524 | ||
| 525 | if u.is_type_variable /\ !_is_type_variable_in_scope(u.symbol, closure) then | |
| 526 | any_foreign.value = true | |
| 527 | fi | |
| 528 | si) | |
| 529 | ||
| 530 | return !any_foreign.value /\ !any_error.value | |
| 531 | si | |
| 532 | ||
| 533 | // Look up the type variable's name from the closure's scope. | |
| 534 | // If `find_enclosing(name)` resolves to the same symbol, | |
| 535 | // the type variable is lexically in scope at the lambda. | |
| 536 | // For foreign type variables (the candidate function's type | |
| 537 | // vars in an overload-resolution constraint), the lookup | |
| 538 | // either returns null or returns a DIFFERENT same-named | |
| 539 | // symbol — either way, not-in-scope, so we return false and | |
| 540 | // let the iterative-inference path resolve from body | |
| 541 | // operations. | |
| 542 | _is_type_variable_in_scope(type_variable: Symbols.Symbol?, closure: Symbols.Closure?) -> bool is | |
| 543 | if !type_variable? \/ !closure? then | |
| 544 | return false | |
| 545 | fi | |
| 546 | ||
| 547 | let found = closure.find_enclosing(type_variable.name) | |
| 548 | ||
| 549 | return found? /\ found == type_variable | |
| 550 | si | |
| 551 | si | |
| 552 | si |