From f0ba3f471adabce3df862adf89f7e8d17888c2b7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 11 Oct 2015 01:12:26 -0700 Subject: [PATCH 1/4] support block scoped vars captured in closures inside loops --- src/compiler/checker.ts | 24 +- src/compiler/diagnosticMessages.json | 4 - src/compiler/emitter.ts | 560 ++++++++- src/compiler/types.ts | 4 +- src/compiler/utilities.ts | 16 + .../reference/capturedLetConstInLoop1.js | 272 ++++ .../reference/capturedLetConstInLoop1.symbols | 260 ++++ .../reference/capturedLetConstInLoop1.types | 428 +++++++ .../reference/capturedLetConstInLoop1_ES6.js | 210 ++++ .../capturedLetConstInLoop1_ES6.symbols | 260 ++++ .../capturedLetConstInLoop1_ES6.types | 428 +++++++ .../reference/capturedLetConstInLoop2.js | 413 ++++++ .../reference/capturedLetConstInLoop2.symbols | 519 ++++++++ .../reference/capturedLetConstInLoop2.types | 726 +++++++++++ .../reference/capturedLetConstInLoop2_ES6.js | 330 +++++ .../capturedLetConstInLoop2_ES6.symbols | 518 ++++++++ .../capturedLetConstInLoop2_ES6.types | 725 +++++++++++ .../reference/capturedLetConstInLoop3.js | 473 +++++++ .../reference/capturedLetConstInLoop3.symbols | 565 +++++++++ .../reference/capturedLetConstInLoop3.types | 794 ++++++++++++ .../reference/capturedLetConstInLoop3_ES6.js | 394 ++++++ .../capturedLetConstInLoop3_ES6.symbols | 566 +++++++++ .../capturedLetConstInLoop3_ES6.types | 795 ++++++++++++ .../reference/capturedLetConstInLoop4.js | 338 +++++ .../reference/capturedLetConstInLoop4.symbols | 394 ++++++ .../reference/capturedLetConstInLoop4.types | 600 +++++++++ .../reference/capturedLetConstInLoop4_ES6.js | 266 ++++ .../capturedLetConstInLoop4_ES6.symbols | 394 ++++++ .../capturedLetConstInLoop4_ES6.types | 600 +++++++++ .../reference/capturedLetConstInLoop5.js | 617 +++++++++ .../reference/capturedLetConstInLoop5.symbols | 682 ++++++++++ .../reference/capturedLetConstInLoop5.types | 951 ++++++++++++++ .../reference/capturedLetConstInLoop5_ES6.js | 518 ++++++++ .../capturedLetConstInLoop5_ES6.symbols | 683 ++++++++++ .../capturedLetConstInLoop5_ES6.types | 952 ++++++++++++++ .../reference/capturedLetConstInLoop6.js | 557 +++++++++ .../reference/capturedLetConstInLoop6.symbols | 481 +++++++ .../reference/capturedLetConstInLoop6.types | 729 +++++++++++ .../reference/capturedLetConstInLoop6_ES6.js | 455 +++++++ .../capturedLetConstInLoop6_ES6.symbols | 481 +++++++ .../capturedLetConstInLoop6_ES6.types | 729 +++++++++++ .../reference/capturedLetConstInLoop7.js | 894 +++++++++++++ .../reference/capturedLetConstInLoop7.symbols | 698 +++++++++++ .../reference/capturedLetConstInLoop7.types | 1106 +++++++++++++++++ .../reference/capturedLetConstInLoop7_ES6.js | 712 +++++++++++ .../capturedLetConstInLoop7_ES6.symbols | 698 +++++++++++ .../capturedLetConstInLoop7_ES6.types | 1106 +++++++++++++++++ .../reference/capturedLetConstInLoop8.js | 269 ++++ .../reference/capturedLetConstInLoop8.symbols | 208 ++++ .../reference/capturedLetConstInLoop8.types | 329 +++++ .../reference/capturedLetConstInLoop8_ES6.js | 222 ++++ .../capturedLetConstInLoop8_ES6.symbols | 209 ++++ .../capturedLetConstInLoop8_ES6.types | 330 +++++ .../reference/capturedLetConstInLoop9.js | 252 ++++ .../reference/capturedLetConstInLoop9.symbols | 219 ++++ .../reference/capturedLetConstInLoop9.types | 297 +++++ .../reference/capturedLetConstInLoop9_ES6.js | 221 ++++ .../capturedLetConstInLoop9_ES6.symbols | 220 ++++ .../capturedLetConstInLoop9_ES6.types | 298 +++++ .../reference/downlevelLetConst18.errors.txt | 23 +- .../reference/downlevelLetConst18.js | 37 +- .../cases/compiler/capturedLetConstInLoop1.ts | 113 ++ .../compiler/capturedLetConstInLoop1_ES6.ts | 114 ++ .../cases/compiler/capturedLetConstInLoop2.ts | 176 +++ .../compiler/capturedLetConstInLoop2_ES6.ts | 176 +++ .../cases/compiler/capturedLetConstInLoop3.ts | 217 ++++ .../compiler/capturedLetConstInLoop3_ES6.ts | 219 ++++ .../cases/compiler/capturedLetConstInLoop4.ts | 143 +++ .../compiler/capturedLetConstInLoop4_ES6.ts | 143 +++ .../cases/compiler/capturedLetConstInLoop5.ts | 279 +++++ .../compiler/capturedLetConstInLoop5_ES6.ts | 281 +++++ .../cases/compiler/capturedLetConstInLoop6.ts | 237 ++++ .../compiler/capturedLetConstInLoop6_ES6.ts | 238 ++++ .../cases/compiler/capturedLetConstInLoop7.ts | 375 ++++++ .../compiler/capturedLetConstInLoop7_ES6.ts | 376 ++++++ .../cases/compiler/capturedLetConstInLoop8.ts | 113 ++ .../compiler/capturedLetConstInLoop8_ES6.ts | 115 ++ .../cases/compiler/capturedLetConstInLoop9.ts | 122 ++ .../compiler/capturedLetConstInLoop9_ES6.ts | 124 ++ 79 files changed, 31556 insertions(+), 64 deletions(-) create mode 100644 tests/baselines/reference/capturedLetConstInLoop1.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop1.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop1.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop1_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop1_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop1_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop2.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop2.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop2.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop2_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop2_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop2_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop3.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop3.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop3.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop3_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop3_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop3_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop4.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop4.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop4.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop4_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop4_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop4_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop5.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop5.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop5.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop5_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop5_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop5_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop6_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop6_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop6_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop7.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop7.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop7.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop7_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop7_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop7_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop8.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop8.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop8.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop8_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop8_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop8_ES6.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop9.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop9.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop9.types create mode 100644 tests/baselines/reference/capturedLetConstInLoop9_ES6.js create mode 100644 tests/baselines/reference/capturedLetConstInLoop9_ES6.symbols create mode 100644 tests/baselines/reference/capturedLetConstInLoop9_ES6.types create mode 100644 tests/cases/compiler/capturedLetConstInLoop1.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop1_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop2.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop2_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop3.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop3_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop4.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop4_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop5.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop5_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop6_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop7.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop7_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop8.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop8_ES6.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop9.ts create mode 100644 tests/cases/compiler/capturedLetConstInLoop9_ES6.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d4ce6655a21..5e73da9a7d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6550,7 +6550,7 @@ namespace ts { while (current && !nodeStartsNewLexicalEnvironment(current)) { if (isIterationStatement(current, /*lookInLabeledStatements*/ false)) { if (inFunction) { - grammarErrorOnFirstToken(current, Diagnostics.Loop_contains_block_scoped_variable_0_referenced_by_a_function_in_the_loop_This_is_only_supported_in_ECMAScript_6_or_higher, declarationNameToString(node)); + getNodeLinks(current).flags |= NodeCheckFlags.LoopWithBlockScopedBindingCapturedInFunction; } // mark value declaration so during emit they can have a special handling getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.BlockScopedBindingInLoop; @@ -14533,6 +14533,10 @@ namespace ts { // Emitter support + function isArgumentsLocalBinding(node: Identifier): boolean { + return getReferencedValueSymbol(node) === argumentsSymbol; + } + // When resolved as an expression identifier, if the given node references an exported entity, return the declaration // node of the exported entity's container. Otherwise, return undefined. function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration { @@ -14837,7 +14841,8 @@ namespace ts { collectLinkedAliases, getReferencedValueDeclaration, getTypeReferenceSerializationKind, - isOptionalParameter + isOptionalParameter, + isArgumentsLocalBinding }; } @@ -15664,21 +15669,6 @@ namespace ts { } } - function isIterationStatement(node: Node, lookInLabeledStatements: boolean): boolean { - switch (node.kind) { - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - return true; - case SyntaxKind.LabeledStatement: - return lookInLabeledStatements && isIterationStatement((node).statement, lookInLabeledStatements); - } - - return false; - } - function checkGrammarBreakOrContinueStatement(node: BreakOrContinueStatement): boolean { let current: Node = node; while (current) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b391545a733..9635610c133 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2008,10 +2008,6 @@ "category": "Error", "code": 4082 }, - "Loop contains block-scoped variable '{0}' referenced by a function in the loop. This is only supported in ECMAScript 6 or higher.": { - "category": "Error", - "code": 4091 - }, "The current host does not support the '{0}' option.": { "category": "Error", "code": 5001 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f01b7cb54a4..cd0967c5717 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -379,6 +379,93 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return true; } + const enum Jump { + Break = 1 << 1, + Continue = 1 << 2, + Return = 1 << 3 + } + + interface ConvertedLoopState { + // set of labels that occured inside the converted loop + // used to determine if labeled jump can be emitted as is or it should be dispatched to calling code + labels?: Map; + // collection of labeled jumps that transfer control outside the converted loop. + // maps store association 'label -> labelMarker' where + // - label - value of label as it apprear in code + // - label marker - return value that should be interpreted by calling code as 'jump to