Appearance
| 1 | namespace Semantic is | |
| 2 | use Types.Type; | |
| 3 | ||
| 4 | // Decides whether a named-delegate formal that a plain | |
| 5 | // assignability check rejects is worth pushing as a constraint | |
| 6 | // and re-walking the argument under - a bare function reference, | |
| 7 | // or a lambda literal that resolved to its own native shape | |
| 8 | // before the delegate slot was known. `Func`/`Action` slots never | |
| 9 | // reach here: `DELEGATE_SHAPE.is_named_delegate` answers false | |
| 10 | // for them, so they keep going through the ordinary function-type | |
| 11 | // assignability path. | |
| 12 | class DELEGATE_PUSH_CANDIDATES( | |
| 13 | _delegate_shape: DELEGATE_SHAPE, | |
| 14 | _innate_symbol_lookup: Lookups.InnateSymbolLookup | |
| 15 | ) is | |
| 16 | super(); | |
| 17 | ||
| 18 | init(..) is | |
| 19 | si | |
| 20 | ||
| 21 | // `formal` is a named delegate `actual` isn't already | |
| 22 | // assignable to, but which `actual` could satisfy once its | |
| 23 | // own call shape is pushed against the delegate's invoke | |
| 24 | // shape and re-walked. | |
| 25 | is_push_candidate(formal: Type, actual: Type) -> bool is | |
| 26 | if !_delegate_shape.is_named_delegate(formal) \/ formal.is_assignable_from(actual) then | |
| 27 | return false; | |
| 28 | fi | |
| 29 | ||
| 30 | if !actual.is_function then | |
| 31 | return false; | |
| 32 | fi | |
| 33 | ||
| 34 | let shape = _delegate_shape.try_get_function_type(formal, _innate_symbol_lookup); | |
| 35 | ||
| 36 | return shape? /\ shape.is_assignable_from(actual); | |
| 37 | si | |
| 38 | ||
| 39 | // True when pushing `candidate`'s own formal types onto the | |
| 40 | // current actuals stands a chance of resolving a named- | |
| 41 | // delegate mismatch that a plain assignability check missed | |
| 42 | // on the first walk. | |
| 43 | has_push_mismatch(candidate: Symbols.Function, argument_types: Collections.LIST[Type]) -> bool is | |
| 44 | for i in 0..argument_types.count do | |
| 45 | if is_push_candidate(candidate.arguments[i], argument_types[i]) then | |
| 46 | return true; | |
| 47 | fi | |
| 48 | od | |
| 49 | ||
| 50 | return false; | |
| 51 | si | |
| 52 | ||
| 53 | // Same shape as a plain single-arity-candidate search, for | |
| 54 | // when that search finds nothing because more than one | |
| 55 | // arity-matching overload exists (`List[T].sort` has both | |
| 56 | // `Sort(Comparison[T])` and `Sort(IComparer[T])`). A named | |
| 57 | // delegate formal narrows the field: an overload whose | |
| 58 | // mismatched argument isn't even delegate-pushable is | |
| 59 | // rejected outright, so genuine ambiguity between two | |
| 60 | // delegate-shaped formals both able to accept the actual | |
| 61 | // still falls through to null - only a group that resolves to | |
| 62 | // exactly one push-worthy overload is picked here. | |
| 63 | find_single_pushable_candidate( | |
| 64 | group: Symbols.FUNCTION_GROUP, | |
| 65 | argument_types: Collections.LIST[Type], | |
| 66 | want_instance: bool | |
| 67 | ) -> Symbols.Function? is | |
| 68 | let result: Symbols.Function? mut = null; | |
| 69 | let count mut = 0; | |
| 70 | ||
| 71 | for f in group.functions do | |
| 72 | if !want_instance /\ f.is_instance then | |
| 73 | continue; | |
| 74 | fi | |
| 75 | ||
| 76 | if !f.are_arguments_declared then | |
| 77 | continue; | |
| 78 | fi | |
| 79 | ||
| 80 | if f.arguments.count != argument_types.count then | |
| 81 | continue; | |
| 82 | fi | |
| 83 | ||
| 84 | let compatible mut = true; | |
| 85 | let any_pushed mut = false; | |
| 86 | ||
| 87 | for i in 0..argument_types.count do | |
| 88 | let formal = f.arguments[i]; | |
| 89 | let actual = argument_types[i]; | |
| 90 | ||
| 91 | if formal.is_assignable_from(actual) then | |
| 92 | continue; | |
| 93 | fi | |
| 94 | ||
| 95 | if is_push_candidate(formal, actual) then | |
| 96 | any_pushed = true; | |
| 97 | continue; | |
| 98 | fi | |
| 99 | ||
| 100 | compatible = false; | |
| 101 | od | |
| 102 | ||
| 103 | if compatible /\ any_pushed then | |
| 104 | result = f; | |
| 105 | count = count + 1; | |
| 106 | fi | |
| 107 | od | |
| 108 | ||
| 109 | if count == 1 then | |
| 110 | return result; | |
| 111 | fi | |
| 112 | ||
| 113 | return null; | |
| 114 | si | |
| 115 | si | |
| 116 | si |