Skip to content

Commit c62cc3f

Browse files
authored
Merge pull request #15010 from Microsoft/static-initialisers-can-refer-to-later-static-methods
Static initializers may refer to later static methods
2 parents 9bfba73 + a5d320a commit c62cc3f

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

src/compiler/checker.ts

+14-5
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ namespace ts {
751751
// declaration is after usage, but it can still be legal if usage is deferred:
752752
// 1. inside a function
753753
// 2. inside an instance property initializer, a reference to a non-instance property
754+
// 3. inside a static property initializer, a reference to a static method in the same class
754755
const container = getEnclosingBlockScopeContainer(declaration);
755756
return isUsedInFunctionOrInstanceProperty(usage, declaration, container);
756757

@@ -792,14 +793,22 @@ namespace ts {
792793
return true;
793794
}
794795

795-
const initializerOfInstanceProperty = current.parent &&
796+
const initializerOfProperty = current.parent &&
796797
current.parent.kind === SyntaxKind.PropertyDeclaration &&
797-
(getModifierFlags(current.parent) & ModifierFlags.Static) === 0 &&
798798
(<PropertyDeclaration>current.parent).initializer === current;
799799

800-
if (initializerOfInstanceProperty) {
801-
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
802-
return !isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration);
800+
if (initializerOfProperty) {
801+
if (getModifierFlags(current.parent) & ModifierFlags.Static) {
802+
if (declaration.kind === SyntaxKind.MethodDeclaration) {
803+
return true;
804+
}
805+
}
806+
else {
807+
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
808+
if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) {
809+
return true;
810+
}
811+
}
803812
}
804813

805814
current = current.parent;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
tests/cases/compiler/scopeCheckStaticInitializer.ts(2,38): error TS2448: Block-scoped variable 'data' used before its declaration.
2+
tests/cases/compiler/scopeCheckStaticInitializer.ts(5,23): error TS2449: Class 'After' used before its declaration.
3+
tests/cases/compiler/scopeCheckStaticInitializer.ts(5,29): error TS2448: Block-scoped variable 'data' used before its declaration.
4+
tests/cases/compiler/scopeCheckStaticInitializer.ts(6,23): error TS2449: Class 'After' used before its declaration.
5+
6+
7+
==== tests/cases/compiler/scopeCheckStaticInitializer.ts (4 errors) ====
8+
class X {
9+
static illegalBeforeProperty = X.data;
10+
~~~~
11+
!!! error TS2448: Block-scoped variable 'data' used before its declaration.
12+
static okBeforeMethod = X.method;
13+
14+
static illegal2 = After.data;
15+
~~~~~
16+
!!! error TS2449: Class 'After' used before its declaration.
17+
~~~~
18+
!!! error TS2448: Block-scoped variable 'data' used before its declaration.
19+
static illegal3 = After.method;
20+
~~~~~
21+
!!! error TS2449: Class 'After' used before its declaration.
22+
static data = 13;
23+
static method() { }
24+
}
25+
class After {
26+
static data = 12;
27+
static method() { };
28+
}
29+
30+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [scopeCheckStaticInitializer.ts]
2+
class X {
3+
static illegalBeforeProperty = X.data;
4+
static okBeforeMethod = X.method;
5+
6+
static illegal2 = After.data;
7+
static illegal3 = After.method;
8+
static data = 13;
9+
static method() { }
10+
}
11+
class After {
12+
static data = 12;
13+
static method() { };
14+
}
15+
16+
17+
18+
//// [scopeCheckStaticInitializer.js]
19+
var X = (function () {
20+
function X() {
21+
}
22+
X.method = function () { };
23+
return X;
24+
}());
25+
X.illegalBeforeProperty = X.data;
26+
X.okBeforeMethod = X.method;
27+
X.illegal2 = After.data;
28+
X.illegal3 = After.method;
29+
X.data = 13;
30+
var After = (function () {
31+
function After() {
32+
}
33+
After.method = function () { };
34+
;
35+
return After;
36+
}());
37+
After.data = 12;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class X {
2+
static illegalBeforeProperty = X.data;
3+
static okBeforeMethod = X.method;
4+
5+
static illegal2 = After.data;
6+
static illegal3 = After.method;
7+
static data = 13;
8+
static method() { }
9+
}
10+
class After {
11+
static data = 12;
12+
static method() { };
13+
}
14+

0 commit comments

Comments
 (0)