Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
*/
argumentsName?: string;

/*
* alias for 'this' from the calling code stack frame in case if this was used inside the converted loop
*/
thisName?: string;

/*
* list of non-block scoped variable declarations that appear inside converted loop
* such variable declarations should be moved outside the loop body
Expand Down Expand Up @@ -1992,6 +1997,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) {
write("_this");
}
else if (convertedLoopState) {
write(convertedLoopState.thisName || (convertedLoopState.thisName = makeUniqueName("this")));
}
else {
write("this");
}
Expand Down Expand Up @@ -3322,6 +3330,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
convertedLoopState.argumentsName = convertedOuterLoopState.argumentsName;
}

if (convertedOuterLoopState.thisName) {
// outer loop has already used 'this' so we've already have some name to alias it
// use the same name in all nested loops
convertedLoopState.thisName = convertedOuterLoopState.thisName;
}

if (convertedOuterLoopState.hoistedLocalVariables) {
// we've already collected some non-block scoped variable declarations in enclosing loop
// use the same storage in nested loop
Expand Down Expand Up @@ -3351,6 +3365,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
writeLine();
}
}
if (convertedLoopState.thisName) {
// if alias for this is set
if (convertedOuterLoopState) {
// pass it to outer converted loop
convertedOuterLoopState.thisName = convertedLoopState.thisName;
}
else {
// this is top level converted loop so we need to create an alias for 'this' here
// NOTE:
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
write(`var ${convertedLoopState.thisName} = this;`);
writeLine();
}
}

if (convertedLoopState.hoistedLocalVariables) {
// if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
Expand Down
124 changes: 124 additions & 0 deletions tests/baselines/reference/capturedLetConstInLoop10.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
//// [capturedLetConstInLoop10.ts]
class A {
foo() {
for (let x of [0]) {
let f = function() { return x; };
this.bar(f());
}
}
bar(a: number) {
}

baz() {
for (let x of [1]) {
let a = function() { return x; };
for (let y of [1]) {
let b = function() { return y; };
this.bar(b());
}
this.bar(a());
}
}
baz2() {
for (let x of [1]) {
let a = function() { return x; };
this.bar(a());
for (let y of [1]) {
let b = function() { return y; };
this.bar(b());
}
}
}
}

class B {
foo() {
let a =
() => {
for (let x of [0]) {
let f = () => x;
this.bar(f());
}
}
}
bar(a: number) {
}
}

//// [capturedLetConstInLoop10.js]
var A = (function () {
function A() {
}
A.prototype.foo = function () {
var _loop_1 = function(x) {
var f = function () { return x; };
this_1.bar(f());
};
var this_1 = this;
for (var _i = 0, _a = [0]; _i < _a.length; _i++) {
var x = _a[_i];
_loop_1(x);
}
};
A.prototype.bar = function (a) {
};
A.prototype.baz = function () {
var _loop_2 = function(x) {
var a = function () { return x; };
var _loop_3 = function(y) {
var b = function () { return y; };
this_2.bar(b());
};
for (var _i = 0, _a = [1]; _i < _a.length; _i++) {
var y = _a[_i];
_loop_3(y);
}
this_2.bar(a());
};
var this_2 = this;
for (var _b = 0, _c = [1]; _b < _c.length; _b++) {
var x = _c[_b];
_loop_2(x);
}
};
A.prototype.baz2 = function () {
var _loop_4 = function(x) {
var a = function () { return x; };
this_3.bar(a());
var _loop_5 = function(y) {
var b = function () { return y; };
this_3.bar(b());
};
for (var _i = 0, _a = [1]; _i < _a.length; _i++) {
var y = _a[_i];
_loop_5(y);
}
};
var this_3 = this;
for (var _b = 0, _c = [1]; _b < _c.length; _b++) {
var x = _c[_b];
_loop_4(x);
}
};
return A;
})();
var B = (function () {
function B() {
}
B.prototype.foo = function () {
var _this = this;
var a = function () {
var _loop_6 = function(x) {
var f = function () { return x; };
_this.bar(f());
};
for (var _i = 0, _a = [0]; _i < _a.length; _i++) {
var x = _a[_i];
_loop_6(x);
}
};
};
B.prototype.bar = function (a) {
};
return B;
})();
119 changes: 119 additions & 0 deletions tests/baselines/reference/capturedLetConstInLoop10.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
=== tests/cases/compiler/capturedLetConstInLoop10.ts ===
class A {
>A : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))

foo() {
>foo : Symbol(foo, Decl(capturedLetConstInLoop10.ts, 0, 9))

for (let x of [0]) {
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 2, 16))

let f = function() { return x; };
>f : Symbol(f, Decl(capturedLetConstInLoop10.ts, 3, 15))
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 2, 16))

this.bar(f());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>this : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>f : Symbol(f, Decl(capturedLetConstInLoop10.ts, 3, 15))
}
}
bar(a: number) {
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 7, 8))
}

baz() {
>baz : Symbol(baz, Decl(capturedLetConstInLoop10.ts, 8, 5))

for (let x of [1]) {
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 11, 16))

let a = function() { return x; };
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 12, 15))
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 11, 16))

for (let y of [1]) {
>y : Symbol(y, Decl(capturedLetConstInLoop10.ts, 13, 20))

let b = function() { return y; };
>b : Symbol(b, Decl(capturedLetConstInLoop10.ts, 14, 19))
>y : Symbol(y, Decl(capturedLetConstInLoop10.ts, 13, 20))

this.bar(b());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>this : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>b : Symbol(b, Decl(capturedLetConstInLoop10.ts, 14, 19))
}
this.bar(a());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>this : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 12, 15))
}
}
baz2() {
>baz2 : Symbol(baz2, Decl(capturedLetConstInLoop10.ts, 19, 5))

for (let x of [1]) {
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 21, 16))

let a = function() { return x; };
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 22, 15))
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 21, 16))

this.bar(a());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>this : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 22, 15))

for (let y of [1]) {
>y : Symbol(y, Decl(capturedLetConstInLoop10.ts, 24, 20))

let b = function() { return y; };
>b : Symbol(b, Decl(capturedLetConstInLoop10.ts, 25, 19))
>y : Symbol(y, Decl(capturedLetConstInLoop10.ts, 24, 20))

this.bar(b());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>this : Symbol(A, Decl(capturedLetConstInLoop10.ts, 0, 0))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 6, 5))
>b : Symbol(b, Decl(capturedLetConstInLoop10.ts, 25, 19))
}
}
}
}

class B {
>B : Symbol(B, Decl(capturedLetConstInLoop10.ts, 30, 1))

foo() {
>foo : Symbol(foo, Decl(capturedLetConstInLoop10.ts, 32, 9))

let a =
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 34, 11))

() => {
for (let x of [0]) {
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 36, 24))

let f = () => x;
>f : Symbol(f, Decl(capturedLetConstInLoop10.ts, 37, 23))
>x : Symbol(x, Decl(capturedLetConstInLoop10.ts, 36, 24))

this.bar(f());
>this.bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 41, 5))
>this : Symbol(B, Decl(capturedLetConstInLoop10.ts, 30, 1))
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 41, 5))
>f : Symbol(f, Decl(capturedLetConstInLoop10.ts, 37, 23))
}
}
}
bar(a: number) {
>bar : Symbol(bar, Decl(capturedLetConstInLoop10.ts, 41, 5))
>a : Symbol(a, Decl(capturedLetConstInLoop10.ts, 42, 8))
}
}
Loading