mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Reset error record in downlevel for-of (#31519)
This commit is contained in:
parent
7611c5b931
commit
b3dc32fec7
@ -145,7 +145,7 @@ namespace ts {
|
||||
loopOutParameters: LoopOutParameter[];
|
||||
}
|
||||
|
||||
type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined) => Statement;
|
||||
type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement;
|
||||
|
||||
// Facts we track as we traverse the tree
|
||||
const enum HierarchyFacts {
|
||||
@ -163,11 +163,12 @@ namespace ts {
|
||||
ExportedVariableStatement = 1 << 5, // Enclosed in an exported variable statement in the current scope
|
||||
TopLevel = 1 << 6, // Enclosing block-scoped container is a top-level container
|
||||
Block = 1 << 7, // Enclosing block-scoped container is a Block
|
||||
IterationStatement = 1 << 8, // Enclosed in an IterationStatement
|
||||
IterationStatement = 1 << 8, // Immediately enclosed in an IterationStatement
|
||||
IterationStatementBlock = 1 << 9, // Enclosing Block is enclosed in an IterationStatement
|
||||
ForStatement = 1 << 10, // Enclosing block-scoped container is a ForStatement
|
||||
ForInOrForOfStatement = 1 << 11, // Enclosing block-scoped container is a ForInStatement or ForOfStatement
|
||||
ConstructorWithCapturedSuper = 1 << 12, // Enclosed in a constructor that captures 'this' for use with 'super'
|
||||
IterationContainer = 1 << 10, // Enclosed in an outer IterationStatement
|
||||
ForStatement = 1 << 11, // Enclosing block-scoped container is a ForStatement
|
||||
ForInOrForOfStatement = 1 << 12, // Enclosing block-scoped container is a ForInStatement or ForOfStatement
|
||||
ConstructorWithCapturedSuper = 1 << 13, // Enclosed in a constructor that captures 'this' for use with 'super'
|
||||
// NOTE: do not add more ancestor flags without also updating AncestorFactsMask below.
|
||||
// NOTE: when adding a new ancestor flag, be sure to update the subtree flags below.
|
||||
|
||||
@ -184,11 +185,11 @@ namespace ts {
|
||||
|
||||
// A source file is a top-level block scope.
|
||||
SourceFileIncludes = TopLevel,
|
||||
SourceFileExcludes = BlockScopeExcludes & ~TopLevel,
|
||||
SourceFileExcludes = BlockScopeExcludes & ~TopLevel | IterationContainer,
|
||||
|
||||
// Functions, methods, and accessors are both new lexical scopes and new block scopes.
|
||||
FunctionIncludes = Function | TopLevel,
|
||||
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper,
|
||||
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer,
|
||||
|
||||
AsyncFunctionBodyIncludes = FunctionIncludes | AsyncFunctionBody,
|
||||
AsyncFunctionBodyExcludes = FunctionExcludes & ~NonStaticClassElement,
|
||||
@ -205,16 +206,16 @@ namespace ts {
|
||||
// 'do' and 'while' statements are not block scopes. We track that the subtree is contained
|
||||
// within an IterationStatement to indicate whether the embedded statement is an
|
||||
// IterationStatementBlock.
|
||||
DoOrWhileStatementIncludes = IterationStatement,
|
||||
DoOrWhileStatementIncludes = IterationStatement | IterationContainer,
|
||||
DoOrWhileStatementExcludes = None,
|
||||
|
||||
// 'for' statements are new block scopes and have special handling for 'let' declarations.
|
||||
ForStatementIncludes = IterationStatement | ForStatement,
|
||||
ForStatementIncludes = IterationStatement | ForStatement | IterationContainer,
|
||||
ForStatementExcludes = BlockScopeExcludes & ~ForStatement,
|
||||
|
||||
// 'for-in' and 'for-of' statements are new block scopes and have special handling for
|
||||
// 'let' declarations.
|
||||
ForInOrForOfStatementIncludes = IterationStatement | ForInOrForOfStatement,
|
||||
ForInOrForOfStatementIncludes = IterationStatement | ForInOrForOfStatement | IterationContainer,
|
||||
ForInOrForOfStatementExcludes = BlockScopeExcludes & ~ForInOrForOfStatement,
|
||||
|
||||
// Blocks (other than function bodies) are new block scopes.
|
||||
@ -228,8 +229,8 @@ namespace ts {
|
||||
// Subtree facts
|
||||
//
|
||||
|
||||
NewTarget = 1 << 13, // Contains a 'new.target' meta-property
|
||||
CapturedLexicalThis = 1 << 14, // Contains a lexical `this` reference captured by an arrow function.
|
||||
NewTarget = 1 << 14, // Contains a 'new.target' meta-property
|
||||
CapturedLexicalThis = 1 << 15, // Contains a lexical `this` reference captured by an arrow function.
|
||||
|
||||
//
|
||||
// Subtree masks
|
||||
@ -2227,7 +2228,7 @@ namespace ts {
|
||||
|
||||
function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) {
|
||||
const ancestorFacts = enterSubtree(excludeFacts, includeFacts);
|
||||
const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, convert);
|
||||
const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert);
|
||||
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
|
||||
return updated;
|
||||
}
|
||||
@ -2434,7 +2435,7 @@ namespace ts {
|
||||
return restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
}
|
||||
|
||||
function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement {
|
||||
function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], ancestorFacts: HierarchyFacts): Statement {
|
||||
const expression = visitNode(node.expression, visitor, isExpression);
|
||||
const iterator = isIdentifier(expression) ? getGeneratedNameForNode(expression) : createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const result = isIdentifier(expression) ? getGeneratedNameForNode(iterator) : createTempVariable(/*recordTempVariable*/ undefined);
|
||||
@ -2447,13 +2448,18 @@ namespace ts {
|
||||
hoistVariableDeclaration(errorRecord);
|
||||
hoistVariableDeclaration(returnMethod);
|
||||
|
||||
// if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration
|
||||
const initializer = ancestorFacts & HierarchyFacts.IterationContainer
|
||||
? inlineExpressions([createAssignment(errorRecord, createVoidZero()), values])
|
||||
: values;
|
||||
|
||||
const forStatement = setEmitFlags(
|
||||
setTextRange(
|
||||
createFor(
|
||||
/*initializer*/ setEmitFlags(
|
||||
setTextRange(
|
||||
createVariableDeclarationList([
|
||||
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, values), node.expression),
|
||||
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, initializer), node.expression),
|
||||
createVariableDeclaration(result, /*type*/ undefined, next)
|
||||
]),
|
||||
node.expression
|
||||
@ -2665,7 +2671,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter): VisitResult<Statement> {
|
||||
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult<Statement> {
|
||||
if (!shouldConvertIterationStatement(node)) {
|
||||
let saveAllowedNonLabeledJumps: Jump | undefined;
|
||||
if (convertedLoopState) {
|
||||
@ -2676,7 +2682,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const result = convert
|
||||
? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined)
|
||||
? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts)
|
||||
: restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
|
||||
if (convertedLoopState) {
|
||||
@ -2708,7 +2714,7 @@ namespace ts {
|
||||
let loop: Statement;
|
||||
if (bodyFunction) {
|
||||
if (convert) {
|
||||
loop = convert(node, outermostLabeledStatement, bodyFunction.part);
|
||||
loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts);
|
||||
}
|
||||
else {
|
||||
const clone = convertIterationStatementCore(node, initializerFunction, createBlock(bodyFunction.part, /*multiLine*/ true));
|
||||
|
||||
64
tests/baselines/reference/ES5For-of37.js
Normal file
64
tests/baselines/reference/ES5For-of37.js
Normal file
@ -0,0 +1,64 @@
|
||||
//// [ES5For-of37.ts]
|
||||
// https://github.com/microsoft/TypeScript/issues/30083
|
||||
|
||||
for (const i of [0, 1, 2, 3, 4]) {
|
||||
try {
|
||||
// Ensure catch binding for the following loop is reset per iteration:
|
||||
for (const j of [1, 2, 3]) {
|
||||
if (i === 2) {
|
||||
throw new Error('ERR');
|
||||
}
|
||||
}
|
||||
console.log(i);
|
||||
} catch (err) {
|
||||
console.log('E %s %s', i, err);
|
||||
}
|
||||
}
|
||||
|
||||
//// [ES5For-of37.js]
|
||||
// https://github.com/microsoft/TypeScript/issues/30083
|
||||
var __values = (this && this.__values) || function (o) {
|
||||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
|
||||
if (m) return m.call(o);
|
||||
return {
|
||||
next: function () {
|
||||
if (o && i >= o.length) o = void 0;
|
||||
return { value: o && o[i++], done: !o };
|
||||
}
|
||||
};
|
||||
};
|
||||
var e_1, _a, e_2, _b;
|
||||
try {
|
||||
for (var _c = __values([0, 1, 2, 3, 4]), _d = _c.next(); !_d.done; _d = _c.next()) {
|
||||
var i = _d.value;
|
||||
try {
|
||||
try {
|
||||
// Ensure catch binding for the following loop is reset per iteration:
|
||||
for (var _e = (e_2 = void 0, __values([1, 2, 3])), _f = _e.next(); !_f.done; _f = _e.next()) {
|
||||
var j = _f.value;
|
||||
if (i === 2) {
|
||||
throw new Error('ERR');
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_f && !_f.done && (_b = _e["return"])) _b.call(_e);
|
||||
}
|
||||
finally { if (e_2) throw e_2.error; }
|
||||
}
|
||||
console.log(i);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('E %s %s', i, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_d && !_d.done && (_a = _c["return"])) _a.call(_c);
|
||||
}
|
||||
finally { if (e_1) throw e_1.error; }
|
||||
}
|
||||
35
tests/baselines/reference/ES5For-of37.symbols
Normal file
35
tests/baselines/reference/ES5For-of37.symbols
Normal file
@ -0,0 +1,35 @@
|
||||
=== tests/cases/conformance/statements/for-ofStatements/ES5For-of37.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/30083
|
||||
|
||||
for (const i of [0, 1, 2, 3, 4]) {
|
||||
>i : Symbol(i, Decl(ES5For-of37.ts, 2, 10))
|
||||
|
||||
try {
|
||||
// Ensure catch binding for the following loop is reset per iteration:
|
||||
for (const j of [1, 2, 3]) {
|
||||
>j : Symbol(j, Decl(ES5For-of37.ts, 5, 18))
|
||||
|
||||
if (i === 2) {
|
||||
>i : Symbol(i, Decl(ES5For-of37.ts, 2, 10))
|
||||
|
||||
throw new Error('ERR');
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
console.log(i);
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>i : Symbol(i, Decl(ES5For-of37.ts, 2, 10))
|
||||
|
||||
} catch (err) {
|
||||
>err : Symbol(err, Decl(ES5For-of37.ts, 11, 13))
|
||||
|
||||
console.log('E %s %s', i, err);
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>i : Symbol(i, Decl(ES5For-of37.ts, 2, 10))
|
||||
>err : Symbol(err, Decl(ES5For-of37.ts, 11, 13))
|
||||
}
|
||||
}
|
||||
52
tests/baselines/reference/ES5For-of37.types
Normal file
52
tests/baselines/reference/ES5For-of37.types
Normal file
@ -0,0 +1,52 @@
|
||||
=== tests/cases/conformance/statements/for-ofStatements/ES5For-of37.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/30083
|
||||
|
||||
for (const i of [0, 1, 2, 3, 4]) {
|
||||
>i : number
|
||||
>[0, 1, 2, 3, 4] : number[]
|
||||
>0 : 0
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
>3 : 3
|
||||
>4 : 4
|
||||
|
||||
try {
|
||||
// Ensure catch binding for the following loop is reset per iteration:
|
||||
for (const j of [1, 2, 3]) {
|
||||
>j : number
|
||||
>[1, 2, 3] : number[]
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
>3 : 3
|
||||
|
||||
if (i === 2) {
|
||||
>i === 2 : boolean
|
||||
>i : number
|
||||
>2 : 2
|
||||
|
||||
throw new Error('ERR');
|
||||
>new Error('ERR') : Error
|
||||
>Error : ErrorConstructor
|
||||
>'ERR' : "ERR"
|
||||
}
|
||||
}
|
||||
console.log(i);
|
||||
>console.log(i) : void
|
||||
>console.log : (message?: any, ...optionalParams: any[]) => void
|
||||
>console : Console
|
||||
>log : (message?: any, ...optionalParams: any[]) => void
|
||||
>i : number
|
||||
|
||||
} catch (err) {
|
||||
>err : any
|
||||
|
||||
console.log('E %s %s', i, err);
|
||||
>console.log('E %s %s', i, err) : void
|
||||
>console.log : (message?: any, ...optionalParams: any[]) => void
|
||||
>console : Console
|
||||
>log : (message?: any, ...optionalParams: any[]) => void
|
||||
>'E %s %s' : "E %s %s"
|
||||
>i : number
|
||||
>err : any
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
// @downlevelIteration: true
|
||||
// https://github.com/microsoft/TypeScript/issues/30083
|
||||
|
||||
for (const i of [0, 1, 2, 3, 4]) {
|
||||
try {
|
||||
// Ensure catch binding for the following loop is reset per iteration:
|
||||
for (const j of [1, 2, 3]) {
|
||||
if (i === 2) {
|
||||
throw new Error('ERR');
|
||||
}
|
||||
}
|
||||
console.log(i);
|
||||
} catch (err) {
|
||||
console.log('E %s %s', i, err);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user