From a21460ff7516e674e98f77b9112399083e8eab75 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Feb 2015 12:35:02 -0800 Subject: [PATCH 1/3] Fix crash on destructuring null or undefined into rest element --- src/compiler/checker.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d2d6e9275bb..a06de62be8d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1722,7 +1722,7 @@ module ts { } else { // For an array binding element the specified or inferred type of the parent must be assignable to any[] - if (!isTypeAssignableTo(parentType, anyArrayType)) { + if (!isArrayLikeType(parentType)) { error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType)); return unknownType; } @@ -4190,6 +4190,10 @@ module ts { return type.flags & TypeFlags.Reference && (type).target === globalArrayType; } + function isArrayLikeType(type: Type): boolean { + return !(type.flags & (TypeFlags.Undefined | TypeFlags.Null)) && isTypeAssignableTo(type, anyArrayType); + } + function isTupleLikeType(type: Type): boolean { return !!getPropertyOfType(type, "0"); } @@ -5466,7 +5470,7 @@ module ts { function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type { var type = checkExpressionCached(node.expression, contextualMapper); - if (!isTypeAssignableTo(type, anyArrayType)) { + if (!isArrayLikeType(type)) { error(node.expression, Diagnostics.Type_0_is_not_an_array_type, typeToString(type)); return unknownType; } @@ -7074,7 +7078,7 @@ module ts { function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { // TODOO(andersh): Allow iterable source type in ES6 - if (!isTypeAssignableTo(sourceType, anyArrayType)) { + if (!isArrayLikeType(sourceType)) { error(node, Diagnostics.Type_0_is_not_an_array_type, typeToString(sourceType)); return sourceType; } From 95b3d6be5867f150739de7330845ad76f1cf1aed Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Feb 2015 12:41:20 -0800 Subject: [PATCH 2/3] Adding test --- .../reference/restElementWithNullInitializer.errors.txt | 8 ++++++++ .../baselines/reference/restElementWithNullInitializer.js | 6 ++++++ .../es6/destructuring/restElementWithNullInitializer.ts | 1 + 3 files changed, 15 insertions(+) create mode 100644 tests/baselines/reference/restElementWithNullInitializer.errors.txt create mode 100644 tests/baselines/reference/restElementWithNullInitializer.js create mode 100644 tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts diff --git a/tests/baselines/reference/restElementWithNullInitializer.errors.txt b/tests/baselines/reference/restElementWithNullInitializer.errors.txt new file mode 100644 index 00000000000..b1222ebc0e7 --- /dev/null +++ b/tests/baselines/reference/restElementWithNullInitializer.errors.txt @@ -0,0 +1,8 @@ +tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts(1,14): error TS2461: Type 'null' is not an array type. + + +==== tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts (1 errors) ==== + function foo([...r] = null) { } + ~~~~~~ +!!! error TS2461: Type 'null' is not an array type. + \ No newline at end of file diff --git a/tests/baselines/reference/restElementWithNullInitializer.js b/tests/baselines/reference/restElementWithNullInitializer.js new file mode 100644 index 00000000000..a4056c665f3 --- /dev/null +++ b/tests/baselines/reference/restElementWithNullInitializer.js @@ -0,0 +1,6 @@ +//// [restElementWithNullInitializer.ts] +function foo([...r] = null) { } + + +//// [restElementWithNullInitializer.js] +function foo(_a) { } diff --git a/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts b/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts new file mode 100644 index 00000000000..f136633e094 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts @@ -0,0 +1 @@ +function foo([...r] = null) { } From ca92653aba44d437476822907493f1386890e5b4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 21 Feb 2015 19:33:53 -0800 Subject: [PATCH 3/3] Addressing CR feedback --- src/compiler/checker.ts | 3 ++- .../restElementWithNullInitializer.errors.txt | 24 +++++++++++++++--- .../restElementWithNullInitializer.js | 25 +++++++++++++++++-- .../restElementWithNullInitializer.ts | 12 ++++++++- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a06de62be8d..01d63c7d85f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1721,7 +1721,7 @@ module ts { } } else { - // For an array binding element the specified or inferred type of the parent must be assignable to any[] + // For an array binding element the specified or inferred type of the parent must be an array-like type if (!isArrayLikeType(parentType)) { error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType)); return unknownType; @@ -4191,6 +4191,7 @@ module ts { } function isArrayLikeType(type: Type): boolean { + // A type is array-like if it is not the undefined or null type and if it is assignable to any[] return !(type.flags & (TypeFlags.Undefined | TypeFlags.Null)) && isTypeAssignableTo(type, anyArrayType); } diff --git a/tests/baselines/reference/restElementWithNullInitializer.errors.txt b/tests/baselines/reference/restElementWithNullInitializer.errors.txt index b1222ebc0e7..7beb7b9a642 100644 --- a/tests/baselines/reference/restElementWithNullInitializer.errors.txt +++ b/tests/baselines/reference/restElementWithNullInitializer.errors.txt @@ -1,8 +1,24 @@ -tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts(1,14): error TS2461: Type 'null' is not an array type. +tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts(1,15): error TS2461: Type 'null' is not an array type. +tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts(4,15): error TS2461: Type 'undefined' is not an array type. +tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts(7,15): error TS2461: Type '{ [x: number]: undefined; }' is not an array type. -==== tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts (1 errors) ==== - function foo([...r] = null) { } - ~~~~~~ +==== tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts (3 errors) ==== + function foo1([...r] = null) { + ~~~~~~ !!! error TS2461: Type 'null' is not an array type. + } + + function foo2([...r] = undefined) { + ~~~~~~ +!!! error TS2461: Type 'undefined' is not an array type. + } + + function foo3([...r] = {}) { + ~~~~~~ +!!! error TS2461: Type '{ [x: number]: undefined; }' is not an array type. + } + + function foo4([...r] = []) { + } \ No newline at end of file diff --git a/tests/baselines/reference/restElementWithNullInitializer.js b/tests/baselines/reference/restElementWithNullInitializer.js index a4056c665f3..9f326602fb8 100644 --- a/tests/baselines/reference/restElementWithNullInitializer.js +++ b/tests/baselines/reference/restElementWithNullInitializer.js @@ -1,6 +1,27 @@ //// [restElementWithNullInitializer.ts] -function foo([...r] = null) { } +function foo1([...r] = null) { +} + +function foo2([...r] = undefined) { +} + +function foo3([...r] = {}) { +} + +function foo4([...r] = []) { +} //// [restElementWithNullInitializer.js] -function foo(_a) { } +function foo1(_a) { + var _b = _a === void 0 ? null : _a, r = _b.slice(0); +} +function foo2(_a) { + var _b = _a === void 0 ? undefined : _a, r = _b.slice(0); +} +function foo3(_a) { + var _b = _a === void 0 ? {} : _a, r = _b.slice(0); +} +function foo4(_a) { + var _b = _a === void 0 ? [] : _a, r = _b.slice(0); +} diff --git a/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts b/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts index f136633e094..1b03c533e7d 100644 --- a/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts +++ b/tests/cases/conformance/es6/destructuring/restElementWithNullInitializer.ts @@ -1 +1,11 @@ -function foo([...r] = null) { } +function foo1([...r] = null) { +} + +function foo2([...r] = undefined) { +} + +function foo3([...r] = {}) { +} + +function foo4([...r] = []) { +}