From 74f57f6144a7109f73bdb54bd3b34f654e873cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 23 Dec 2023 15:14:52 +0100 Subject: [PATCH 1/2] Fixed narrowing based on aliased discriminants coming from destructured parameters --- src/compiler/checker.ts | 2 +- ...controlFlowAliasedDiscriminants.errors.txt | 10 +++++ .../controlFlowAliasedDiscriminants.js | 20 ++++++++++ .../controlFlowAliasedDiscriminants.symbols | 35 +++++++++++++++++ .../controlFlowAliasedDiscriminants.types | 38 +++++++++++++++++++ .../controlFlowAliasedDiscriminants.ts | 13 ++++++- 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3d4f288f1293b..1d9d1db4e1851 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27461,7 +27461,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: const rootDeclaration = getRootDeclaration(node.parent); - return isVariableDeclaration(rootDeclaration) && isVarConstLike(rootDeclaration); + return isVariableDeclaration(rootDeclaration) ? isVarConstLike(rootDeclaration) : !isSomeSymbolAssigned(rootDeclaration); } return false; } diff --git a/tests/baselines/reference/controlFlowAliasedDiscriminants.errors.txt b/tests/baselines/reference/controlFlowAliasedDiscriminants.errors.txt index 81779d897385d..222ca0c5312b2 100644 --- a/tests/baselines/reference/controlFlowAliasedDiscriminants.errors.txt +++ b/tests/baselines/reference/controlFlowAliasedDiscriminants.errors.txt @@ -126,4 +126,14 @@ controlFlowAliasedDiscriminants.ts(98,19): error TS1360: Type 'string | number' resp.resp.data satisfies string; } } + + function bindingPatternInParameter({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) { + const { data: data2, isSuccess: isSuccess2 } = useQuery(); + + const areSuccess = isSuccess1 && isSuccess2; + if (areSuccess) { + data1.toExponential(); + data2.toExponential(); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowAliasedDiscriminants.js b/tests/baselines/reference/controlFlowAliasedDiscriminants.js index 0be7340f29f63..b848d5efca86e 100644 --- a/tests/baselines/reference/controlFlowAliasedDiscriminants.js +++ b/tests/baselines/reference/controlFlowAliasedDiscriminants.js @@ -104,9 +104,20 @@ type Nested = { resp.resp.data satisfies string; } } + +function bindingPatternInParameter({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) { + const { data: data2, isSuccess: isSuccess2 } = useQuery(); + + const areSuccess = isSuccess1 && isSuccess2; + if (areSuccess) { + data1.toExponential(); + data2.toExponential(); + } +} //// [controlFlowAliasedDiscriminants.js] +"use strict"; function useQuery() { return { isSuccess: false, @@ -180,3 +191,12 @@ if (areSuccess) { resp.resp.data; } } +function bindingPatternInParameter(_a) { + var data1 = _a.data, isSuccess1 = _a.isSuccess; + var _b = useQuery(), data2 = _b.data, isSuccess2 = _b.isSuccess; + var areSuccess = isSuccess1 && isSuccess2; + if (areSuccess) { + data1.toExponential(); + data2.toExponential(); + } +} diff --git a/tests/baselines/reference/controlFlowAliasedDiscriminants.symbols b/tests/baselines/reference/controlFlowAliasedDiscriminants.symbols index 971b4be1c5c73..fab75c2bd92c2 100644 --- a/tests/baselines/reference/controlFlowAliasedDiscriminants.symbols +++ b/tests/baselines/reference/controlFlowAliasedDiscriminants.symbols @@ -325,3 +325,38 @@ type Nested = { } } +function bindingPatternInParameter({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) { +>bindingPatternInParameter : Symbol(bindingPatternInParameter, Decl(controlFlowAliasedDiscriminants.ts, 102, 1)) +>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20)) +>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 104, 36)) +>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5)) +>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 104, 49)) +>UseQueryResult : Symbol(UseQueryResult, Decl(controlFlowAliasedDiscriminants.ts, 0, 0)) + + const { data: data2, isSuccess: isSuccess2 } = useQuery(); +>data : Symbol(data, Decl(controlFlowAliasedDiscriminants.ts, 1, 21), Decl(controlFlowAliasedDiscriminants.ts, 4, 20)) +>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 105, 9)) +>isSuccess : Symbol(isSuccess, Decl(controlFlowAliasedDiscriminants.ts, 0, 26), Decl(controlFlowAliasedDiscriminants.ts, 3, 5)) +>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 105, 22)) +>useQuery : Symbol(useQuery, Decl(controlFlowAliasedDiscriminants.ts, 6, 2)) + + const areSuccess = isSuccess1 && isSuccess2; +>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 107, 7)) +>isSuccess1 : Symbol(isSuccess1, Decl(controlFlowAliasedDiscriminants.ts, 104, 49)) +>isSuccess2 : Symbol(isSuccess2, Decl(controlFlowAliasedDiscriminants.ts, 105, 22)) + + if (areSuccess) { +>areSuccess : Symbol(areSuccess, Decl(controlFlowAliasedDiscriminants.ts, 107, 7)) + + data1.toExponential(); +>data1.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +>data1 : Symbol(data1, Decl(controlFlowAliasedDiscriminants.ts, 104, 36)) +>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) + + data2.toExponential(); +>data2.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +>data2 : Symbol(data2, Decl(controlFlowAliasedDiscriminants.ts, 105, 9)) +>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) + } +} + diff --git a/tests/baselines/reference/controlFlowAliasedDiscriminants.types b/tests/baselines/reference/controlFlowAliasedDiscriminants.types index 5925a680bcc89..a22e71c309a38 100644 --- a/tests/baselines/reference/controlFlowAliasedDiscriminants.types +++ b/tests/baselines/reference/controlFlowAliasedDiscriminants.types @@ -376,3 +376,41 @@ type Nested = { } } +function bindingPatternInParameter({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) { +>bindingPatternInParameter : ({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) => void +>data : any +>data1 : number | undefined +>isSuccess : any +>isSuccess1 : boolean + + const { data: data2, isSuccess: isSuccess2 } = useQuery(); +>data : any +>data2 : number | undefined +>isSuccess : any +>isSuccess2 : boolean +>useQuery() : UseQueryResult +>useQuery : () => UseQueryResult + + const areSuccess = isSuccess1 && isSuccess2; +>areSuccess : boolean +>isSuccess1 && isSuccess2 : boolean +>isSuccess1 : boolean +>isSuccess2 : boolean + + if (areSuccess) { +>areSuccess : boolean + + data1.toExponential(); +>data1.toExponential() : string +>data1.toExponential : (fractionDigits?: number | undefined) => string +>data1 : number +>toExponential : (fractionDigits?: number | undefined) => string + + data2.toExponential(); +>data2.toExponential() : string +>data2.toExponential : (fractionDigits?: number | undefined) => string +>data2 : number +>toExponential : (fractionDigits?: number | undefined) => string + } +} + diff --git a/tests/cases/compiler/controlFlowAliasedDiscriminants.ts b/tests/cases/compiler/controlFlowAliasedDiscriminants.ts index 53e7bdd8bd352..b177724568278 100644 --- a/tests/cases/compiler/controlFlowAliasedDiscriminants.ts +++ b/tests/cases/compiler/controlFlowAliasedDiscriminants.ts @@ -1,5 +1,4 @@ -// @strictNullChecks: true -// @noImplicitAny: true +// @strict: true type UseQueryResult = { isSuccess: false; @@ -104,3 +103,13 @@ type Nested = { resp.resp.data satisfies string; } } + +function bindingPatternInParameter({ data: data1, isSuccess: isSuccess1 }: UseQueryResult) { + const { data: data2, isSuccess: isSuccess2 } = useQuery(); + + const areSuccess = isSuccess1 && isSuccess2; + if (areSuccess) { + data1.toExponential(); + data2.toExponential(); + } +} From 725310065bf89cfa1cb18d57a8d932c5647e5648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 23 Dec 2023 15:25:34 +0100 Subject: [PATCH 2/2] tweak the check --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1d9d1db4e1851..a3c83f76b6a1a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -476,6 +476,7 @@ import { isCallOrNewExpression, isCallSignatureDeclaration, isCatchClause, + isCatchClauseVariableDeclaration, isCatchClauseVariableDeclarationOrBindingElement, isCheckJsEnabledForFile, isClassDeclaration, @@ -27461,7 +27462,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: const rootDeclaration = getRootDeclaration(node.parent); - return isVariableDeclaration(rootDeclaration) ? isVarConstLike(rootDeclaration) : !isSomeSymbolAssigned(rootDeclaration); + return isParameter(rootDeclaration) || isCatchClauseVariableDeclaration(rootDeclaration) + ? !isSomeSymbolAssigned(rootDeclaration) + : isVariableDeclaration(rootDeclaration) && isVarConstLike(rootDeclaration); } return false; }