From f952873ef10d2ad70b680fa773c4999fc0555193 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 12 Oct 2015 15:58:34 -0700 Subject: [PATCH 1/4] allow forward references to block scoped variables from functions --- src/compiler/checker.ts | 106 +++++++++++++----- .../blockScopedVariablesUseBeforeDef.js | 74 ++++++++++++ .../blockScopedVariablesUseBeforeDef.symbols | 76 +++++++++++++ .../blockScopedVariablesUseBeforeDef.types | 81 +++++++++++++ .../blockScopedVariablesUseBeforeDef.ts | 35 ++++++ 5 files changed, 341 insertions(+), 31 deletions(-) create mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.js create mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols create mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.types create mode 100644 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ad772bd1a70..3eead9fc957 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -383,20 +383,42 @@ namespace ts { // return undefined if we can't find a symbol. } - /** Returns true if node1 is defined before node 2**/ - function isDefinedBefore(node1: Node, node2: Node): boolean { - let file1 = getSourceFileOfNode(node1); - let file2 = getSourceFileOfNode(node2); + const enum RelativeLocation { + Unknown, + SameFileLocatedBefore, + SameFileLocatedAfter, + DifferentFilesLocatedBefore, + DifferentFilesLocatedAfter, + } + + function isLocatedBefore(origin: Node, target: Node): boolean { + switch (getRelativeLocation(origin, target)) { + // unknown is returned with nodes are in different files and order cannot be determined based on compilation settings + // optimistically assume this is ok + case RelativeLocation.Unknown: + case RelativeLocation.SameFileLocatedBefore: + case RelativeLocation.DifferentFilesLocatedBefore: + return true; + default: + return false; + } + } + + /** gets relative location of target comparing to origin **/ + function getRelativeLocation(origin: Node, target: Node): RelativeLocation { + let file1 = getSourceFileOfNode(origin); + let file2 = getSourceFileOfNode(target); if (file1 === file2) { - return node1.pos <= node2.pos; + return origin.pos > target.pos ? RelativeLocation.SameFileLocatedBefore : RelativeLocation.SameFileLocatedAfter; } if (!compilerOptions.outFile && !compilerOptions.out) { - return true; + // nodes are in different files and order cannot be determines + return RelativeLocation.Unknown; } let sourceFiles = host.getSourceFiles(); - return sourceFiles.indexOf(file1) <= sourceFiles.indexOf(file2); + return sourceFiles.indexOf(file1) > sourceFiles.indexOf(file2) ? RelativeLocation.DifferentFilesLocatedBefore : RelativeLocation.DifferentFilesLocatedAfter; } // Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and @@ -628,31 +650,53 @@ namespace ts { Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); // first check if usage is lexically located after the declaration - let isUsedBeforeDeclaration = !isDefinedBefore(declaration, errorLocation); - if (!isUsedBeforeDeclaration) { - // lexical check succeeded however code still can be illegal. - // - block scoped variables cannot be used in its initializers - // let x = x; // illegal but usage is lexically after definition - // - in ForIn/ForOf statements variable cannot be contained in expression part - // for (let x in x) - // for (let x of x) + let isUsedBeforeDeclaration = false; + switch (getRelativeLocation(declaration, errorLocation)) { + case RelativeLocation.DifferentFilesLocatedBefore: + isUsedBeforeDeclaration = true; + break; + case RelativeLocation.SameFileLocatedBefore: + // try to detect if forward reference to block scoped variable is inside function + // such forward references are permitted (they are still technically can be incorrect (i.e. in case of IIFEs) + // but detecting these case is more complicated task) + const declarationContainer = getEnclosingBlockScopeContainer(declaration); + let current = errorLocation; + while (current) { + if (current === declarationContainer) { + isUsedBeforeDeclaration = true; + break; + } + else if (isFunctionLike(current)) { + break; + } + current = current.parent; + } + break; + case RelativeLocation.SameFileLocatedAfter: + // lexical check succeeded however code still can be illegal. + // - block scoped variables cannot be used in its initializers + // let x = x; // illegal but usage is lexically after definition + // - in ForIn/ForOf statements variable cannot be contained in expression part + // for (let x in x) + // for (let x of x) - // climb up to the variable declaration skipping binding patterns - let variableDeclaration = getAncestor(declaration, SyntaxKind.VariableDeclaration); - let container = getEnclosingBlockScopeContainer(variableDeclaration); + // climb up to the variable declaration skipping binding patterns + let variableDeclaration = getAncestor(declaration, SyntaxKind.VariableDeclaration); + let container = getEnclosingBlockScopeContainer(variableDeclaration); - if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement || - variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) { - // variable statement/for statement case, - // use site should not be inside variable declaration (initializer of declaration or binding element) - isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); - } - else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement || - variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { - // ForIn/ForOf case - use site should not be used in expression part - let expression = (variableDeclaration.parent.parent).expression; - isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container); - } + if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement || + variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) { + // variable statement/for statement case, + // use site should not be inside variable declaration (initializer of declaration or binding element) + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); + } + else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement || + variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { + // ForIn/ForOf case - use site should not be used in expression part + let expression = (variableDeclaration.parent.parent).expression; + isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container); + } + break; } if (isUsedBeforeDeclaration) { error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name)); @@ -13356,7 +13400,7 @@ namespace ts { } // illegal case: forward reference - if (!isDefinedBefore(propertyDecl, member)) { + if (isLocatedBefore(propertyDecl, member)) { reportError = false; error(e, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); return undefined; diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js new file mode 100644 index 00000000000..2792521344f --- /dev/null +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js @@ -0,0 +1,74 @@ +//// [blockScopedVariablesUseBeforeDef.ts] +function foo1() { + let a = () => x; + let x; +} + +function foo2() { + let a = function () { return x; } + let x; +} + +function foo3() { + class X { + m() { return x;} + } + let x; +} + +function foo4() { + let y = class { + m() { return x; } + }; + let x; +} + +function foo5() { + let x = () => y; + let y = () => x; +} + +function foo6() { + function f() { + return x; + } + let x; +} + +//// [blockScopedVariablesUseBeforeDef.js] +function foo1() { + var a = function () { return x; }; + var x; +} +function foo2() { + var a = function () { return x; }; + var x; +} +function foo3() { + var X = (function () { + function X() { + } + X.prototype.m = function () { return x; }; + return X; + })(); + var x; +} +function foo4() { + var y = (function () { + function class_1() { + } + class_1.prototype.m = function () { return x; }; + return class_1; + })(); + var x; +} +function foo5() { + var x = function () { return y; }; + var y = function () { return x; }; +} +function foo6() { + function f() { + return x; + } + var x; +} diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols new file mode 100644 index 00000000000..a528af236c1 --- /dev/null +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols @@ -0,0 +1,76 @@ +=== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts === +function foo1() { +>foo1 : Symbol(foo1, Decl(blockScopedVariablesUseBeforeDef.ts, 0, 0)) + + let a = () => x; +>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 1, 4)) +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 2, 4)) + + let x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 2, 4)) +} + +function foo2() { +>foo2 : Symbol(foo2, Decl(blockScopedVariablesUseBeforeDef.ts, 3, 1)) + + let a = function () { return x; } +>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 6, 4)) +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 7, 4)) + + let x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 7, 4)) +} + +function foo3() { +>foo3 : Symbol(foo3, Decl(blockScopedVariablesUseBeforeDef.ts, 8, 1)) + + class X { +>X : Symbol(X, Decl(blockScopedVariablesUseBeforeDef.ts, 10, 17)) + + m() { return x;} +>m : Symbol(m, Decl(blockScopedVariablesUseBeforeDef.ts, 11, 10)) +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 14, 4)) + } + let x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 14, 4)) +} + +function foo4() { +>foo4 : Symbol(foo4, Decl(blockScopedVariablesUseBeforeDef.ts, 15, 1)) + + let y = class { +>y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 18, 4)) + + m() { return x; } +>m : Symbol((Anonymous class).m, Decl(blockScopedVariablesUseBeforeDef.ts, 18, 16)) +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 21, 4)) + + }; + let x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 21, 4)) +} + +function foo5() { +>foo5 : Symbol(foo5, Decl(blockScopedVariablesUseBeforeDef.ts, 22, 1)) + + let x = () => y; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 25, 4)) +>y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 26, 4)) + + let y = () => x; +>y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 26, 4)) +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 25, 4)) +} + +function foo6() { +>foo6 : Symbol(foo6, Decl(blockScopedVariablesUseBeforeDef.ts, 27, 1)) + + function f() { +>f : Symbol(f, Decl(blockScopedVariablesUseBeforeDef.ts, 29, 17)) + + return x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 33, 4)) + } + let x; +>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 33, 4)) +} diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types new file mode 100644 index 00000000000..bc3d5f8eba8 --- /dev/null +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types @@ -0,0 +1,81 @@ +=== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts === +function foo1() { +>foo1 : () => void + + let a = () => x; +>a : () => any +>() => x : () => any +>x : any + + let x; +>x : any +} + +function foo2() { +>foo2 : () => void + + let a = function () { return x; } +>a : () => any +>function () { return x; } : () => any +>x : any + + let x; +>x : any +} + +function foo3() { +>foo3 : () => void + + class X { +>X : X + + m() { return x;} +>m : () => any +>x : any + } + let x; +>x : any +} + +function foo4() { +>foo4 : () => void + + let y = class { +>y : typeof (Anonymous class) +>class { m() { return x; } } : typeof (Anonymous class) + + m() { return x; } +>m : () => any +>x : any + + }; + let x; +>x : any +} + +function foo5() { +>foo5 : () => void + + let x = () => y; +>x : () => () => any +>() => y : () => () => any +>y : () => () => any + + let y = () => x; +>y : () => () => any +>() => x : () => () => any +>x : () => () => any +} + +function foo6() { +>foo6 : () => void + + function f() { +>f : () => any + + return x; +>x : any + } + let x; +>x : any +} diff --git a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts new file mode 100644 index 00000000000..7ded92df4c9 --- /dev/null +++ b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts @@ -0,0 +1,35 @@ +function foo1() { + let a = () => x; + let x; +} + +function foo2() { + let a = function () { return x; } + let x; +} + +function foo3() { + class X { + m() { return x;} + } + let x; +} + +function foo4() { + let y = class { + m() { return x; } + }; + let x; +} + +function foo5() { + let x = () => y; + let y = () => x; +} + +function foo6() { + function f() { + return x; + } + let x; +} \ No newline at end of file From eb3b91cf1b1e681eac27c9b650830b8c3c978cd6 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 12 Oct 2015 17:24:39 -0700 Subject: [PATCH 2/4] addressed PR feedback --- src/compiler/checker.ts | 15 +- ...lockScopedVariablesUseBeforeDef.errors.txt | 93 ++++++++++++ .../blockScopedVariablesUseBeforeDef.js | 143 +++++++++++++++--- .../blockScopedVariablesUseBeforeDef.symbols | 76 ---------- .../blockScopedVariablesUseBeforeDef.types | 81 ---------- ...clarations-useBeforeDefinition2.errors.txt | 11 -- ...tDeclarations-useBeforeDefinition2.symbols | 9 ++ ...nstDeclarations-useBeforeDefinition2.types | 10 ++ ...clarations-useBeforeDefinition2.errors.txt | 11 -- ...tDeclarations-useBeforeDefinition2.symbols | 9 ++ ...letDeclarations-useBeforeDefinition2.types | 10 ++ .../blockScopedVariablesUseBeforeDef.ts | 85 ++++++++--- 12 files changed, 336 insertions(+), 217 deletions(-) create mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt delete mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols delete mode 100644 tests/baselines/reference/blockScopedVariablesUseBeforeDef.types delete mode 100644 tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt create mode 100644 tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols create mode 100644 tests/baselines/reference/constDeclarations-useBeforeDefinition2.types delete mode 100644 tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt create mode 100644 tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols create mode 100644 tests/baselines/reference/letDeclarations-useBeforeDefinition2.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3eead9fc957..0213f594f5b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -412,7 +412,7 @@ namespace ts { return origin.pos > target.pos ? RelativeLocation.SameFileLocatedBefore : RelativeLocation.SameFileLocatedAfter; } - if (!compilerOptions.outFile && !compilerOptions.out) { + if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) { // nodes are in different files and order cannot be determines return RelativeLocation.Unknown; } @@ -666,7 +666,18 @@ namespace ts { isUsedBeforeDeclaration = true; break; } - else if (isFunctionLike(current)) { + + if (isFunctionLike(current)) { + break; + } + + const isInitializerOfNonStaticProperty = + current.parent && + current.parent.kind === SyntaxKind.PropertyDeclaration && + (current.parent.flags & NodeFlags.Static) === 0 && + (current.parent).initializer === current; + + if (isInitializerOfNonStaticProperty) { break; } current = current.parent; diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt new file mode 100644 index 00000000000..a2bae3307a1 --- /dev/null +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt @@ -0,0 +1,93 @@ +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(53,20): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(60,20): error TS2448: Block-scoped variable 'x' used before its declaration. + + +==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (2 errors) ==== + function foo1() { + let a = () => x; + let x; + } + + function foo2() { + let a = function () { return x; } + let x; + } + + function foo3() { + class X { + m() { return x;} + } + let x; + } + + function foo4() { + let y = class { + m() { return x; } + }; + let x; + } + + function foo5() { + let x = () => y; + let y = () => x; + } + + function foo6() { + function f() { + return x; + } + let x; + } + + function foo7() { + class A { + a = x; + } + let x; + } + + function foo8() { + let y = class { + a = x; + } + let x; + } + + function foo9() { + let y = class { + static a = x; + ~ +!!! error TS2448: Block-scoped variable 'x' used before its declaration. + } + let x; + } + + function foo10() { + class A { + static a = x; + ~ +!!! error TS2448: Block-scoped variable 'x' used before its declaration. + } + let x; + } + + function foo11() { + function f () { + let y = class { + static a = x; + } + } + let x; + } + + function foo12() { + function f () { + let y = class { + a; + constructor() { + this.a = x; + } + } + } + let x; + } \ No newline at end of file diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js index 2792521344f..212b9d8b7b8 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js @@ -1,38 +1,87 @@ //// [blockScopedVariablesUseBeforeDef.ts] function foo1() { - let a = () => x; - let x; + let a = () => x; + let x; } function foo2() { - let a = function () { return x; } - let x; + let a = function () { return x; } + let x; } function foo3() { - class X { - m() { return x;} - } - let x; + class X { + m() { return x;} + } + let x; } function foo4() { - let y = class { - m() { return x; } - }; - let x; + let y = class { + m() { return x; } + }; + let x; } function foo5() { - let x = () => y; - let y = () => x; + let x = () => y; + let y = () => x; } function foo6() { - function f() { - return x; - } - let x; + function f() { + return x; + } + let x; +} + +function foo7() { + class A { + a = x; + } + let x; +} + +function foo8() { + let y = class { + a = x; + } + let x; +} + +function foo9() { + let y = class { + static a = x; + } + let x; +} + +function foo10() { + class A { + static a = x; + } + let x; +} + +function foo11() { + function f () { + let y = class { + static a = x; + } + } + let x; +} + +function foo12() { + function f () { + let y = class { + a; + constructor() { + this.a = x; + } + } + } + let x; } //// [blockScopedVariablesUseBeforeDef.js] @@ -72,3 +121,61 @@ function foo6() { } var x; } +function foo7() { + var A = (function () { + function A() { + this.a = x; + } + return A; + })(); + var x; +} +function foo8() { + var y = (function () { + function class_2() { + this.a = x; + } + return class_2; + })(); + var x; +} +function foo9() { + var y = (function () { + function class_3() { + } + class_3.a = x; + return class_3; + })(); + var x; +} +function foo10() { + var A = (function () { + function A() { + } + A.a = x; + return A; + })(); + var x; +} +function foo11() { + function f() { + var y = (function () { + function class_4() { + } + class_4.a = x; + return class_4; + })(); + } + var x; +} +function foo12() { + function f() { + var y = (function () { + function class_5() { + this.a = x; + } + return class_5; + })(); + } + var x; +} diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols deleted file mode 100644 index a528af236c1..00000000000 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols +++ /dev/null @@ -1,76 +0,0 @@ -=== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts === -function foo1() { ->foo1 : Symbol(foo1, Decl(blockScopedVariablesUseBeforeDef.ts, 0, 0)) - - let a = () => x; ->a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 1, 4)) ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 2, 4)) - - let x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 2, 4)) -} - -function foo2() { ->foo2 : Symbol(foo2, Decl(blockScopedVariablesUseBeforeDef.ts, 3, 1)) - - let a = function () { return x; } ->a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 6, 4)) ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 7, 4)) - - let x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 7, 4)) -} - -function foo3() { ->foo3 : Symbol(foo3, Decl(blockScopedVariablesUseBeforeDef.ts, 8, 1)) - - class X { ->X : Symbol(X, Decl(blockScopedVariablesUseBeforeDef.ts, 10, 17)) - - m() { return x;} ->m : Symbol(m, Decl(blockScopedVariablesUseBeforeDef.ts, 11, 10)) ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 14, 4)) - } - let x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 14, 4)) -} - -function foo4() { ->foo4 : Symbol(foo4, Decl(blockScopedVariablesUseBeforeDef.ts, 15, 1)) - - let y = class { ->y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 18, 4)) - - m() { return x; } ->m : Symbol((Anonymous class).m, Decl(blockScopedVariablesUseBeforeDef.ts, 18, 16)) ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 21, 4)) - - }; - let x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 21, 4)) -} - -function foo5() { ->foo5 : Symbol(foo5, Decl(blockScopedVariablesUseBeforeDef.ts, 22, 1)) - - let x = () => y; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 25, 4)) ->y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 26, 4)) - - let y = () => x; ->y : Symbol(y, Decl(blockScopedVariablesUseBeforeDef.ts, 26, 4)) ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 25, 4)) -} - -function foo6() { ->foo6 : Symbol(foo6, Decl(blockScopedVariablesUseBeforeDef.ts, 27, 1)) - - function f() { ->f : Symbol(f, Decl(blockScopedVariablesUseBeforeDef.ts, 29, 17)) - - return x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 33, 4)) - } - let x; ->x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 33, 4)) -} diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types deleted file mode 100644 index bc3d5f8eba8..00000000000 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.types +++ /dev/null @@ -1,81 +0,0 @@ -=== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts === -function foo1() { ->foo1 : () => void - - let a = () => x; ->a : () => any ->() => x : () => any ->x : any - - let x; ->x : any -} - -function foo2() { ->foo2 : () => void - - let a = function () { return x; } ->a : () => any ->function () { return x; } : () => any ->x : any - - let x; ->x : any -} - -function foo3() { ->foo3 : () => void - - class X { ->X : X - - m() { return x;} ->m : () => any ->x : any - } - let x; ->x : any -} - -function foo4() { ->foo4 : () => void - - let y = class { ->y : typeof (Anonymous class) ->class { m() { return x; } } : typeof (Anonymous class) - - m() { return x; } ->m : () => any ->x : any - - }; - let x; ->x : any -} - -function foo5() { ->foo5 : () => void - - let x = () => y; ->x : () => () => any ->() => y : () => () => any ->y : () => () => any - - let y = () => x; ->y : () => () => any ->() => x : () => () => any ->x : () => () => any -} - -function foo6() { ->foo6 : () => void - - function f() { ->f : () => any - - return x; ->x : any - } - let x; ->x : any -} diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt deleted file mode 100644 index a4d28f51878..00000000000 --- a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.errors.txt +++ /dev/null @@ -1,11 +0,0 @@ -tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'c' used before its declaration. - - -==== tests/cases/compiler/file1.ts (1 errors) ==== - - c; - ~ -!!! error TS2448: Block-scoped variable 'c' used before its declaration. - -==== tests/cases/compiler/file2.ts (0 errors) ==== - const c = 0; \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols new file mode 100644 index 00000000000..281ce427733 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/file1.ts === + +c; +>c : Symbol(c, Decl(file2.ts, 0, 5)) + +=== tests/cases/compiler/file2.ts === +const c = 0; +>c : Symbol(c, Decl(file2.ts, 0, 5)) + diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types new file mode 100644 index 00000000000..ae60fdfa477 --- /dev/null +++ b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/file1.ts === + +c; +>c : number + +=== tests/cases/compiler/file2.ts === +const c = 0; +>c : number +>0 : number + diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt deleted file mode 100644 index 5b8633312d9..00000000000 --- a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.errors.txt +++ /dev/null @@ -1,11 +0,0 @@ -tests/cases/compiler/file1.ts(2,1): error TS2448: Block-scoped variable 'l' used before its declaration. - - -==== tests/cases/compiler/file1.ts (1 errors) ==== - - l; - ~ -!!! error TS2448: Block-scoped variable 'l' used before its declaration. - -==== tests/cases/compiler/file2.ts (0 errors) ==== - const l = 0; \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols new file mode 100644 index 00000000000..c5a067ede4d --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/file1.ts === + +l; +>l : Symbol(l, Decl(file2.ts, 0, 5)) + +=== tests/cases/compiler/file2.ts === +const l = 0; +>l : Symbol(l, Decl(file2.ts, 0, 5)) + diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types new file mode 100644 index 00000000000..793a7a78ba7 --- /dev/null +++ b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/file1.ts === + +l; +>l : number + +=== tests/cases/compiler/file2.ts === +const l = 0; +>l : number +>0 : number + diff --git a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts index 7ded92df4c9..287f5ae117e 100644 --- a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts +++ b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts @@ -1,35 +1,84 @@ function foo1() { - let a = () => x; - let x; + let a = () => x; + let x; } function foo2() { - let a = function () { return x; } - let x; + let a = function () { return x; } + let x; } function foo3() { - class X { - m() { return x;} - } - let x; + class X { + m() { return x;} + } + let x; } function foo4() { - let y = class { - m() { return x; } - }; - let x; + let y = class { + m() { return x; } + }; + let x; } function foo5() { - let x = () => y; - let y = () => x; + let x = () => y; + let y = () => x; } function foo6() { - function f() { - return x; - } - let x; + function f() { + return x; + } + let x; +} + +function foo7() { + class A { + a = x; + } + let x; +} + +function foo8() { + let y = class { + a = x; + } + let x; +} + +function foo9() { + let y = class { + static a = x; + } + let x; +} + +function foo10() { + class A { + static a = x; + } + let x; +} + +function foo11() { + function f () { + let y = class { + static a = x; + } + } + let x; +} + +function foo12() { + function f () { + let y = class { + a; + constructor() { + this.a = x; + } + } + } + let x; } \ No newline at end of file From 48b24343b19769c175796a5fa9f769cf2bf44f1d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 13 Oct 2015 00:06:59 -0700 Subject: [PATCH 3/4] use isBlockScopedNameDeclaredBeforeUse for block scoped variables and enums --- src/compiler/checker.ts | 159 +++++++----------- ...lockScopedVariablesUseBeforeDef.errors.txt | 45 ++++- .../blockScopedVariablesUseBeforeDef.js | 48 +++++- .../blockScopedVariablesUseBeforeDef.ts | 31 +++- 4 files changed, 183 insertions(+), 100 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0213f594f5b..9db3d49b9af 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -383,42 +383,72 @@ namespace ts { // return undefined if we can't find a symbol. } - const enum RelativeLocation { - Unknown, - SameFileLocatedBefore, - SameFileLocatedAfter, - DifferentFilesLocatedBefore, - DifferentFilesLocatedAfter, - } - - function isLocatedBefore(origin: Node, target: Node): boolean { - switch (getRelativeLocation(origin, target)) { - // unknown is returned with nodes are in different files and order cannot be determined based on compilation settings - // optimistically assume this is ok - case RelativeLocation.Unknown: - case RelativeLocation.SameFileLocatedBefore: - case RelativeLocation.DifferentFilesLocatedBefore: + function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { + const declarationFile = getSourceFileOfNode(declaration); + const useFile = getSourceFileOfNode(usage); + if (declarationFile !== useFile) { + if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) { + // nodes are in different files and order cannot be determines return true; - default: - return false; - } - } + } - /** gets relative location of target comparing to origin **/ - function getRelativeLocation(origin: Node, target: Node): RelativeLocation { - let file1 = getSourceFileOfNode(origin); - let file2 = getSourceFileOfNode(target); - if (file1 === file2) { - return origin.pos > target.pos ? RelativeLocation.SameFileLocatedBefore : RelativeLocation.SameFileLocatedAfter; + const sourceFiles = host.getSourceFiles(); + return indexOf(sourceFiles, declarationFile) <= indexOf(sourceFiles, useFile); } - if (modulekind || (!compilerOptions.outFile && !compilerOptions.out)) { - // nodes are in different files and order cannot be determines - return RelativeLocation.Unknown; + if (declaration.pos <= usage.pos) { + // declaration is before usage + // still might be illegal if usage is in the initializer of the variable declaration + return declaration.kind !== SyntaxKind.VariableDeclaration || + !isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration, usage); } - let sourceFiles = host.getSourceFiles(); - return sourceFiles.indexOf(file1) > sourceFiles.indexOf(file2) ? RelativeLocation.DifferentFilesLocatedBefore : RelativeLocation.DifferentFilesLocatedAfter; + // declaration is after usage + // can be legal if usage is deferred (i.e. inside function or in initializer of instance property) + return isUsedInFunctionOrNonStaticProperty(declaration, usage); + + function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { + const container = getEnclosingBlockScopeContainer(declaration); + + if (declaration.parent.parent.kind === SyntaxKind.VariableStatement || + declaration.parent.parent.kind === SyntaxKind.ForStatement) { + // variable statement/for statement case, + // use site should not be inside variable declaration (initializer of declaration or binding element) + return isSameScopeDescendentOf(usage, declaration, container); + } + else if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement || + declaration.parent.parent.kind === SyntaxKind.ForInStatement) { + // ForIn/ForOf case - use site should not be used in expression part + let expression = (declaration.parent.parent).expression; + return isSameScopeDescendentOf(usage, expression, container); + } + } + + function isUsedInFunctionOrNonStaticProperty(declaration: Declaration, usage: Node): boolean { + const container = getEnclosingBlockScopeContainer(declaration); + let current = usage; + while (current) { + if (current === container) { + return false; + } + + if (isFunctionLike(current)) { + return true; + } + + const initializerOfNonStaticProperty = current.parent && + current.parent.kind === SyntaxKind.PropertyDeclaration && + (current.parent.flags & NodeFlags.Static) === 0 && + (current.parent).initializer === current; + + if (initializerOfNonStaticProperty) { + return true; + } + + current = current.parent; + } + return false; + } } // Resolve a given name for a given meaning at a given location. An error is reported if the name was not found and @@ -649,67 +679,7 @@ namespace ts { Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); - // first check if usage is lexically located after the declaration - let isUsedBeforeDeclaration = false; - switch (getRelativeLocation(declaration, errorLocation)) { - case RelativeLocation.DifferentFilesLocatedBefore: - isUsedBeforeDeclaration = true; - break; - case RelativeLocation.SameFileLocatedBefore: - // try to detect if forward reference to block scoped variable is inside function - // such forward references are permitted (they are still technically can be incorrect (i.e. in case of IIFEs) - // but detecting these case is more complicated task) - const declarationContainer = getEnclosingBlockScopeContainer(declaration); - let current = errorLocation; - while (current) { - if (current === declarationContainer) { - isUsedBeforeDeclaration = true; - break; - } - - if (isFunctionLike(current)) { - break; - } - - const isInitializerOfNonStaticProperty = - current.parent && - current.parent.kind === SyntaxKind.PropertyDeclaration && - (current.parent.flags & NodeFlags.Static) === 0 && - (current.parent).initializer === current; - - if (isInitializerOfNonStaticProperty) { - break; - } - current = current.parent; - } - break; - case RelativeLocation.SameFileLocatedAfter: - // lexical check succeeded however code still can be illegal. - // - block scoped variables cannot be used in its initializers - // let x = x; // illegal but usage is lexically after definition - // - in ForIn/ForOf statements variable cannot be contained in expression part - // for (let x in x) - // for (let x of x) - - // climb up to the variable declaration skipping binding patterns - let variableDeclaration = getAncestor(declaration, SyntaxKind.VariableDeclaration); - let container = getEnclosingBlockScopeContainer(variableDeclaration); - - if (variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement || - variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement) { - // variable statement/for statement case, - // use site should not be inside variable declaration (initializer of declaration or binding element) - isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, variableDeclaration, container); - } - else if (variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement || - variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { - // ForIn/ForOf case - use site should not be used in expression part - let expression = (variableDeclaration.parent.parent).expression; - isUsedBeforeDeclaration = isSameScopeDescendentOf(errorLocation, expression, container); - } - break; - } - if (isUsedBeforeDeclaration) { + if (!isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration), errorLocation)) { error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name)); } } @@ -13233,6 +13203,8 @@ namespace ts { let nodeLinks = getNodeLinks(node); if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { + nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; + let enumSymbol = getSymbolOfNode(node); let enumType = getDeclaredTypeOfSymbol(enumSymbol); let autoValue = 0; // set to undefined when enum member is non-constant @@ -13270,8 +13242,6 @@ namespace ts { getNodeLinks(member).enumMemberValue = autoValue++; } } - - nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; } function computeConstantValueForEnumMemberInitializer(initializer: Expression, enumType: Type, enumIsConst: boolean, ambient: boolean): number { @@ -13411,12 +13381,13 @@ namespace ts { } // illegal case: forward reference - if (isLocatedBefore(propertyDecl, member)) { + if (!isBlockScopedNameDeclaredBeforeUse(propertyDecl, member)) { reportError = false; error(e, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); return undefined; } + computeEnumMemberValues(propertyDecl.parent); return getNodeLinks(propertyDecl).enumMemberValue; } } diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt index a2bae3307a1..15697e9cf61 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt @@ -1,8 +1,18 @@ -tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(53,20): error TS2448: Block-scoped variable 'x' used before its declaration. -tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(60,20): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(2,13): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(58,20): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(65,20): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448: Block-scoped variable 'x' used before its declaration. +tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(105,20): error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums. -==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (2 errors) ==== +==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (5 errors) ==== + function foo0() { + let a = x; + ~ +!!! error TS2448: Block-scoped variable 'x' used before its declaration. + let x; + } + function foo1() { let a = () => x; let x; @@ -90,4 +100,31 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(60,20): error TS2448: B } } let x; - } \ No newline at end of file + } + + function foo13() { + let a = { + get a() { return x } + } + let x + } + + function foo14() { + let a = { + a: x + ~ +!!! error TS2448: Block-scoped variable 'x' used before its declaration. + } + let x + } + + const enum A { X = B.Y } + ~~~ +!!! error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums. + + const enum B { Y } + + function foo15() { + const enum A1 { X = B1.Y } + } + const enum B1 { Y } \ No newline at end of file diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js index 212b9d8b7b8..2030b0eed59 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js @@ -1,4 +1,9 @@ //// [blockScopedVariablesUseBeforeDef.ts] +function foo0() { + let a = x; + let x; +} + function foo1() { let a = () => x; let x; @@ -82,9 +87,36 @@ function foo12() { } } let x; -} +} + +function foo13() { + let a = { + get a() { return x } + } + let x +} + +function foo14() { + let a = { + a: x + } + let x +} + +const enum A { X = B.Y } + +const enum B { Y } + +function foo15() { + const enum A1 { X = B1.Y } +} +const enum B1 { Y } //// [blockScopedVariablesUseBeforeDef.js] +function foo0() { + var a = x; + var x; +} function foo1() { var a = function () { return x; }; var x; @@ -179,3 +211,17 @@ function foo12() { } var x; } +function foo13() { + var a = { + get a() { return x; } + }; + var x; +} +function foo14() { + var a = { + a: x + }; + var x; +} +function foo15() { +} diff --git a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts index 287f5ae117e..1cade31d238 100644 --- a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts +++ b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts @@ -1,3 +1,9 @@ +// @target: ES5 +function foo0() { + let a = x; + let x; +} + function foo1() { let a = () => x; let x; @@ -81,4 +87,27 @@ function foo12() { } } let x; -} \ No newline at end of file +} + +function foo13() { + let a = { + get a() { return x } + } + let x +} + +function foo14() { + let a = { + a: x + } + let x +} + +const enum A { X = B.Y } + +const enum B { Y } + +function foo15() { + const enum A1 { X = B1.Y } +} +const enum B1 { Y } \ No newline at end of file From 0465f1b0bb13f08ac307d74c59f9dd3adbdf1198 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 13 Oct 2015 13:18:58 -0700 Subject: [PATCH 4/4] revert enum related changes --- src/compiler/checker.ts | 5 ++--- .../blockScopedVariablesUseBeforeDef.errors.txt | 16 ++-------------- .../blockScopedVariablesUseBeforeDef.js | 13 +------------ .../compiler/blockScopedVariablesUseBeforeDef.ts | 11 +---------- 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9db3d49b9af..db9661289bd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13203,8 +13203,6 @@ namespace ts { let nodeLinks = getNodeLinks(node); if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { - nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; - let enumSymbol = getSymbolOfNode(node); let enumType = getDeclaredTypeOfSymbol(enumSymbol); let autoValue = 0; // set to undefined when enum member is non-constant @@ -13242,6 +13240,8 @@ namespace ts { getNodeLinks(member).enumMemberValue = autoValue++; } } + + nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; } function computeConstantValueForEnumMemberInitializer(initializer: Expression, enumType: Type, enumIsConst: boolean, ambient: boolean): number { @@ -13387,7 +13387,6 @@ namespace ts { return undefined; } - computeEnumMemberValues(propertyDecl.parent); return getNodeLinks(propertyDecl).enumMemberValue; } } diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt index 15697e9cf61..94c58bccb04 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt @@ -2,10 +2,9 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(2,13): error TS2448: Bl tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(58,20): error TS2448: Block-scoped variable 'x' used before its declaration. tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(65,20): error TS2448: Block-scoped variable 'x' used before its declaration. tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448: Block-scoped variable 'x' used before its declaration. -tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(105,20): error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums. -==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (5 errors) ==== +==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (4 errors) ==== function foo0() { let a = x; ~ @@ -116,15 +115,4 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(105,20): error TS2651: !!! error TS2448: Block-scoped variable 'x' used before its declaration. } let x - } - - const enum A { X = B.Y } - ~~~ -!!! error TS2651: A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums. - - const enum B { Y } - - function foo15() { - const enum A1 { X = B1.Y } - } - const enum B1 { Y } \ No newline at end of file + } \ No newline at end of file diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js index 2030b0eed59..5ed3ac62e6a 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js @@ -101,16 +101,7 @@ function foo14() { a: x } let x -} - -const enum A { X = B.Y } - -const enum B { Y } - -function foo15() { - const enum A1 { X = B1.Y } -} -const enum B1 { Y } +} //// [blockScopedVariablesUseBeforeDef.js] function foo0() { @@ -223,5 +214,3 @@ function foo14() { }; var x; } -function foo15() { -} diff --git a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts index 1cade31d238..956705bd7d3 100644 --- a/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts +++ b/tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts @@ -101,13 +101,4 @@ function foo14() { a: x } let x -} - -const enum A { X = B.Y } - -const enum B { Y } - -function foo15() { - const enum A1 { X = B1.Y } -} -const enum B1 { Y } \ No newline at end of file +} \ No newline at end of file