mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-03 07:54:40 +08:00
Lower each closure argument of an implicit-any call once (#2150)
This commit is contained in:
@@ -2082,6 +2082,10 @@ function storedImplicitArgumentType(lowerer: Lowerer, arg: ts.Expression): IrTyp
|
||||
isJsSourceFile(ts.getSourceFileOfNode(arg)) &&
|
||||
(ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))
|
||||
) {
|
||||
// A closure lowered here before (another call site's instance key, or
|
||||
// a repeated demand) keeps its value for the argument's own lowering.
|
||||
const known = lowerer.speculatedClosure(arg);
|
||||
if (known !== null) return known.type;
|
||||
const saved = lowerer.diagSink;
|
||||
const diagnostics: typeof lowerer.diags = [];
|
||||
lowerer.diagSink = diagnostics;
|
||||
@@ -2092,8 +2096,17 @@ function storedImplicitArgumentType(lowerer: Lowerer, arg: ts.Expression): IrTyp
|
||||
lowerer.diagSink = saved;
|
||||
}
|
||||
// Direct inferred helpers can receive native callbacks even when their
|
||||
// result is an opaque handle that cannot cross checked storage.
|
||||
if (diagnostics.length === 0 && value?.type.kind === "func") return value.type;
|
||||
// result is an opaque handle that cannot cross checked storage. The
|
||||
// argument's own lowering then takes this value instead of lowering
|
||||
// the closure a second time.
|
||||
if (diagnostics.length === 0 && value?.type.kind === "func") {
|
||||
lowerer.speculatedClosures.set(arg, {
|
||||
ctx: lowerer.ctx,
|
||||
bindings: lowerer.typeParamBindings,
|
||||
value,
|
||||
});
|
||||
return value.type;
|
||||
}
|
||||
}
|
||||
if (arg.kind === ts.SyntaxKind.ThisKeyword) return lowerer.resolveThis()?.type ?? null;
|
||||
if (ts.isAwaitExpression(arg)) {
|
||||
|
||||
@@ -3178,6 +3178,14 @@ export class Lowerer {
|
||||
* (builtins/fs-paths.ts): each lowers to the hidden local that holds its
|
||||
* value, which is null until the path's lowering has saved it. */
|
||||
readonly stagedArguments = new Map<ts.Expression, { localId: string; type: IrType } | null>();
|
||||
/** Closure arguments an implicit-any call already lowered to learn their
|
||||
* type (storedImplicitArgumentType), by node: the argument's own lowering
|
||||
* in the same function and with the same type bindings takes that value
|
||||
* once instead of lowering the closure again. */
|
||||
readonly speculatedClosures = new Map<
|
||||
ts.Expression,
|
||||
{ ctx: FnCtx; bindings: Map<ts.Symbol, IrType> | null; value: IrExpr }
|
||||
>();
|
||||
/** What each fs path argument of a URL-path call lowers to (the plans
|
||||
* of builtins/fs-paths.ts). */
|
||||
readonly fsPathPlans = new Map<ts.Expression, FsPathPlan>();
|
||||
@@ -12946,12 +12954,30 @@ export class Lowerer {
|
||||
/* ── expressions ──────────────────────────────────────────────────── */
|
||||
|
||||
lowerExpr(expr: ts.Expression): IrExpr {
|
||||
if (this.speculatedClosures.size > 0) {
|
||||
const speculated = this.speculatedClosure(expr);
|
||||
if (speculated !== null) {
|
||||
this.speculatedClosures.delete(expr);
|
||||
return speculated;
|
||||
}
|
||||
}
|
||||
const streamValue = this.valueStreamReceivers.get(expr);
|
||||
if (streamValue)
|
||||
return valueStreamOf(varRef(streamValue.localId, streamValue.type, locOf(expr)));
|
||||
return this.stagedArgument(expr) ?? lowerExpr(this, expr);
|
||||
}
|
||||
|
||||
/** The value storedImplicitArgumentType lowered for `expr` in the active
|
||||
* function and type bindings (speculatedClosures), or null. */
|
||||
speculatedClosure(expr: ts.Expression): IrExpr | null {
|
||||
const entry = this.speculatedClosures.get(expr);
|
||||
return entry !== undefined &&
|
||||
entry.ctx === this.ctx &&
|
||||
entry.bindings === this.typeParamBindings
|
||||
? entry.value
|
||||
: null;
|
||||
}
|
||||
|
||||
/** The saved value of a staged fs argument (stagedArguments, keyed
|
||||
* without type-only wrappers), or null for every other expression. */
|
||||
private stagedArgument(node: ts.Expression): IrExpr | null {
|
||||
|
||||
Reference in New Issue
Block a user