Appearance
| 1 | namespace Semantic is | |
| 2 | use Logging; | |
| 3 | use Types.Type; | |
| 4 | ||
| 5 | // Resolve closure argument types from the lambda's AST argument | |
| 6 | // expressions, mutating each argument symbol's `.type` and | |
| 7 | // recording any captured type-variables on the closure. Picks | |
| 8 | // among four resolution branches in priority order: | |
| 9 | // | |
| 10 | // 1. Symbol already carries a usable (non-inferred / non- | |
| 11 | // error) type — keep it. This is set by a previous walk | |
| 12 | // (overload resolution's second pass set the symbol's | |
| 13 | // type from the chosen formal, or a function-level retry | |
| 14 | // is re-walking the body). | |
| 15 | // | |
| 16 | // 2. Argument has a written type expression that isn't INFER | |
| 17 | // — use it directly. | |
| 18 | // | |
| 19 | // 3. An implied type from the enclosing context | |
| 20 | // (function.constraint.arguments) is available and | |
| 21 | // "usable" — install it on the symbol. "Usable" means the | |
| 22 | // type is concrete OR an in-scope type-variable. Foreign | |
| 23 | // type-variables (carried over from an overload-resolution | |
| 24 | // constraint where the candidate is a different generic | |
| 25 | // function) are rejected — see #1210 commentary. Any | |
| 26 | // in-scope type-variables embedded in the implied type are | |
| 27 | // recorded via `closure.add_type_argument_reference` so IL | |
| 28 | // emission generates a generic closure method with | |
| 29 | // matching `!!N` slots. | |
| 30 | // | |
| 31 | // 4. Fall back to the iterative-inference path: try the | |
| 32 | // argument variable's accumulated LUB. On success install | |
| 33 | // that as the resolved type. On failure (still inferred / | |
| 34 | // error) emit "cannot infer type here" and install a | |
| 35 | // fresh INFERRED_VARIABLE_TYPE placeholder, leaving the | |
| 36 | // outer body-retry loop to resolve from body operations. | |
| 37 | // | |
| 38 | // `resolve(...)` returns true when the loop completed and the | |
| 39 | // closure's `arguments` / `argument_names` were populated. | |
| 40 | // Returns false on an unexpected argument shape (anything other | |
| 41 | // than a `Syntax.Trees.Expressions.VARIABLE`) without writing | |
| 42 | // anything back to the closure. | |
| 43 | // | |
| 44 | // A parameter written as a destructure pattern carries its pattern | |
| 45 | // on that node's `left`. It stays one physical argument here — the | |
| 46 | // resolution above settles the aggregate type, and the pattern's | |
| 47 | // leaves take their types from it. | |
| 48 | class CLOSURE_ARG_RESOLVER(_logger: Logger) is | |
| 49 | super(); | |
| 50 | ||
| 51 | resolve( | |
| 52 | arguments: Collections.List[Syntax.Trees.Expressions.Expression], | |
| 53 | closure: Symbols.Closure, | |
| 54 | implied_argument_types: Collections.List[Type]? | |
| 55 | ) -> bool is | |
| 56 | let argument_names = Collections.LIST[string](); | |
| 57 | let argument_types = Collections.LIST[Type](); | |
| 58 | ||
| 59 | for index in 0..arguments.count do | |
| 60 | let a = arguments[index]; | |
| 61 | ||
| 62 | if !isa Syntax.Trees.Expressions.VARIABLE(a) then | |
| 63 | _logger.error(a.location, "unexpected kind of argument ({a.get_type()})"); | |
| 64 | return false; | |
| 65 | fi | |
| 66 | ||
| 67 | let argument = a; | |
| 68 | ||
| 69 | argument_names.add(argument.name.name); | |
| 70 | ||
| 71 | let symbol = cast Symbols.Variable?(closure.find_direct(argument.name.name))!; | |
| 72 | ||
| 73 | let argument_type = _resolve_one(a, argument, symbol, index, implied_argument_types, closure); | |
| 74 | ||
| 75 | argument_types.add(argument_type); | |
| 76 | ||
| 77 | // The physical argument's type is what the pattern | |
| 78 | // unpacks; push it through the leaves so the body sees | |
| 79 | // each bound name at its element type. | |
| 80 | if let argument.left? then | |
| 81 | _assign_destructure_element_types(left, argument_type, closure); | |
| 82 | fi | |
| 83 | od | |
| 84 | ||
| 85 | closure.arguments = Collections.LIST[Type](argument_types); | |
| 86 | closure.argument_names = argument_names; | |
| 87 | ||
| 88 | return true; | |
| 89 | si | |
| 90 | ||
| 91 | // Push a destructured parameter's aggregate type down onto the | |
| 92 | // names its pattern binds, so the body sees each leaf at its | |
| 93 | // element type. Shares DESTRUCTURE_RESOLVER with `let` | |
| 94 | // destructuring and with a named function's destructured | |
| 95 | // formal argument, so a value tuple, a `deconstruct(...)` | |
| 96 | // source and positional members all resolve the same way. | |
| 97 | _assign_destructure_element_types( | |
| 98 | left: Syntax.Trees.Variables.VariableLeft, | |
| 99 | from_type: Type?, | |
| 100 | closure: Symbols.Closure | |
| 101 | ) is | |
| 102 | let elements = left.elements!; | |
| 103 | ||
| 104 | let strategy = | |
| 105 | Syntax.Process.DESTRUCTURE_RESOLVER.resolve_strategy_reporting( | |
| 106 | _logger, left.location, from_type, elements.count, null | |
| 107 | ); | |
| 108 | ||
| 109 | for i in 0..elements.count do | |
| 110 | let element = elements[i]; | |
| 111 | ||
| 112 | let element_type = | |
| 113 | if strategy.is_deconstruct then | |
| 114 | strategy.deconstruct_function!.arguments[i].get_element_type() | |
| 115 | else | |
| 116 | let member = strategy.members[i] in | |
| 117 | if member? then member.type else null fi | |
| 118 | fi; | |
| 119 | ||
| 120 | if element.is_simple_name then | |
| 121 | let symbol = cast Symbols.Variable?(closure.find_direct(element.name!.name)); | |
| 122 | ||
| 123 | if let typed_symbol = cast Types.SettableTyped?(symbol) then | |
| 124 | symbol.define(); | |
| 125 | typed_symbol.set_type(if element_type? then element_type else Types.ERROR() fi); | |
| 126 | fi | |
| 127 | else | |
| 128 | _assign_destructure_element_types(element, element_type, closure); | |
| 129 | fi | |
| 130 | od | |
| 131 | si | |
| 132 | ||
| 133 | _resolve_one( | |
| 134 | a: Syntax.Trees.Expressions.Expression, | |
| 135 | argument: Syntax.Trees.Expressions.VARIABLE, | |
| 136 | symbol: Symbols.Variable, | |
| 137 | index: int, | |
| 138 | implied_argument_types: Collections.List[Type]?, | |
| 139 | closure: Symbols.Closure | |
| 140 | ) -> Type is | |
| 141 | if symbol.type? /\ symbol.type.is_settled then | |
| 142 | return symbol.type!; | |
| 143 | fi | |
| 144 | ||
| 145 | if !isa Syntax.Trees.TypeExpressions.INFER(argument.type_expression) then | |
| 146 | let te_type = argument.type_expression.type; | |
| 147 | assert te_type? else "argument type-expression has no resolved type"; | |
| 148 | return te_type; | |
| 149 | fi | |
| 150 | ||
| 151 | if implied_argument_types? then | |
| 152 | let implied_argument_type = implied_argument_types[index]; | |
| 153 | ||
| 154 | if _is_implied_type_usable(implied_argument_type, closure) then | |
| 155 | symbol.set_type(implied_argument_type); | |
| 156 | _record_method_level_type_arguments(implied_argument_type, symbol); | |
| 157 | return implied_argument_type; | |
| 158 | fi | |
| 159 | fi | |
| 160 | ||
| 161 | return _resolve_from_inference_or_placeholder(a, symbol); | |
| 162 | si | |
| 163 | ||
| 164 | _resolve_from_inference_or_placeholder( | |
| 165 | a: Syntax.Trees.Expressions.Expression, | |
| 166 | symbol: Symbols.Variable | |
| 167 | ) -> Type is | |
| 168 | let inferred = symbol.try_get_inferred_type(); | |
| 169 | ||
| 170 | if inferred? /\ !inferred.is_sentinel then | |
| 171 | symbol.set_type(inferred); | |
| 172 | _record_method_level_type_arguments(inferred, symbol); | |
| 173 | return inferred; | |
| 174 | fi | |
| 175 | ||
| 176 | _logger.error(a.location, "cannot infer type here"); | |
| 177 | ||
| 178 | let placeholder = Types.INFERRED_VARIABLE_TYPE(symbol); | |
| 179 | symbol.set_type(placeholder); | |
| 180 | return placeholder; | |
| 181 | si | |
| 182 | ||
| 183 | // Same intent as the implied-type-path walk: when a closure | |
| 184 | // arg's type contains method-level type variables (T from an | |
| 185 | // enclosing generic method, not class-level T from a Box[T]'s | |
| 186 | // members) the closure has to capture them so IL emission | |
| 187 | // generates a generic closure method with matching `!!N` | |
| 188 | // slots. For the inference path the type carries no AST node, | |
| 189 | // so the explicit walk-and-record is the only way the | |
| 190 | // RECORD_TYPE_ARGUMENT_USES pass — which keys off written | |
| 191 | // type expressions — would otherwise miss them. | |
| 192 | _record_method_level_type_arguments(t: Type, symbol: Symbols.Variable) is | |
| 193 | if !isa Symbols.Closure(symbol.owner) then | |
| 194 | return; | |
| 195 | fi | |
| 196 | ||
| 197 | let closure = cast Symbols.Closure(symbol.owner); | |
| 198 | ||
| 199 | let collected = Collections.LIST[Symbols.Symbol](); | |
| 200 | INFERENCE_HELPERS.collect_method_level_type_variables(t, collected); | |
| 201 | ||
| 202 | for u in collected do | |
| 203 | closure.add_type_argument_reference(u); | |
| 204 | od | |
| 205 | si | |
| 206 | ||
| 207 | // True when the implied type for a closure argument is safe | |
| 208 | // to install as the symbol's type. Concrete types are always | |
| 209 | // usable. Type-variable-containing types are usable only when | |
| 210 | // every embedded type-variable is declared by a lexical | |
| 211 | // ancestor of the closure — i.e. it's in scope. Foreign type | |
| 212 | // variables (from overload-resolution constraints carrying | |
| 213 | // the *candidate* function's type vars) are rejected so the | |
| 214 | // iterative-inference fallback runs and resolves the arg | |
| 215 | // from body operations. | |
| 216 | // | |
| 217 | // ERROR-bearing types are also rejected. The call-site retry | |
| 218 | // walks tuple actuals under the candidate's still-generic | |
| 219 | // formal, and partial-binding can produce an `(ERROR, ERROR)` | |
| 220 | // tuple substitution when an earlier walk left ERROR fragments | |
| 221 | // around. Installing that as the closure arg's type silently | |
| 222 | // turns the destructure-on-arg path into a tuple-with-ERRORs | |
| 223 | // destructure, which the existing path accepts without an | |
| 224 | // error — `g2` ends up with ERROR type, IL gen runs (no errors | |
| 225 | // logged), and ICEs in Type.gen_type. Rejecting the implied | |
| 226 | // pushes us into the placeholder-or-LUB path, which emits | |
| 227 | // "cannot infer type here" so IL gen short-circuits cleanly. | |
| 228 | _is_implied_type_usable(t: Type, closure: Symbols.Closure) -> bool is | |
| 229 | // ghūl closures capture locals by value, so the inner | |
| 230 | // lambda can't assign to a primitive local in this | |
| 231 | // scope. BOX[bool] gives us a mutable holder the lambda | |
| 232 | // can write to via property assignment. | |
| 233 | let any_foreign = Ghul.BOX(false); | |
| 234 | let any_error = Ghul.BOX(false); | |
| 235 | ||
| 236 | t.walk((u: Type) is | |
| 237 | if u.is_error then | |
| 238 | any_error.value = true; | |
| 239 | fi | |
| 240 | ||
| 241 | if u.is_type_variable /\ !_is_type_variable_in_scope(u.symbol, closure) then | |
| 242 | any_foreign.value = true; | |
| 243 | fi | |
| 244 | si); | |
| 245 | ||
| 246 | return !any_foreign.value /\ !any_error.value; | |
| 247 | si | |
| 248 | ||
| 249 | // Look up the type variable's name from the closure's scope. | |
| 250 | // If `find_enclosing(name)` resolves to the same symbol, | |
| 251 | // the type variable is lexically in scope at the lambda. | |
| 252 | // For foreign type variables (the candidate function's type | |
| 253 | // vars in an overload-resolution constraint), the lookup | |
| 254 | // either returns null or returns a DIFFERENT same-named | |
| 255 | // symbol — either way, not-in-scope, so we return false and | |
| 256 | // let the iterative-inference path resolve from body | |
| 257 | // operations. | |
| 258 | _is_type_variable_in_scope(type_variable: Symbols.Symbol?, closure: Symbols.Closure?) -> bool is | |
| 259 | if !type_variable? \/ !closure? then | |
| 260 | return false; | |
| 261 | fi | |
| 262 | ||
| 263 | let found = closure.find_enclosing(type_variable.name); | |
| 264 | ||
| 265 | return found? /\ found == type_variable; | |
| 266 | si | |
| 267 | si | |
| 268 | si |