Skip to content

Commit

Permalink
Fix compiler crash with object rest in catch binding (#31522)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed May 22, 2019
1 parent b3dc32f commit c3055e5
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -30169,12 +30169,17 @@ namespace ts {
return undefined;
}

function isSymbolOfDestructuredElementOfCatchBinding(symbol: Symbol) {
return isBindingElement(symbol.valueDeclaration)
&& walkUpBindingElementsAndPatterns(symbol.valueDeclaration).parent.kind === SyntaxKind.CatchClause;
}

function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean {
if (symbol.flags & SymbolFlags.BlockScoped && !isSourceFile(symbol.valueDeclaration)) {
const links = getSymbolLinks(symbol);
if (links.isDeclarationWithCollidingName === undefined) {
const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration);
if (isStatementWithLocals(container)) {
if (isStatementWithLocals(container) || isSymbolOfDestructuredElementOfCatchBinding(symbol)) {
const nodeLinks = getNodeLinks(symbol.valueDeclaration);
if (resolveName(container.parent, symbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)) {
// redeclaration - always should be renamed
Expand Down
24 changes: 24 additions & 0 deletions src/compiler/transformers/es2018.ts
Expand Up @@ -77,6 +77,8 @@ namespace ts {
return visitObjectLiteralExpression(node as ObjectLiteralExpression);
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(node as BinaryExpression, noDestructuringValue);
case SyntaxKind.CatchClause:
return visitCatchClause(node as CatchClause);
case SyntaxKind.VariableDeclaration:
return visitVariableDeclaration(node as VariableDeclaration);
case SyntaxKind.ForOfStatement:
Expand Down Expand Up @@ -272,6 +274,28 @@ namespace ts {
return visitEachChild(node, visitor, context);
}

function visitCatchClause(node: CatchClause) {
if (node.variableDeclaration &&
isBindingPattern(node.variableDeclaration.name) &&
node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
const name = getGeneratedNameForNode(node.variableDeclaration.name);
const updatedDecl = updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*type*/ undefined, name);
const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest);
let block = visitNode(node.block, visitor, isBlock);
if (some(visitedBindings)) {
block = updateBlock(block, [
createVariableStatement(/*modifiers*/ undefined, visitedBindings),
...block.statements,
]);
}
return updateCatchClause(
node,
updateVariableDeclaration(node.variableDeclaration, name, /*type*/ undefined, /*initializer*/ undefined),
block);
}
return visitEachChild(node, visitor, context);
}

/**
* Visits a VariableDeclaration node with a binding pattern.
*
Expand Down
21 changes: 21 additions & 0 deletions tests/baselines/reference/objectRestCatchES5.js
@@ -0,0 +1,21 @@
//// [objectRestCatchES5.ts]
let a = 1, b = 2;
try {} catch ({ a, ...b }) {}

//// [objectRestCatchES5.js]
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var a = 1, b = 2;
try { }
catch (_a) {
var a_1 = _a.a, b_1 = __rest(_a, ["a"]);
}
9 changes: 9 additions & 0 deletions tests/baselines/reference/objectRestCatchES5.symbols
@@ -0,0 +1,9 @@
=== tests/cases/conformance/types/rest/objectRestCatchES5.ts ===
let a = 1, b = 2;
>a : Symbol(a, Decl(objectRestCatchES5.ts, 0, 3))
>b : Symbol(b, Decl(objectRestCatchES5.ts, 0, 10))

try {} catch ({ a, ...b }) {}
>a : Symbol(a, Decl(objectRestCatchES5.ts, 1, 15))
>b : Symbol(b, Decl(objectRestCatchES5.ts, 1, 18))

11 changes: 11 additions & 0 deletions tests/baselines/reference/objectRestCatchES5.types
@@ -0,0 +1,11 @@
=== tests/cases/conformance/types/rest/objectRestCatchES5.ts ===
let a = 1, b = 2;
>a : number
>1 : 1
>b : number
>2 : 2

try {} catch ({ a, ...b }) {}
>a : any
>b : any

2 changes: 2 additions & 0 deletions tests/cases/conformance/types/rest/objectRestCatchES5.ts
@@ -0,0 +1,2 @@
let a = 1, b = 2;
try {} catch ({ a, ...b }) {}

0 comments on commit c3055e5

Please sign in to comment.