Appearance
| 1 | namespace Semantic is | |
| 2 | use Ghul.Pipes | |
| 3 | ||
| 4 | use Types.Type | |
| 5 | ||
| 6 | // Last-resort tie-break for candidates the earlier filters left | |
| 7 | // tied: prefer the one whose formals sit furthest down the | |
| 8 | // inheritance graph, which is the one that widened the actual | |
| 9 | // least. `Type.depth` is the same metric the least-upper-bound | |
| 10 | // map ranks by, memoised per symbol. | |
| 11 | class CANDIDATE_SPECIFICITY is | |
| 12 | pick( | |
| 13 | candidates: Collections.List[Symbols.Function], | |
| 14 | arguments: Collections.List[Type] | |
| 15 | ) -> Symbols.Function? static is | |
| 16 | if candidates.count < 2 \/ !can_rank(arguments) then | |
| 17 | return null | |
| 18 | fi | |
| 19 | ||
| 20 | let best mut = candidates[0] | |
| 21 | ||
| 22 | for i in 1..candidates.count do | |
| 23 | if dominates(candidates[i].arguments, best.arguments) then | |
| 24 | best = candidates[i] | |
| 25 | fi | |
| 26 | od | |
| 27 | ||
| 28 | for c in candidates do | |
| 29 | if c !~ best /\ !dominates(best.arguments, c.arguments) then | |
| 30 | return null | |
| 31 | fi | |
| 32 | od | |
| 33 | ||
| 34 | return best | |
| 35 | si | |
| 36 | ||
| 37 | // An ambiguity whose cause is an actual with no type yet - a | |
| 38 | // bare `_`, an untargeted `cast(..)`, an inference placeholder | |
| 39 | // - is not one specificity can settle: every candidate matched | |
| 40 | // that position vacuously, and choosing between them would | |
| 41 | // answer a question the call has not asked yet. | |
| 42 | @suppress("presence-test-non-optional") | |
| 43 | can_rank(arguments: Collections.List[Type]) -> bool static => | |
| 44 | !(arguments |> | |
| 45 | any(a => !a? \/ a.is_sentinel \/ a.is_error \/ a.contains_inferred)) | |
| 46 | ||
| 47 | // Dominance rather than a summed score: `a` has to be at least | |
| 48 | // as deep in every position and strictly deeper in one, so | |
| 49 | // being nearer in one argument never pays for being further | |
| 50 | // away in another. Candidates that trade off against each | |
| 51 | // other stay ambiguous, as they were before this step existed. | |
| 52 | dominates(a: Collections.List[Type], b: Collections.List[Type]) -> bool static is | |
| 53 | if a.count != b.count \/ a.count == 0 then | |
| 54 | return false | |
| 55 | fi | |
| 56 | ||
| 57 | let saw_deeper mut = false | |
| 58 | ||
| 59 | for i in 0..a.count do | |
| 60 | let a_arg = a[i] | |
| 61 | let b_arg = b[i] | |
| 62 | ||
| 63 | @suppress("presence-test-non-optional") | |
| 64 | if !a_arg? \/ !b_arg? \/ a_arg.is_wild \/ b_arg.is_wild then | |
| 65 | return false | |
| 66 | fi | |
| 67 | ||
| 68 | let ranked = rank(a_arg, b_arg) | |
| 69 | ||
| 70 | if ranked < 0 then | |
| 71 | return false | |
| 72 | elif ranked > 0 then | |
| 73 | saw_deeper = true | |
| 74 | fi | |
| 75 | od | |
| 76 | ||
| 77 | return saw_deeper | |
| 78 | si | |
| 79 | ||
| 80 | // How `a` ranks against `b`: positive when `a` sits further | |
| 81 | // down, negative when `b` does, zero when neither does or the | |
| 82 | // two cannot be ranked against each other. | |
| 83 | // | |
| 84 | // Two instantiations of one generic have the same depth - the | |
| 85 | // depth of the type they instantiate - so a formal taking | |
| 86 | // `Iterable[CAT]` ranks level with one taking `Iterable[Animal]` | |
| 87 | // until their arguments are compared. Comparing them is what | |
| 88 | // lets a candidate whose formals differ only inside a generic | |
| 89 | // be picked, and a function type is the case that reaches this | |
| 90 | // most often, since every one of them is an instantiation of | |
| 91 | // the same type. | |
| 92 | rank(a: Type, b: Type) -> int static is | |
| 93 | if a.depth != b.depth then | |
| 94 | return if a.depth > b.depth then 1 else -1 fi | |
| 95 | fi | |
| 96 | ||
| 97 | // The instantiations are distinct symbols, so what has to | |
| 98 | // agree is the type they instantiate. | |
| 99 | if a.symbol.root_unspecialized_symbol != b.symbol.root_unspecialized_symbol then | |
| 100 | return 0 | |
| 101 | fi | |
| 102 | ||
| 103 | let a_arguments = a.arguments | |
| 104 | let b_arguments = b.arguments | |
| 105 | ||
| 106 | if | |
| 107 | a_arguments.count == 0 \/ | |
| 108 | a_arguments.count != b_arguments.count | |
| 109 | then | |
| 110 | return 0 | |
| 111 | fi | |
| 112 | ||
| 113 | // The arguments have to agree on a direction, for the same | |
| 114 | // reason the formals do: an argument that ranks deeper does | |
| 115 | // not pay for a sibling that ranks shallower. | |
| 116 | let result mut = 0 | |
| 117 | ||
| 118 | for i in 0..a_arguments.count do | |
| 119 | let a_argument = a_arguments[i] | |
| 120 | let b_argument = b_arguments[i] | |
| 121 | ||
| 122 | @suppress("presence-test-non-optional") | |
| 123 | if | |
| 124 | !a_argument? \/ !b_argument? \/ | |
| 125 | a_argument.is_wild \/ b_argument.is_wild | |
| 126 | then | |
| 127 | return 0 | |
| 128 | fi | |
| 129 | ||
| 130 | let ranked = rank(a_argument, b_argument) | |
| 131 | ||
| 132 | if ranked != 0 then | |
| 133 | if result != 0 /\ result != ranked then | |
| 134 | return 0 | |
| 135 | fi | |
| 136 | ||
| 137 | result = ranked | |
| 138 | fi | |
| 139 | od | |
| 140 | ||
| 141 | return result | |
| 142 | si | |
| 143 | si | |
| 144 | si |