diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7bdde91f286..2fe44641efd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -751,6 +751,7 @@ namespace ts { // declaration is after usage, but it can still be legal if usage is deferred: // 1. inside a function // 2. inside an instance property initializer, a reference to a non-instance property + // 3. inside a static property initializer, a reference to a static method in the same class const container = getEnclosingBlockScopeContainer(declaration); return isUsedInFunctionOrInstanceProperty(usage, declaration, container); @@ -792,14 +793,22 @@ namespace ts { return true; } - const initializerOfInstanceProperty = current.parent && + const initializerOfProperty = current.parent && current.parent.kind === SyntaxKind.PropertyDeclaration && - (getModifierFlags(current.parent) & ModifierFlags.Static) === 0 && (current.parent).initializer === current; - if (initializerOfInstanceProperty) { - const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static); - return !isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration); + if (initializerOfProperty) { + if (getModifierFlags(current.parent) & ModifierFlags.Static) { + if (declaration.kind === SyntaxKind.MethodDeclaration) { + return true; + } + } + else { + const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static); + if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) { + return true; + } + } } current = current.parent; diff --git a/tests/baselines/reference/scopeCheckStaticInitializer.errors.txt b/tests/baselines/reference/scopeCheckStaticInitializer.errors.txt new file mode 100644 index 00000000000..c023c356a2a --- /dev/null +++ b/tests/baselines/reference/scopeCheckStaticInitializer.errors.txt @@ -0,0 +1,30 @@ +tests/cases/compiler/scopeCheckStaticInitializer.ts(2,38): error TS2448: Block-scoped variable 'data' used before its declaration. +tests/cases/compiler/scopeCheckStaticInitializer.ts(5,23): error TS2449: Class 'After' used before its declaration. +tests/cases/compiler/scopeCheckStaticInitializer.ts(5,29): error TS2448: Block-scoped variable 'data' used before its declaration. +tests/cases/compiler/scopeCheckStaticInitializer.ts(6,23): error TS2449: Class 'After' used before its declaration. + + +==== tests/cases/compiler/scopeCheckStaticInitializer.ts (4 errors) ==== + class X { + static illegalBeforeProperty = X.data; + ~~~~ +!!! error TS2448: Block-scoped variable 'data' used before its declaration. + static okBeforeMethod = X.method; + + static illegal2 = After.data; + ~~~~~ +!!! error TS2449: Class 'After' used before its declaration. + ~~~~ +!!! error TS2448: Block-scoped variable 'data' used before its declaration. + static illegal3 = After.method; + ~~~~~ +!!! error TS2449: Class 'After' used before its declaration. + static data = 13; + static method() { } + } + class After { + static data = 12; + static method() { }; + } + + \ No newline at end of file diff --git a/tests/baselines/reference/scopeCheckStaticInitializer.js b/tests/baselines/reference/scopeCheckStaticInitializer.js new file mode 100644 index 00000000000..59711f07380 --- /dev/null +++ b/tests/baselines/reference/scopeCheckStaticInitializer.js @@ -0,0 +1,37 @@ +//// [scopeCheckStaticInitializer.ts] +class X { + static illegalBeforeProperty = X.data; + static okBeforeMethod = X.method; + + static illegal2 = After.data; + static illegal3 = After.method; + static data = 13; + static method() { } +} +class After { + static data = 12; + static method() { }; +} + + + +//// [scopeCheckStaticInitializer.js] +var X = (function () { + function X() { + } + X.method = function () { }; + return X; +}()); +X.illegalBeforeProperty = X.data; +X.okBeforeMethod = X.method; +X.illegal2 = After.data; +X.illegal3 = After.method; +X.data = 13; +var After = (function () { + function After() { + } + After.method = function () { }; + ; + return After; +}()); +After.data = 12; diff --git a/tests/cases/compiler/scopeCheckStaticInitializer.ts b/tests/cases/compiler/scopeCheckStaticInitializer.ts new file mode 100644 index 00000000000..a5c7b6ccd62 --- /dev/null +++ b/tests/cases/compiler/scopeCheckStaticInitializer.ts @@ -0,0 +1,14 @@ +class X { + static illegalBeforeProperty = X.data; + static okBeforeMethod = X.method; + + static illegal2 = After.data; + static illegal3 = After.method; + static data = 13; + static method() { } +} +class After { + static data = 12; + static method() { }; +} +