Skip to content

Commit

Permalink
🤖 Pick PR #47927 (Don't error if binding pattern type...) into releas…
Browse files Browse the repository at this point in the history
…e-4.6 (#48005)

* Cherry-pick PR #47927 into release-4.6

Component commits:
c4aa31b early return if pattern type is never

* Update LKG

Co-authored-by: Gabriela Araujo Britto <gabrielaa@microsoft.com>
Co-authored-by: typescript-bot <typescript@microsoft.com>
  • Loading branch information
3 people committed Feb 23, 2022
1 parent f4fe064 commit 78ee4ca
Show file tree
Hide file tree
Showing 16 changed files with 353 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/tsc.js
Expand Up @@ -58514,6 +58514,9 @@ var ts;
if (parentType && parentType.flags & 1048576 && !(parent.kind === 163 && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, undefined, location.flowNode);
if (narrowedType.flags & 131072) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/tsserver.js
Expand Up @@ -70031,6 +70031,9 @@ var ts;
if (parentType && parentType.flags & 1048576 /* Union */ && !(parent.kind === 163 /* Parameter */ && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & 131072 /* Never */) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/tsserverlibrary.js
Expand Up @@ -70225,6 +70225,9 @@ var ts;
if (parentType && parentType.flags & 1048576 /* Union */ && !(parent.kind === 163 /* Parameter */ && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & 131072 /* Never */) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/typescript.js
Expand Up @@ -70225,6 +70225,9 @@ var ts;
if (parentType && parentType.flags & 1048576 /* Union */ && !(parent.kind === 163 /* Parameter */ && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & 131072 /* Never */) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/typescriptServices.js
Expand Up @@ -70225,6 +70225,9 @@ var ts;
if (parentType && parentType.flags & 1048576 /* Union */ && !(parent.kind === 163 /* Parameter */ && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & 131072 /* Never */) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions lib/typingsInstaller.js
Expand Up @@ -70020,6 +70020,9 @@ var ts;
if (parentType && parentType.flags & 1048576 /* Union */ && !(parent.kind === 163 /* Parameter */ && isSymbolAssigned(symbol))) {
var pattern = declaration.parent;
var narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & 131072 /* Never */) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/checker.ts
Expand Up @@ -25127,6 +25127,9 @@ namespace ts {
if (parentType && parentType.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) {
const pattern = declaration.parent;
const narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & TypeFlags.Never) {
return neverType;
}
return getBindingElementTypeFromParentType(declaration, narrowedType);
}
}
Expand Down
47 changes: 47 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch1.js
@@ -0,0 +1,47 @@
//// [arrayDestructuringInSwitch1.ts]
export type Expression = BooleanLogicExpression | 'true' | 'false';
export type BooleanLogicExpression = ['and', ...Expression[]] | ['not', Expression];

export function evaluate(expression: Expression): boolean {
if (Array.isArray(expression)) {
const [operator, ...operands] = expression;
switch (operator) {
case 'and': {
return operands.every((child) => evaluate(child));
}
case 'not': {
return !evaluate(operands[0]);
}
default: {
throw new Error(`${operator} is not a supported operator`);
}
}
} else {
return expression === 'true';
}
}

//// [arrayDestructuringInSwitch1.js]
"use strict";
exports.__esModule = true;
exports.evaluate = void 0;
function evaluate(expression) {
if (Array.isArray(expression)) {
var operator = expression[0], operands = expression.slice(1);
switch (operator) {
case 'and': {
return operands.every(function (child) { return evaluate(child); });
}
case 'not': {
return !evaluate(operands[0]);
}
default: {
throw new Error("".concat(operator, " is not a supported operator"));
}
}
}
else {
return expression === 'true';
}
}
exports.evaluate = evaluate;
55 changes: 55 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch1.symbols
@@ -0,0 +1,55 @@
=== tests/cases/compiler/arrayDestructuringInSwitch1.ts ===
export type Expression = BooleanLogicExpression | 'true' | 'false';
>Expression : Symbol(Expression, Decl(arrayDestructuringInSwitch1.ts, 0, 0))
>BooleanLogicExpression : Symbol(BooleanLogicExpression, Decl(arrayDestructuringInSwitch1.ts, 0, 67))

export type BooleanLogicExpression = ['and', ...Expression[]] | ['not', Expression];
>BooleanLogicExpression : Symbol(BooleanLogicExpression, Decl(arrayDestructuringInSwitch1.ts, 0, 67))
>Expression : Symbol(Expression, Decl(arrayDestructuringInSwitch1.ts, 0, 0))
>Expression : Symbol(Expression, Decl(arrayDestructuringInSwitch1.ts, 0, 0))

export function evaluate(expression: Expression): boolean {
>evaluate : Symbol(evaluate, Decl(arrayDestructuringInSwitch1.ts, 1, 84))
>expression : Symbol(expression, Decl(arrayDestructuringInSwitch1.ts, 3, 25))
>Expression : Symbol(Expression, Decl(arrayDestructuringInSwitch1.ts, 0, 0))

if (Array.isArray(expression)) {
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>expression : Symbol(expression, Decl(arrayDestructuringInSwitch1.ts, 3, 25))

const [operator, ...operands] = expression;
>operator : Symbol(operator, Decl(arrayDestructuringInSwitch1.ts, 5, 11))
>operands : Symbol(operands, Decl(arrayDestructuringInSwitch1.ts, 5, 20))
>expression : Symbol(expression, Decl(arrayDestructuringInSwitch1.ts, 3, 25))

switch (operator) {
>operator : Symbol(operator, Decl(arrayDestructuringInSwitch1.ts, 5, 11))

case 'and': {
return operands.every((child) => evaluate(child));
>operands.every : Symbol(Array.every, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>operands : Symbol(operands, Decl(arrayDestructuringInSwitch1.ts, 5, 20))
>every : Symbol(Array.every, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>child : Symbol(child, Decl(arrayDestructuringInSwitch1.ts, 8, 31))
>evaluate : Symbol(evaluate, Decl(arrayDestructuringInSwitch1.ts, 1, 84))
>child : Symbol(child, Decl(arrayDestructuringInSwitch1.ts, 8, 31))
}
case 'not': {
return !evaluate(operands[0]);
>evaluate : Symbol(evaluate, Decl(arrayDestructuringInSwitch1.ts, 1, 84))
>operands : Symbol(operands, Decl(arrayDestructuringInSwitch1.ts, 5, 20))
>0 : Symbol(0)
}
default: {
throw new Error(`${operator} is not a supported operator`);
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>operator : Symbol(operator, Decl(arrayDestructuringInSwitch1.ts, 5, 11))
}
}
} else {
return expression === 'true';
>expression : Symbol(expression, Decl(arrayDestructuringInSwitch1.ts, 3, 25))
}
}
66 changes: 66 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch1.types
@@ -0,0 +1,66 @@
=== tests/cases/compiler/arrayDestructuringInSwitch1.ts ===
export type Expression = BooleanLogicExpression | 'true' | 'false';
>Expression : Expression

export type BooleanLogicExpression = ['and', ...Expression[]] | ['not', Expression];
>BooleanLogicExpression : BooleanLogicExpression

export function evaluate(expression: Expression): boolean {
>evaluate : (expression: Expression) => boolean
>expression : Expression

if (Array.isArray(expression)) {
>Array.isArray(expression) : boolean
>Array.isArray : (arg: any) => arg is any[]
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>expression : Expression

const [operator, ...operands] = expression;
>operator : "and" | "not"
>operands : Expression[] | [Expression]
>expression : BooleanLogicExpression

switch (operator) {
>operator : "and" | "not"

case 'and': {
>'and' : "and"

return operands.every((child) => evaluate(child));
>operands.every((child) => evaluate(child)) : boolean
>operands.every : { <S extends Expression>(predicate: (value: Expression, index: number, array: Expression[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Expression, index: number, array: Expression[]) => unknown, thisArg?: any): boolean; } | { <S extends Expression>(predicate: (value: Expression, index: number, array: Expression[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Expression, index: number, array: Expression[]) => unknown, thisArg?: any): boolean; }
>operands : Expression[] | [Expression]
>every : { <S extends Expression>(predicate: (value: Expression, index: number, array: Expression[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Expression, index: number, array: Expression[]) => unknown, thisArg?: any): boolean; } | { <S extends Expression>(predicate: (value: Expression, index: number, array: Expression[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: Expression, index: number, array: Expression[]) => unknown, thisArg?: any): boolean; }
>(child) => evaluate(child) : (child: Expression) => boolean
>child : Expression
>evaluate(child) : boolean
>evaluate : (expression: Expression) => boolean
>child : Expression
}
case 'not': {
>'not' : "not"

return !evaluate(operands[0]);
>!evaluate(operands[0]) : boolean
>evaluate(operands[0]) : boolean
>evaluate : (expression: Expression) => boolean
>operands[0] : Expression
>operands : Expression[] | [Expression]
>0 : 0
}
default: {
throw new Error(`${operator} is not a supported operator`);
>new Error(`${operator} is not a supported operator`) : Error
>Error : ErrorConstructor
>`${operator} is not a supported operator` : string
>operator : never
}
}
} else {
return expression === 'true';
>expression === 'true' : boolean
>expression : "true" | "false"
>'true' : "true"
}
}
20 changes: 20 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch2.errors.txt
@@ -0,0 +1,20 @@
tests/cases/compiler/arrayDestructuringInSwitch2.ts(11,13): error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.


==== tests/cases/compiler/arrayDestructuringInSwitch2.ts (1 errors) ====
type X = { kind: "a", a: [1] } | { kind: "b", a: [] }

function foo(x: X): 1 {
const { kind, a } = x;
switch (kind) {
case "a":
return a[0];
case "b":
return 1;
default:
const [n] = a;
~~~
!!! error TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.
return a;
}
}
29 changes: 29 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch2.js
@@ -0,0 +1,29 @@
//// [arrayDestructuringInSwitch2.ts]
type X = { kind: "a", a: [1] } | { kind: "b", a: [] }

function foo(x: X): 1 {
const { kind, a } = x;
switch (kind) {
case "a":
return a[0];
case "b":
return 1;
default:
const [n] = a;
return a;
}
}

//// [arrayDestructuringInSwitch2.js]
function foo(x) {
var kind = x.kind, a = x.a;
switch (kind) {
case "a":
return a[0];
case "b":
return 1;
default:
var n = a[0];
return a;
}
}
37 changes: 37 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch2.symbols
@@ -0,0 +1,37 @@
=== tests/cases/compiler/arrayDestructuringInSwitch2.ts ===
type X = { kind: "a", a: [1] } | { kind: "b", a: [] }
>X : Symbol(X, Decl(arrayDestructuringInSwitch2.ts, 0, 0))
>kind : Symbol(kind, Decl(arrayDestructuringInSwitch2.ts, 0, 10))
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 0, 21))
>kind : Symbol(kind, Decl(arrayDestructuringInSwitch2.ts, 0, 34))
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 0, 45))

function foo(x: X): 1 {
>foo : Symbol(foo, Decl(arrayDestructuringInSwitch2.ts, 0, 53))
>x : Symbol(x, Decl(arrayDestructuringInSwitch2.ts, 2, 13))
>X : Symbol(X, Decl(arrayDestructuringInSwitch2.ts, 0, 0))

const { kind, a } = x;
>kind : Symbol(kind, Decl(arrayDestructuringInSwitch2.ts, 3, 9))
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 3, 15))
>x : Symbol(x, Decl(arrayDestructuringInSwitch2.ts, 2, 13))

switch (kind) {
>kind : Symbol(kind, Decl(arrayDestructuringInSwitch2.ts, 3, 9))

case "a":
return a[0];
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 3, 15))
>0 : Symbol(0)

case "b":
return 1;
default:
const [n] = a;
>n : Symbol(n, Decl(arrayDestructuringInSwitch2.ts, 10, 13))
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 3, 15))

return a;
>a : Symbol(a, Decl(arrayDestructuringInSwitch2.ts, 3, 15))
}
}
43 changes: 43 additions & 0 deletions tests/baselines/reference/arrayDestructuringInSwitch2.types
@@ -0,0 +1,43 @@
=== tests/cases/compiler/arrayDestructuringInSwitch2.ts ===
type X = { kind: "a", a: [1] } | { kind: "b", a: [] }
>X : X
>kind : "a"
>a : [1]
>kind : "b"
>a : []

function foo(x: X): 1 {
>foo : (x: X) => 1
>x : X

const { kind, a } = x;
>kind : "a" | "b"
>a : [1] | []
>x : X

switch (kind) {
>kind : "a" | "b"

case "a":
>"a" : "a"

return a[0];
>a[0] : 1
>a : [1]
>0 : 0

case "b":
>"b" : "b"

return 1;
>1 : 1

default:
const [n] = a;
>n : never
>a : never

return a;
>a : never
}
}
21 changes: 21 additions & 0 deletions tests/cases/compiler/arrayDestructuringInSwitch1.ts
@@ -0,0 +1,21 @@
export type Expression = BooleanLogicExpression | 'true' | 'false';
export type BooleanLogicExpression = ['and', ...Expression[]] | ['not', Expression];

export function evaluate(expression: Expression): boolean {
if (Array.isArray(expression)) {
const [operator, ...operands] = expression;
switch (operator) {
case 'and': {
return operands.every((child) => evaluate(child));
}
case 'not': {
return !evaluate(operands[0]);
}
default: {
throw new Error(`${operator} is not a supported operator`);
}
}
} else {
return expression === 'true';
}
}

0 comments on commit 78ee4ca

Please sign in to comment.