Appearance
| 1 | namespace Semantic is | |
| 2 | use Types.Type; | |
| 3 | ||
| 4 | use Ghul.Pipes; | |
| 5 | ||
| 6 | // Predicate helper: does an under-determined-actual-vs-formal | |
| 7 | // pair look like the constraint-push retry could fix it? | |
| 8 | // | |
| 9 | // The call-site path is: first overload resolve fails or returns | |
| 10 | // PARTIAL; before spending the speculate / roll-back / re-walk | |
| 11 | // cost, ask this helper whether at least one argument has the | |
| 12 | // shape where pushing the formal as a constraint stands a chance | |
| 13 | // of changing the outcome. | |
| 14 | // | |
| 15 | // Two shapes qualify: | |
| 16 | // | |
| 17 | // 1. Function-typed formal with a function-typed actual whose | |
| 18 | // generic arguments contain at least one inferred | |
| 19 | // placeholder. Lambda literals walked without a parameter- | |
| 20 | // type constraint produce this shape (`x => ...` where the | |
| 21 | // body offers no clue about `x`'s type). Pushing the formal | |
| 22 | // function type as a constraint flows its argument types | |
| 23 | // into the lambda's `implied_argument_types` on re-walk. | |
| 24 | // | |
| 25 | // 2. GENERIC formal of class C, with a NAMED actual wrapping | |
| 26 | // an unspecialised C. `let b: Box[int] = ...` where the | |
| 27 | // actual is `Box` (no T binding from args). Pushing | |
| 28 | // `Box[int]` as a constraint lets the constructor pick | |
| 29 | // `int` for T. | |
| 30 | // | |
| 31 | // Pushing on any other shape — an already-specialised tuple, | |
| 32 | // a sequence, a primitive — typically just introduces new | |
| 33 | // element-mismatch errors that don't improve on the original | |
| 34 | // "no overload found" diagnostic. | |
| 35 | class UNDER_DETERMINATION_DETECTOR is | |
| 36 | init() is | |
| 37 | super.init(); | |
| 38 | si | |
| 39 | ||
| 40 | // Returns true when at least one argument's first-walk type | |
| 41 | // is under-determined for the corresponding formal type. | |
| 42 | any_arg_under_determined( | |
| 43 | candidate: Symbols.Function, | |
| 44 | argument_types: Collections.List[Type] | |
| 45 | ) -> bool is | |
| 46 | for i in 0..argument_types.count do | |
| 47 | if arg_under_determined_for_formal(candidate.arguments[i], argument_types[i]) then | |
| 48 | return true; | |
| 49 | fi | |
| 50 | od | |
| 51 | ||
| 52 | return false; | |
| 53 | si | |
| 54 | ||
| 55 | arg_under_determined_for_formal( | |
| 56 | formal: Type?, | |
| 57 | arg_value_type: Type? | |
| 58 | ) -> bool is | |
| 59 | if !formal? \/ !arg_value_type? then | |
| 60 | return false; | |
| 61 | fi | |
| 62 | ||
| 63 | let formal_generic = cast Types.GENERIC?(formal); | |
| 64 | ||
| 65 | if !formal_generic? then | |
| 66 | return false; | |
| 67 | fi | |
| 68 | ||
| 69 | // Function-typed formal with placeholder-argued function | |
| 70 | // actual: lambda literal whose parameter types weren't | |
| 71 | // inferred from the body. Pushing the formal flows arg | |
| 72 | // types into `implied_argument_types` on re-walk. | |
| 73 | if formal.is_function /\ arg_value_type.is_function then | |
| 74 | let arg_generic = cast Types.GENERIC?(arg_value_type); | |
| 75 | ||
| 76 | if arg_generic? /\ arg_generic.arguments |> any(a => a.is_inferred) then | |
| 77 | return true; | |
| 78 | fi | |
| 79 | fi | |
| 80 | ||
| 81 | // Already-specialised generic actual — the constraint | |
| 82 | // push won't make it more bindable. | |
| 83 | if isa Types.GENERIC(arg_value_type) then | |
| 84 | return false; | |
| 85 | fi | |
| 86 | ||
| 87 | let arg_named = cast Types.NAMED?(arg_value_type); | |
| 88 | ||
| 89 | if !arg_named? then | |
| 90 | return false; | |
| 91 | fi | |
| 92 | ||
| 93 | let arg_classy = cast Symbols.Classy?(arg_named.symbol); | |
| 94 | ||
| 95 | if !arg_classy? \/ !arg_classy.is_generic then | |
| 96 | return false; | |
| 97 | fi | |
| 98 | ||
| 99 | let formal_symbol_generic = cast Symbols.GENERIC?(formal_generic.symbol); | |
| 100 | ||
| 101 | if !formal_symbol_generic? then | |
| 102 | return false; | |
| 103 | fi | |
| 104 | ||
| 105 | return arg_classy =~ formal_symbol_generic.symbol; | |
| 106 | si | |
| 107 | si | |
| 108 | si |