Skip to content

Commit 0365c96

Browse files
domchenmhegazy
authored andcommitted
Fix #11660: wrong reports that block-scoped variable used before its … (#11692)
* Fix #11660: wrong reports that block-scoped variable used before its declaration * Fix code style in checker.ts * Add unit test for #11660 * Fix the unit test for #11660
1 parent 06afadd commit 0365c96

File tree

5 files changed

+139
-4
lines changed

5 files changed

+139
-4
lines changed

src/compiler/checker.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,11 @@ namespace ts {
591591
// nodes are in different files and order cannot be determines
592592
return true;
593593
}
594-
594+
// declaration is after usage
595+
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
596+
if (isUsedInFunctionOrNonStaticProperty(usage)) {
597+
return true;
598+
}
595599
const sourceFiles = host.getSourceFiles();
596600
return indexOf(sourceFiles, declarationFile) <= indexOf(sourceFiles, useFile);
597601
}
@@ -605,7 +609,8 @@ namespace ts {
605609

606610
// declaration is after usage
607611
// can be legal if usage is deferred (i.e. inside function or in initializer of instance property)
608-
return isUsedInFunctionOrNonStaticProperty(declaration, usage);
612+
const container = getEnclosingBlockScopeContainer(declaration);
613+
return isUsedInFunctionOrNonStaticProperty(usage, container);
609614

610615
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
611616
const container = getEnclosingBlockScopeContainer(declaration);
@@ -634,8 +639,7 @@ namespace ts {
634639
return false;
635640
}
636641

637-
function isUsedInFunctionOrNonStaticProperty(declaration: Declaration, usage: Node): boolean {
638-
const container = getEnclosingBlockScopeContainer(declaration);
642+
function isUsedInFunctionOrNonStaticProperty(usage: Node, container?: Node): boolean {
639643
let current = usage;
640644
while (current) {
641645
if (current === container) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [tests/cases/compiler/useBeforeDeclaration.ts] ////
2+
3+
//// [A.ts]
4+
5+
namespace ts {
6+
export function printVersion():void {
7+
log("Version: " + sys.version); // the call of sys.version is deferred, should not report an error.
8+
}
9+
10+
export function log(info:string):void {
11+
12+
}
13+
}
14+
15+
//// [B.ts]
16+
namespace ts {
17+
18+
export let sys:{version:string} = {version: "2.0.5"};
19+
20+
}
21+
22+
23+
24+
//// [test.js]
25+
var ts;
26+
(function (ts) {
27+
function printVersion() {
28+
log("Version: " + ts.sys.version); // the call of sys.version is deferred, should not report an error.
29+
}
30+
ts.printVersion = printVersion;
31+
function log(info) {
32+
}
33+
ts.log = log;
34+
})(ts || (ts = {}));
35+
var ts;
36+
(function (ts) {
37+
ts.sys = { version: "2.0.5" };
38+
})(ts || (ts = {}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
=== tests/cases/compiler/A.ts ===
2+
3+
namespace ts {
4+
>ts : Symbol(ts, Decl(A.ts, 0, 0), Decl(B.ts, 0, 0))
5+
6+
export function printVersion():void {
7+
>printVersion : Symbol(printVersion, Decl(A.ts, 1, 14))
8+
9+
log("Version: " + sys.version); // the call of sys.version is deferred, should not report an error.
10+
>log : Symbol(log, Decl(A.ts, 4, 5))
11+
>sys.version : Symbol(version, Decl(B.ts, 2, 20))
12+
>sys : Symbol(sys, Decl(B.ts, 2, 14))
13+
>version : Symbol(version, Decl(B.ts, 2, 20))
14+
}
15+
16+
export function log(info:string):void {
17+
>log : Symbol(log, Decl(A.ts, 4, 5))
18+
>info : Symbol(info, Decl(A.ts, 6, 24))
19+
20+
}
21+
}
22+
23+
=== tests/cases/compiler/B.ts ===
24+
namespace ts {
25+
>ts : Symbol(ts, Decl(A.ts, 0, 0), Decl(B.ts, 0, 0))
26+
27+
export let sys:{version:string} = {version: "2.0.5"};
28+
>sys : Symbol(sys, Decl(B.ts, 2, 14))
29+
>version : Symbol(version, Decl(B.ts, 2, 20))
30+
>version : Symbol(version, Decl(B.ts, 2, 39))
31+
32+
}
33+
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
=== tests/cases/compiler/A.ts ===
2+
3+
namespace ts {
4+
>ts : typeof ts
5+
6+
export function printVersion():void {
7+
>printVersion : () => void
8+
9+
log("Version: " + sys.version); // the call of sys.version is deferred, should not report an error.
10+
>log("Version: " + sys.version) : void
11+
>log : (info: string) => void
12+
>"Version: " + sys.version : string
13+
>"Version: " : "Version: "
14+
>sys.version : string
15+
>sys : { version: string; }
16+
>version : string
17+
}
18+
19+
export function log(info:string):void {
20+
>log : (info: string) => void
21+
>info : string
22+
23+
}
24+
}
25+
26+
=== tests/cases/compiler/B.ts ===
27+
namespace ts {
28+
>ts : typeof ts
29+
30+
export let sys:{version:string} = {version: "2.0.5"};
31+
>sys : { version: string; }
32+
>version : string
33+
>{version: "2.0.5"} : { version: string; }
34+
>version : string
35+
>"2.0.5" : "2.0.5"
36+
37+
}
38+
39+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @outFile: test.js
2+
3+
// @fileName: A.ts
4+
namespace ts {
5+
export function printVersion():void {
6+
log("Version: " + sys.version); // the call of sys.version is deferred, should not report an error.
7+
}
8+
9+
export function log(info:string):void {
10+
11+
}
12+
}
13+
14+
// @fileName: B.ts
15+
namespace ts {
16+
17+
export let sys:{version:string} = {version: "2.0.5"};
18+
19+
}
20+

0 commit comments

Comments
 (0)