@@ -1529,6 +1529,63 @@ namespace ts {
15291529 }
15301530 }
15311531
1532+ function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) {
1533+ const target = getEmitScriptTarget(compilerOptions);
1534+ const functionLocation = <FunctionLikeDeclaration>location;
1535+ if (isParameter(lastLocation) && functionLocation.body && result.valueDeclaration.pos >= functionLocation.body.pos && result.valueDeclaration.end <= functionLocation.body.end) {
1536+ // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body
1537+ // - static field in a class expression
1538+ // - optional chaining pre-es2020
1539+ // - nullish coalesce pre-es2020
1540+ // - spread assignment in binding pattern pre-es2017
1541+ if (target >= ScriptTarget.ES2015) {
1542+ const links = getNodeLinks(functionLocation);
1543+ if (links.declarationRequiresScopeChange === undefined) {
1544+ links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false;
1545+ }
1546+ return !links.declarationRequiresScopeChange;
1547+ }
1548+ }
1549+ return false;
1550+
1551+ function requiresScopeChange(node: ParameterDeclaration): boolean {
1552+ return requiresScopeChangeWorker(node.name)
1553+ || !!node.initializer && requiresScopeChangeWorker(node.initializer);
1554+ }
1555+
1556+ function requiresScopeChangeWorker(node: Node): boolean {
1557+ switch (node.kind) {
1558+ case SyntaxKind.ArrowFunction:
1559+ case SyntaxKind.FunctionExpression:
1560+ case SyntaxKind.FunctionDeclaration:
1561+ case SyntaxKind.Constructor:
1562+ // do not descend into these
1563+ return false;
1564+ case SyntaxKind.MethodDeclaration:
1565+ case SyntaxKind.GetAccessor:
1566+ case SyntaxKind.SetAccessor:
1567+ case SyntaxKind.PropertyAssignment:
1568+ return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name);
1569+ case SyntaxKind.PropertyDeclaration:
1570+ // static properties in classes introduce temporary variables
1571+ if (hasStaticModifier(node)) {
1572+ return target < ScriptTarget.ESNext || !compilerOptions.useDefineForClassFields;
1573+ }
1574+ return requiresScopeChangeWorker((node as PropertyDeclaration).name);
1575+ default:
1576+ // null coalesce and optional chain pre-es2020 produce temporary variables
1577+ if (isNullishCoalesce(node) || isOptionalChain(node)) {
1578+ return target < ScriptTarget.ES2020;
1579+ }
1580+ if (isBindingElement(node) && node.dotDotDotToken && isObjectBindingPattern(node.parent)) {
1581+ return target < ScriptTarget.ES2017;
1582+ }
1583+ if (isTypeNode(node)) return false;
1584+ return forEachChild(node, requiresScopeChangeWorker) || false;
1585+ }
1586+ }
1587+ }
1588+
15321589 /**
15331590 * Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and
15341591 * the nameNotFoundMessage argument is not undefined. Returns the resolved symbol, or undefined if no symbol with
@@ -1563,7 +1620,7 @@ namespace ts {
15631620 let lastLocation: Node | undefined;
15641621 let lastSelfReferenceLocation: Node | undefined;
15651622 let propertyWithInvalidInitializer: Node | undefined;
1566- let associatedDeclarationForContainingInitializer : ParameterDeclaration | BindingElement | undefined;
1623+ let associatedDeclarationForContainingInitializerOrBindingName : ParameterDeclaration | BindingElement | undefined;
15671624 let withinDeferredContext = false;
15681625 const errorLocation = location;
15691626 let grandparent: Node;
@@ -1592,9 +1649,7 @@ namespace ts {
15921649 }
15931650 if (meaning & result.flags & SymbolFlags.Variable) {
15941651 // expression inside parameter will lookup as normal variable scope when targeting es2015+
1595- const functionLocation = <FunctionLikeDeclaration>location;
1596- if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) &&
1597- functionLocation.body && result.valueDeclaration.pos >= functionLocation.body.pos && result.valueDeclaration.end <= functionLocation.body.end) {
1652+ if (useOuterVariableScopeInParameter(result, location, lastLocation)) {
15981653 useResult = false;
15991654 }
16001655 else if (result.flags & SymbolFlags.FunctionScopedVariable) {
@@ -1822,15 +1877,21 @@ namespace ts {
18221877 location = getJSDocHost(location);
18231878 break;
18241879 case SyntaxKind.Parameter:
1825- if (lastLocation && lastLocation === (location as ParameterDeclaration).initializer) {
1826- associatedDeclarationForContainingInitializer = location as ParameterDeclaration;
1880+ if (lastLocation && (
1881+ lastLocation === (location as ParameterDeclaration).initializer ||
1882+ lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation))) {
1883+ if (!associatedDeclarationForContainingInitializerOrBindingName) {
1884+ associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration;
1885+ }
18271886 }
18281887 break;
18291888 case SyntaxKind.BindingElement:
1830- if (lastLocation && lastLocation === (location as BindingElement).initializer) {
1889+ if (lastLocation && (
1890+ lastLocation === (location as BindingElement).initializer ||
1891+ lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation))) {
18311892 const root = getRootDeclaration(location);
18321893 if (root.kind === SyntaxKind.Parameter) {
1833- associatedDeclarationForContainingInitializer = location as BindingElement;
1894+ associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement;
18341895 }
18351896 }
18361897 break;
@@ -1941,17 +2002,17 @@ namespace ts {
19412002 }
19422003 }
19432004
1944- // 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
1945- if (result && associatedDeclarationForContainingInitializer && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
2005+ // If we're in a parameter initializer or binding name , we can't reference the values of the parameter whose initializer we're within or parameters to the right
2006+ if (result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
19462007 const candidate = getMergedSymbol(getLateBoundSymbol(result));
1947- const root = (getRootDeclaration(associatedDeclarationForContainingInitializer ) as ParameterDeclaration);
2008+ const root = (getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName ) as ParameterDeclaration);
19482009 // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself
1949- if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializer )) {
1950- error(errorLocation, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer , declarationNameToString(associatedDeclarationForContainingInitializer .name));
2010+ if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializerOrBindingName )) {
2011+ error(errorLocation, Diagnostics.Parameter_0_cannot_reference_itself , declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName .name));
19512012 }
19522013 // And it cannot refer to any declarations which come after it
1953- else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializer .pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) {
1954- error(errorLocation, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it , declarationNameToString(associatedDeclarationForContainingInitializer .name), declarationNameToString(<Identifier>errorLocation));
2014+ else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializerOrBindingName .pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) {
2015+ error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it , declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName .name), declarationNameToString(<Identifier>errorLocation));
19552016 }
19562017 }
19572018 if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias) {
0 commit comments