Skip to content

Commit 8379613

Browse files
committed
Fix closure capture for default parameter values
Ensure that default values of function parameters are scanned for variable captures before parameter names are added to the inner function scope. This fixes issues where closures in default parameter expressions could not capture outer variables. Adds new tests for closures in default parameter values.
1 parent 17e08b1 commit 8379613

File tree

4 files changed

+673
-111
lines changed

4 files changed

+673
-111
lines changed

src/compiler.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7719,6 +7719,13 @@ export class Compiler extends DiagnosticEmitter {
77197719
let funcExpr = <FunctionExpression>node;
77207720
let decl = funcExpr.declaration;
77217721
let params = decl.signature.parameters;
7722+
// Scan parameter default values for captures (before adding params to inner names)
7723+
for (let i = 0, k = params.length; i < k; i++) {
7724+
let paramInit = params[i].initializer;
7725+
if (paramInit) {
7726+
this.scanNodeForCaptures(paramInit, outerFlow, innerFunctionNames, captures);
7727+
}
7728+
}
77227729
for (let i = 0, k = params.length; i < k; i++) {
77237730
innerFunctionNames.add(params[i].name.text);
77247731
}
@@ -7940,8 +7947,16 @@ export class Compiler extends DiagnosticEmitter {
79407947
let captures = new Map<Local, i32>();
79417948
let innerFunctionNames = new Set<string>();
79427949

7943-
// Add the function's own parameters to the inner names set
7950+
// Scan parameter default values for captures (before adding params to inner names)
79447951
let params = declaration.signature.parameters;
7952+
for (let i = 0, k = params.length; i < k; i++) {
7953+
let paramInit = params[i].initializer;
7954+
if (paramInit) {
7955+
this.scanNodeForCaptures(paramInit, outerFlow, innerFunctionNames, captures);
7956+
}
7957+
}
7958+
7959+
// Add the function's own parameters to the inner names set
79457960
for (let i = 0, k = params.length; i < k; i++) {
79467961
innerFunctionNames.add(params[i].name.text);
79477962
}
@@ -8415,8 +8430,9 @@ export class Compiler extends DiagnosticEmitter {
84158430
case NodeKind.Empty:
84168431
break;
84178432

8418-
// Class expression - scan members would be complex, but class expressions with closures are rare
8433+
// Class expressions are not supported (will error during compilation)
84198434
case NodeKind.Class:
8435+
// Constructor keyword - not a capturable expression
84208436
case NodeKind.Constructor:
84218437
break;
84228438

@@ -8473,8 +8489,16 @@ export class Compiler extends DiagnosticEmitter {
84738489
let capturedNames = new Map<string, null>();
84748490
let innerFunctionNames = new Set<string>();
84758491

8476-
// Add the function's own parameters to the inner names set
8492+
// Scan parameter default values for captures (before adding params to inner names)
84778493
let params = declaration.signature.parameters;
8494+
for (let i = 0, k = params.length; i < k; i++) {
8495+
let paramInit = params[i].initializer;
8496+
if (paramInit) {
8497+
this.collectCapturedNames(paramInit, innerFunctionNames, outerFlow, declaredVars, capturedNames);
8498+
}
8499+
}
8500+
8501+
// Add the function's own parameters to the inner names set
84788502
for (let i = 0, k = params.length; i < k; i++) {
84798503
innerFunctionNames.add(params[i].name.text);
84808504
}
@@ -8639,6 +8663,13 @@ export class Compiler extends DiagnosticEmitter {
86398663
let funcExpr = <FunctionExpression>node;
86408664
let decl = funcExpr.declaration;
86418665
let params = decl.signature.parameters;
8666+
// Scan parameter default values for captures (before adding params to inner names)
8667+
for (let i = 0, k = params.length; i < k; i++) {
8668+
let paramInit = params[i].initializer;
8669+
if (paramInit) {
8670+
this.collectCapturedNames(paramInit, innerFunctionNames, outerFlow, declaredVars, capturedNames);
8671+
}
8672+
}
86428673
// Add the nested function's params to inner names
86438674
for (let i = 0, k = params.length; i < k; i++) {
86448675
innerFunctionNames.add(params[i].name.text);
@@ -8788,8 +8819,9 @@ export class Compiler extends DiagnosticEmitter {
87888819
case NodeKind.Empty:
87898820
break;
87908821

8791-
// Class expression - would need to scan members, but rare in closure context
8822+
// Class expressions are not supported (will error during compilation)
87928823
case NodeKind.Class:
8824+
// Constructor keyword - not a capturable expression
87938825
case NodeKind.Constructor:
87948826
break;
87958827

0 commit comments

Comments
 (0)