Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use Types.Type | |
| 3 | ||
| 4 | // Pairing formals with actuals can only bind an owner type argument | |
| 5 | // that some formal's type mentions. One that appears only in the | |
| 6 | // return type - TResult on IAdditionOperators[TSelf, TOther, TResult] | |
| 7 | // - is unreachable that way, so the candidate is discarded as | |
| 8 | // unbindable however well the arguments actually fit. | |
| 9 | // | |
| 10 | // Such an argument does not need inferring. An actual whose type is | |
| 11 | // bounded by an instantiation of the owner has already pinned every | |
| 12 | // one of the owner's arguments: `[T: INumber[T]]` instantiates | |
| 13 | // IAdditionOperators[T, T, T], so TResult is T by declaration. Read | |
| 14 | // the bindings off that instantiation instead of trying to infer | |
| 15 | // them. | |
| 16 | class OWNER_INSTANTIATION_BINDER is | |
| 17 | _MAX_ANCESTOR_DEPTH: int static => 8 | |
| 18 | ||
| 19 | // Bind the type arguments of `owner_classy` that the formals | |
| 20 | // left unbound, from the first actual that is, or descends | |
| 21 | // from, an instantiation of it. Does nothing at all when the | |
| 22 | // formals already covered every one, which is the ordinary | |
| 23 | // case - the ancestor walk below only runs where the binding | |
| 24 | // would otherwise be rejected as incomplete. | |
| 25 | bind_unbound_from_actual_instantiations( | |
| 26 | owner_classy: Classy, | |
| 27 | args: Collections.List[Type], | |
| 28 | results: Types.GENERIC_ARGUMENT_BIND_RESULTS | |
| 29 | ) static is | |
| 30 | if _is_complete(owner_classy, results) then | |
| 31 | return | |
| 32 | fi | |
| 33 | ||
| 34 | let names = owner_classy.argument_names | |
| 35 | ||
| 36 | for actual in args do | |
| 37 | let instantiation = _find_owner_instantiation(actual, owner_classy, 0) | |
| 38 | ||
| 39 | if !instantiation? then | |
| 40 | continue | |
| 41 | fi | |
| 42 | ||
| 43 | let arguments = instantiation.arguments | |
| 44 | ||
| 45 | if arguments.count != names.count then | |
| 46 | continue | |
| 47 | fi | |
| 48 | ||
| 49 | for i in 0..names.count do | |
| 50 | let parameter = _type_parameter_at(owner_classy, i) | |
| 51 | ||
| 52 | if !parameter? then | |
| 53 | continue | |
| 54 | fi | |
| 55 | ||
| 56 | if results.bindings.contains_key(parameter.symbol) then | |
| 57 | continue | |
| 58 | fi | |
| 59 | ||
| 60 | results.bind(parameter, arguments[i]) | |
| 61 | od | |
| 62 | ||
| 63 | return | |
| 64 | od | |
| 65 | si | |
| 66 | ||
| 67 | _type_parameter_at(owner_classy: Classy, index: int) -> Types.GenericArgument? static is | |
| 68 | if let declared = cast GenericArgument?(owner_classy.type_parameter_at(index)) then | |
| 69 | return cast Types.GenericArgument?(declared.type) | |
| 70 | fi | |
| 71 | ||
| 72 | return null | |
| 73 | si | |
| 74 | ||
| 75 | _is_complete(owner_classy: Classy, results: Types.GENERIC_ARGUMENT_BIND_RESULTS) -> bool static is | |
| 76 | for i in 0..owner_classy.argument_names.count do | |
| 77 | if let parameter = _type_parameter_at(owner_classy, i) then | |
| 78 | if !results.bindings.contains_key(parameter.symbol) then | |
| 79 | return false | |
| 80 | fi | |
| 81 | fi | |
| 82 | od | |
| 83 | ||
| 84 | return true | |
| 85 | si | |
| 86 | ||
| 87 | // The instantiation of `owner_classy` that `t` is, or that one | |
| 88 | // of its ancestors is. A type variable reports its bound as its | |
| 89 | // sole ancestor, so this reaches through `[T: INumber[T]]` to | |
| 90 | // the interfaces INumber itself extends. Ancestors are read | |
| 91 | // through `get_ancestor` so each hop carries the substitution | |
| 92 | // of the hop above it. | |
| 93 | _find_owner_instantiation(t: Type?, owner_classy: Classy, depth: int) -> GENERIC? static is | |
| 94 | if !t? \/ depth > _MAX_ANCESTOR_DEPTH then | |
| 95 | return null | |
| 96 | fi | |
| 97 | ||
| 98 | let symbol = t.symbol | |
| 99 | ||
| 100 | if let generic = cast GENERIC?(symbol) /\ generic.symbol == owner_classy then | |
| 101 | return generic | |
| 102 | fi | |
| 103 | ||
| 104 | for i in 0..symbol.ancestors.count do | |
| 105 | let found = _find_owner_instantiation(symbol.get_ancestor(i), owner_classy, depth + 1) | |
| 106 | ||
| 107 | if found? then | |
| 108 | return found | |
| 109 | fi | |
| 110 | od | |
| 111 | ||
| 112 | return null | |
| 113 | si | |
| 114 | si | |
| 115 | si |