diff --git a/scripts/test262_whitelist.txt b/scripts/test262_whitelist.txt index c61322e4f2..5514f994a9 100644 --- a/scripts/test262_whitelist.txt +++ b/scripts/test262_whitelist.txt @@ -750,8 +750,6 @@ language/block-scope/syntax/redeclaration/let-declaration-attempt-to-redeclare-w language/block-scope/syntax/redeclaration/let-declaration-attempt-to-redeclare-with-async-generator-declaration.js(strict mode) language/block-scope/syntax/redeclaration/var-declaration-attempt-to-redeclare-with-async-generator-declaration.js(default) language/block-scope/syntax/redeclaration/var-declaration-attempt-to-redeclare-with-async-generator-declaration.js(strict mode) -language/expressions/assignment/dstr-obj-rest-not-last-element-invalid.js(default) -language/expressions/assignment/dstr-obj-rest-not-last-element-invalid.js(strict mode) language/expressions/async-generator/dflt-params-duplicates.js(default) language/expressions/async-generator/early-errors-expression-await-as-function-binding-identifier.js(default) language/expressions/async-generator/early-errors-expression-await-as-function-binding-identifier.js(strict mode) @@ -784,12 +782,8 @@ language/statements/for-await-of/escaped-of.js(default) language/statements/for-await-of/escaped-of.js(strict mode) language/statements/for-in/decl-async-gen.js(default) language/statements/for-in/decl-async-gen.js(strict mode) -language/statements/for-in/dstr-obj-rest-not-last-element-invalid.js(default) -language/statements/for-in/dstr-obj-rest-not-last-element-invalid.js(strict mode) language/statements/for-of/decl-async-gen.js(default) language/statements/for-of/decl-async-gen.js(strict mode) -language/statements/for-of/dstr-obj-rest-not-last-element-invalid.js(default) -language/statements/for-of/dstr-obj-rest-not-last-element-invalid.js(strict mode) language/statements/if/if-async-gen-else-async-gen.js(default) language/statements/if/if-async-gen-else-async-gen.js(strict mode) language/statements/if/if-async-gen-else-stmt.js(default) diff --git a/src/parser/lval.js b/src/parser/lval.js index 981eaf9018..d5156a634c 100644 --- a/src/parser/lval.js +++ b/src/parser/lval.js @@ -56,26 +56,12 @@ export default class LValParser extends NodeUtils { case "ObjectExpression": node.type = "ObjectPattern"; - for (const prop of node.properties) { - if (prop.type === "ObjectMethod") { - if (prop.kind === "get" || prop.kind === "set") { - this.raise( - prop.key.start, - "Object pattern can't contain getter or setter", - ); - } else { - this.raise( - prop.key.start, - "Object pattern can't contain methods", - ); - } - } else { - this.toAssignable( - prop, - isBinding, - "object destructuring pattern", - ); - } + for (const [index, prop] of node.properties.entries()) { + this.toAssignableObjectExpressionProp( + prop, + isBinding, + index === node.properties.length - 1, + ); } break; @@ -124,6 +110,28 @@ export default class LValParser extends NodeUtils { return node; } + toAssignableObjectExpressionProp( + prop: Node, + isBinding: ?boolean, + isLast: boolean, + ) { + if (prop.type === "ObjectMethod") { + const error = + prop.kind === "get" || prop.kind === "set" + ? "Object pattern can't contain getter or setter" + : "Object pattern can't contain methods"; + + this.raise(prop.key.start, error); + } else if (prop.type === "SpreadElement" && !isLast) { + this.raise( + prop.start, + "The rest element has to be the last element when destructuring", + ); + } else { + this.toAssignable(prop, isBinding, "object destructuring pattern"); + } + } + // Convert list of expression atoms to binding list. toAssignableList( diff --git a/src/plugins/estree.js b/src/plugins/estree.js index 86129d2731..7f227778df 100644 --- a/src/plugins/estree.js +++ b/src/plugins/estree.js @@ -317,25 +317,26 @@ export default (superClass: Class): Class => if (isSimpleProperty(node)) { this.toAssignable(node.value, isBinding, contextDescription); - return node; - } else if (node.type === "ObjectExpression") { - node.type = "ObjectPattern"; - for (const prop of node.properties) { - if (prop.kind === "get" || prop.kind === "set") { - this.raise( - prop.key.start, - "Object pattern can't contain getter or setter", - ); - } else if (prop.method) { - this.raise(prop.key.start, "Object pattern can't contain methods"); - } else { - this.toAssignable(prop, isBinding, "object destructuring pattern"); - } - } - return node; } return super.toAssignable(node, isBinding, contextDescription); } + + toAssignableObjectExpressionProp( + prop: N.Node, + isBinding: ?boolean, + isLast: boolean, + ) { + if (prop.kind === "get" || prop.kind === "set") { + this.raise( + prop.key.start, + "Object pattern can't contain getter or setter", + ); + } else if (prop.method) { + this.raise(prop.key.start, "Object pattern can't contain methods"); + } else { + super.toAssignableObjectExpressionProp(prop, isBinding, isLast); + } + } }; diff --git a/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/actual.js b/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/actual.js new file mode 100644 index 0000000000..27193c0b18 --- /dev/null +++ b/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/actual.js @@ -0,0 +1 @@ +({...rest, b} = {}) diff --git a/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/options.json b/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/options.json new file mode 100644 index 0000000000..d2981263bf --- /dev/null +++ b/test/fixtures/experimental/object-rest-spread/expression-rest-not-last-invalid/options.json @@ -0,0 +1,3 @@ +{ + "throws": "The rest element has to be the last element when destructuring (1:2)" +}