From b45df892a88ab751c4d2289b1e585eee9ad3d632 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Thu, 25 Apr 2019 22:33:49 +0200 Subject: [PATCH] emit error on destructuring of rest property (#29609) Fixes: #26005 --- src/compiler/checker.ts | 7 +++++ .../restPropertyWithBindingPattern.errors.txt | 28 +++++++++++++++++ .../restPropertyWithBindingPattern.js | 21 +++++++++++++ .../restPropertyWithBindingPattern.symbols | 6 ++++ .../restPropertyWithBindingPattern.types | 31 +++++++++++++++++++ .../restPropertyWithBindingPattern.ts | 4 +++ 6 files changed, 97 insertions(+) create mode 100644 tests/baselines/reference/restPropertyWithBindingPattern.errors.txt create mode 100644 tests/baselines/reference/restPropertyWithBindingPattern.js create mode 100644 tests/baselines/reference/restPropertyWithBindingPattern.symbols create mode 100644 tests/baselines/reference/restPropertyWithBindingPattern.types create mode 100644 tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9020d9e47dfd9..0c4d9e3aa71df 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31186,6 +31186,13 @@ namespace ts { for (const prop of node.properties) { if (prop.kind === SyntaxKind.SpreadAssignment) { + if (inDestructuring) { + // a rest property cannot be destructured any further + const expression = skipParentheses(prop.expression); + if (isArrayLiteralExpression(expression) || isObjectLiteralExpression(expression)) { + return grammarErrorOnNode(prop.expression, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + } + } continue; } const name = prop.name; diff --git a/tests/baselines/reference/restPropertyWithBindingPattern.errors.txt b/tests/baselines/reference/restPropertyWithBindingPattern.errors.txt new file mode 100644 index 0000000000000..7ad0cac9ce3bc --- /dev/null +++ b/tests/baselines/reference/restPropertyWithBindingPattern.errors.txt @@ -0,0 +1,28 @@ +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(1,6): error TS2501: A rest element cannot contain a binding pattern. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(2,6): error TS2501: A rest element cannot contain a binding pattern. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(2,6): error TS2701: The target of an object rest assignment must be a variable or a property access. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(3,6): error TS2461: Type '{}' is not an array type. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(3,6): error TS2501: A rest element cannot contain a binding pattern. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(4,6): error TS2501: A rest element cannot contain a binding pattern. +tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts(4,6): error TS2701: The target of an object rest assignment must be a variable or a property access. + + +==== tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts (7 errors) ==== + ({...{}} = {}); + ~~ +!!! error TS2501: A rest element cannot contain a binding pattern. + ({...({})} = {}); + ~~~~ +!!! error TS2501: A rest element cannot contain a binding pattern. + ~~~~ +!!! error TS2701: The target of an object rest assignment must be a variable or a property access. + ({...[]} = {}); + ~~ +!!! error TS2461: Type '{}' is not an array type. + ~~ +!!! error TS2501: A rest element cannot contain a binding pattern. + ({...([])} = {}); + ~~~~ +!!! error TS2501: A rest element cannot contain a binding pattern. + ~~~~ +!!! error TS2701: The target of an object rest assignment must be a variable or a property access. \ No newline at end of file diff --git a/tests/baselines/reference/restPropertyWithBindingPattern.js b/tests/baselines/reference/restPropertyWithBindingPattern.js new file mode 100644 index 0000000000000..c4a4795d6827b --- /dev/null +++ b/tests/baselines/reference/restPropertyWithBindingPattern.js @@ -0,0 +1,21 @@ +//// [restPropertyWithBindingPattern.ts] +({...{}} = {}); +({...({})} = {}); +({...[]} = {}); +({...([])} = {}); + +//// [restPropertyWithBindingPattern.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) + t[p[i]] = s[p[i]]; + return t; +}; +var _a, _b; +(_a = __rest({}, [])); +(({}) = __rest({}, [])); +(_b = __rest({}, [])); +(([]) = __rest({}, [])); diff --git a/tests/baselines/reference/restPropertyWithBindingPattern.symbols b/tests/baselines/reference/restPropertyWithBindingPattern.symbols new file mode 100644 index 0000000000000..79b4b6745e3b4 --- /dev/null +++ b/tests/baselines/reference/restPropertyWithBindingPattern.symbols @@ -0,0 +1,6 @@ +=== tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts === +({...{}} = {}); +No type information for this code.({...({})} = {}); +No type information for this code.({...[]} = {}); +No type information for this code.({...([])} = {}); +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/restPropertyWithBindingPattern.types b/tests/baselines/reference/restPropertyWithBindingPattern.types new file mode 100644 index 0000000000000..0cf290c792a4e --- /dev/null +++ b/tests/baselines/reference/restPropertyWithBindingPattern.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts === +({...{}} = {}); +>({...{}} = {}) : {} +>{...{}} = {} : {} +>{...{}} : {} +>{} : {} +>{} : {} + +({...({})} = {}); +>({...({})} = {}) : {} +>{...({})} = {} : {} +>{...({})} : {} +>({}) : {} +>{} : {} +>{} : {} + +({...[]} = {}); +>({...[]} = {}) : {} +>{...[]} = {} : {} +>{...[]} : { [n: number]: undefined; length: number; toString(): string; toLocaleString(): string; pop(): undefined; push(...items: undefined[]): number; concat(...items: ConcatArray[]): undefined[]; concat(...items: ConcatArray[]): undefined[]; join(separator?: string): string; reverse(): undefined[]; shift(): undefined; slice(start?: number, end?: number): undefined[]; sort(compareFn?: (a: undefined, b: undefined) => number): undefined[]; splice(start: number, deleteCount?: number): undefined[]; splice(start: number, deleteCount: number, ...items: undefined[]): undefined[]; unshift(...items: undefined[]): number; indexOf(searchElement: undefined, fromIndex?: number): number; lastIndexOf(searchElement: undefined, fromIndex?: number): number; every(callbackfn: (value: undefined, index: number, array: undefined[]) => boolean, thisArg?: any): boolean; some(callbackfn: (value: undefined, index: number, array: undefined[]) => boolean, thisArg?: any): boolean; forEach(callbackfn: (value: undefined, index: number, array: undefined[]) => void, thisArg?: any): void; map(callbackfn: (value: undefined, index: number, array: undefined[]) => U, thisArg?: any): U[]; filter(callbackfn: (value: undefined, index: number, array: undefined[]) => value is S, thisArg?: any): S[]; filter(callbackfn: (value: undefined, index: number, array: undefined[]) => any, thisArg?: any): undefined[]; reduce(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined): undefined; reduce(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined, initialValue: undefined): undefined; reduce(callbackfn: (previousValue: U, currentValue: undefined, currentIndex: number, array: undefined[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined): undefined; reduceRight(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined, initialValue: undefined): undefined; reduceRight(callbackfn: (previousValue: U, currentValue: undefined, currentIndex: number, array: undefined[]) => U, initialValue: U): U; } +>[] : undefined[] +>{} : {} + +({...([])} = {}); +>({...([])} = {}) : {} +>{...([])} = {} : {} +>{...([])} : { [n: number]: undefined; length: number; toString(): string; toLocaleString(): string; pop(): undefined; push(...items: undefined[]): number; concat(...items: ConcatArray[]): undefined[]; concat(...items: ConcatArray[]): undefined[]; join(separator?: string): string; reverse(): undefined[]; shift(): undefined; slice(start?: number, end?: number): undefined[]; sort(compareFn?: (a: undefined, b: undefined) => number): undefined[]; splice(start: number, deleteCount?: number): undefined[]; splice(start: number, deleteCount: number, ...items: undefined[]): undefined[]; unshift(...items: undefined[]): number; indexOf(searchElement: undefined, fromIndex?: number): number; lastIndexOf(searchElement: undefined, fromIndex?: number): number; every(callbackfn: (value: undefined, index: number, array: undefined[]) => boolean, thisArg?: any): boolean; some(callbackfn: (value: undefined, index: number, array: undefined[]) => boolean, thisArg?: any): boolean; forEach(callbackfn: (value: undefined, index: number, array: undefined[]) => void, thisArg?: any): void; map(callbackfn: (value: undefined, index: number, array: undefined[]) => U, thisArg?: any): U[]; filter(callbackfn: (value: undefined, index: number, array: undefined[]) => value is S, thisArg?: any): S[]; filter(callbackfn: (value: undefined, index: number, array: undefined[]) => any, thisArg?: any): undefined[]; reduce(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined): undefined; reduce(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined, initialValue: undefined): undefined; reduce(callbackfn: (previousValue: U, currentValue: undefined, currentIndex: number, array: undefined[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined): undefined; reduceRight(callbackfn: (previousValue: undefined, currentValue: undefined, currentIndex: number, array: undefined[]) => undefined, initialValue: undefined): undefined; reduceRight(callbackfn: (previousValue: U, currentValue: undefined, currentIndex: number, array: undefined[]) => U, initialValue: U): U; } +>([]) : undefined[] +>[] : undefined[] +>{} : {} + diff --git a/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts b/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts new file mode 100644 index 0000000000000..fc7bd03561045 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/restPropertyWithBindingPattern.ts @@ -0,0 +1,4 @@ +({...{}} = {}); +({...({})} = {}); +({...[]} = {}); +({...([])} = {}); \ No newline at end of file