Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Logging | |
| 3 | use Ghul.Disposable | |
| 4 | ||
| 5 | use Semantic.Types.Type | |
| 6 | ||
| 7 | use IR.Values | |
| 8 | ||
| 9 | use Ghul.Pipes | |
| 10 | ||
| 11 | // Compiles function bodies and function literals: the method-body | |
| 12 | // walk with its iterative type-inference retry loop, lambda | |
| 13 | // (closure) literals and `rec` references. Split out of | |
| 14 | // COMPILE_EXPRESSIONS, which delegates the matching visit methods | |
| 15 | // here. The `super.pre` / `super.visit` base-visitor calls and | |
| 16 | // the exception / environment-save wrapper of visit(function | |
| 17 | // literal) stay in the visitor; the methods here are the enclosed | |
| 18 | // logic. | |
| 19 | class COMPILE_LAMBDAS is | |
| 20 | _logger: Logger | |
| 21 | _symbol_table: Semantic.SYMBOL_TABLE | |
| 22 | _symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS | |
| 23 | _symbol_loader: Semantic.SYMBOL_LOADER | |
| 24 | _innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup | |
| 25 | _task_conversion: Semantic.TASK_CONVERSION | |
| 26 | _task_like_resolver: Semantic.TASK_LIKE_RESOLVER | |
| 27 | _closure_arg_resolver: Semantic.CLOSURE_ARG_RESOLVER | |
| 28 | _type_arg_placeholder_registry: Semantic.TYPE_ARG_PLACEHOLDER_REGISTRY | |
| 29 | _flow: NARROWING_FLOW | |
| 30 | _build_flags: Compiler.GLOBAL_BUILD_FLAGS | |
| 31 | _visitor: ScopedVisitor | |
| 32 | ||
| 33 | _field_assignment_checker: FIELD_ASSIGNMENT_CHECKER | |
| 34 | _delegate_shape: Semantic.DELEGATE_SHAPE | |
| 35 | _attribute_resolver: ATTRIBUTE_RESOLVER | |
| 36 | _composite_spill_state: COMPOSITE_SPILL_STORE | |
| 37 | _function_reference_adapter: FUNCTION_REFERENCE_ADAPTER | |
| 38 | ||
| 39 | init( | |
| 40 | logger: Logger, | |
| 41 | symbol_table: Semantic.SYMBOL_TABLE, | |
| 42 | symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS, | |
| 43 | symbol_loader: Semantic.SYMBOL_LOADER, | |
| 44 | innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup, | |
| 45 | task_conversion: Semantic.TASK_CONVERSION, | |
| 46 | closure_arg_resolver: Semantic.CLOSURE_ARG_RESOLVER, | |
| 47 | type_arg_placeholder_registry: Semantic.TYPE_ARG_PLACEHOLDER_REGISTRY, | |
| 48 | flow: NARROWING_FLOW, | |
| 49 | build_flags: Compiler.GLOBAL_BUILD_FLAGS, | |
| 50 | visitor: ScopedVisitor, | |
| 51 | attribute_resolver: ATTRIBUTE_RESOLVER, | |
| 52 | composite_spill_state: COMPOSITE_SPILL_STORE, | |
| 53 | function_reference_adapter: FUNCTION_REFERENCE_ADAPTER | |
| 54 | ) is | |
| 55 | super.init() | |
| 56 | ||
| 57 | _function_reference_adapter = function_reference_adapter | |
| 58 | ||
| 59 | _logger = logger | |
| 60 | _symbol_table = symbol_table | |
| 61 | _symbol_use_locations = symbol_use_locations | |
| 62 | _symbol_loader = symbol_loader | |
| 63 | _innate_symbol_lookup = innate_symbol_lookup | |
| 64 | _task_conversion = task_conversion | |
| 65 | _task_like_resolver = Semantic.TASK_LIKE_RESOLVER(logger) | |
| 66 | _closure_arg_resolver = closure_arg_resolver | |
| 67 | _type_arg_placeholder_registry = type_arg_placeholder_registry | |
| 68 | _flow = flow | |
| 69 | _build_flags = build_flags | |
| 70 | _visitor = visitor | |
| 71 | _field_assignment_checker = FIELD_ASSIGNMENT_CHECKER(logger) | |
| 72 | _attribute_resolver = attribute_resolver | |
| 73 | _composite_spill_state = composite_spill_state | |
| 74 | _delegate_shape = Semantic.DELEGATE_SHAPE() | |
| 75 | si | |
| 76 | ||
| 77 | visit_function_definition(function: Trees.Definitions.FUNCTION) is | |
| 78 | KILL_LEDGER.current_function = function | |
| 79 | KILL_LEDGER.current_file = function.location.file_name | |
| 80 | ||
| 81 | if function.name? then | |
| 82 | function.name.walk(_visitor) | |
| 83 | fi | |
| 84 | ||
| 85 | function.type_expression.walk(_visitor) | |
| 86 | ||
| 87 | function.arguments.walk(_visitor) | |
| 88 | ||
| 89 | if function.body? then | |
| 90 | // Implicit tail return: a body's final statement is a | |
| 91 | // tail candidate, terminated or not - the tail is judged | |
| 92 | // by its type, never by its terminator. Under a declared | |
| 93 | // non-void return type - generators exempted - the body | |
| 94 | // list is compiled as value-demanding but void-tolerant, | |
| 95 | // so a tail assignable to the return type flows to the | |
| 96 | // function's return while a void one stays the statement | |
| 97 | // it is. Void-returning bodies tolerate any tail and are | |
| 98 | // left untouched here. | |
| 99 | let body_block = cast Trees.Bodies.BLOCK?(function.body) | |
| 100 | let function_symbol = _symbol_table.current_function | |
| 101 | ||
| 102 | let tail_demand mut = false | |
| 103 | ||
| 104 | // `try` has no expression form yet, labelled loops are | |
| 105 | // statement-only, and a trailing `return`/`throw` already | |
| 106 | // diverges on its own - none of them can stand as a value | |
| 107 | // tail. | |
| 108 | if let bb = body_block, fs = function_symbol, rt = fs.return_type then | |
| 109 | // A body lowered through an async state machine and | |
| 110 | // returning a result-less task-like completes via its | |
| 111 | // builder at fall-through: no tail can deliver | |
| 112 | // anything the return wants, so no demand is set and | |
| 113 | // the tail stays the statement it is. | |
| 114 | let machine_completed = | |
| 115 | Semantic.Symbols.async_state_machine_for(fs)? /\ | |
| 116 | _returns_result_less_task_like(fs) | |
| 117 | ||
| 118 | let tail = bb.statements.last | |
| 119 | ||
| 120 | if | |
| 121 | !machine_completed /\ | |
| 122 | !rt.is_sentinel /\ | |
| 123 | !rt.is_inferred /\ | |
| 124 | !Semantic.Symbols.state_machine_for(fs)? /\ | |
| 125 | !rt.matches(_innate_symbol_lookup.get_void_type()) | |
| 126 | then | |
| 127 | // A machine-less return of a result-less task | |
| 128 | // return type completes at fall-through: the body | |
| 129 | // is marked a function tail whatever shape its | |
| 130 | // tail is, so the statement-list visitor appends | |
| 131 | // the completing return when the tail delivers | |
| 132 | // nothing - a value tail may still deliver a | |
| 133 | // handle to return directly, and an empty body, a | |
| 134 | // `try` or a labelled loop complete like any other | |
| 135 | // fall-through. A `return` tail settles itself and | |
| 136 | // a `throw` tail diverges, so neither wants the | |
| 137 | // append. | |
| 138 | let completes_at_fall_through = | |
| 139 | _task_conversion.completes_without_machine(rt) | |
| 140 | ||
| 141 | let tail_settles_itself = | |
| 142 | if let t = tail then | |
| 143 | isa Trees.Statements.RETURN(t) \/ isa Trees.Statements.THROW(t) | |
| 144 | else | |
| 145 | false | |
| 146 | fi | |
| 147 | ||
| 148 | if completes_at_fall_through /\ !tail_settles_itself then | |
| 149 | bb.statements.function_tail = true | |
| 150 | fi | |
| 151 | ||
| 152 | let tail_is_value = | |
| 153 | if let t = tail then | |
| 154 | t.provides_value /\ | |
| 155 | !isa Trees.Statements.TRY(t) /\ | |
| 156 | !isa Trees.Statements.LABELLED(t) /\ | |
| 157 | !isa Trees.Statements.THROW(t) /\ | |
| 158 | !isa Trees.Statements.RETURN(t) | |
| 159 | else | |
| 160 | false | |
| 161 | fi | |
| 162 | ||
| 163 | if tail_is_value then | |
| 164 | bb.statements.function_tail = true | |
| 165 | bb.statements.compile_expressions_state.want_value = true | |
| 166 | bb.statements.compile_expressions_state.void_tolerated = true | |
| 167 | ||
| 168 | bb.statements.set_expected_type( | |
| 169 | rt, | |
| 170 | "cannot return value of type {{0}} where {{1}} expected" | |
| 171 | ) | |
| 172 | ||
| 173 | tail_demand = true | |
| 174 | fi | |
| 175 | fi | |
| 176 | fi | |
| 177 | _type_arg_placeholder_registry.begin_body() | |
| 178 | Semantic.OBLIGATIONS.begin_body() | |
| 179 | ||
| 180 | let retry_body = RETRY_SITE_STATS.begin_body() | |
| 181 | let trace_body = Semantic.INFERENCE_TRACE.begin_body(function_symbol, function.location) | |
| 182 | ||
| 183 | // Recorded symbol uses follow the diagnostics speculation | |
| 184 | // discipline through this walk: every roll_back below is | |
| 185 | // followed by a full body re-walk, so uses recorded | |
| 186 | // against not-yet-settled types are discarded with the | |
| 187 | // diagnostics of the walk that produced them rather than | |
| 188 | // surviving to shadow the settled walk's records. | |
| 189 | _logger.speculate() | |
| 190 | _symbol_use_locations.speculate() | |
| 191 | ||
| 192 | let retries = 20 | |
| 193 | let walks mut = 0 | |
| 194 | ||
| 195 | for i in 1::retries do | |
| 196 | walks = i | |
| 197 | RETRY_SITE_STATS.begin_walk() | |
| 198 | Semantic.OBLIGATIONS.begin_walk() | |
| 199 | Semantic.INFERENCE_TRACE.begin_walk(i) | |
| 200 | ||
| 201 | // Narrowing is method-local — start each body | |
| 202 | // walk (and each inference-retry re-walk) from | |
| 203 | // an empty environment. | |
| 204 | _flow.reset() | |
| 205 | ||
| 206 | function.body!.walk(_visitor) | |
| 207 | ||
| 208 | Semantic.INFERENCE_TRACE.end_walk(_logger.is_clean, _logger.has_consumed_any) | |
| 209 | ||
| 210 | // Convergence: clean or no progress signal raised. | |
| 211 | // Without a `has_consumed_any` flag from somewhere | |
| 212 | // in the walk, errors that did fire are real and | |
| 213 | // persistent — re-walking won't change them, and | |
| 214 | // re-walking AST nodes that hold partial state | |
| 215 | // produces *different* (often worse) error sets | |
| 216 | // because the second walk sees state left over | |
| 217 | // from the first. So retry only when something | |
| 218 | // explicitly flagged "I consumed an unresolved | |
| 219 | // type" — that's the case where iteration N+1 | |
| 220 | // might find narrower constraints and make | |
| 221 | // progress. | |
| 222 | // An obligation left standing is a progress signal in | |
| 223 | // its own right - the mark it set can be lost to a local | |
| 224 | // retry's roll back - until a walk leaves exactly the | |
| 225 | // obligations the walk before it did, which is a walk | |
| 226 | // that can only repeat. | |
| 227 | let waiting = Semantic.OBLIGATIONS.standing.count > 0 | |
| 228 | ||
| 229 | if _logger.is_clean /\ !waiting then | |
| 230 | break | |
| 231 | fi | |
| 232 | ||
| 233 | // A walk that leaves exactly the obligations the walk | |
| 234 | // before it did, and that learned no bound or | |
| 235 | // constraint while doing so, can only repeat - whatever | |
| 236 | // else it marked as consumed. The default for what is | |
| 237 | // still standing is taken below. | |
| 238 | if waiting /\ Semantic.OBLIGATIONS.is_stuck then | |
| 239 | break | |
| 240 | fi | |
| 241 | ||
| 242 | if !_logger.has_consumed_any /\ !waiting then | |
| 243 | break | |
| 244 | fi | |
| 245 | ||
| 246 | if i < retries then | |
| 247 | _logger.roll_back() | |
| 248 | _logger.speculate() | |
| 249 | ||
| 250 | _symbol_use_locations.roll_back() | |
| 251 | _symbol_use_locations.speculate() | |
| 252 | ||
| 253 | // Prototype: start the re-walk from the state a | |
| 254 | // first walk would see, keeping only what lives | |
| 255 | // on symbols and in the placeholder registry. | |
| 256 | if RETRY_STATS.iteration_clear then | |
| 257 | CLEAR_STATE_VISITOR(true, true).apply(function.body!) | |
| 258 | fi | |
| 259 | fi | |
| 260 | od | |
| 261 | ||
| 262 | // The loop has stopped with obligations standing, and | |
| 263 | // some rule that recorded one has a default the language | |
| 264 | // defines. Taking it here rather than during a walk is | |
| 265 | // what keeps a walk from pre-empting the uses that would | |
| 266 | // have settled the origin properly; the default then | |
| 267 | // needs one more walk to reach the site that waited and | |
| 268 | // everything typed from it. | |
| 269 | if Semantic.OBLIGATIONS.take_defaults() then | |
| 270 | _logger.roll_back() | |
| 271 | _logger.speculate() | |
| 272 | ||
| 273 | _symbol_use_locations.roll_back() | |
| 274 | _symbol_use_locations.speculate() | |
| 275 | ||
| 276 | if RETRY_STATS.iteration_clear then | |
| 277 | CLEAR_STATE_VISITOR(true, true).apply(function.body!) | |
| 278 | fi | |
| 279 | ||
| 280 | walks = walks + 1 | |
| 281 | ||
| 282 | RETRY_SITE_STATS.begin_walk() | |
| 283 | Semantic.OBLIGATIONS.begin_walk() | |
| 284 | Semantic.INFERENCE_TRACE.begin_walk(walks) | |
| 285 | ||
| 286 | _flow.reset() | |
| 287 | ||
| 288 | function.body!.walk(_visitor) | |
| 289 | ||
| 290 | Semantic.INFERENCE_TRACE.end_walk(_logger.is_clean, _logger.has_consumed_any) | |
| 291 | fi | |
| 292 | ||
| 293 | RETRY_STATS.note(walks, function_symbol, function.location) | |
| 294 | RETRY_SITE_STATS.end_body(retry_body, walks, function_symbol, function.location) | |
| 295 | Semantic.INFERENCE_TRACE.end_body(trace_body, walks, retries, _logger.is_clean, _logger.has_consumed_any) | |
| 296 | ||
| 297 | // Any constructor-type-arg placeholder that didn't | |
| 298 | // acquire a concrete constraint from any usage has no | |
| 299 | // type to settle to - report rather than guess. This | |
| 300 | // is also the backstop that keeps such a placeholder | |
| 301 | // from surviving to IL emission, where the signature | |
| 302 | // encoder would refuse it. | |
| 303 | // | |
| 304 | // Only sweep when the retry loop failed to converge. | |
| 305 | // A walk that converged clean consumed no unresolved | |
| 306 | // types, so every phantom that matters has settled - | |
| 307 | // but the registry also holds phantom sets minted for | |
| 308 | // overload candidates that lost their resolution and | |
| 309 | // were rolled back, and those stay unresolved without | |
| 310 | // being errors. Non-convergence is the signal that an | |
| 311 | // unresolved phantom actually reached committed code. | |
| 312 | if _logger.has_consumed_any /\ !_logger.is_clean then | |
| 313 | _type_arg_placeholder_registry.report_unresolved(_logger) | |
| 314 | fi | |
| 315 | ||
| 316 | // Likewise an obligation still waiting on a placeholder | |
| 317 | // nothing in the body settled: reported at the variable it | |
| 318 | // names, since the loop has stopped walking. | |
| 319 | if !_logger.is_clean then | |
| 320 | Semantic.OBLIGATIONS.fix(_logger) | |
| 321 | fi | |
| 322 | ||
| 323 | Semantic.OBLIGATIONS.end_body() | |
| 324 | ||
| 325 | // Definite return: control can reach the end of a | |
| 326 | // non-void, block-bodied function's body without a | |
| 327 | // value having been returned. `_flow.is_unreachable` | |
| 328 | // is false here only when at least one path falls | |
| 329 | // off the end — every path that returns / throws | |
| 330 | // leaves the flow at `bottom`. | |
| 331 | // | |
| 332 | // With a tail demand set up before the walk, the | |
| 333 | // outcome is judged like an explicit `return` instead: | |
| 334 | // a value assignable to the declared return type consumes | |
| 335 | // the obligation, and an incompatible non-void value is | |
| 336 | // an error at the tail with no warning doubled on top. | |
| 337 | let is_generator = Semantic.Symbols.state_machine_for(function_symbol)? | |
| 338 | ||
| 339 | // A demanded tail is judged during the walk, by the | |
| 340 | // function-tail branch of the statement-list visitor, | |
| 341 | // which records whether the tail delivered. A void or | |
| 342 | // valueless tail delivers nothing and is compiled as the | |
| 343 | // statement it is - so a demand left standing undelivered | |
| 344 | // is exactly the fall-through case, and the | |
| 345 | // definite-return warning judges it. | |
| 346 | let tail_delivered = | |
| 347 | tail_demand /\ | |
| 348 | body_block? /\ | |
| 349 | body_block.statements.compile_expressions_state.function_tail_delivered | |
| 350 | ||
| 351 | if | |
| 352 | !tail_delivered /\ | |
| 353 | !_build_flags.no_warn_definite_return /\ | |
| 354 | !is_generator /\ | |
| 355 | function.body!.is_block /\ | |
| 356 | !_flow.is_unreachable /\ | |
| 357 | function_symbol? /\ | |
| 358 | function_symbol.return_type? /\ | |
| 359 | !function_symbol.return_type.is_sentinel /\ | |
| 360 | !function_symbol.return_type.is_inferred /\ | |
| 361 | !function_symbol.return_type.matches(_innate_symbol_lookup.get_void_type()) /\ | |
| 362 | !_completes_at_fall_through(function_symbol) /\ | |
| 363 | !(function_symbol.is_top_level_entry /\ _build_flags.submission_name?) | |
| 364 | then | |
| 365 | let header = function.location.start_position :: function.type_expression.location | |
| 366 | _logger.warn(header, "definite-return", "function may not return a value on all paths") | |
| 367 | fi | |
| 368 | ||
| 369 | _record_field_assignment_summary(function, function_symbol) | |
| 370 | ||
| 371 | _logger.commit() | |
| 372 | _symbol_use_locations.commit() | |
| 373 | fi | |
| 374 | ||
| 375 | KILL_LEDGER.current_function = null | |
| 376 | si | |
| 377 | ||
| 378 | // Called once every method has been walked - see | |
| 379 | // FIELD_ASSIGNMENT_CHECKER. | |
| 380 | report_field_assignments() is | |
| 381 | _field_assignment_checker.report() | |
| 382 | si | |
| 383 | ||
| 384 | // What a method did, for the constructor field check that runs once | |
| 385 | // every method has been walked. Two facts, both taken from the | |
| 386 | // must-domains at the end of the body: the fields it definitely | |
| 387 | // assigned, and the methods on `self` it definitely called. | |
| 388 | // | |
| 389 | // The check itself cannot run here. A constructor is routinely | |
| 390 | // written before the helper it delegates to, so the helper's own | |
| 391 | // summary does not exist yet; FIELD_ASSIGNMENT_CHECKER closes over | |
| 392 | // the call graph after the build and reports then. | |
| 393 | _record_field_assignment_summary( | |
| 394 | function: Trees.Definitions.FUNCTION, | |
| 395 | function_symbol: Semantic.Symbols.Function? | |
| 396 | ) is | |
| 397 | if | |
| 398 | _build_flags.no_warn_field_definite_assignment \/ | |
| 399 | !function_symbol? \/ | |
| 400 | !function_symbol.is_instance | |
| 401 | then | |
| 402 | return | |
| 403 | fi | |
| 404 | ||
| 405 | if !isa Semantic.Symbols.Classy(function_symbol.owner) then | |
| 406 | return | |
| 407 | fi | |
| 408 | ||
| 409 | let assigned = Collections.LIST[Semantic.Symbols.Symbol]() | |
| 410 | ||
| 411 | for v in _flow.assigned_variables do | |
| 412 | assigned.add(v) | |
| 413 | od | |
| 414 | ||
| 415 | let called = Collections.LIST[Semantic.Symbols.Symbol]() | |
| 416 | ||
| 417 | for f in _flow.called_methods do | |
| 418 | called.add(f) | |
| 419 | od | |
| 420 | ||
| 421 | // function_symbol.location is the constructor name alone | |
| 422 | // (declare-members hands declare_function the name's own | |
| 423 | // location as the symbol location, function.location - the | |
| 424 | // whole declaration - as its separate span), so the warning | |
| 425 | // this summary eventually produces squiggles just "init" | |
| 426 | // rather than the entire constructor body. | |
| 427 | _field_assignment_checker.record( | |
| 428 | function_symbol, | |
| 429 | function_symbol.location, | |
| 430 | assigned, | |
| 431 | called, | |
| 432 | _flow.is_unreachable | |
| 433 | ) | |
| 434 | si | |
| 435 | ||
| 436 | // A function whose fall-through completes its return rather | |
| 437 | // than owing a value: a state-machine body returning a | |
| 438 | // result-less task-like (its builder completes the handle), | |
| 439 | // and a machine-less return that can be completed without a | |
| 440 | // machine - Tasks.TASK via completed_task, any other | |
| 441 | // result-less task-like via its own builder (the statement- | |
| 442 | // list visitor appends the completing return). | |
| 443 | _completes_at_fall_through(function_symbol: Semantic.Symbols.Function) -> bool is | |
| 444 | if | |
| 445 | Semantic.Symbols.async_state_machine_for(function_symbol)? /\ | |
| 446 | _returns_result_less_task_like(function_symbol) | |
| 447 | then | |
| 448 | return true | |
| 449 | fi | |
| 450 | ||
| 451 | return _task_conversion.completes_without_machine(function_symbol.return_type) | |
| 452 | si | |
| 453 | ||
| 454 | // A declared return type that carries no result - `Tasks.TASK`, | |
| 455 | // or any task-like with no type argument. | |
| 456 | _returns_result_less_task_like(function_symbol: Semantic.Symbols.Function) -> bool is | |
| 457 | let return_type = function_symbol.return_type | |
| 458 | ||
| 459 | if !return_type? then | |
| 460 | return false | |
| 461 | fi | |
| 462 | ||
| 463 | if let void_task = _innate_symbol_lookup.get_void_task_type() then | |
| 464 | if return_type.matches(void_task) then | |
| 465 | return true | |
| 466 | fi | |
| 467 | fi | |
| 468 | ||
| 469 | let task_like = _task_like_resolver.try_resolve(return_type) | |
| 470 | ||
| 471 | return task_like? /\ task_like.is_void_like | |
| 472 | si | |
| 473 | ||
| 474 | // The task-like a closure's slot asks its async body to return, | |
| 475 | // when the slot's return type names one other than Task. Task | |
| 476 | // keeps its own path: the wrap-as-task pin and the from_result | |
| 477 | // wrap both spell it directly. | |
| 478 | _slot_task_like(slot_return_type: Type?) -> Semantic.TASK_LIKE? is | |
| 479 | if !slot_return_type? then | |
| 480 | return null | |
| 481 | fi | |
| 482 | ||
| 483 | let task_like = _task_like_resolver.try_resolve(slot_return_type) | |
| 484 | ||
| 485 | if !task_like? then | |
| 486 | return null | |
| 487 | fi | |
| 488 | ||
| 489 | if _task_conversion.is_task_type(slot_return_type) then | |
| 490 | return null | |
| 491 | fi | |
| 492 | ||
| 493 | return task_like | |
| 494 | si | |
| 495 | ||
| 496 | // Whether a literal's body might end on a value the literal | |
| 497 | // returns: an expression body always does, and a block body | |
| 498 | // does when its last statement is one a tail demand would be | |
| 499 | // put to. Syntactic, because it is asked before the body is | |
| 500 | // walked - the tail's type settles later, and only then is | |
| 501 | // the question answerable for certain. | |
| 502 | _body_may_yield_value(function: Trees.Expressions.FUNCTION) -> bool is | |
| 503 | if isa Trees.Bodies.EXPRESSION(function.body) then | |
| 504 | return true | |
| 505 | fi | |
| 506 | ||
| 507 | if let block = cast Trees.Bodies.BLOCK?(function.body) then | |
| 508 | if let tail = block.statements.last then | |
| 509 | return | |
| 510 | tail.provides_value /\ | |
| 511 | !isa Trees.Statements.TRY(tail) /\ | |
| 512 | !isa Trees.Statements.LABELLED(tail) /\ | |
| 513 | !isa Trees.Statements.THROW(tail) /\ | |
| 514 | !isa Trees.Statements.RETURN(tail) | |
| 515 | fi | |
| 516 | fi | |
| 517 | ||
| 518 | return false | |
| 519 | si | |
| 520 | ||
| 521 | // A literal two or more returns from the marker whose body is not | |
| 522 | // itself a literal - a name, a local, a call - evaluates to a | |
| 523 | // function that returns the N-ary one. It is expanded into a | |
| 524 | // literal over its own parameters, so that the marker has a body | |
| 525 | // to go on to, and the body is walked again around it. | |
| 526 | _expand_deeper_pack_body(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) -> bool is | |
| 527 | let depth = function.nested_pack_depth | |
| 528 | ||
| 529 | if depth < 2 then | |
| 530 | return false | |
| 531 | fi | |
| 532 | ||
| 533 | let body = cast Trees.Bodies.EXPRESSION?(function.body) | |
| 534 | ||
| 535 | if !body? \/ isa Trees.Expressions.FUNCTION(body.expression) then | |
| 536 | return false | |
| 537 | fi | |
| 538 | ||
| 539 | let type = body.expression.value?.type | |
| 540 | ||
| 541 | if !type? \/ !type.is_function \/ type.is_action then | |
| 542 | return false | |
| 543 | fi | |
| 544 | ||
| 545 | let inner = _function_reference_adapter.try_adapt(body.expression, Semantic.ARGUMENT_PACK.parameter_count(type)) | |
| 546 | ||
| 547 | if !inner? then | |
| 548 | return false | |
| 549 | fi | |
| 550 | ||
| 551 | body.expression = inner | |
| 552 | ||
| 553 | inner.set_expects_pack(depth - 1) | |
| 554 | ||
| 555 | if closure.return_type_was_inferred then | |
| 556 | closure.set_return_type(Semantic.Types.INFERRED_RETURN_TYPE()) | |
| 557 | else | |
| 558 | _present_declared_return_as_packed(function, depth - 1) | |
| 559 | fi | |
| 560 | ||
| 561 | return true | |
| 562 | si | |
| 563 | ||
| 564 | // A literal at a marked position may write its return as the | |
| 565 | // N-ary function type the marker licenses there, at whatever | |
| 566 | // depth the marker sits. What it returns is the wrapper, so | |
| 567 | // its return is rewritten to the shape the wrapper has: at the | |
| 568 | // marked hop the parameters are packed into the tuple the pack | |
| 569 | // binds to, and the hops above it are kept as written. | |
| 570 | _present_declared_return_as_packed(function: Trees.Expressions.FUNCTION, depth: int) is | |
| 571 | let declared = function.type_expression.type | |
| 572 | ||
| 573 | if !declared? then | |
| 574 | return | |
| 575 | fi | |
| 576 | ||
| 577 | let closure = cast Semantic.Symbols.Closure?(_symbol_table.scope_for(function)) | |
| 578 | ||
| 579 | if !closure? then | |
| 580 | return | |
| 581 | fi | |
| 582 | ||
| 583 | if let packed = _pack_spine(declared, depth) then | |
| 584 | closure.set_return_type(packed) | |
| 585 | fi | |
| 586 | si | |
| 587 | ||
| 588 | // `type` with the function `depth` returns along its spine | |
| 589 | // rewritten to take its parameters as one tuple. Absent where | |
| 590 | // the spine is shorter than that, or where what it arrives at | |
| 591 | // is not a function of two to seven parameters. | |
| 592 | _pack_spine(type: Type, depth: int) -> Type? is | |
| 593 | if !type.is_function then | |
| 594 | return null | |
| 595 | fi | |
| 596 | ||
| 597 | let count = Semantic.ARGUMENT_PACK.parameter_count(type) | |
| 598 | let types = Collections.LIST[Type]() | |
| 599 | ||
| 600 | if depth > 0 then | |
| 601 | if type.is_action then | |
| 602 | return null | |
| 603 | fi | |
| 604 | ||
| 605 | let inner = _pack_spine(type.arguments[count], depth - 1) | |
| 606 | ||
| 607 | if !inner? then | |
| 608 | return null | |
| 609 | fi | |
| 610 | ||
| 611 | for i in 0..count do | |
| 612 | types.add(type.arguments[i]) | |
| 613 | od | |
| 614 | ||
| 615 | types.add(inner) | |
| 616 | ||
| 617 | return _innate_symbol_lookup.get_function_type(types, type.is_pure_function) | |
| 618 | fi | |
| 619 | ||
| 620 | if count < 2 \/ count > Semantic.ARGUMENT_PACK.MAXIMUM_ARITY then | |
| 621 | return null | |
| 622 | fi | |
| 623 | ||
| 624 | let elements = Collections.LIST[Type]() | |
| 625 | ||
| 626 | for i in 0..count do | |
| 627 | elements.add(type.arguments[i]) | |
| 628 | od | |
| 629 | ||
| 630 | types.add(_innate_symbol_lookup.get_tuple_type(elements, null)) | |
| 631 | types.add( | |
| 632 | if type.is_action then | |
| 633 | _innate_symbol_lookup.get_void_type() | |
| 634 | else | |
| 635 | type.arguments[count] | |
| 636 | fi | |
| 637 | ) | |
| 638 | ||
| 639 | return _innate_symbol_lookup.get_function_type(types, type.is_pure_function) | |
| 640 | si | |
| 641 | ||
| 642 | // What the slot a literal goes into says it returns, where the | |
| 643 | // slot is known and says anything a body could be held to. | |
| 644 | _slot_return_type(function: Trees.Expressions.FUNCTION) -> Type? is | |
| 645 | let expected = function.expected_type | |
| 646 | ||
| 647 | if !expected? then | |
| 648 | return null | |
| 649 | fi | |
| 650 | ||
| 651 | let shape = | |
| 652 | if expected.is_function then | |
| 653 | expected | |
| 654 | else | |
| 655 | _delegate_shape.try_get_function_type(expected, _innate_symbol_lookup) | |
| 656 | fi | |
| 657 | ||
| 658 | if !shape? then | |
| 659 | return null | |
| 660 | fi | |
| 661 | ||
| 662 | let raw = Semantic.SLOT_RETURN_TYPE.of(shape, _innate_symbol_lookup.get_void_type()) | |
| 663 | ||
| 664 | if !raw? then | |
| 665 | return null | |
| 666 | fi | |
| 667 | ||
| 668 | let candidate = Semantic.SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(raw) | |
| 669 | ||
| 670 | if !Semantic.LAMBDA_RETURN_CONSTRAINT.should_push(candidate, null) then | |
| 671 | return null | |
| 672 | fi | |
| 673 | ||
| 674 | return candidate | |
| 675 | si | |
| 676 | ||
| 677 | // The tuple a literal's parameters are the elements of, where the | |
| 678 | // literal is written with an argument pack spread out and is | |
| 679 | // going into a formal that takes the pack as one tuple. Absent | |
| 680 | // for every other literal, and for one that cannot be compiled | |
| 681 | // taking the tuple directly. | |
| 682 | _packed_literal_tuple(function: Trees.Expressions.FUNCTION, expected_type: Type?) -> Type? is | |
| 683 | if !_is_packed_literal(function, expected_type) \/ !expected_type? then | |
| 684 | return null | |
| 685 | fi | |
| 686 | ||
| 687 | return expected_type.arguments[Semantic.ARGUMENT_PACK.fixed_count(expected_type)] | |
| 688 | si | |
| 689 | ||
| 690 | // Whether this literal is compiled taking the pack's tuple. The | |
| 691 | // marker says the position takes one; an expected type, where one | |
| 692 | // has arrived, has to be the shape that does. | |
| 693 | _is_packed_literal(function: Trees.Expressions.FUNCTION, expected_type: Type?) -> bool is | |
| 694 | if !function.expects_pack then | |
| 695 | return false | |
| 696 | fi | |
| 697 | ||
| 698 | if !expected_type? then | |
| 699 | return PACKED_LITERAL.is_eligible(function) | |
| 700 | fi | |
| 701 | ||
| 702 | return | |
| 703 | Semantic.ARGUMENT_PACK.is_pack_slot(expected_type) /\ | |
| 704 | PACKED_LITERAL.is_eligible(function, Semantic.ARGUMENT_PACK.fixed_count(expected_type)) | |
| 705 | si | |
| 706 | ||
| 707 | // The types of the parameters a pack slot takes of its own before | |
| 708 | // the pack. | |
| 709 | _fixed_parameter_types(expected_type: Type?) -> Collections.List[Type] is | |
| 710 | let types = Collections.LIST[Type]() | |
| 711 | ||
| 712 | if let expected = expected_type /\ Semantic.ARGUMENT_PACK.is_pack_slot(expected) then | |
| 713 | for i in 0..Semantic.ARGUMENT_PACK.fixed_count(expected) do | |
| 714 | types.add(expected.arguments[i]) | |
| 715 | od | |
| 716 | fi | |
| 717 | ||
| 718 | return types | |
| 719 | si | |
| 720 | ||
| 721 | // A pack nothing else has pinned is what the literal's own | |
| 722 | // parameters say it is: once they have settled, their tuple is | |
| 723 | // offered to the pack the formal names. | |
| 724 | _feed_pack_from_parameters(expected_tuple: Type, closure: Semantic.Symbols.Closure) is | |
| 725 | if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected_tuple then | |
| 726 | if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin /\ origin.is_argument_pack then | |
| 727 | let group_type = closure.arguments[closure.arguments.count - 1] | |
| 728 | ||
| 729 | if group_type.is_settled /\ !_is_origin_settled(origin) then | |
| 730 | _logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_from_parameters", origin, group_type)) | |
| 731 | fi | |
| 732 | fi | |
| 733 | fi | |
| 734 | si | |
| 735 | ||
| 736 | // The same for a parameter the formal takes of its own before the | |
| 737 | // pack, where nothing but the literal says what it is. | |
| 738 | _feed_fixed_from_parameters(expected_type: Type?, closure: Semantic.Symbols.Closure) is | |
| 739 | if !expected_type? \/ !Semantic.ARGUMENT_PACK.is_pack_slot(expected_type) then | |
| 740 | return | |
| 741 | fi | |
| 742 | ||
| 743 | for i in 0..Semantic.ARGUMENT_PACK.fixed_count(expected_type) do | |
| 744 | if i >= closure.arguments.count then | |
| 745 | return | |
| 746 | fi | |
| 747 | ||
| 748 | if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected_type.arguments[i] then | |
| 749 | if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin then | |
| 750 | if closure.arguments[i].is_settled /\ !_is_origin_settled(origin) then | |
| 751 | _logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_fixed_from_parameters", origin, closure.arguments[i])) | |
| 752 | fi | |
| 753 | fi | |
| 754 | fi | |
| 755 | od | |
| 756 | si | |
| 757 | ||
| 758 | _is_origin_settled(origin: Semantic.Symbols.Variable) -> bool is | |
| 759 | let settled = origin.try_get_inferred_type() | |
| 760 | ||
| 761 | return settled? /\ settled.is_settled | |
| 762 | si | |
| 763 | ||
| 764 | visit_function(function: Trees.Expressions.FUNCTION) is | |
| 765 | if !function.value? then | |
| 766 | function.compile_expressions_state.value = IR.Values.WRAPPER() | |
| 767 | fi | |
| 768 | ||
| 769 | let closure = cast Semantic.Symbols.Closure?(_symbol_table.scope_for(function))! | |
| 770 | ||
| 771 | closure.map_type_arguments() | |
| 772 | ||
| 773 | // Every walk of an async closure starts from a fresh | |
| 774 | // state-machine frame: the return type this walk settles on | |
| 775 | // decides the frame's builder and result, and nothing | |
| 776 | // registered against an earlier walk's frame may survive. | |
| 777 | if function.contains_let_await then | |
| 778 | if let state_machine = Semantic.Symbols.async_state_machine_for(closure) then | |
| 779 | if let dropped = state_machine.reset() then | |
| 780 | _composite_spill_state.drop_owned_by(dropped) | |
| 781 | fi | |
| 782 | fi | |
| 783 | fi | |
| 784 | ||
| 785 | let implied_type: Type mut | |
| 786 | let implied_argument_types: Collections.List[Type]? mut = null | |
| 787 | let constraint_return_type: Type? mut = null | |
| 788 | let slot_return_type: Type? mut = null | |
| 789 | ||
| 790 | // have we been passed expected arguments types? If so we'll use them | |
| 791 | // to argument types of any anonymous function literal arguments. | |
| 792 | // Single source of truth: function.expected_type, set by the parent | |
| 793 | // context — LHS of an assignment, typed variable initializer, or | |
| 794 | // overload-resolution second-pass when this lambda was an actual | |
| 795 | // arg whose chosen-formal type is now known (#1174). | |
| 796 | // A context expecting a named delegate constrains the literal | |
| 797 | // exactly as a function type does: the literal is compiled to | |
| 798 | // the delegate's call shape and the delegate itself is | |
| 799 | // constructed at the load site. | |
| 800 | let expected_type: Type? mut = function.expected_type | |
| 801 | ||
| 802 | if let expected = expected_type then | |
| 803 | if !expected.is_function then | |
| 804 | let shape = _delegate_shape.try_get_function_type(expected, _innate_symbol_lookup) | |
| 805 | ||
| 806 | // A delegate is constructed over the literal's own method, | |
| 807 | // which the runtime never checks against the delegate's | |
| 808 | // signature, so a literal of another arity is not the | |
| 809 | // delegate: left as the function it is, it is reported | |
| 810 | // where it fails to fit. | |
| 811 | if shape? then | |
| 812 | expected_type = shape | |
| 813 | ||
| 814 | if Semantic.ARGUMENT_PACK.parameter_count(shape) == function.arguments.count then | |
| 815 | closure.delegate_target_type = expected | |
| 816 | fi | |
| 817 | fi | |
| 818 | fi | |
| 819 | fi | |
| 820 | ||
| 821 | if let effective = expected_type /\ effective.is_function then | |
| 822 | // The slot's types are listed parameters first and return last, | |
| 823 | // so a literal of more parameters than the slot has would, read | |
| 824 | // by position, take the return as a parameter's type. | |
| 825 | let slot_parameters = Collections.LIST[Type]() | |
| 826 | ||
| 827 | for i in 0..Semantic.ARGUMENT_PACK.parameter_count(effective) do | |
| 828 | slot_parameters.add(effective.arguments[i]) | |
| 829 | od | |
| 830 | ||
| 831 | implied_argument_types = slot_parameters | |
| 832 | ||
| 833 | if let | |
| 834 | raw = | |
| 835 | Semantic.SLOT_RETURN_TYPE.of( | |
| 836 | effective, | |
| 837 | _innate_symbol_lookup.get_void_type() | |
| 838 | ) | |
| 839 | then | |
| 840 | // The slot type may embed placeholders whose | |
| 841 | // origins settled on an earlier iteration - | |
| 842 | // collapse them, or the stale composite gets | |
| 843 | // pushed onto the body and committed as the | |
| 844 | // closure's return type every iteration, | |
| 845 | // keeping the retry loop from converging. | |
| 846 | let candidate = Semantic.SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(raw) | |
| 847 | ||
| 848 | slot_return_type = candidate | |
| 849 | ||
| 850 | if Semantic.LAMBDA_RETURN_CONSTRAINT.should_push(candidate, closure) then | |
| 851 | constraint_return_type = candidate | |
| 852 | fi | |
| 853 | fi | |
| 854 | fi | |
| 855 | ||
| 856 | _symbol_table.current_closure_context.add_closure(closure) | |
| 857 | ||
| 858 | // we are walking the arguments here while speculating | |
| 859 | let is_packed = _is_packed_literal(function, expected_type) | |
| 860 | let packed_tuple = _packed_literal_tuple(function, expected_type) | |
| 861 | ||
| 862 | let arguments_resolved = | |
| 863 | if is_packed then | |
| 864 | _closure_arg_resolver.resolve_packed(function.arguments.expressions, closure, packed_tuple, _fixed_parameter_types(expected_type)) | |
| 865 | else | |
| 866 | _closure_arg_resolver.resolve(function.arguments.expressions, closure, implied_argument_types) | |
| 867 | fi | |
| 868 | ||
| 869 | if packed_tuple? /\ arguments_resolved then | |
| 870 | _feed_pack_from_parameters(packed_tuple, closure) | |
| 871 | fi | |
| 872 | ||
| 873 | if is_packed /\ arguments_resolved then | |
| 874 | _feed_fixed_from_parameters(expected_type, closure) | |
| 875 | fi | |
| 876 | ||
| 877 | _resolve_argument_attributes(function, closure) | |
| 878 | ||
| 879 | if arguments_resolved then | |
| 880 | let return_type: Type mut | |
| 881 | ||
| 882 | if function.type_expression.type? then | |
| 883 | return_type = function.type_expression.type | |
| 884 | else | |
| 885 | return_type = Semantic.Types.INFERRED_RETURN_TYPE() | |
| 886 | closure.return_type_was_inferred = true | |
| 887 | fi | |
| 888 | ||
| 889 | // Body contains `await` → the closure returns a | |
| 890 | // task-like. A declared return type names it outright. | |
| 891 | // Otherwise the slot's return type does, when it names | |
| 892 | // one: adopted as-is when settled, and kept as the | |
| 893 | // template the body's value is applied to when its | |
| 894 | // result argument is still to be inferred. With neither, | |
| 895 | // void-async (no value returns) pins to non-generic | |
| 896 | // `Tasks.TASK` and value-async stays | |
| 897 | // INFERRED_RETURN_TYPE, pinning to `Tasks.TASK[T]` via | |
| 898 | // the wrap-paths. | |
| 899 | if function.contains_let_await then | |
| 900 | closure.is_void_async = false | |
| 901 | closure.wrap_inferred_return_as_task = false | |
| 902 | closure.async_task_like_template = null | |
| 903 | ||
| 904 | if function.type_expression.type? then | |
| 905 | let declared = _task_like_resolver.resolve(function.location, return_type) | |
| 906 | ||
| 907 | closure.is_void_async = | |
| 908 | if declared? then declared.is_void_like else function.is_void_async fi | |
| 909 | elif let slot_task_like = _slot_task_like(slot_return_type) then | |
| 910 | if constraint_return_type? /\ constraint_return_type.is_settled then | |
| 911 | return_type = constraint_return_type | |
| 912 | closure.return_type_was_inferred = false | |
| 913 | closure.is_void_async = slot_task_like.is_void_like | |
| 914 | else | |
| 915 | closure.wrap_inferred_return_as_task = true | |
| 916 | closure.async_task_like_template = | |
| 917 | cast Semantic.Symbols.Classy?(slot_task_like.task_type.symbol.unspecialized_symbol) | |
| 918 | fi | |
| 919 | elif function.is_void_async /\ !_body_may_yield_value(function) then | |
| 920 | let void_task = _innate_symbol_lookup.get_void_task_type() | |
| 921 | if void_task? then | |
| 922 | return_type = void_task | |
| 923 | closure.return_type_was_inferred = false | |
| 924 | closure.is_void_async = true | |
| 925 | fi | |
| 926 | else | |
| 927 | closure.wrap_inferred_return_as_task = true | |
| 928 | fi | |
| 929 | elif | |
| 930 | closure.return_type_was_inferred /\ | |
| 931 | constraint_return_type? /\ | |
| 932 | _task_conversion.try_get_task_element_type(constraint_return_type)? | |
| 933 | then | |
| 934 | // Slot expects `Tasks.TASK[T]`; mark the closure | |
| 935 | // so a bare-T body return wraps to | |
| 936 | // `Tasks.TASK.from_result(orig)` via the same | |
| 937 | // inferred-return paths used for async closures. | |
| 938 | closure.wrap_inferred_return_as_task = true | |
| 939 | elif | |
| 940 | closure.return_type_was_inferred /\ | |
| 941 | closure.is_carrier_adapter /\ | |
| 942 | slot_return_type? /\ | |
| 943 | slot_return_type.is_settled /\ | |
| 944 | !slot_return_type.is_void | |
| 945 | then | |
| 946 | // An adapter literal is there to present the slot's | |
| 947 | // shape: its body's own carrier is what the | |
| 948 | // adaptation is coercing away from, so the return is | |
| 949 | // the slot's and the boundary makes the coercion. | |
| 950 | return_type = slot_return_type | |
| 951 | closure.return_type_was_inferred = false | |
| 952 | elif | |
| 953 | closure.return_type_was_inferred /\ | |
| 954 | slot_return_type? /\ | |
| 955 | slot_return_type.is_maybe | |
| 956 | then | |
| 957 | // The slot's `U?` is `MAYBE[U]` whatever U turns out to | |
| 958 | // be, and a `string?` or bare `int` body is not that | |
| 959 | // type: mark the closure so the body's value pins the | |
| 960 | // return as `MAYBE[T]` over itself. | |
| 961 | closure.wrap_inferred_return_as_maybe = true | |
| 962 | elif | |
| 963 | closure.return_type_was_inferred /\ | |
| 964 | slot_return_type? /\ | |
| 965 | slot_return_type.is_void | |
| 966 | then | |
| 967 | // A void slot settles the return the body would | |
| 968 | // otherwise have inferred, so a body producing a | |
| 969 | // value is discarded rather than making the literal | |
| 970 | // the wrong shape for the only formal on offer. | |
| 971 | // This is reached on the constrained re-walk alone - | |
| 972 | // the first walk carries no expected type - so a | |
| 973 | // candidate that wants the body's value is chosen | |
| 974 | // before a void one is ever considered. | |
| 975 | return_type = slot_return_type | |
| 976 | closure.return_type_was_inferred = false | |
| 977 | fi | |
| 978 | ||
| 979 | closure.set_return_type(return_type) | |
| 980 | fi | |
| 981 | ||
| 982 | // Push the constraint's return-type slot onto the body's | |
| 983 | // last expression before walking. The implicit-return path | |
| 984 | // (pre(Bodies.EXPRESSION)) is gated on | |
| 985 | // `!function.return_type.is_sentinel` and skips when the closure | |
| 986 | // hasn't been given an explicit return-type annotation — | |
| 987 | // but that's exactly the case where a bare variant | |
| 988 | // constructor (`DONE()`) in the body would benefit from | |
| 989 | // knowing the expected type. Set it here so the body's | |
| 990 | // CALL nodes see the constraint; without setting | |
| 991 | // closure.return_type, the lambda's emitted return type | |
| 992 | // is still inferred from the body so covariant-return-via- | |
| 993 | // assignment is unaffected. | |
| 994 | if | |
| 995 | constraint_return_type? /\ | |
| 996 | !function.type_expression.type? /\ | |
| 997 | isa Trees.Bodies.EXPRESSION(function.body) | |
| 998 | then | |
| 999 | let body = cast Trees.Bodies.EXPRESSION?(function.body)! | |
| 1000 | ||
| 1001 | body.expression.set_expected_type(constraint_return_type, "cannot return value of type {{0}} where {{1}} expected") | |
| 1002 | fi | |
| 1003 | ||
| 1004 | // A formal that wrote the pack marker past its own function | |
| 1005 | // type asked for the N-ary function this literal returns. The | |
| 1006 | // marker goes on to the value the body evaluates to, one | |
| 1007 | // return nearer, beside whatever type that value is expected | |
| 1008 | // to have; a return written out as the N-ary function the | |
| 1009 | // marker licenses is the literal's in the shape the formal | |
| 1010 | // takes. | |
| 1011 | if function.nested_pack_depth > 0 then | |
| 1012 | if let body: Trees.Bodies.EXPRESSION = function.body then | |
| 1013 | body.expression.set_expects_pack(function.nested_pack_depth - 1) | |
| 1014 | fi | |
| 1015 | ||
| 1016 | _present_declared_return_as_packed(function, function.nested_pack_depth - 1) | |
| 1017 | fi | |
| 1018 | ||
| 1019 | // Implicit tail return, the literal counterpart of the | |
| 1020 | // setup in `visit_function_definition`: a block body's | |
| 1021 | // final statement is a tail candidate, terminated or not, | |
| 1022 | // so the body list is compiled as value-demanding but | |
| 1023 | // void-tolerant and a type-compatible tail's value flows | |
| 1024 | // to the literal's return at IL emission. | |
| 1025 | // | |
| 1026 | // A literal whose return type was written out is judged | |
| 1027 | // exactly as a named function's tail is. One that leaves | |
| 1028 | // the return to be inferred carries the same demand with | |
| 1029 | // nothing to judge against - as the `=> body` path does | |
| 1030 | // for an inferred return - and the statement-list visitor | |
| 1031 | // settles the return from the tail's own type. Either way | |
| 1032 | // a void tail is the statement it is, so a void body may | |
| 1033 | // still end on a guard `if`. | |
| 1034 | if | |
| 1035 | isa Trees.Bodies.BLOCK(function.body) /\ | |
| 1036 | arguments_resolved | |
| 1037 | then | |
| 1038 | let bb = cast Trees.Bodies.BLOCK?(function.body)! | |
| 1039 | ||
| 1040 | if let tail = bb.statements.last, rt = closure.return_type then | |
| 1041 | let return_inferred = rt.is_inferred | |
| 1042 | ||
| 1043 | if | |
| 1044 | tail.provides_value /\ | |
| 1045 | !isa Trees.Statements.TRY(tail) /\ | |
| 1046 | !isa Trees.Statements.LABELLED(tail) /\ | |
| 1047 | !isa Trees.Statements.THROW(tail) /\ | |
| 1048 | !isa Trees.Statements.RETURN(tail) /\ | |
| 1049 | !Semantic.Symbols.state_machine_for(closure)? /\ | |
| 1050 | ( | |
| 1051 | return_inferred \/ | |
| 1052 | ( | |
| 1053 | !rt.is_sentinel /\ | |
| 1054 | !rt.matches(_innate_symbol_lookup.get_void_type()) | |
| 1055 | ) | |
| 1056 | ) | |
| 1057 | then | |
| 1058 | bb.statements.compile_expressions_state.want_value = true | |
| 1059 | bb.statements.compile_expressions_state.void_tolerated = true | |
| 1060 | bb.statements.function_tail = true | |
| 1061 | ||
| 1062 | if !return_inferred then | |
| 1063 | bb.statements.set_expected_type( | |
| 1064 | rt, | |
| 1065 | "cannot return value of type {{0}} where {{1}} expected" | |
| 1066 | ) | |
| 1067 | fi | |
| 1068 | else | |
| 1069 | // A literal walked first with nothing to judge | |
| 1070 | // against, and re-walked once a void slot | |
| 1071 | // settled its return, carries the tail demand | |
| 1072 | // the first walk left behind. Clear it: a void | |
| 1073 | // body has no tail to deliver, and the demand | |
| 1074 | // would judge the tail against the void it is | |
| 1075 | // discarded by. | |
| 1076 | bb.statements.compile_expressions_state.want_value = false | |
| 1077 | bb.statements.compile_expressions_state.void_tolerated = false | |
| 1078 | bb.statements.function_tail = false | |
| 1079 | fi | |
| 1080 | fi | |
| 1081 | fi | |
| 1082 | ||
| 1083 | _logger.commit() | |
| 1084 | _logger.speculate() | |
| 1085 | ||
| 1086 | _symbol_use_locations.commit() | |
| 1087 | _symbol_use_locations.speculate() | |
| 1088 | ||
| 1089 | // Each body re-walk below must start from the narrowing | |
| 1090 | // facts in force at the literal, not the ones the previous | |
| 1091 | // walk recorded: a body ending in `return` leaves the | |
| 1092 | // environment unreachable (a re-walk from there loses every | |
| 1093 | // narrow in the body), and a body that unwraps its own | |
| 1094 | // parameter leaves the recorded presence fact (a re-walk | |
| 1095 | // over it misreports the unwrap redundant). | |
| 1096 | let use flow_speculation = _flow.speculate_then_commit() | |
| 1097 | ||
| 1098 | _walk_literal_body(function, closure) | |
| 1099 | ||
| 1100 | if _expand_deeper_pack_body(function, closure) then | |
| 1101 | let use retry_site = RETRY_SITE_STATS.enter("lambdas.carry_nested_pack", RetrySiteKind.REWALK_WITH_INFORMATION) | |
| 1102 | _logger.roll_back() | |
| 1103 | _logger.speculate() | |
| 1104 | ||
| 1105 | _symbol_use_locations.roll_back() | |
| 1106 | _symbol_use_locations.speculate() | |
| 1107 | ||
| 1108 | _flow.restore() | |
| 1109 | ||
| 1110 | CLEAR_STATE_VISITOR(true, true).apply(function.body) | |
| 1111 | ||
| 1112 | _walk_literal_body(function, closure) | |
| 1113 | fi | |
| 1114 | ||
| 1115 | let reported_inference_failure = false | |
| 1116 | ||
| 1117 | if closure.is_recursive then | |
| 1118 | let use retry_site = RETRY_SITE_STATS.enter("lambdas.recursive_rewalk", RetrySiteKind.REWALK_WITH_INFORMATION) | |
| 1119 | _logger.roll_back() | |
| 1120 | _logger.speculate() | |
| 1121 | ||
| 1122 | _symbol_use_locations.roll_back() | |
| 1123 | _symbol_use_locations.speculate() | |
| 1124 | ||
| 1125 | _flow.restore() | |
| 1126 | ||
| 1127 | _walk_literal_body(function, closure) | |
| 1128 | fi | |
| 1129 | ||
| 1130 | if _build_flags.want_assembler /\ arguments_resolved /\ closure.could_be_delegate then | |
| 1131 | // The roll_back below is for the re-walk's diagnostics, | |
| 1132 | // which stand in for the first walk's: converting to a | |
| 1133 | // delegate changes nothing the body resolves against, so | |
| 1134 | // the two walks normally agree. Where they don't - | |
| 1135 | // typically because something enclosing this closure is | |
| 1136 | // still mid-retry and the second walk runs one step | |
| 1137 | // behind it - the discarded walk still learned something | |
| 1138 | // the retry loop needs to see, or it is simply the more | |
| 1139 | // trustworthy of the two. Keep its progress-and-error | |
| 1140 | // signal regardless of which walk the caller reads | |
| 1141 | // diagnostics from. | |
| 1142 | let use retry_site = RETRY_SITE_STATS.enter("lambdas.convert_to_delegate", RetrySiteKind.ALTERNATIVE) | |
| 1143 | let first_walk_state = _logger.roll_back() | |
| 1144 | ||
| 1145 | _logger.speculate() | |
| 1146 | ||
| 1147 | _symbol_use_locations.roll_back() | |
| 1148 | _symbol_use_locations.speculate() | |
| 1149 | ||
| 1150 | _flow.restore() | |
| 1151 | ||
| 1152 | closure.convert_to_delegate() | |
| 1153 | ||
| 1154 | _walk_literal_body(function, closure) | |
| 1155 | ||
| 1156 | _logger.mark_consumed_any_if(first_walk_state.has_consumed_any) | |
| 1157 | ||
| 1158 | if first_walk_state.has_consumed_error then | |
| 1159 | _logger.mark_consumed_error() | |
| 1160 | fi | |
| 1161 | fi | |
| 1162 | ||
| 1163 | // Default an unresolved return type to void only when the | |
| 1164 | // arguments are *fully* resolved — concrete types, not still | |
| 1165 | // INFERRED_VARIABLE_TYPE placeholders. With placeholder args, | |
| 1166 | // an unresolved return is the symptom of an identity-shaped | |
| 1167 | // body (`a => a`) where the body offered no constraint and | |
| 1168 | // we're depending on the call-site formal-arg-push to | |
| 1169 | // resolve the args on the next outer iteration. Defaulting | |
| 1170 | // the return to void here would lock in `*** -> void` and | |
| 1171 | // poison the overload resolution that follows. | |
| 1172 | if closure.return_type!.is_inferred /\ closure.arguments |> all(a => a.is_settled) then | |
| 1173 | // A body whose tail failed to compile says nothing about what | |
| 1174 | // the literal returns. Settled as void, the literal would | |
| 1175 | // take a shape that a later walk, once the failure clears, | |
| 1176 | // could not displace from a variable it was assigned to. | |
| 1177 | let tail_value = | |
| 1178 | if let block: Trees.Bodies.BLOCK = function.body then | |
| 1179 | block.statements.last?.value | |
| 1180 | elif let expression: Trees.Bodies.EXPRESSION = function.body then | |
| 1181 | expression.expression.value | |
| 1182 | else | |
| 1183 | null | |
| 1184 | fi | |
| 1185 | ||
| 1186 | function.returned_only_null_without_slot = false | |
| 1187 | ||
| 1188 | let null_join = Semantic.ARM_NULL_JOIN() | |
| 1189 | ||
| 1190 | let tail_is_null = | |
| 1191 | if let tail_type = tail_value?.type then | |
| 1192 | null_join.is_genuine_null(tail_type) | |
| 1193 | else | |
| 1194 | false | |
| 1195 | fi | |
| 1196 | ||
| 1197 | if let tail_type = tail_value?.type /\ Semantic.OPERAND_WAIT.is_held_by(tail_type) then | |
| 1198 | // The tail is a rule waiting for an operand the call | |
| 1199 | // site types. Void is the answer for a body that | |
| 1200 | // produced nothing, and this one has not answered yet: | |
| 1201 | // the return stays inferred for the walk that settles | |
| 1202 | // the operand to pin. | |
| 1203 | elif let tail_type = tail_value?.type /\ tail_type.is_error then | |
| 1204 | closure.set_return_type(Semantic.Types.ERROR()) | |
| 1205 | elif | |
| 1206 | let from_slot = _slot_return_type(function) /\ | |
| 1207 | (tail_is_null \/ closure.returned_genuine_null) | |
| 1208 | then | |
| 1209 | // Every value the body produced was null, which says | |
| 1210 | // the return can be absent without saying what it | |
| 1211 | // holds when present. What it is optional of is the | |
| 1212 | // slot's to say; void would be an answer the body | |
| 1213 | // never gave. | |
| 1214 | closure.set_return_type(from_slot) | |
| 1215 | elif closure.returned_genuine_null then | |
| 1216 | // Only null was returned, and with no slot to say | |
| 1217 | // what the return is optional of there is no type to | |
| 1218 | // settle it at. | |
| 1219 | function.returned_only_null_without_slot = true | |
| 1220 | ||
| 1221 | _logger.error(function.location, "cannot infer type here") | |
| 1222 | ||
| 1223 | closure.set_return_type(Semantic.Types.ERROR()) | |
| 1224 | else | |
| 1225 | closure.set_return_type(_innate_symbol_lookup.get_void_type()) | |
| 1226 | ||
| 1227 | // A recursive literal's self-call was compiled during | |
| 1228 | // the body walks above, against a `$recurse` field | |
| 1229 | // typed with the then-unresolved function type, and | |
| 1230 | // the frozen call value keeps that stale composite — | |
| 1231 | // set_return_type refreshes the field, not the IR | |
| 1232 | // already recorded against it. With no value-producing | |
| 1233 | // arm to settle the return mid-walk, this is the only | |
| 1234 | // point the closure's type becomes final, so walk the | |
| 1235 | // body once more to re-record the self-call at the | |
| 1236 | // settled type. | |
| 1237 | if closure.is_recursive then | |
| 1238 | let use retry_site = RETRY_SITE_STATS.enter("lambdas.return_defaulted_recursive_rewalk", RetrySiteKind.REWALK_WITH_INFORMATION) | |
| 1239 | _logger.roll_back() | |
| 1240 | _logger.speculate() | |
| 1241 | ||
| 1242 | _symbol_use_locations.roll_back() | |
| 1243 | _symbol_use_locations.speculate() | |
| 1244 | ||
| 1245 | _flow.restore() | |
| 1246 | ||
| 1247 | _walk_literal_body(function, closure) | |
| 1248 | fi | |
| 1249 | fi | |
| 1250 | fi | |
| 1251 | ||
| 1252 | closure.unmap_type_arguments() | |
| 1253 | ||
| 1254 | let value mut = closure.load(function.location, _symbol_loader) | |
| 1255 | ||
| 1256 | // A literal whose body proved store-free surfaces at the | |
| 1257 | // pure shape of its function type, so it satisfies a pure | |
| 1258 | // function-typed slot on type alone — freezing to raw IL | |
| 1259 | // has discarded the closure symbol by the time the slot | |
| 1260 | // check sees the value. The shape is the literal's own | |
| 1261 | // property, so it does not depend on the slot it is | |
| 1262 | // heading for: a store-free literal reads as pure | |
| 1263 | // wherever its type is shown. | |
| 1264 | if | |
| 1265 | !closure.literal_body_impure /\ value.type? | |
| 1266 | then | |
| 1267 | let pure_type = Semantic.Types.PURE_FUNCTION_SHAPE.pure_shape_of(value.type, _innate_symbol_lookup) | |
| 1268 | ||
| 1269 | if pure_type? then | |
| 1270 | value = IR.Values.TYPE_WRAPPER(pure_type, value) | |
| 1271 | fi | |
| 1272 | fi | |
| 1273 | ||
| 1274 | // The first resolve of a call taking this literal fails on its | |
| 1275 | // arity, and the retry that follows mints a placeholder for | |
| 1276 | // each of the callee's type arguments. Later walks resolve | |
| 1277 | // plainly and never reach the one standing for the formal's | |
| 1278 | // return, so the literal's own settled return is what it is | |
| 1279 | // bounded by - once, since a bound offered on every walk | |
| 1280 | // reads as progress and keeps the body from converging. | |
| 1281 | if closure.packed_parameters? then | |
| 1282 | if let expected = function.expected_type /\ expected.is_function /\ !expected.is_action then | |
| 1283 | if let placeholder: Semantic.Types.INFERRED_VARIABLE_TYPE = expected.arguments[expected.arguments.count - 1] then | |
| 1284 | if let origin: Semantic.Symbols.INFERRED_TYPE_ARG_ORIGIN = placeholder.origin, returned = closure.return_type then | |
| 1285 | if returned.is_settled /\ !returned.is_void /\ !_is_origin_settled(origin) then | |
| 1286 | _logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_lower_bound("lambdas.pack_literal_return", origin, returned)) | |
| 1287 | fi | |
| 1288 | fi | |
| 1289 | fi | |
| 1290 | fi | |
| 1291 | fi | |
| 1292 | ||
| 1293 | cast IR.Values.WRAPPER?(function.value)!.value = value | |
| 1294 | si | |
| 1295 | ||
| 1296 | // visit_function re-runs on every retry of the enclosing | |
| 1297 | // function's body (a lambda literal is re-walked along with | |
| 1298 | // everything else in the body until the retry loop converges), | |
| 1299 | // so guard on custom_attributes already being populated — | |
| 1300 | // otherwise the same attribute would be resolved and appended | |
| 1301 | // again on each retry. | |
| 1302 | _resolve_argument_attributes(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) is | |
| 1303 | for expr in function.arguments.expressions do | |
| 1304 | if let argument: Trees.Expressions.VARIABLE = expr, pragmas = argument.pragmas then | |
| 1305 | // Trees.Expressions.FUNCTION.pre() suppresses the | |
| 1306 | // default child walk (so visit_function can walk | |
| 1307 | // the body up to N times), so nothing else ever | |
| 1308 | // walks a pragma's own argument expressions. | |
| 1309 | for pragma in pragmas do | |
| 1310 | pragma.walk(_visitor) | |
| 1311 | od | |
| 1312 | ||
| 1313 | let symbol = closure.find_direct(argument.name.name) | |
| 1314 | ||
| 1315 | if symbol? /\ !symbol.custom_attributes? then | |
| 1316 | for pragma in pragmas do | |
| 1317 | _attribute_resolver.resolve(pragma, symbol) | |
| 1318 | od | |
| 1319 | fi | |
| 1320 | fi | |
| 1321 | od | |
| 1322 | si | |
| 1323 | ||
| 1324 | // Walk a literal's body with a purity frame in force, so the | |
| 1325 | // flow transfers record whether the body performed anything | |
| 1326 | // possibly heap-visible. Re-walks (recursion, delegate | |
| 1327 | // conversion) overwrite the recorded flag — the last walk is | |
| 1328 | // the one whose compilation stands. | |
| 1329 | _walk_literal_body(function: Trees.Expressions.FUNCTION, closure: Semantic.Symbols.Closure) is | |
| 1330 | _flow.push_literal_frame() | |
| 1331 | ||
| 1332 | closure.enter_literal_body() | |
| 1333 | function.body.walk(_visitor) | |
| 1334 | closure.leave_literal_body() | |
| 1335 | ||
| 1336 | closure.literal_body_impure = _flow.pop_literal_frame() | |
| 1337 | si | |
| 1338 | ||
| 1339 | // A nested named function referring to itself, by its own name. | |
| 1340 | // The name is a local of the enclosing body that nothing assigns | |
| 1341 | // until the definition statement completes, so the value comes | |
| 1342 | // from the closure's recurse field, the same place `rec` reads | |
| 1343 | // it. Returns null for every other reference to the name - | |
| 1344 | // a call from the enclosing body after the definition, or from a | |
| 1345 | // sibling function - which the ordinary local load serves. | |
| 1346 | try_load_self_reference(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol) -> IR.Values.Value? is | |
| 1347 | let stack = _symbol_table.stack | |
| 1348 | let index mut = stack.count - 1 | |
| 1349 | ||
| 1350 | while index >= 0 do | |
| 1351 | let scope = stack[index] | |
| 1352 | ||
| 1353 | if let target: Semantic.Symbols.Closure = scope then | |
| 1354 | if target.self_reference_variable? /\ target.self_reference_variable == symbol then | |
| 1355 | return _load_recurse_from(location, target) | |
| 1356 | fi | |
| 1357 | fi | |
| 1358 | ||
| 1359 | index = index - 1 | |
| 1360 | od | |
| 1361 | ||
| 1362 | return null | |
| 1363 | si | |
| 1364 | ||
| 1365 | // The recurse value for a closure, read from wherever the walk | |
| 1366 | // currently is. Inside that closure's own body it is its recurse | |
| 1367 | // field; from a literal written inside it, the field has to be | |
| 1368 | // threaded down through every frame in between, so each one in | |
| 1369 | // the chain captures it. | |
| 1370 | // | |
| 1371 | // A null target means the nearest recursive ancestor, which is | |
| 1372 | // what `rec` names. A nested named function names one closure in | |
| 1373 | // particular, so it passes that one. | |
| 1374 | _load_recurse_from(location: Source.LOCATION, target: Semantic.Symbols.Closure?) -> IR.Values.Value? is | |
| 1375 | let function = _symbol_table.current_function | |
| 1376 | ||
| 1377 | if !function? \/ !function.is_closure then | |
| 1378 | return null | |
| 1379 | fi | |
| 1380 | ||
| 1381 | let closure = cast Semantic.Symbols.Closure?(function)! | |
| 1382 | ||
| 1383 | let is_target = (candidate: Semantic.Symbols.Closure) -> bool => | |
| 1384 | if let wanted = target then | |
| 1385 | candidate == wanted | |
| 1386 | else | |
| 1387 | candidate.is_recursive | |
| 1388 | fi | |
| 1389 | ||
| 1390 | if is_target(closure) then | |
| 1391 | return closure.load_recurse(location, _symbol_loader) | |
| 1392 | fi | |
| 1393 | ||
| 1394 | let stack = _symbol_table.stack | |
| 1395 | let index mut = stack.count - 1 | |
| 1396 | let seen_self mut = false | |
| 1397 | let intermediates = Collections.LIST[Semantic.Symbols.Closure]() | |
| 1398 | ||
| 1399 | while index >= 0 do | |
| 1400 | let scope = stack[index] | |
| 1401 | ||
| 1402 | if let c: Semantic.Symbols.Closure = scope then | |
| 1403 | if seen_self then | |
| 1404 | if is_target(c) then | |
| 1405 | for intermediate in intermediates do | |
| 1406 | intermediate.find_or_add_captured_outer_recurse(c) | |
| 1407 | od | |
| 1408 | ||
| 1409 | return closure.load_captured_outer_recurse(location, c, _symbol_loader) | |
| 1410 | fi | |
| 1411 | ||
| 1412 | intermediates.add(c) | |
| 1413 | elif c == closure then | |
| 1414 | seen_self = true | |
| 1415 | fi | |
| 1416 | fi | |
| 1417 | ||
| 1418 | index = index - 1 | |
| 1419 | od | |
| 1420 | ||
| 1421 | return null | |
| 1422 | si | |
| 1423 | ||
| 1424 | visit_recurse(recurse: Trees.Expressions.RECURSE) is | |
| 1425 | let function = _symbol_table.current_function | |
| 1426 | ||
| 1427 | if !function? \/ !function.is_closure then | |
| 1428 | recurse.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), recurse.location) | |
| 1429 | ||
| 1430 | _logger.error(recurse.location, "rec can only be used in a function literal body") | |
| 1431 | return | |
| 1432 | fi | |
| 1433 | ||
| 1434 | if let value = _load_recurse_from(recurse.location, null) then | |
| 1435 | recurse.compile_expressions_state.value = value | |
| 1436 | return | |
| 1437 | fi | |
| 1438 | ||
| 1439 | recurse.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), recurse.location) | |
| 1440 | ||
| 1441 | _logger.error(recurse.location, "rec can only be used in a recursive function") | |
| 1442 | si | |
| 1443 | si | |
| 1444 | si |