Skip to content

Commit 013d52a

Browse files
authored
Merge pull request #14952 from Microsoft/fix-scope-checks-of-class-properties
Fix scope checks of class properties
2 parents dd48dd1 + f65819a commit 013d52a

File tree

5 files changed

+89
-5
lines changed

5 files changed

+89
-5
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ namespace ts {
721721
}
722722
// declaration is after usage
723723
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
724-
if (isUsedInFunctionOrInstanceProperty(usage)) {
724+
if (isUsedInFunctionOrInstanceProperty(usage, declaration)) {
725725
return true;
726726
}
727727
const sourceFiles = host.getSourceFiles();
@@ -752,8 +752,7 @@ namespace ts {
752752
// 1. inside a function
753753
// 2. inside an instance property initializer, a reference to a non-instance property
754754
const container = getEnclosingBlockScopeContainer(declaration);
755-
const isInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
756-
return isUsedInFunctionOrInstanceProperty(usage, isInstanceProperty, container);
755+
return isUsedInFunctionOrInstanceProperty(usage, declaration, container);
757756

758757
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
759758
const container = getEnclosingBlockScopeContainer(declaration);
@@ -782,7 +781,7 @@ namespace ts {
782781
return false;
783782
}
784783

785-
function isUsedInFunctionOrInstanceProperty(usage: Node, isDeclarationInstanceProperty?: boolean, container?: Node): boolean {
784+
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node, container?: Node): boolean {
786785
let current = usage;
787786
while (current) {
788787
if (current === container) {
@@ -799,7 +798,8 @@ namespace ts {
799798
(<PropertyDeclaration>current.parent).initializer === current;
800799

801800
if (initializerOfInstanceProperty) {
802-
return !isDeclarationInstanceProperty;
801+
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
802+
return !isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration);
803803
}
804804

805805
current = current.parent;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [scopeCheckClassProperty.ts]
2+
class C {
3+
constructor() {
4+
new A().p; // ok
5+
}
6+
public x = new A().p; // should also be ok
7+
}
8+
class A {
9+
public p = '';
10+
}
11+
12+
13+
//// [scopeCheckClassProperty.js]
14+
var C = (function () {
15+
function C() {
16+
this.x = new A().p; // should also be ok
17+
new A().p; // ok
18+
}
19+
return C;
20+
}());
21+
var A = (function () {
22+
function A() {
23+
this.p = '';
24+
}
25+
return A;
26+
}());
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/compiler/scopeCheckClassProperty.ts ===
2+
class C {
3+
>C : Symbol(C, Decl(scopeCheckClassProperty.ts, 0, 0))
4+
5+
constructor() {
6+
new A().p; // ok
7+
>new A().p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9))
8+
>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1))
9+
>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9))
10+
}
11+
public x = new A().p; // should also be ok
12+
>x : Symbol(C.x, Decl(scopeCheckClassProperty.ts, 3, 3))
13+
>new A().p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9))
14+
>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1))
15+
>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9))
16+
}
17+
class A {
18+
>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1))
19+
20+
public p = '';
21+
>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9))
22+
}
23+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/scopeCheckClassProperty.ts ===
2+
class C {
3+
>C : C
4+
5+
constructor() {
6+
new A().p; // ok
7+
>new A().p : string
8+
>new A() : A
9+
>A : typeof A
10+
>p : string
11+
}
12+
public x = new A().p; // should also be ok
13+
>x : string
14+
>new A().p : string
15+
>new A() : A
16+
>A : typeof A
17+
>p : string
18+
}
19+
class A {
20+
>A : A
21+
22+
public p = '';
23+
>p : string
24+
>'' : ""
25+
}
26+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class C {
2+
constructor() {
3+
new A().p; // ok
4+
}
5+
public x = new A().p; // should also be ok
6+
}
7+
class A {
8+
public p = '';
9+
}

0 commit comments

Comments
 (0)