From b02b823f0333a58544f18c733f79a997ccab9e93 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 23 Apr 2019 13:46:19 -0700 Subject: [PATCH] Track parameter references errors in resolve name rather than secondary pass (#30349) --- src/compiler/checker.ts | 118 +++++++----------- ...pturedParametersInInitializers1.errors.txt | 52 ++++++++ .../capturedParametersInInitializers1.js | 76 ++++++++--- .../capturedParametersInInitializers1.symbols | 51 ++++++++ .../capturedParametersInInitializers1.types | 73 +++++++++++ ...pturedParametersInInitializers2.errors.txt | 28 ++++- .../capturedParametersInInitializers2.js | 21 +++- .../capturedParametersInInitializers2.symbols | 52 +++++--- .../capturedParametersInInitializers2.types | 31 ++++- ...ctionLikeInParameterInitializer.errors.txt | 34 ----- ...InitializersForwardReferencing1.errors.txt | 5 +- .../capturedParametersInInitializers1.ts | 27 +++- .../capturedParametersInInitializers2.ts | 12 +- 13 files changed, 430 insertions(+), 150 deletions(-) create mode 100644 tests/baselines/reference/capturedParametersInInitializers1.errors.txt delete mode 100644 tests/baselines/reference/functionLikeInParameterInitializer.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3851c031429..df3f9fc624f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1292,6 +1292,8 @@ namespace ts { let lastLocation: Node | undefined; let lastSelfReferenceLocation: Node | undefined; let propertyWithInvalidInitializer: Node | undefined; + let associatedDeclarationForContainingInitializer: ParameterDeclaration | BindingElement | undefined; + let withinDeferredContext = false; const errorLocation = location; let grandparent: Node; let isInExternalModule = false; @@ -1352,6 +1354,7 @@ namespace ts { } } } + withinDeferredContext = withinDeferredContext || getIsDeferredContext(location, lastLocation); switch (location.kind) { case SyntaxKind.SourceFile: if (!isExternalOrCommonJsModule(location)) break; @@ -1547,6 +1550,19 @@ namespace ts { // js type aliases do not resolve names from their host, so skip past it location = getJSDocHost(location); break; + case SyntaxKind.Parameter: + if (lastLocation && lastLocation === (location as ParameterDeclaration).initializer) { + associatedDeclarationForContainingInitializer = location as ParameterDeclaration; + } + break; + case SyntaxKind.BindingElement: + if (lastLocation && lastLocation === (location as BindingElement).initializer) { + const root = getRootDeclaration(location); + if (root.kind === SyntaxKind.Parameter) { + associatedDeclarationForContainingInitializer = location as BindingElement; + } + } + break; } if (isSelfReferenceLocation(location)) { lastSelfReferenceLocation = location; @@ -1651,10 +1667,42 @@ namespace ts { 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)); } } + + // 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 + if (result && associatedDeclarationForContainingInitializer && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { + const candidate = getMergedSymbol(getLateBoundSymbol(result)); + const root = (getRootDeclaration(associatedDeclarationForContainingInitializer) as ParameterDeclaration); + // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself + if (candidate === getSymbolOfNode(associatedDeclarationForContainingInitializer)) { + error(errorLocation, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(associatedDeclarationForContainingInitializer.name)); + } + // And it cannot refer to any declarations which come after it + else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializer.pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) { + error(errorLocation, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializer.name), declarationNameToString(errorLocation)); + } + } } return result; } + function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean { + if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { + // initializers in instance property declaration of class like entities are executed in constructor and thus deferred + return isTypeQueryNode(location) || (( + isFunctionLikeDeclaration(location) || + (location.kind === SyntaxKind.PropertyDeclaration && !hasModifier(location, ModifierFlags.Static)) + ) && (!lastLocation || lastLocation !== (location as FunctionLike | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred + } + if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { + return false; + } + // generator functions and async functions are not inlined in control flow when immediately invoked + if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasModifier(location, ModifierFlags.Async)) { + return true; + } + return !getImmediatelyInvokedFunctionExpression(location); + } + function isSelfReferenceLocation(node: Node): boolean { switch (node.kind) { case SyntaxKind.FunctionDeclaration: @@ -26304,74 +26352,6 @@ namespace ts { } } - // Check that a parameter initializer contains no references to parameters declared to the right of itself - function checkParameterInitializer(node: HasExpressionInitializer): void { - if (getRootDeclaration(node).kind !== SyntaxKind.Parameter) { - return; - } - - const func = getContainingFunction(node); - visit(node.initializer!); - - function visit(n: Node): void { - if (isTypeNode(n) || isDeclarationName(n)) { - // do not dive in types - // skip declaration names (i.e. in object literal expressions) - return; - } - if (n.kind === SyntaxKind.PropertyAccessExpression) { - // skip property names in property access expression - return visit((n).expression); - } - else if (n.kind === SyntaxKind.Identifier) { - // check FunctionLikeDeclaration.locals (stores parameters\function local variable) - // if it contains entry with a specified name - const symbol = resolveName(n, (n).escapedText, SymbolFlags.Value | SymbolFlags.Alias, /*nameNotFoundMessage*/undefined, /*nameArg*/undefined, /*isUse*/ false); - if (!symbol || symbol === unknownSymbol || !symbol.valueDeclaration) { - return; - } - if (symbol.valueDeclaration === node) { - error(n, Diagnostics.Parameter_0_cannot_be_referenced_in_its_initializer, declarationNameToString(node.name)); - return; - } - // locals map for function contain both parameters and function locals - // so we need to do a bit of extra work to check if reference is legal - const enclosingContainer = getEnclosingBlockScopeContainer(symbol.valueDeclaration); - if (enclosingContainer === func) { - if (symbol.valueDeclaration.kind === SyntaxKind.Parameter || - symbol.valueDeclaration.kind === SyntaxKind.BindingElement) { - // it is ok to reference parameter in initializer if either - // - parameter is located strictly on the left of current parameter declaration - if (symbol.valueDeclaration.pos < node.pos) { - return; - } - // - parameter is wrapped in function-like entity - if (findAncestor( - n, - current => { - if (current === node.initializer) { - return "quit"; - } - return isFunctionLike(current.parent) || - // computed property names/initializers in instance property declaration of class like entities - // are executed in constructor and thus deferred - (current.parent.kind === SyntaxKind.PropertyDeclaration && - !(hasModifier(current.parent, ModifierFlags.Static)) && - isClassLike(current.parent.parent)); - })) { - return; - } - // fall through to report error - } - error(n, Diagnostics.Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(node.name), declarationNameToString(n)); - } - } - else { - return forEachChild(n, visit); - } - } - } - function convertAutoToAny(type: Type) { return type === autoType ? anyType : type === autoArrayType ? anyArrayType : type; } @@ -26448,7 +26428,6 @@ namespace ts { else { checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); } - checkParameterInitializer(node); } return; } @@ -26465,7 +26444,6 @@ namespace ts { hasEntries(symbol.exports); if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(initializer), type, node, initializer, /*headMessage*/ undefined); - checkParameterInitializer(node); } } if (symbol.declarations.length > 1) { diff --git a/tests/baselines/reference/capturedParametersInInitializers1.errors.txt b/tests/baselines/reference/capturedParametersInInitializers1.errors.txt new file mode 100644 index 00000000000..fce7c6ee488 --- /dev/null +++ b/tests/baselines/reference/capturedParametersInInitializers1.errors.txt @@ -0,0 +1,52 @@ +tests/cases/compiler/capturedParametersInInitializers1.ts(18,20): error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. +tests/cases/compiler/capturedParametersInInitializers1.ts(22,26): error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. +tests/cases/compiler/capturedParametersInInitializers1.ts(38,21): error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. + + +==== tests/cases/compiler/capturedParametersInInitializers1.ts (3 errors) ==== + // ok - usage is deferred + function foo1(y = class {c = x}, x = 1) { + new y().c; + } + + // ok - used in file + function foo2(y = function(x: typeof z) {}, z = 1) { + + } + + // ok -used in type + let a; + function foo3(y = { x: a }, z = 1) { + + } + + // error - used before declaration + function foo4(y = {z}, z = 1) { + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. + } + + // error - used before declaration, IIFEs are inlined + function foo5(y = (() => z)(), z = 1) { + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. + } + + // ok - IIFE inside another function + function foo6(y = () => (() => z)(), z = 1) { + } + + // ok - used inside immediately invoked generator function + function foo7(y = (function*() {yield z})(), z = 1) { + } + + // ok - used inside immediately invoked async function + function foo8(y = (async () => z)(), z = 1) { + } + + // error - used as computed name of method + function foo9(y = {[z]() { return z; }}, z = 1) { + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. + } + \ No newline at end of file diff --git a/tests/baselines/reference/capturedParametersInInitializers1.js b/tests/baselines/reference/capturedParametersInInitializers1.js index 49b031e8b19..7ec393e2e39 100644 --- a/tests/baselines/reference/capturedParametersInInitializers1.js +++ b/tests/baselines/reference/capturedParametersInInitializers1.js @@ -13,28 +13,72 @@ function foo2(y = function(x: typeof z) {}, z = 1) { let a; function foo3(y = { x: a }, z = 1) { -} +} + +// error - used before declaration +function foo4(y = {z}, z = 1) { +} + +// error - used before declaration, IIFEs are inlined +function foo5(y = (() => z)(), z = 1) { +} + +// ok - IIFE inside another function +function foo6(y = () => (() => z)(), z = 1) { +} + +// ok - used inside immediately invoked generator function +function foo7(y = (function*() {yield z})(), z = 1) { +} + +// ok - used inside immediately invoked async function +function foo8(y = (async () => z)(), z = 1) { +} + +// error - used as computed name of method +function foo9(y = {[z]() { return z; }}, z = 1) { +} + //// [capturedParametersInInitializers1.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; // ok - usage is deferred -function foo1(y, x) { - if (y === void 0) { y = /** @class */ (function () { - function class_1() { - this.c = x; - } - return class_1; - }()); } - if (x === void 0) { x = 1; } +function foo1(y = class { + constructor() { + this.c = x; + } +}, x = 1) { new y().c; } // ok - used in file -function foo2(y, z) { - if (y === void 0) { y = function (x) { }; } - if (z === void 0) { z = 1; } +function foo2(y = function (x) { }, z = 1) { } // ok -used in type -var a; -function foo3(y, z) { - if (y === void 0) { y = { x: a }; } - if (z === void 0) { z = 1; } +let a; +function foo3(y = { x: a }, z = 1) { +} +// error - used before declaration +function foo4(y = { z }, z = 1) { +} +// error - used before declaration, IIFEs are inlined +function foo5(y = (() => z)(), z = 1) { +} +// ok - IIFE inside another function +function foo6(y = () => (() => z)(), z = 1) { +} +// ok - used inside immediately invoked generator function +function foo7(y = (function* () { yield z; })(), z = 1) { +} +// ok - used inside immediately invoked async function +function foo8(y = (() => __awaiter(this, void 0, void 0, function* () { return z; }))(), z = 1) { +} +// error - used as computed name of method +function foo9(y = { [z]() { return z; } }, z = 1) { } diff --git a/tests/baselines/reference/capturedParametersInInitializers1.symbols b/tests/baselines/reference/capturedParametersInInitializers1.symbols index b72a2c75ef1..d9ab1ef6cc2 100644 --- a/tests/baselines/reference/capturedParametersInInitializers1.symbols +++ b/tests/baselines/reference/capturedParametersInInitializers1.symbols @@ -36,3 +36,54 @@ function foo3(y = { x: a }, z = 1) { >z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 12, 37)) } + +// error - used before declaration +function foo4(y = {z}, z = 1) { +>foo4 : Symbol(foo4, Decl(capturedParametersInInitializers1.ts, 14, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 17, 14)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 17, 19)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 17, 22)) +} + +// error - used before declaration, IIFEs are inlined +function foo5(y = (() => z)(), z = 1) { +>foo5 : Symbol(foo5, Decl(capturedParametersInInitializers1.ts, 18, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 21, 14)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 21, 30)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 21, 30)) +} + +// ok - IIFE inside another function +function foo6(y = () => (() => z)(), z = 1) { +>foo6 : Symbol(foo6, Decl(capturedParametersInInitializers1.ts, 22, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 25, 14)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 25, 36)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 25, 36)) +} + +// ok - used inside immediately invoked generator function +function foo7(y = (function*() {yield z})(), z = 1) { +>foo7 : Symbol(foo7, Decl(capturedParametersInInitializers1.ts, 26, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 29, 14)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 29, 44)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 29, 44)) +} + +// ok - used inside immediately invoked async function +function foo8(y = (async () => z)(), z = 1) { +>foo8 : Symbol(foo8, Decl(capturedParametersInInitializers1.ts, 30, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 33, 14)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 33, 36)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 33, 36)) +} + +// error - used as computed name of method +function foo9(y = {[z]() { return z; }}, z = 1) { +>foo9 : Symbol(foo9, Decl(capturedParametersInInitializers1.ts, 34, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers1.ts, 37, 14)) +>[z] : Symbol([z], Decl(capturedParametersInInitializers1.ts, 37, 19)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 37, 40)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 37, 40)) +>z : Symbol(z, Decl(capturedParametersInInitializers1.ts, 37, 40)) +} + diff --git a/tests/baselines/reference/capturedParametersInInitializers1.types b/tests/baselines/reference/capturedParametersInInitializers1.types index 9e5dee1b82e..4819298d1af 100644 --- a/tests/baselines/reference/capturedParametersInInitializers1.types +++ b/tests/baselines/reference/capturedParametersInInitializers1.types @@ -44,3 +44,76 @@ function foo3(y = { x: a }, z = 1) { >1 : 1 } + +// error - used before declaration +function foo4(y = {z}, z = 1) { +>foo4 : (y?: { z: number; }, z?: number) => void +>y : { z: number; } +>{z} : { z: number; } +>z : number +>z : number +>1 : 1 +} + +// error - used before declaration, IIFEs are inlined +function foo5(y = (() => z)(), z = 1) { +>foo5 : (y?: number, z?: number) => void +>y : number +>(() => z)() : number +>(() => z) : () => number +>() => z : () => number +>z : number +>z : number +>1 : 1 +} + +// ok - IIFE inside another function +function foo6(y = () => (() => z)(), z = 1) { +>foo6 : (y?: () => number, z?: number) => void +>y : () => number +>() => (() => z)() : () => number +>(() => z)() : number +>(() => z) : () => number +>() => z : () => number +>z : number +>z : number +>1 : 1 +} + +// ok - used inside immediately invoked generator function +function foo7(y = (function*() {yield z})(), z = 1) { +>foo7 : (y?: IterableIterator, z?: number) => void +>y : IterableIterator +>(function*() {yield z})() : IterableIterator +>(function*() {yield z}) : () => IterableIterator +>function*() {yield z} : () => IterableIterator +>yield z : any +>z : number +>z : number +>1 : 1 +} + +// ok - used inside immediately invoked async function +function foo8(y = (async () => z)(), z = 1) { +>foo8 : (y?: Promise, z?: number) => void +>y : Promise +>(async () => z)() : Promise +>(async () => z) : () => Promise +>async () => z : () => Promise +>z : number +>z : number +>1 : 1 +} + +// error - used as computed name of method +function foo9(y = {[z]() { return z; }}, z = 1) { +>foo9 : (y?: { [x: number]: () => number; }, z?: number) => void +>y : { [x: number]: () => number; } +>{[z]() { return z; }} : { [x: number]: () => number; } +>[z] : () => number +>z : number +>z : number +>z : number +>1 : 1 +} + diff --git a/tests/baselines/reference/capturedParametersInInitializers2.errors.txt b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt index 70435b77cee..df6c71f544b 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.errors.txt +++ b/tests/baselines/reference/capturedParametersInInitializers2.errors.txt @@ -1,14 +1,32 @@ -tests/cases/compiler/capturedParametersInInitializers2.ts(1,36): error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. -tests/cases/compiler/capturedParametersInInitializers2.ts(4,26): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type. +tests/cases/compiler/capturedParametersInInitializers2.ts(3,20): error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. +tests/cases/compiler/capturedParametersInInitializers2.ts(4,14): error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. +tests/cases/compiler/capturedParametersInInitializers2.ts(6,10): error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. +tests/cases/compiler/capturedParametersInInitializers2.ts(13,26): error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type. +tests/cases/compiler/capturedParametersInInitializers2.ts(13,27): error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. -==== tests/cases/compiler/capturedParametersInInitializers2.ts (2 errors) ==== - function foo(y = class {static c = x}, x = 1) { - ~ +==== tests/cases/compiler/capturedParametersInInitializers2.ts (5 errors) ==== + function foo( + y = class { + static c = x; + ~ !!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. + get [x]() {return x;} + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. + constructor() { x; } + [z]() { return z; } + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'z' declared after it. + }, + x = 1, + z = 2 + ) { y.c } function foo2(y = class {[x] = x}, x = 1) { ~~~ !!! error TS1166: A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type. + ~ +!!! error TS2373: Initializer of parameter 'y' cannot reference identifier 'x' declared after it. } \ No newline at end of file diff --git a/tests/baselines/reference/capturedParametersInInitializers2.js b/tests/baselines/reference/capturedParametersInInitializers2.js index 5b5f06fc5b0..26b01dbab9a 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.js +++ b/tests/baselines/reference/capturedParametersInInitializers2.js @@ -1,20 +1,37 @@ //// [capturedParametersInInitializers2.ts] -function foo(y = class {static c = x}, x = 1) { +function foo( + y = class { + static c = x; + get [x]() {return x;} + constructor() { x; } + [z]() { return z; } + }, + x = 1, + z = 2 +) { y.c } function foo2(y = class {[x] = x}, x = 1) { } //// [capturedParametersInInitializers2.js] -function foo(y, x) { +function foo(y, x, z) { if (y === void 0) { y = (_a = /** @class */ (function () { function class_1() { + x; } + Object.defineProperty(class_1.prototype, x, { + get: function () { return x; }, + enumerable: true, + configurable: true + }); + class_1.prototype[z] = function () { return z; }; return class_1; }()), _a.c = x, _a); } if (x === void 0) { x = 1; } + if (z === void 0) { z = 2; } var _a; y.c; } diff --git a/tests/baselines/reference/capturedParametersInInitializers2.symbols b/tests/baselines/reference/capturedParametersInInitializers2.symbols index 9de6714868d..e3cf3a07dff 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.symbols +++ b/tests/baselines/reference/capturedParametersInInitializers2.symbols @@ -1,21 +1,45 @@ === tests/cases/compiler/capturedParametersInInitializers2.ts === -function foo(y = class {static c = x}, x = 1) { +function foo( >foo : Symbol(foo, Decl(capturedParametersInInitializers2.ts, 0, 0)) ->y : Symbol(y, Decl(capturedParametersInInitializers2.ts, 0, 13)) ->c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 0, 24)) ->x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 0, 38)) ->x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 0, 38)) - y.c ->y.c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 0, 24)) + y = class { >y : Symbol(y, Decl(capturedParametersInInitializers2.ts, 0, 13)) ->c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 0, 24)) + + static c = x; +>c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 1, 15)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 6, 6)) + + get [x]() {return x;} +>[x] : Symbol((Anonymous class)[x], Decl(capturedParametersInInitializers2.ts, 2, 21)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 6, 6)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 6, 6)) + + constructor() { x; } +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 6, 6)) + + [z]() { return z; } +>[z] : Symbol((Anonymous class)[z], Decl(capturedParametersInInitializers2.ts, 4, 28)) +>z : Symbol(z, Decl(capturedParametersInInitializers2.ts, 7, 10)) +>z : Symbol(z, Decl(capturedParametersInInitializers2.ts, 7, 10)) + + }, + x = 1, +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 6, 6)) + + z = 2 +>z : Symbol(z, Decl(capturedParametersInInitializers2.ts, 7, 10)) + +) { + y.c +>y.c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 1, 15)) +>y : Symbol(y, Decl(capturedParametersInInitializers2.ts, 0, 13)) +>c : Symbol((Anonymous class).c, Decl(capturedParametersInInitializers2.ts, 1, 15)) } function foo2(y = class {[x] = x}, x = 1) { ->foo2 : Symbol(foo2, Decl(capturedParametersInInitializers2.ts, 2, 1)) ->y : Symbol(y, Decl(capturedParametersInInitializers2.ts, 3, 14)) ->[x] : Symbol((Anonymous class)[x], Decl(capturedParametersInInitializers2.ts, 3, 25)) ->x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 3, 34)) ->x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 3, 34)) ->x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 3, 34)) +>foo2 : Symbol(foo2, Decl(capturedParametersInInitializers2.ts, 11, 1)) +>y : Symbol(y, Decl(capturedParametersInInitializers2.ts, 12, 14)) +>[x] : Symbol((Anonymous class)[x], Decl(capturedParametersInInitializers2.ts, 12, 25)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 12, 34)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 12, 34)) +>x : Symbol(x, Decl(capturedParametersInInitializers2.ts, 12, 34)) } diff --git a/tests/baselines/reference/capturedParametersInInitializers2.types b/tests/baselines/reference/capturedParametersInInitializers2.types index 89ce29f5476..bc135347bca 100644 --- a/tests/baselines/reference/capturedParametersInInitializers2.types +++ b/tests/baselines/reference/capturedParametersInInitializers2.types @@ -1,13 +1,38 @@ === tests/cases/compiler/capturedParametersInInitializers2.ts === -function foo(y = class {static c = x}, x = 1) { ->foo : (y?: typeof (Anonymous class), x?: number) => void +function foo( +>foo : (y?: typeof (Anonymous class), x?: number, z?: number) => void + + y = class { >y : typeof (Anonymous class) ->class {static c = x} : typeof (Anonymous class) +>class { static c = x; get [x]() {return x;} constructor() { x; } [z]() { return z; } } : typeof (Anonymous class) + + static c = x; >c : number >x : number + + get [x]() {return x;} +>[x] : number +>x : number +>x : number + + constructor() { x; } +>x : number + + [z]() { return z; } +>[z] : () => number +>z : number +>z : number + + }, + x = 1, >x : number >1 : 1 + z = 2 +>z : number +>2 : 2 + +) { y.c >y.c : number >y : typeof (Anonymous class) diff --git a/tests/baselines/reference/functionLikeInParameterInitializer.errors.txt b/tests/baselines/reference/functionLikeInParameterInitializer.errors.txt deleted file mode 100644 index b6ae78623b8..00000000000 --- a/tests/baselines/reference/functionLikeInParameterInitializer.errors.txt +++ /dev/null @@ -1,34 +0,0 @@ -tests/cases/compiler/functionLikeInParameterInitializer.ts(2,34): error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. -tests/cases/compiler/functionLikeInParameterInitializer.ts(6,44): error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. -tests/cases/compiler/functionLikeInParameterInitializer.ts(11,50): error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. -tests/cases/compiler/functionLikeInParameterInitializer.ts(16,41): error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. - - -==== tests/cases/compiler/functionLikeInParameterInitializer.ts (4 errors) ==== - // error - export function bar(func = () => foo) { - ~~~ -!!! error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. - let foo = "in"; - } - // error - export function baz1(func = { f() { return foo } }) { - ~~~ -!!! error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. - let foo = "in"; - } - - // error - export function baz2(func = function () { return foo }) { - ~~~ -!!! error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. - let foo = "in"; - } - - // error - export function baz3(func = class { x = foo }) { - ~~~ -!!! error TS2373: Initializer of parameter 'func' cannot reference identifier 'foo' declared after it. - let foo = "in"; - } - \ No newline at end of file diff --git a/tests/baselines/reference/parameterInitializersForwardReferencing1.errors.txt b/tests/baselines/reference/parameterInitializersForwardReferencing1.errors.txt index 73f4f27d08b..91d200adbcd 100644 --- a/tests/baselines/reference/parameterInitializersForwardReferencing1.errors.txt +++ b/tests/baselines/reference/parameterInitializersForwardReferencing1.errors.txt @@ -1,12 +1,11 @@ tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(3,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. -tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(8,27): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(13,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer. tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer. tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(29,15): error TS2448: Block-scoped variable 'foo' used before its declaration. -==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts (6 errors) ==== +==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts (5 errors) ==== let foo: string = ""; function f1 (bar = foo) { // unexpected compiler error; works at runtime @@ -17,8 +16,6 @@ tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(29 } function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime - ~~~ -!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it. var foo: number = 2; return bar(); // returns 1 } diff --git a/tests/cases/compiler/capturedParametersInInitializers1.ts b/tests/cases/compiler/capturedParametersInInitializers1.ts index b4150f6b623..be989e92f8b 100644 --- a/tests/cases/compiler/capturedParametersInInitializers1.ts +++ b/tests/cases/compiler/capturedParametersInInitializers1.ts @@ -1,3 +1,4 @@ +// @target: es6 // ok - usage is deferred function foo1(y = class {c = x}, x = 1) { new y().c; @@ -12,4 +13,28 @@ function foo2(y = function(x: typeof z) {}, z = 1) { let a; function foo3(y = { x: a }, z = 1) { -} \ No newline at end of file +} + +// error - used before declaration +function foo4(y = {z}, z = 1) { +} + +// error - used before declaration, IIFEs are inlined +function foo5(y = (() => z)(), z = 1) { +} + +// ok - IIFE inside another function +function foo6(y = () => (() => z)(), z = 1) { +} + +// ok - used inside immediately invoked generator function +function foo7(y = (function*() {yield z})(), z = 1) { +} + +// ok - used inside immediately invoked async function +function foo8(y = (async () => z)(), z = 1) { +} + +// error - used as computed name of method +function foo9(y = {[z]() { return z; }}, z = 1) { +} diff --git a/tests/cases/compiler/capturedParametersInInitializers2.ts b/tests/cases/compiler/capturedParametersInInitializers2.ts index 718c2db7131..852d91d374d 100644 --- a/tests/cases/compiler/capturedParametersInInitializers2.ts +++ b/tests/cases/compiler/capturedParametersInInitializers2.ts @@ -1,4 +1,14 @@ -function foo(y = class {static c = x}, x = 1) { +// @target: es5 +function foo( + y = class { + static c = x; + get [x]() {return x;} + constructor() { x; } + [z]() { return z; } + }, + x = 1, + z = 2 +) { y.c } function foo2(y = class {[x] = x}, x = 1) {