mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 23:08:20 -06:00
Merge pull request #5412 from Microsoft/classesInLoop
treat local classes as block scoped variables
This commit is contained in:
commit
ea054f7cbb
@ -6581,26 +6581,34 @@ namespace ts {
|
||||
|
||||
function checkBlockScopedBindingCapturedInLoop(node: Identifier, symbol: Symbol): void {
|
||||
if (languageVersion >= ScriptTarget.ES6 ||
|
||||
(symbol.flags & SymbolFlags.BlockScopedVariable) === 0 ||
|
||||
(symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 ||
|
||||
symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) {
|
||||
return;
|
||||
}
|
||||
|
||||
// - check if binding is used in some function
|
||||
// (stop the walk when reaching container of binding declaration)
|
||||
// - if first check succeeded - check if variable is declared inside the loop
|
||||
// 1. walk from the use site up to the declaration and check
|
||||
// if there is anything function like between declaration and use-site (is binding/class is captured in function).
|
||||
// 2. walk from the declaration up to the boundary of lexical environment and check
|
||||
// if there is an iteration statement in between declaration and boundary (is binding/class declared inside iteration statement)
|
||||
|
||||
// nesting structure:
|
||||
// (variable declaration or binding element) -> variable declaration list -> container
|
||||
let container: Node = symbol.valueDeclaration;
|
||||
while (container.kind !== SyntaxKind.VariableDeclarationList) {
|
||||
container = container.parent;
|
||||
let container: Node;
|
||||
if (symbol.flags & SymbolFlags.Class) {
|
||||
// get parent of class declaration
|
||||
container = getClassLikeDeclarationOfSymbol(symbol).parent;
|
||||
}
|
||||
// get the parent of variable declaration list
|
||||
container = container.parent;
|
||||
if (container.kind === SyntaxKind.VariableStatement) {
|
||||
// if parent is variable statement - get its parent
|
||||
else {
|
||||
// nesting structure:
|
||||
// (variable declaration or binding element) -> variable declaration list -> container
|
||||
container = symbol.valueDeclaration;
|
||||
while (container.kind !== SyntaxKind.VariableDeclarationList) {
|
||||
container = container.parent;
|
||||
}
|
||||
// get the parent of variable declaration list
|
||||
container = container.parent;
|
||||
if (container.kind === SyntaxKind.VariableStatement) {
|
||||
// if parent is variable statement - get its parent
|
||||
container = container.parent;
|
||||
}
|
||||
}
|
||||
|
||||
let inFunction = isInsideFunction(node.parent, container);
|
||||
|
||||
27
tests/baselines/reference/localClassesInLoop.js
Normal file
27
tests/baselines/reference/localClassesInLoop.js
Normal file
@ -0,0 +1,27 @@
|
||||
//// [localClassesInLoop.ts]
|
||||
declare function use(a: any);
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
class C { }
|
||||
data.push(() => C);
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
|
||||
//// [localClassesInLoop.js]
|
||||
"use strict";
|
||||
var data = [];
|
||||
var _loop_1 = function(x) {
|
||||
var C = (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
})();
|
||||
data.push(function () { return C; });
|
||||
};
|
||||
for (var x = 0; x < 2; ++x) {
|
||||
_loop_1(x);
|
||||
}
|
||||
use(data[0]() === data[1]());
|
||||
29
tests/baselines/reference/localClassesInLoop.symbols
Normal file
29
tests/baselines/reference/localClassesInLoop.symbols
Normal file
@ -0,0 +1,29 @@
|
||||
=== tests/cases/compiler/localClassesInLoop.ts ===
|
||||
declare function use(a: any);
|
||||
>use : Symbol(use, Decl(localClassesInLoop.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(localClassesInLoop.ts, 0, 21))
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
>data : Symbol(data, Decl(localClassesInLoop.ts, 3, 3))
|
||||
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
>x : Symbol(x, Decl(localClassesInLoop.ts, 4, 8))
|
||||
>x : Symbol(x, Decl(localClassesInLoop.ts, 4, 8))
|
||||
>x : Symbol(x, Decl(localClassesInLoop.ts, 4, 8))
|
||||
|
||||
class C { }
|
||||
>C : Symbol(C, Decl(localClassesInLoop.ts, 4, 29))
|
||||
|
||||
data.push(() => C);
|
||||
>data.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>data : Symbol(data, Decl(localClassesInLoop.ts, 3, 3))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>C : Symbol(C, Decl(localClassesInLoop.ts, 4, 29))
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
>use : Symbol(use, Decl(localClassesInLoop.ts, 0, 0))
|
||||
>data : Symbol(data, Decl(localClassesInLoop.ts, 3, 3))
|
||||
>data : Symbol(data, Decl(localClassesInLoop.ts, 3, 3))
|
||||
|
||||
46
tests/baselines/reference/localClassesInLoop.types
Normal file
46
tests/baselines/reference/localClassesInLoop.types
Normal file
@ -0,0 +1,46 @@
|
||||
=== tests/cases/compiler/localClassesInLoop.ts ===
|
||||
declare function use(a: any);
|
||||
>use : (a: any) => any
|
||||
>a : any
|
||||
|
||||
"use strict"
|
||||
>"use strict" : string
|
||||
|
||||
var data = [];
|
||||
>data : any[]
|
||||
>[] : undefined[]
|
||||
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
>x : number
|
||||
>0 : number
|
||||
>x < 2 : boolean
|
||||
>x : number
|
||||
>2 : number
|
||||
>++x : number
|
||||
>x : number
|
||||
|
||||
class C { }
|
||||
>C : C
|
||||
|
||||
data.push(() => C);
|
||||
>data.push(() => C) : number
|
||||
>data.push : (...items: any[]) => number
|
||||
>data : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>() => C : () => typeof C
|
||||
>C : typeof C
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
>use(data[0]() === data[1]()) : any
|
||||
>use : (a: any) => any
|
||||
>data[0]() === data[1]() : boolean
|
||||
>data[0]() : any
|
||||
>data[0] : any
|
||||
>data : any[]
|
||||
>0 : number
|
||||
>data[1]() : any
|
||||
>data[1] : any
|
||||
>data : any[]
|
||||
>1 : number
|
||||
|
||||
22
tests/baselines/reference/localClassesInLoop_ES6.js
Normal file
22
tests/baselines/reference/localClassesInLoop_ES6.js
Normal file
@ -0,0 +1,22 @@
|
||||
//// [localClassesInLoop_ES6.ts]
|
||||
|
||||
declare function use(a: any);
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
class C { }
|
||||
data.push(() => C);
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
|
||||
//// [localClassesInLoop_ES6.js]
|
||||
"use strict";
|
||||
var data = [];
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
class C {
|
||||
}
|
||||
data.push(() => C);
|
||||
}
|
||||
use(data[0]() === data[1]());
|
||||
30
tests/baselines/reference/localClassesInLoop_ES6.symbols
Normal file
30
tests/baselines/reference/localClassesInLoop_ES6.symbols
Normal file
@ -0,0 +1,30 @@
|
||||
=== tests/cases/compiler/localClassesInLoop_ES6.ts ===
|
||||
|
||||
declare function use(a: any);
|
||||
>use : Symbol(use, Decl(localClassesInLoop_ES6.ts, 0, 0))
|
||||
>a : Symbol(a, Decl(localClassesInLoop_ES6.ts, 1, 21))
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
>data : Symbol(data, Decl(localClassesInLoop_ES6.ts, 4, 3))
|
||||
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
>x : Symbol(x, Decl(localClassesInLoop_ES6.ts, 5, 8))
|
||||
>x : Symbol(x, Decl(localClassesInLoop_ES6.ts, 5, 8))
|
||||
>x : Symbol(x, Decl(localClassesInLoop_ES6.ts, 5, 8))
|
||||
|
||||
class C { }
|
||||
>C : Symbol(C, Decl(localClassesInLoop_ES6.ts, 5, 29))
|
||||
|
||||
data.push(() => C);
|
||||
>data.push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>data : Symbol(data, Decl(localClassesInLoop_ES6.ts, 4, 3))
|
||||
>push : Symbol(Array.push, Decl(lib.d.ts, --, --))
|
||||
>C : Symbol(C, Decl(localClassesInLoop_ES6.ts, 5, 29))
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
>use : Symbol(use, Decl(localClassesInLoop_ES6.ts, 0, 0))
|
||||
>data : Symbol(data, Decl(localClassesInLoop_ES6.ts, 4, 3))
|
||||
>data : Symbol(data, Decl(localClassesInLoop_ES6.ts, 4, 3))
|
||||
|
||||
47
tests/baselines/reference/localClassesInLoop_ES6.types
Normal file
47
tests/baselines/reference/localClassesInLoop_ES6.types
Normal file
@ -0,0 +1,47 @@
|
||||
=== tests/cases/compiler/localClassesInLoop_ES6.ts ===
|
||||
|
||||
declare function use(a: any);
|
||||
>use : (a: any) => any
|
||||
>a : any
|
||||
|
||||
"use strict"
|
||||
>"use strict" : string
|
||||
|
||||
var data = [];
|
||||
>data : any[]
|
||||
>[] : undefined[]
|
||||
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
>x : number
|
||||
>0 : number
|
||||
>x < 2 : boolean
|
||||
>x : number
|
||||
>2 : number
|
||||
>++x : number
|
||||
>x : number
|
||||
|
||||
class C { }
|
||||
>C : C
|
||||
|
||||
data.push(() => C);
|
||||
>data.push(() => C) : number
|
||||
>data.push : (...items: any[]) => number
|
||||
>data : any[]
|
||||
>push : (...items: any[]) => number
|
||||
>() => C : () => typeof C
|
||||
>C : typeof C
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
>use(data[0]() === data[1]()) : any
|
||||
>use : (a: any) => any
|
||||
>data[0]() === data[1]() : boolean
|
||||
>data[0]() : any
|
||||
>data[0] : any
|
||||
>data : any[]
|
||||
>0 : number
|
||||
>data[1]() : any
|
||||
>data[1] : any
|
||||
>data : any[]
|
||||
>1 : number
|
||||
|
||||
10
tests/cases/compiler/localClassesInLoop.ts
Normal file
10
tests/cases/compiler/localClassesInLoop.ts
Normal file
@ -0,0 +1,10 @@
|
||||
declare function use(a: any);
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
class C { }
|
||||
data.push(() => C);
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
12
tests/cases/compiler/localClassesInLoop_ES6.ts
Normal file
12
tests/cases/compiler/localClassesInLoop_ES6.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @target: ES6
|
||||
|
||||
declare function use(a: any);
|
||||
|
||||
"use strict"
|
||||
var data = [];
|
||||
for (let x = 0; x < 2; ++x) {
|
||||
class C { }
|
||||
data.push(() => C);
|
||||
}
|
||||
|
||||
use(data[0]() === data[1]());
|
||||
Loading…
x
Reference in New Issue
Block a user