|
3 | 3 | * function/lambda lowering and signature collection, and monomorphizing |
4 | 4 | * generic instantiation (bounded by MAX_GENERIC_INSTANCES). */ |
5 | 5 | import * as ts from "../ts7/adapter.js"; |
| 6 | +import { InternalCompilerError } from "../../errors.js"; |
6 | 7 | import type { Lowerer } from "./lowerer.js"; |
7 | 8 | import { lowerGenMethodCall } from "./lower-generators.js"; |
8 | 9 | import { BOOL, CAUGHT, DYN, F64, IrExpr, IrFunction, IrLocal, IrParam, IrStmt, IrType, JSVAL, STRING, SYMBOL_T, SrcLoc, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js"; |
@@ -5502,20 +5503,19 @@ const inliningPredicates = new Set<ts.Symbol>(); |
5502 | 5503 | ); |
5503 | 5504 | } |
5504 | 5505 |
|
5505 | | -/** Nested `function name(...) {...}`: lowered as `const name = <lambda>` |
5506 | | - * at the declaration's statement position (JS hoists function declarations |
5507 | | - * to the top of the enclosing function — calling one before this statement |
5508 | | - * is a compile error here, not a silent divergence). Self-references inside |
5509 | | - * the body lower to `selfRef`, not a capture: a box holding its own |
5510 | | - * closure would be an RC cycle. Reserve the box before lowering the body so |
5511 | | - * mutually recursive declarations can capture each other's live boxes. */ |
| 5506 | +/** Nested `function name(...) {...}` reserves its binding first, then lowers |
| 5507 | + * the lambda and assigns the resulting closure to that binding. The local is |
| 5508 | + * mutable in IR because this two-phase form lets mutually recursive |
| 5509 | + * declarations capture each other's live boxes before either closure is |
| 5510 | + * initialized. Self-references inside the body lower to `selfRef`, not a |
| 5511 | + * capture: a box holding its own closure would be an RC cycle. */ |
5512 | 5512 | export function lowerNestedFunctionDecl(lowerer: Lowerer, stmt: ts.FunctionDeclaration): IrStmt { |
5513 | 5513 | if (!stmt.name) lowerer.unsupported("SC1090", stmt, "anonymous function declarations"); |
5514 | 5514 | const { funcType } = lowerer.lambdaSignature(stmt); |
5515 | | - const local = lowerer.declareLocal(stmt.name, stmt.name.text, funcType, false); |
5516 | | - local.mutable = true; |
| 5515 | + const local = lowerer.declareLocal(stmt.name, stmt.name.text, funcType, true); |
5517 | 5516 | const active = [...lowerer.activeStmtLists].reverse().find((entry) => entry.stmts.includes(stmt)); |
5518 | | - active?.out.push({ kind: "varDecl", localId: local.id, init: null, loc: locOf(stmt) }); |
| 5517 | + if (!active) throw new InternalCompilerError("lowerer bug: nested function has no owning statement list"); |
| 5518 | + active.out.push({ kind: "varDecl", localId: local.id, init: null, loc: locOf(stmt) }); |
5519 | 5519 | const init = lowerer.lowerLambda(stmt); |
5520 | 5520 | return { kind: "assign", localId: local.id, value: init, loc: locOf(stmt) }; |
5521 | 5521 | } |
|
0 commit comments