Merge pull request #15010 from Microsoft/static-initialisers-can-refer-to-later-static-methods

Static initializers may refer to later static methods
This commit is contained in:
Nathan Shively-Sanders 2017-04-04 15:30:17 -07:00 committed by GitHub
commit c62cc3fea3
4 changed files with 95 additions and 5 deletions

View File

@ -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 &&
(<PropertyDeclaration>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;

View File

@ -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() { };
}

View File

@ -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;

View File

@ -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() { };
}