Skip to content

Fix 16628: "undefined" exception when name of binding element in binding pattern is empty #17132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 9, 2017

Conversation

yuit
Copy link
Contributor

@yuit yuit commented Jul 12, 2017

Fix #16628

@@ -1367,6 +1367,11 @@ namespace ts {
}

function writeVariableStatement(node: VariableStatement) {
// If binding pattern doesn't have name, then there is nothing to be emitted for declaration file i.e. const [,] = [1,2].
if (node.declarationList.declarations.length && isBindingPattern(node.declarationList.declarations[0].name) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be a recursive check, as binding patterns can nest infinitely, and of not just omitted expressions, but omitted expressions or binding patterns containing only the aforementioned.

Also, a test for that:

// @declaration: true
export let [,,[,[],,[],]] = undefined as any;

@@ -331,11 +331,14 @@ namespace ts {
location
);
}
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0) ||
every(elements, (element) => isOmittedExpression(element))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This... might? Need to be recursive? Depends on how the transform works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer: No. To be spec compliant, we still emit temporaries in js for empty binding patterns in order to attempt to get the elements for the sub-binding patterns/invoke their side-effects (and potentially error if they do not exist).

// If the first or last declaration is a binding pattern, we need to modify
// the source map range for the declaration list.
const firstDeclaration = firstOrUndefined(declarations);
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
if (firstDeclaration && lastDeclaration) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably bail much before here - up before createVariableDeclarationList if declarations is empty.

@weswigham weswigham self-assigned this Aug 4, 2017
@weswigham weswigham requested review from rbuckton and amcasey August 5, 2017 00:14
if (node.transformFlags & TransformFlags.ContainsBindingPattern
&& (isBindingPattern(node.declarations[0].name)
|| isBindingPattern(lastOrUndefined(node.declarations).name))) {
const firstDeclaration = firstOrUndefined(declarations);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why look up the declarations before checking if there is work to do? If we need to ensure firstDeclaration is not undefined, add another if inside of the existing block.

Also, you shouldn't need to check both firstDeclaration and lastDeclaration as both will be undefined if declarations.length === 0 and both will have values if declarations.length > 0.

@@ -331,11 +331,14 @@ namespace ts {
location
);
}
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)
|| every(elements, (element) => isOmittedExpression(element))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just use every(elements, isOmittedExpression)? No need to introduce a new function here.

@weswigham
Copy link
Member

@rbuckton Done

@weswigham weswigham merged commit 39e0cc6 into master Aug 9, 2017
@weswigham weswigham deleted the master-16628 branch August 9, 2017 20:47
uniqueiniquity pushed a commit to uniqueiniquity/TypeScript that referenced this pull request Aug 9, 2017
…ing pattern is empty (microsoft#17132)

* Handle the case where binding pattern name element is empty

* Update tests and baselines

* Feedback from PR

* Handle empty binding patterns more generally in emitter

* Dont simply handling fo empty binding patterns and stay spec compliant

* PR feedback
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants