@@ -1292,6 +1292,8 @@ namespace ts {
1292
1292
let lastLocation: Node | undefined;
1293
1293
let lastSelfReferenceLocation: Node | undefined;
1294
1294
let propertyWithInvalidInitializer: Node | undefined;
1295
+ let associatedDeclarationForContainingInitializer: ParameterDeclaration | BindingElement | undefined;
1296
+ let withinDeferredContext = false;
1295
1297
const errorLocation = location;
1296
1298
let grandparent: Node;
1297
1299
let isInExternalModule = false;
@@ -1352,6 +1354,7 @@ namespace ts {
1352
1354
}
1353
1355
}
1354
1356
}
1357
+ withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation);
1355
1358
switch (location.kind) {
1356
1359
case SyntaxKind.SourceFile:
1357
1360
if (!isExternalOrCommonJsModule(<SourceFile>location)) break;
@@ -1547,6 +1550,19 @@ namespace ts {
1547
1550
// js type aliases do not resolve names from their host, so skip past it
1548
1551
location = getJSDocHost(location);
1549
1552
break;
1553
+ case SyntaxKind.Parameter:
1554
+ if (lastLocation && lastLocation === (location as ParameterDeclaration).initializer) {
1555
+ associatedDeclarationForContainingInitializer = location as ParameterDeclaration;
1556
+ }
1557
+ break;
1558
+ case SyntaxKind.BindingElement:
1559
+ if (lastLocation && lastLocation === (location as BindingElement).initializer) {
1560
+ const root = getRootDeclaration(location);
1561
+ if (root.kind === SyntaxKind.Parameter) {
1562
+ associatedDeclarationForContainingInitializer = location as BindingElement;
1563
+ }
1564
+ }
1565
+ break;
1550
1566
}
1551
1567
if (isSelfReferenceLocation(location)) {
1552
1568
lastSelfReferenceLocation = location;
@@ -1651,10 +1667,42 @@ namespace ts {
1651
1667
errorOrSuggestion(!compilerOptions.allowUmdGlobalAccess, errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name));
1652
1668
}
1653
1669
}
1670
+
1671
+ // If we're in a parameter initializer, we can't reference the values of the parameter whose initializer we're within or parameters to the right
1672
+ if (result && associatedDeclarationForContainingInitializer && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
1673
+ const candidate = getMergedSymbol(getLateBoundSymbol(result));
1674
+ const root = (getRootDeclaration(associatedDeclarationForContainingInitializer) as ParameterDeclaration);
1675
+ // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself
1676
+ if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializer)) {
1677
+ error(errorLocation, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(associatedDeclarationForContainingInitializer.name));
1678
+ }
1679
+ // And it cannot refer to any declarations which come after it
1680
+ else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializer.pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) {
1681
+ error(errorLocation, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializer.name), declarationNameToString(<Identifier>errorLocation));
1682
+ }
1683
+ }
1654
1684
}
1655
1685
return result;
1656
1686
}
1657
1687
1688
+ function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean {
1689
+ if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) {
1690
+ // initializers in instance property declaration of class like entities are executed in constructor and thus deferred
1691
+ return isTypeQueryNode(location) || ((
1692
+ isFunctionLikeDeclaration(location) ||
1693
+ (location.kind === SyntaxKind.PropertyDeclaration && !hasModifier(location, ModifierFlags.Static))
1694
+ ) && (!lastLocation || lastLocation !== (location as FunctionLike | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred
1695
+ }
1696
+ if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) {
1697
+ return false;
1698
+ }
1699
+ // generator functions and async functions are not inlined in control flow when immediately invoked
1700
+ if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasModifier(location, ModifierFlags.Async)) {
1701
+ return true;
1702
+ }
1703
+ return !getImmediatelyInvokedFunctionExpression(location);
1704
+ }
1705
+
1658
1706
function isSelfReferenceLocation(node: Node): boolean {
1659
1707
switch (node.kind) {
1660
1708
case SyntaxKind.FunctionDeclaration:
@@ -26304,74 +26352,6 @@ namespace ts {
26304
26352
}
26305
26353
}
26306
26354
26307
- // Check that a parameter initializer contains no references to parameters declared to the right of itself
26308
- function checkParameterInitializer(node: HasExpressionInitializer): void {
26309
- if (getRootDeclaration(node).kind !== SyntaxKind.Parameter) {
26310
- return;
26311
- }
26312
-
26313
- const func = getContainingFunction(node);
26314
- visit(node.initializer!);
26315
-
26316
- function visit(n: Node): void {
26317
- if (isTypeNode(n) || isDeclarationName(n)) {
26318
- // do not dive in types
26319
- // skip declaration names (i.e. in object literal expressions)
26320
- return;
26321
- }
26322
- if (n.kind === SyntaxKind.PropertyAccessExpression) {
26323
- // skip property names in property access expression
26324
- return visit((<PropertyAccessExpression>n).expression);
26325
- }
26326
- else if (n.kind === SyntaxKind.Identifier) {
26327
- // check FunctionLikeDeclaration.locals (stores parameters\function local variable)
26328
- // if it contains entry with a specified name
26329
- const symbol = resolveName(n, (<Identifier>n).escapedText, SymbolFlags.Value | SymbolFlags.Alias, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false);
26330
- if (!symbol || symbol === unknownSymbol || !symbol.valueDeclaration) {
26331
- return;
26332
- }
26333
- if (symbol.valueDeclaration === node) {
26334
- error(n, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(node.name));
26335
- return;
26336
- }
26337
- // locals map for function contain both parameters and function locals
26338
- // so we need to do a bit of extra work to check if reference is legal
26339
- const enclosingContainer = getEnclosingBlockScopeContainer(symbol.valueDeclaration);
26340
- if (enclosingContainer === func) {
26341
- if (symbol.valueDeclaration.kind === SyntaxKind.Parameter ||
26342
- symbol.valueDeclaration.kind === SyntaxKind.BindingElement) {
26343
- // it is ok to reference parameter in initializer if either
26344
- // - parameter is located strictly on the left of current parameter declaration
26345
- if (symbol.valueDeclaration.pos < node.pos) {
26346
- return;
26347
- }
26348
- // - parameter is wrapped in function-like entity
26349
- if (findAncestor(
26350
- n,
26351
- current => {
26352
- if (current === node.initializer) {
26353
- return "quit";
26354
- }
26355
- return isFunctionLike(current.parent) ||
26356
- // computed property names/initializers in instance property declaration of class like entities
26357
- // are executed in constructor and thus deferred
26358
- (current.parent.kind === SyntaxKind.PropertyDeclaration &&
26359
- !(hasModifier(current.parent, ModifierFlags.Static)) &&
26360
- isClassLike(current.parent.parent));
26361
- })) {
26362
- return;
26363
- }
26364
- // fall through to report error
26365
- }
26366
- error(n, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(node.name), declarationNameToString(<Identifier>n));
26367
- }
26368
- }
26369
- else {
26370
- return forEachChild(n, visit);
26371
- }
26372
- }
26373
- }
26374
-
26375
26355
function convertAutoToAny(type: Type) {
26376
26356
return type === autoType ? anyType : type === autoArrayType ? anyArrayType : type;
26377
26357
}
@@ -26448,7 +26428,6 @@ namespace ts {
26448
26428
else {
26449
26429
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
26450
26430
}
26451
- checkParameterInitializer(node);
26452
26431
}
26453
26432
return;
26454
26433
}
@@ -26465,7 +26444,6 @@ namespace ts {
26465
26444
hasEntries(symbol.exports);
26466
26445
if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
26467
26446
checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(initializer), type, node, initializer, /*headMessage*/ undefined);
26468
- checkParameterInitializer(node);
26469
26447
}
26470
26448
}
26471
26449
if (symbol.declarations.length > 1) {
0 commit comments