Skip to content

Commit

Permalink
Merge pull request #15010 from Microsoft/static-initialisers-can-refe…
Browse files Browse the repository at this point in the history
…r-to-later-static-methods

Static initializers may refer to later static methods
  • Loading branch information
sandersn authored Apr 4, 2017
2 parents 9bfba73 + a5d320a commit c62cc3f
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
30 changes: 30 additions & 0 deletions tests/baselines/reference/scopeCheckStaticInitializer.errors.txt
Original file line number Diff line number Diff line change
@@ -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() { };
}


37 changes: 37 additions & 0 deletions tests/baselines/reference/scopeCheckStaticInitializer.js
Original file line number Diff line number Diff line change
@@ -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;
14 changes: 14 additions & 0 deletions tests/cases/compiler/scopeCheckStaticInitializer.ts
Original file line number Diff line number Diff line change
@@ -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() { };
}

0 comments on commit c62cc3f

Please sign in to comment.