From 87565daf4d6f62d8dbdf6357b3c2236d496640d5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 31 Mar 2017 12:03:18 -0700 Subject: [PATCH 1/2] Props of class A usable in prop initializer of class B Regardless of the order of declaration of class A and class B. --- src/compiler/checker.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4e55a1c46b564..86d3e3b5d6015 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -717,7 +717,7 @@ namespace ts { } // declaration is after usage // can be legal if usage is deferred (i.e. inside function or in initializer of instance property) - if (isUsedInFunctionOrInstanceProperty(usage)) { + if (isUsedInFunctionOrInstanceProperty(usage, declaration)) { return true; } const sourceFiles = host.getSourceFiles(); @@ -748,8 +748,7 @@ namespace ts { // 1. inside a function // 2. inside an instance property initializer, a reference to a non-instance property const container = getEnclosingBlockScopeContainer(declaration); - const isInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static); - return isUsedInFunctionOrInstanceProperty(usage, isInstanceProperty, container); + return isUsedInFunctionOrInstanceProperty(usage, declaration, container); function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { const container = getEnclosingBlockScopeContainer(declaration); @@ -778,7 +777,7 @@ namespace ts { return false; } - function isUsedInFunctionOrInstanceProperty(usage: Node, isDeclarationInstanceProperty?: boolean, container?: Node): boolean { + function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node, container?: Node): boolean { let current = usage; while (current) { if (current === container) { @@ -795,7 +794,8 @@ namespace ts { (current.parent).initializer === current; if (initializerOfInstanceProperty) { - return !isDeclarationInstanceProperty; + const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static); + return !isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration); } current = current.parent; From f65819a2538eb642f6ae1beae4b920d4c3bae03c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 31 Mar 2017 12:05:12 -0700 Subject: [PATCH 2/2] Test:props of class A are usable in prop initialisers of class B Regardless of order of class A and class B --- .../reference/scopeCheckClassProperty.js | 26 +++++++++++++++++++ .../reference/scopeCheckClassProperty.symbols | 23 ++++++++++++++++ .../reference/scopeCheckClassProperty.types | 26 +++++++++++++++++++ .../cases/compiler/scopeCheckClassProperty.ts | 9 +++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/baselines/reference/scopeCheckClassProperty.js create mode 100644 tests/baselines/reference/scopeCheckClassProperty.symbols create mode 100644 tests/baselines/reference/scopeCheckClassProperty.types create mode 100644 tests/cases/compiler/scopeCheckClassProperty.ts diff --git a/tests/baselines/reference/scopeCheckClassProperty.js b/tests/baselines/reference/scopeCheckClassProperty.js new file mode 100644 index 0000000000000..13324e7447d1c --- /dev/null +++ b/tests/baselines/reference/scopeCheckClassProperty.js @@ -0,0 +1,26 @@ +//// [scopeCheckClassProperty.ts] +class C { + constructor() { + new A().p; // ok + } + public x = new A().p; // should also be ok +} +class A { + public p = ''; +} + + +//// [scopeCheckClassProperty.js] +var C = (function () { + function C() { + this.x = new A().p; // should also be ok + new A().p; // ok + } + return C; +}()); +var A = (function () { + function A() { + this.p = ''; + } + return A; +}()); diff --git a/tests/baselines/reference/scopeCheckClassProperty.symbols b/tests/baselines/reference/scopeCheckClassProperty.symbols new file mode 100644 index 0000000000000..bd77e5413d07a --- /dev/null +++ b/tests/baselines/reference/scopeCheckClassProperty.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/scopeCheckClassProperty.ts === +class C { +>C : Symbol(C, Decl(scopeCheckClassProperty.ts, 0, 0)) + + constructor() { + new A().p; // ok +>new A().p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9)) +>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1)) +>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9)) + } + public x = new A().p; // should also be ok +>x : Symbol(C.x, Decl(scopeCheckClassProperty.ts, 3, 3)) +>new A().p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9)) +>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1)) +>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9)) +} +class A { +>A : Symbol(A, Decl(scopeCheckClassProperty.ts, 5, 1)) + + public p = ''; +>p : Symbol(A.p, Decl(scopeCheckClassProperty.ts, 6, 9)) +} + diff --git a/tests/baselines/reference/scopeCheckClassProperty.types b/tests/baselines/reference/scopeCheckClassProperty.types new file mode 100644 index 0000000000000..188d1308a1822 --- /dev/null +++ b/tests/baselines/reference/scopeCheckClassProperty.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/scopeCheckClassProperty.ts === +class C { +>C : C + + constructor() { + new A().p; // ok +>new A().p : string +>new A() : A +>A : typeof A +>p : string + } + public x = new A().p; // should also be ok +>x : string +>new A().p : string +>new A() : A +>A : typeof A +>p : string +} +class A { +>A : A + + public p = ''; +>p : string +>'' : "" +} + diff --git a/tests/cases/compiler/scopeCheckClassProperty.ts b/tests/cases/compiler/scopeCheckClassProperty.ts new file mode 100644 index 0000000000000..ef961a560fc66 --- /dev/null +++ b/tests/cases/compiler/scopeCheckClassProperty.ts @@ -0,0 +1,9 @@ +class C { + constructor() { + new A().p; // ok + } + public x = new A().p; // should also be ok +} +class A { + public p = ''; +}