From 1302133c2143b95875535b54898d2fca8950c37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Wed, 27 Jun 2018 17:29:37 +0800 Subject: [PATCH 1/4] check more case for empty binding patten --- src/compiler/checker.ts | 12 +++++- ...destructuringAssignabilityCheck.errors.txt | 43 +++++++++++++++++++ .../destructuringAssignabilityCheck.js | 32 ++++++++++++++ .../destructuringAssignabilityCheck.symbols | 24 +++++++++++ .../destructuringAssignabilityCheck.types | 40 +++++++++++++++++ .../strictNullEmptyDestructuring.errors.txt | 5 ++- .../destructuringAssignabilityCheck.ts | 17 ++++++++ 7 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/destructuringAssignabilityCheck.errors.txt create mode 100644 tests/baselines/reference/destructuringAssignabilityCheck.js create mode 100644 tests/baselines/reference/destructuringAssignabilityCheck.symbols create mode 100644 tests/baselines/reference/destructuringAssignabilityCheck.types create mode 100644 tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3a0fee79b3e7..162ed58854334 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23665,16 +23665,26 @@ namespace ts { // For a binding pattern, validate the initializer and exit if (isBindingPattern(node.name)) { // Don't validate for-in initializer as it is already an error + const widenedType = getWidenedTypeForVariableLikeDeclaration(node); if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { const initializerType = checkExpressionCached(node.initializer); if (strictNullChecks && node.name.elements.length === 0) { checkNonNullType(initializerType, node); } else { - checkTypeAssignableTo(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined); + checkTypeAssignableTo(initializerType, widenedType, node, /*headMessage*/ undefined); } checkParameterInitializer(node); } + // check the binding pattern with empty elements + if (node.name.elements.length === 0) { + if (isArrayBindingPattern(node.name)) { + checkIteratedTypeOrElementType(widenedType,node, /* allowStringInput */ false, /* allowAsyncIterables */ false); + } + else if(strictNullChecks) { + checkNonNullType(widenedType, node); + } + } return; } const symbol = getSymbolOfNode(node); diff --git a/tests/baselines/reference/destructuringAssignabilityCheck.errors.txt b/tests/baselines/reference/destructuringAssignabilityCheck.errors.txt new file mode 100644 index 0000000000000..bbb4812cf00ed --- /dev/null +++ b/tests/baselines/reference/destructuringAssignabilityCheck.errors.txt @@ -0,0 +1,43 @@ +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(1,7): error TS2461: Type '{}' is not an array type. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(2,7): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(3,3): error TS2461: Type '{}' is not an array type. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(4,3): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(6,14): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(9,14): error TS2461: Type '{}' is not an array type. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(13,7): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts(15,7): error TS2461: Type '{}' is not an array type. + + +==== tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts (8 errors) ==== + const [] = {}; // should be error + ~~ +!!! error TS2461: Type '{}' is not an array type. + const {} = undefined; // error correctly + ~~ +!!! error TS2532: Object is possibly 'undefined'. + (([]) => 0)({}); // should be error + ~~ +!!! error TS2461: Type '{}' is not an array type. + (({}) => 0)(undefined); // should be error + ~~ +!!! error TS2532: Object is possibly 'undefined'. + + function foo({}: undefined) { + ~~~~~~~~~~~~~ +!!! error TS2532: Object is possibly 'undefined'. + return 0 + } + function bar([]: {}) { + ~~~~~~ +!!! error TS2461: Type '{}' is not an array type. + return 0 + } + + const { }: undefined = 1 + ~~~ +!!! error TS2532: Object is possibly 'undefined'. + + const []: {} = {} + ~~ +!!! error TS2461: Type '{}' is not an array type. + \ No newline at end of file diff --git a/tests/baselines/reference/destructuringAssignabilityCheck.js b/tests/baselines/reference/destructuringAssignabilityCheck.js new file mode 100644 index 0000000000000..2702d8b7f5c59 --- /dev/null +++ b/tests/baselines/reference/destructuringAssignabilityCheck.js @@ -0,0 +1,32 @@ +//// [destructuringAssignabilityCheck.ts] +const [] = {}; // should be error +const {} = undefined; // error correctly +(([]) => 0)({}); // should be error +(({}) => 0)(undefined); // should be error + +function foo({}: undefined) { + return 0 +} +function bar([]: {}) { + return 0 +} + +const { }: undefined = 1 + +const []: {} = {} + + +//// [destructuringAssignabilityCheck.js] +"use strict"; +var _a = {}; // should be error +var _b = undefined; // error correctly +(function (_a) { return 0; })({}); // should be error +(function (_a) { return 0; })(undefined); // should be error +function foo(_a) { + return 0; +} +function bar(_a) { + return 0; +} +var _c = 1; +var _d = {}; diff --git a/tests/baselines/reference/destructuringAssignabilityCheck.symbols b/tests/baselines/reference/destructuringAssignabilityCheck.symbols new file mode 100644 index 0000000000000..c9465f0e41aea --- /dev/null +++ b/tests/baselines/reference/destructuringAssignabilityCheck.symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts === +const [] = {}; // should be error +const {} = undefined; // error correctly +>undefined : Symbol(undefined) + +(([]) => 0)({}); // should be error +(({}) => 0)(undefined); // should be error +>undefined : Symbol(undefined) + +function foo({}: undefined) { +>foo : Symbol(foo, Decl(destructuringAssignabilityCheck.ts, 3, 23)) + + return 0 +} +function bar([]: {}) { +>bar : Symbol(bar, Decl(destructuringAssignabilityCheck.ts, 7, 1)) + + return 0 +} + +const { }: undefined = 1 + +const []: {} = {} + diff --git a/tests/baselines/reference/destructuringAssignabilityCheck.types b/tests/baselines/reference/destructuringAssignabilityCheck.types new file mode 100644 index 0000000000000..df4467cce6433 --- /dev/null +++ b/tests/baselines/reference/destructuringAssignabilityCheck.types @@ -0,0 +1,40 @@ +=== tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts === +const [] = {}; // should be error +>{} : {} + +const {} = undefined; // error correctly +>undefined : undefined + +(([]) => 0)({}); // should be error +>(([]) => 0)({}) : number +>(([]) => 0) : ([]: {}) => number +>([]) => 0 : ([]: {}) => number +>0 : 0 +>{} : {} + +(({}) => 0)(undefined); // should be error +>(({}) => 0)(undefined) : number +>(({}) => 0) : ({}: undefined) => number +>({}) => 0 : ({}: undefined) => number +>0 : 0 +>undefined : undefined + +function foo({}: undefined) { +>foo : ({}: undefined) => number + + return 0 +>0 : 0 +} +function bar([]: {}) { +>bar : ([]: {}) => number + + return 0 +>0 : 0 +} + +const { }: undefined = 1 +>1 : 1 + +const []: {} = {} +>{} : {} + diff --git a/tests/baselines/reference/strictNullEmptyDestructuring.errors.txt b/tests/baselines/reference/strictNullEmptyDestructuring.errors.txt index 2406ac27d98a1..cb50303d3500d 100644 --- a/tests/baselines/reference/strictNullEmptyDestructuring.errors.txt +++ b/tests/baselines/reference/strictNullEmptyDestructuring.errors.txt @@ -1,3 +1,4 @@ +tests/cases/compiler/strictNullEmptyDestructuring.ts(3,5): error TS2461: Type 'null' is not an array type. tests/cases/compiler/strictNullEmptyDestructuring.ts(3,5): error TS2531: Object is possibly 'null'. tests/cases/compiler/strictNullEmptyDestructuring.ts(5,5): error TS2531: Object is possibly 'null'. tests/cases/compiler/strictNullEmptyDestructuring.ts(7,2): error TS2531: Object is possibly 'null'. @@ -11,11 +12,13 @@ tests/cases/compiler/strictNullEmptyDestructuring.ts(21,5): error TS2533: Object tests/cases/compiler/strictNullEmptyDestructuring.ts(23,2): error TS2533: Object is possibly 'null' or 'undefined'. -==== tests/cases/compiler/strictNullEmptyDestructuring.ts (11 errors) ==== +==== tests/cases/compiler/strictNullEmptyDestructuring.ts (12 errors) ==== // Repro from #20873 let [] = null; ~~ +!!! error TS2461: Type 'null' is not an array type. + ~~ !!! error TS2531: Object is possibly 'null'. let { } = null; diff --git a/tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts b/tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts new file mode 100644 index 0000000000000..af595c1621f96 --- /dev/null +++ b/tests/cases/conformance/es6/destructuring/destructuringAssignabilityCheck.ts @@ -0,0 +1,17 @@ +// @strict: true + +const [] = {}; // should be error +const {} = undefined; // error correctly +(([]) => 0)({}); // should be error +(({}) => 0)(undefined); // should be error + +function foo({}: undefined) { + return 0 +} +function bar([]: {}) { + return 0 +} + +const { }: undefined = 1 + +const []: {} = {} From af362cc666b1698080010ff936a4ee596530d515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Wed, 27 Jun 2018 17:52:32 +0800 Subject: [PATCH 2/4] refactor binding pattern checking getWidenedType --- src/compiler/checker.ts | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 162ed58854334..01536c456fc80 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23664,25 +23664,29 @@ namespace ts { } // For a binding pattern, validate the initializer and exit if (isBindingPattern(node.name)) { - // Don't validate for-in initializer as it is already an error - const widenedType = getWidenedTypeForVariableLikeDeclaration(node); - if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { - const initializerType = checkExpressionCached(node.initializer); - if (strictNullChecks && node.name.elements.length === 0) { - checkNonNullType(initializerType, node); - } - else { - checkTypeAssignableTo(initializerType, widenedType, node, /*headMessage*/ undefined); - } - checkParameterInitializer(node); - } - // check the binding pattern with empty elements - if (node.name.elements.length === 0) { - if (isArrayBindingPattern(node.name)) { - checkIteratedTypeOrElementType(widenedType,node, /* allowStringInput */ false, /* allowAsyncIterables */ false); + const needCheckInitializer = node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; + const needCheckWinendType = node.name.elements.length === 0; + if (needCheckInitializer || needCheckWinendType) { + // Don't validate for-in initializer as it is already an error + const widenedType = getWidenedTypeForVariableLikeDeclaration(node); + if (needCheckInitializer) { + const initializerType = checkExpressionCached(node.initializer!); + if (strictNullChecks && node.name.elements.length === 0) { + checkNonNullType(initializerType, node); + } + else { + checkTypeAssignableTo(initializerType, widenedType, node, /*headMessage*/ undefined); + } + checkParameterInitializer(node); } - else if(strictNullChecks) { - checkNonNullType(widenedType, node); + // check the binding pattern with empty elements + if (needCheckWinendType) { + if (isArrayBindingPattern(node.name)) { + checkIteratedTypeOrElementType(widenedType, node, /* allowStringInput */ false, /* allowAsyncIterables */ false); + } + else if (strictNullChecks) { + checkNonNullType(widenedType, node); + } } } return; From 9eb45eae9ba41da3ff3805fe01778604f91b8077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Fri, 25 Jan 2019 14:30:30 +0800 Subject: [PATCH 3/4] fix spelling --- src/compiler/checker.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fc1f6e7cb5b64..f16353f057496 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25666,8 +25666,8 @@ namespace ts { // For a binding pattern, validate the initializer and exit if (isBindingPattern(node.name)) { const needCheckInitializer = node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; - const needCheckWinendType = node.name.elements.length === 0; - if (needCheckInitializer || needCheckWinendType) { + const needCheckWidenedType = node.name.elements.length === 0; + if (needCheckInitializer || needCheckWidenedType) { // Don't validate for-in initializer as it is already an error const widenedType = getWidenedTypeForVariableLikeDeclaration(node); if (needCheckInitializer) { @@ -25676,15 +25676,12 @@ namespace ts { checkNonNullType(initializerType, node); } else { - checkTypeAssignableTo(initializerType, widenedType, node, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); } checkParameterInitializer(node); - } else { - checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); } - // check the binding pattern with empty elements - if (needCheckWinendType) { + if (needCheckWidenedType) { if (isArrayBindingPattern(node.name)) { checkIteratedTypeOrElementType(widenedType, node, /* allowStringInput */ false, /* allowAsyncIterables */ false); } From bd46038ca99d7f02f98f6c5145c277381c7301b8 Mon Sep 17 00:00:00 2001 From: kingwl Date: Sat, 27 Apr 2019 00:16:11 +0800 Subject: [PATCH 4/4] fix merge and rebase --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7e976c20a46e8..8ee0a4c051996 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26475,7 +26475,6 @@ namespace ts { else { checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); } - checkParameterInitializer(node); } // check the binding pattern with empty elements if (needCheckWidenedType) { @@ -26483,7 +26482,7 @@ namespace ts { checkIteratedTypeOrElementType(widenedType, node, /* allowStringInput */ false, /* allowAsyncIterables */ false); } else if (strictNullChecks) { - checkNonNullType(widenedType, node); + checkNonNullNonVoidType(widenedType, node); } } }