From 12d5296b6cbdfa691e4b42ca2d0a218e2edfc04c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Sat, 26 Jun 2021 09:26:42 -0700 Subject: [PATCH 1/5] Check entire access path is constant when narrowing by inlining --- src/compiler/checker.ts | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5625bbc171ea2..aa2196752a13f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22975,7 +22975,20 @@ namespace ts { } } - function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, isConstant?: boolean, flowContainer?: Node) { + function isConstantReference(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.Identifier: + const symbol = getResolvedSymbol(node as Identifier); + return isConstVariable(symbol) || !!symbol.valueDeclaration && getRootDeclaration(symbol.valueDeclaration).kind === SyntaxKind.Parameter && !isParameterAssigned(symbol); + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. + return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); + } + return false; + } + + function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node) { let key: string | undefined; let isKeySet = false; let flowDepth = 0; @@ -24020,11 +24033,11 @@ namespace ts { case SyntaxKind.Identifier: // When narrowing a reference to a const variable, non-assigned parameter, or readonly property, we inline // up to five levels of aliased conditional expressions that are themselves declared as const variables. - if (isConstant && !isMatchingReference(reference, expr) && inlineLevel < 5) { + if (!isMatchingReference(reference, expr) && inlineLevel < 5) { const symbol = getResolvedSymbol(expr as Identifier); if (isConstVariable(symbol)) { const declaration = symbol.valueDeclaration; - if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer) { + if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isConstantReference(reference)) { inlineLevel++; const result = narrowType(type, declaration.initializer, assumeTrue); inlineLevel--; @@ -24370,12 +24383,12 @@ namespace ts { const isOuterVariable = flowContainer !== declarationContainer; const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); const isModuleExports = symbol.flags & SymbolFlags.ModuleExports; - const isConstant = isConstVariable(localOrExportSymbol) && getTypeOfSymbol(localOrExportSymbol) !== autoArrayType || isParameter && !isParameterAssigned(localOrExportSymbol); // When the control flow originates in a function expression or arrow function and we are referencing // a const variable or parameter from an outer function, we extend the origin of the control flow // analysis to include the immediately enclosing function. - while (isConstant && flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression || - flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethod(flowContainer))) { + while (flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression || + flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethod(flowContainer)) && + (isConstVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isParameterAssigned(localOrExportSymbol))) { flowContainer = getControlFlowContainer(flowContainer); } // We only look for uninitialized variables in strict null checking mode, and only when we can analyze @@ -24390,7 +24403,7 @@ namespace ts { const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : getOptionalType(type); - const flowType = getFlowTypeOfReference(node, type, initialType, isConstant, flowContainer); + const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the // control flow based type does include undefined. @@ -27608,7 +27621,7 @@ namespace ts { getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration)) { assumeUninitialized = true; } - const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType, prop && isReadonlySymbol(prop)); + const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors From 19eba22294b9f99123e45d5ac53dc6af3cd2c79d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Sat, 26 Jun 2021 14:21:37 -0700 Subject: [PATCH 2/5] Add tests --- .../controlFlow/controlFlowAliasing.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts index 9ac9e98c3f2bc..2e16fa29eb78c 100644 --- a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts +++ b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts @@ -48,6 +48,36 @@ function f14(x: number | null | undefined): number | null { return notUndefined ? x : 0; } +function f15(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + if (isString) { + let s: string = obj.x; + } +} + +function f16(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + obj = { x: 42 }; + if (isString) { + let s: string = obj.x; // Not narrowed because of is assigned in function body + } +} + +function f17(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + if (isString) { + let s: string = obj[0]; + } +} + +function f18(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + obj = [42]; + if (isString) { + let s: string = obj[0]; // Not narrowed because of is assigned in function body + } +} + function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { const isFoo = obj.kind === 'foo'; if (isFoo) { From d535af6cc50bcad492b9b8067253b1d1ed700284 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg <andersh@microsoft.com> Date: Sat, 26 Jun 2021 14:21:44 -0700 Subject: [PATCH 3/5] Accept new baselines --- .../reference/controlFlowAliasing.errors.txt | 66 +- .../reference/controlFlowAliasing.js | 64 ++ .../reference/controlFlowAliasing.symbols | 627 ++++++++++-------- .../reference/controlFlowAliasing.types | 111 ++++ 4 files changed, 586 insertions(+), 282 deletions(-) diff --git a/tests/baselines/reference/controlFlowAliasing.errors.txt b/tests/baselines/reference/controlFlowAliasing.errors.txt index d747a3215928a..93bb7936eeebb 100644 --- a/tests/baselines/reference/controlFlowAliasing.errors.txt +++ b/tests/baselines/reference/controlFlowAliasing.errors.txt @@ -1,30 +1,34 @@ -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(61,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(59,13): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(74,13): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(91,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(64,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(94,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(71,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(101,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(74,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(104,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(82,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(112,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(85,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(115,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(104,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(134,13): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(107,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(137,13): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(124,19): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(154,19): error TS2339: Property 'foo' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(127,19): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(157,19): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(207,13): error TS2322: Type 'string | number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(237,13): error TS2322: Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(210,13): error TS2322: Type 'string | number' is not assignable to type 'number'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(240,13): error TS2322: Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. -==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (12 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (14 errors) ==== // Narrowing by aliased conditional expressions function f10(x: string | number) { @@ -72,6 +76,42 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(210,13): error TS2322 return notUndefined ? x : 0; } + function f15(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + if (isString) { + let s: string = obj.x; + } + } + + function f16(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + obj = { x: 42 }; + if (isString) { + let s: string = obj.x; // Not narrowed because of is assigned in function body + ~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + } + + function f17(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + if (isString) { + let s: string = obj[0]; + } + } + + function f18(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + obj = [42]; + if (isString) { + let s: string = obj[0]; // Not narrowed because of is assigned in function body + ~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + } + function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { const isFoo = obj.kind === 'foo'; if (isFoo) { diff --git a/tests/baselines/reference/controlFlowAliasing.js b/tests/baselines/reference/controlFlowAliasing.js index 91615ba43e139..6f663d2daf71c 100644 --- a/tests/baselines/reference/controlFlowAliasing.js +++ b/tests/baselines/reference/controlFlowAliasing.js @@ -46,6 +46,36 @@ function f14(x: number | null | undefined): number | null { return notUndefined ? x : 0; } +function f15(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + if (isString) { + let s: string = obj.x; + } +} + +function f16(obj: { readonly x: string | number }) { + const isString = typeof obj.x === 'string'; + obj = { x: 42 }; + if (isString) { + let s: string = obj.x; // Not narrowed because of is assigned in function body + } +} + +function f17(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + if (isString) { + let s: string = obj[0]; + } +} + +function f18(obj: readonly [string | number]) { + const isString = typeof obj[0] === 'string'; + obj = [42]; + if (isString) { + let s: string = obj[0]; // Not narrowed because of is assigned in function body + } +} + function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { const isFoo = obj.kind === 'foo'; if (isFoo) { @@ -256,6 +286,32 @@ function f14(x) { var notUndefined = x !== undefined; return notUndefined ? x : 0; } +function f15(obj) { + var isString = typeof obj.x === 'string'; + if (isString) { + var s = obj.x; + } +} +function f16(obj) { + var isString = typeof obj.x === 'string'; + obj = { x: 42 }; + if (isString) { + var s = obj.x; // Not narrowed because of is assigned in function body + } +} +function f17(obj) { + var isString = typeof obj[0] === 'string'; + if (isString) { + var s = obj[0]; + } +} +function f18(obj) { + var isString = typeof obj[0] === 'string'; + obj = [42]; + if (isString) { + var s = obj[0]; // Not narrowed because of is assigned in function body + } +} function f20(obj) { var isFoo = obj.kind === 'foo'; if (isFoo) { @@ -413,6 +469,14 @@ declare function f11(x: unknown): void; declare function f12(x: string | number | boolean): void; declare function f13(x: string | number | boolean): void; declare function f14(x: number | null | undefined): number | null; +declare function f15(obj: { + readonly x: string | number; +}): void; +declare function f16(obj: { + readonly x: string | number; +}): void; +declare function f17(obj: readonly [string | number]): void; +declare function f18(obj: readonly [string | number]): void; declare function f20(obj: { kind: 'foo'; foo: string; diff --git a/tests/baselines/reference/controlFlowAliasing.symbols b/tests/baselines/reference/controlFlowAliasing.symbols index c8db499c15ac2..efe11532c9b24 100644 --- a/tests/baselines/reference/controlFlowAliasing.symbols +++ b/tests/baselines/reference/controlFlowAliasing.symbols @@ -112,491 +112,580 @@ function f14(x: number | null | undefined): number | null { >x : Symbol(x, Decl(controlFlowAliasing.ts, 42, 13)) } -function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f20 : Symbol(f20, Decl(controlFlowAliasing.ts, 45, 1)) +function f15(obj: { readonly x: string | number }) { +>f15 : Symbol(f15, Decl(controlFlowAliasing.ts, 45, 1)) >obj : Symbol(obj, Decl(controlFlowAliasing.ts, 47, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 47, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 47, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 47, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 47, 63)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 47, 19)) - const isFoo = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 48, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 47, 19), Decl(controlFlowAliasing.ts, 47, 50)) + const isString = typeof obj.x === 'string'; +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 48, 9)) +>obj.x : Symbol(x, Decl(controlFlowAliasing.ts, 47, 19)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 47, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 47, 19)) + + if (isString) { +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 48, 9)) + + let s: string = obj.x; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 50, 11)) +>obj.x : Symbol(x, Decl(controlFlowAliasing.ts, 47, 19)) >obj : Symbol(obj, Decl(controlFlowAliasing.ts, 47, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 47, 19), Decl(controlFlowAliasing.ts, 47, 50)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 47, 19)) + } +} + +function f16(obj: { readonly x: string | number }) { +>f16 : Symbol(f16, Decl(controlFlowAliasing.ts, 52, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 54, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 54, 19)) + + const isString = typeof obj.x === 'string'; +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 55, 9)) +>obj.x : Symbol(x, Decl(controlFlowAliasing.ts, 54, 19)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 54, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 54, 19)) + + obj = { x: 42 }; +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 54, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 56, 11)) + + if (isString) { +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 55, 9)) + + let s: string = obj.x; // Not narrowed because of is assigned in function body +>s : Symbol(s, Decl(controlFlowAliasing.ts, 58, 11)) +>obj.x : Symbol(x, Decl(controlFlowAliasing.ts, 54, 19)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 54, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 54, 19)) + } +} + +function f17(obj: readonly [string | number]) { +>f17 : Symbol(f17, Decl(controlFlowAliasing.ts, 60, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 62, 13)) + + const isString = typeof obj[0] === 'string'; +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 63, 9)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 62, 13)) +>0 : Symbol(0) + + if (isString) { +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 63, 9)) + + let s: string = obj[0]; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 65, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 62, 13)) +>0 : Symbol(0) + } +} + +function f18(obj: readonly [string | number]) { +>f18 : Symbol(f18, Decl(controlFlowAliasing.ts, 67, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 69, 13)) + + const isString = typeof obj[0] === 'string'; +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 70, 9)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 69, 13)) +>0 : Symbol(0) + + obj = [42]; +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 69, 13)) + + if (isString) { +>isString : Symbol(isString, Decl(controlFlowAliasing.ts, 70, 9)) + + let s: string = obj[0]; // Not narrowed because of is assigned in function body +>s : Symbol(s, Decl(controlFlowAliasing.ts, 73, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 69, 13)) +>0 : Symbol(0) + } +} + +function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { +>f20 : Symbol(f20, Decl(controlFlowAliasing.ts, 75, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 77, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 77, 63)) + + const isFoo = obj.kind === 'foo'; +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 78, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19), Decl(controlFlowAliasing.ts, 77, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19), Decl(controlFlowAliasing.ts, 77, 50)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 48, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 78, 9)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 47, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 47, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 47, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 77, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 77, 32)) } else { obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 47, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 47, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 47, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 77, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 77, 63)) } } function f21(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f21 : Symbol(f21, Decl(controlFlowAliasing.ts, 55, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 57, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 57, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 57, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 57, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 57, 63)) +>f21 : Symbol(f21, Decl(controlFlowAliasing.ts, 85, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 87, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 87, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 87, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 87, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 87, 63)) const isFoo: boolean = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 58, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 57, 19), Decl(controlFlowAliasing.ts, 57, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 57, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 57, 19), Decl(controlFlowAliasing.ts, 57, 50)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 88, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 87, 19), Decl(controlFlowAliasing.ts, 87, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 87, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 87, 19), Decl(controlFlowAliasing.ts, 87, 50)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 58, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 88, 9)) obj.foo; // Not narrowed because isFoo has type annotation ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 57, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 87, 13)) } else { obj.bar; // Not narrowed because isFoo has type annotation ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 57, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 87, 13)) } } function f22(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f22 : Symbol(f22, Decl(controlFlowAliasing.ts, 65, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 67, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 67, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 67, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 67, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 67, 63)) +>f22 : Symbol(f22, Decl(controlFlowAliasing.ts, 95, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 97, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 97, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 97, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 97, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 97, 63)) let isFoo = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 68, 7)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 67, 19), Decl(controlFlowAliasing.ts, 67, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 67, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 67, 19), Decl(controlFlowAliasing.ts, 67, 50)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 98, 7)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 97, 19), Decl(controlFlowAliasing.ts, 97, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 97, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 97, 19), Decl(controlFlowAliasing.ts, 97, 50)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 68, 7)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 98, 7)) obj.foo; // Not narrowed because isFoo is mutable ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 67, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 97, 13)) } else { obj.bar; // Not narrowed because isFoo is mutable ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 67, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 97, 13)) } } function f23(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f23 : Symbol(f23, Decl(controlFlowAliasing.ts, 75, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 77, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 77, 63)) +>f23 : Symbol(f23, Decl(controlFlowAliasing.ts, 105, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 107, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 107, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 107, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 107, 63)) const isFoo = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 78, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19), Decl(controlFlowAliasing.ts, 77, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 77, 19), Decl(controlFlowAliasing.ts, 77, 50)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 108, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 107, 19), Decl(controlFlowAliasing.ts, 107, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 107, 19), Decl(controlFlowAliasing.ts, 107, 50)) obj = obj; ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 78, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 108, 9)) obj.foo; // Not narrowed because obj is assigned in function body ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) } else { obj.bar; // Not narrowed because obj is assigned in function body ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 77, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 107, 13)) } } function f24(arg: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f24 : Symbol(f24, Decl(controlFlowAliasing.ts, 86, 1)) ->arg : Symbol(arg, Decl(controlFlowAliasing.ts, 88, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 88, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 88, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 88, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 88, 63)) +>f24 : Symbol(f24, Decl(controlFlowAliasing.ts, 116, 1)) +>arg : Symbol(arg, Decl(controlFlowAliasing.ts, 118, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 118, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 118, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 118, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 118, 63)) const obj = arg; ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 89, 9)) ->arg : Symbol(arg, Decl(controlFlowAliasing.ts, 88, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 119, 9)) +>arg : Symbol(arg, Decl(controlFlowAliasing.ts, 118, 13)) const isFoo = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 90, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 88, 19), Decl(controlFlowAliasing.ts, 88, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 89, 9)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 88, 19), Decl(controlFlowAliasing.ts, 88, 50)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 120, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 118, 19), Decl(controlFlowAliasing.ts, 118, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 119, 9)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 118, 19), Decl(controlFlowAliasing.ts, 118, 50)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 90, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 120, 9)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 88, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 89, 9)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 88, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 118, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 119, 9)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 118, 32)) } else { obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 88, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 89, 9)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 88, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 118, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 119, 9)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 118, 63)) } } function f25(arg: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f25 : Symbol(f25, Decl(controlFlowAliasing.ts, 97, 1)) ->arg : Symbol(arg, Decl(controlFlowAliasing.ts, 99, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 99, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 99, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 99, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 99, 63)) +>f25 : Symbol(f25, Decl(controlFlowAliasing.ts, 127, 1)) +>arg : Symbol(arg, Decl(controlFlowAliasing.ts, 129, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 129, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 129, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 129, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 129, 63)) let obj = arg; ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 100, 7)) ->arg : Symbol(arg, Decl(controlFlowAliasing.ts, 99, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 7)) +>arg : Symbol(arg, Decl(controlFlowAliasing.ts, 129, 13)) const isFoo = obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 101, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 99, 19), Decl(controlFlowAliasing.ts, 99, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 100, 7)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 99, 19), Decl(controlFlowAliasing.ts, 99, 50)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 131, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 129, 19), Decl(controlFlowAliasing.ts, 129, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 7)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 129, 19), Decl(controlFlowAliasing.ts, 129, 50)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 101, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 131, 9)) obj.foo; // Not narrowed because obj is mutable ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 100, 7)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 7)) } else { obj.bar; // Not narrowed because obj is mutable ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 100, 7)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 7)) } } function f26(outer: { readonly obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number } }) { ->f26 : Symbol(f26, Decl(controlFlowAliasing.ts, 108, 1)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 110, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 110, 37)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 110, 50)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 110, 68)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 110, 81)) +>f26 : Symbol(f26, Decl(controlFlowAliasing.ts, 138, 1)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 140, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 140, 37)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 140, 50)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 140, 68)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 140, 81)) const isFoo = outer.obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 111, 9)) ->outer.obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 110, 37), Decl(controlFlowAliasing.ts, 110, 68)) ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 110, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 110, 37), Decl(controlFlowAliasing.ts, 110, 68)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 141, 9)) +>outer.obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 140, 37), Decl(controlFlowAliasing.ts, 140, 68)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 140, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 140, 37), Decl(controlFlowAliasing.ts, 140, 68)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 111, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 141, 9)) outer.obj.foo; ->outer.obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 110, 50)) ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 110, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 110, 50)) +>outer.obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 140, 50)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 140, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 140, 50)) } else { outer.obj.bar; ->outer.obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 110, 81)) ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 110, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 110, 21)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 110, 81)) +>outer.obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 140, 81)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 140, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 140, 21)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 140, 81)) } } function f27(outer: { obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number } }) { ->f27 : Symbol(f27, Decl(controlFlowAliasing.ts, 118, 1)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 120, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 120, 28)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 120, 41)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 120, 59)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 120, 72)) +>f27 : Symbol(f27, Decl(controlFlowAliasing.ts, 148, 1)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 150, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 150, 28)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 150, 41)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 150, 59)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 150, 72)) const isFoo = outer.obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 121, 9)) ->outer.obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 120, 28), Decl(controlFlowAliasing.ts, 120, 59)) ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 120, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 120, 28), Decl(controlFlowAliasing.ts, 120, 59)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 151, 9)) +>outer.obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 150, 28), Decl(controlFlowAliasing.ts, 150, 59)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 150, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 150, 28), Decl(controlFlowAliasing.ts, 150, 59)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 121, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 151, 9)) outer.obj.foo; // Not narrowed because obj is mutable ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 120, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 150, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) } else { outer.obj.bar; // Not narrowed because obj is mutable ->outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) ->outer : Symbol(outer, Decl(controlFlowAliasing.ts, 120, 13)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 120, 21)) +>outer.obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) +>outer : Symbol(outer, Decl(controlFlowAliasing.ts, 150, 13)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 150, 21)) } } function f28(obj?: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f28 : Symbol(f28, Decl(controlFlowAliasing.ts, 128, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 20)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 130, 33)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 51)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 130, 64)) +>f28 : Symbol(f28, Decl(controlFlowAliasing.ts, 158, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 20)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 160, 33)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 51)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 160, 64)) const isFoo = obj && obj.kind === 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 131, 9)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 20), Decl(controlFlowAliasing.ts, 130, 51)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 20), Decl(controlFlowAliasing.ts, 130, 51)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 161, 9)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 20), Decl(controlFlowAliasing.ts, 160, 51)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 20), Decl(controlFlowAliasing.ts, 160, 51)) const isBar = obj && obj.kind === 'bar'; ->isBar : Symbol(isBar, Decl(controlFlowAliasing.ts, 132, 9)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 20), Decl(controlFlowAliasing.ts, 130, 51)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 130, 20), Decl(controlFlowAliasing.ts, 130, 51)) +>isBar : Symbol(isBar, Decl(controlFlowAliasing.ts, 162, 9)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 20), Decl(controlFlowAliasing.ts, 160, 51)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 160, 20), Decl(controlFlowAliasing.ts, 160, 51)) if (isFoo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 131, 9)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 161, 9)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 130, 33)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 130, 33)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 160, 33)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 160, 33)) } if (isBar) { ->isBar : Symbol(isBar, Decl(controlFlowAliasing.ts, 132, 9)) +>isBar : Symbol(isBar, Decl(controlFlowAliasing.ts, 162, 9)) obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 130, 64)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 130, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 130, 64)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 160, 64)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 160, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 160, 64)) } } // Narrowing by aliased discriminant property access function f30(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f30 : Symbol(f30, Decl(controlFlowAliasing.ts, 139, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 143, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 143, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 143, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 143, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 143, 63)) +>f30 : Symbol(f30, Decl(controlFlowAliasing.ts, 169, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) const kind = obj.kind; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 144, 9)) ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 143, 19), Decl(controlFlowAliasing.ts, 143, 50)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 143, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 143, 19), Decl(controlFlowAliasing.ts, 143, 50)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 174, 9)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 19), Decl(controlFlowAliasing.ts, 173, 50)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 19), Decl(controlFlowAliasing.ts, 173, 50)) if (kind === 'foo') { ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 144, 9)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 174, 9)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 143, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 143, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 143, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) } else { obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 143, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 143, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 143, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) } } function f31(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f31 : Symbol(f31, Decl(controlFlowAliasing.ts, 151, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 153, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 153, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 153, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 153, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 153, 63)) +>f31 : Symbol(f31, Decl(controlFlowAliasing.ts, 181, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 183, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 183, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 183, 63)) const { kind } = obj; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 154, 11)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 153, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 184, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) if (kind === 'foo') { ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 154, 11)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 184, 11)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 153, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 153, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 153, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) } else { obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 153, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 153, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 153, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 183, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 183, 63)) } } function f32(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f32 : Symbol(f32, Decl(controlFlowAliasing.ts, 161, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 163, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 163, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 163, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 163, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 163, 63)) +>f32 : Symbol(f32, Decl(controlFlowAliasing.ts, 191, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 193, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 193, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 193, 63)) const { kind: k } = obj; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 163, 19), Decl(controlFlowAliasing.ts, 163, 50)) ->k : Symbol(k, Decl(controlFlowAliasing.ts, 164, 11)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 163, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 19), Decl(controlFlowAliasing.ts, 193, 50)) +>k : Symbol(k, Decl(controlFlowAliasing.ts, 194, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 193, 13)) if (k === 'foo') { ->k : Symbol(k, Decl(controlFlowAliasing.ts, 164, 11)) +>k : Symbol(k, Decl(controlFlowAliasing.ts, 194, 11)) obj.foo; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 163, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 163, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 163, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 193, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 193, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 193, 32)) } else { obj.bar; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 163, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 163, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 163, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 193, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 193, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 193, 63)) } } function f33(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { ->f33 : Symbol(f33, Decl(controlFlowAliasing.ts, 171, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 173, 50)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) +>f33 : Symbol(f33, Decl(controlFlowAliasing.ts, 201, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 203, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 203, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 203, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 203, 50)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 203, 63)) const { kind } = obj; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 174, 11)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 204, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 203, 13)) switch (kind) { ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 174, 11)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 204, 11)) case 'foo': obj.foo; break; ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 173, 32)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 203, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 203, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 203, 32)) case 'bar': obj.bar; break; ->obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 173, 13)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 173, 63)) +>obj.bar : Symbol(bar, Decl(controlFlowAliasing.ts, 203, 63)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 203, 13)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 203, 63)) } } // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) { ->f40 : Symbol(f40, Decl(controlFlowAliasing.ts, 179, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 183, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 183, 51)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 183, 64)) +>f40 : Symbol(f40, Decl(controlFlowAliasing.ts, 209, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 213, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 213, 51)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 213, 64)) const { kind } = obj; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 184, 11)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 214, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) const isFoo = kind == 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 185, 9)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 184, 11)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 215, 9)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 214, 11)) if (isFoo && obj.foo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 185, 9)) ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 215, 9)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) let t: string = obj.foo; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 187, 11)) ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 183, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 183, 32)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 217, 11)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) } } // Unsupported narrowing of destructured payload by destructured discriminant type Data = { kind: 'str', payload: string } | { kind: 'num', payload: number }; ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 189, 1)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 26)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 48)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 61)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 48)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) function gg2(obj: Data) { ->gg2 : Symbol(gg2, Decl(controlFlowAliasing.ts, 193, 80)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 195, 13)) ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 189, 1)) +>gg2 : Symbol(gg2, Decl(controlFlowAliasing.ts, 223, 80)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) if (obj.kind === 'str') { ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 13), Decl(controlFlowAliasing.ts, 193, 48)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 195, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 193, 13), Decl(controlFlowAliasing.ts, 193, 48)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13), Decl(controlFlowAliasing.ts, 223, 48)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13), Decl(controlFlowAliasing.ts, 223, 48)) let t: string = obj.payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 197, 11)) ->obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 26)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 195, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 26)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 227, 11)) +>obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) } else { let t: number = obj.payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 200, 11)) ->obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 61)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 195, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 193, 61)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 230, 11)) +>obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) } } function foo({ kind, payload }: Data) { ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 202, 1)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 204, 14)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 204, 20)) ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 189, 1)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 232, 1)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 234, 14)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) if (kind === 'str') { ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 204, 14)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 234, 14)) let t: string = payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 206, 11)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 204, 20)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 236, 11)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) } else { let t: number = payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 209, 11)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 204, 20)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 239, 11)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) } } diff --git a/tests/baselines/reference/controlFlowAliasing.types b/tests/baselines/reference/controlFlowAliasing.types index a3af9609566a1..5db01a1cc0498 100644 --- a/tests/baselines/reference/controlFlowAliasing.types +++ b/tests/baselines/reference/controlFlowAliasing.types @@ -137,6 +137,117 @@ function f14(x: number | null | undefined): number | null { >0 : 0 } +function f15(obj: { readonly x: string | number }) { +>f15 : (obj: { readonly x: string | number;}) => void +>obj : { readonly x: string | number; } +>x : string | number + + const isString = typeof obj.x === 'string'; +>isString : boolean +>typeof obj.x === 'string' : boolean +>typeof obj.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>obj.x : string | number +>obj : { readonly x: string | number; } +>x : string | number +>'string' : "string" + + if (isString) { +>isString : boolean + + let s: string = obj.x; +>s : string +>obj.x : string +>obj : { readonly x: string | number; } +>x : string + } +} + +function f16(obj: { readonly x: string | number }) { +>f16 : (obj: { readonly x: string | number;}) => void +>obj : { readonly x: string | number; } +>x : string | number + + const isString = typeof obj.x === 'string'; +>isString : boolean +>typeof obj.x === 'string' : boolean +>typeof obj.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>obj.x : string | number +>obj : { readonly x: string | number; } +>x : string | number +>'string' : "string" + + obj = { x: 42 }; +>obj = { x: 42 } : { x: number; } +>obj : { readonly x: string | number; } +>{ x: 42 } : { x: number; } +>x : number +>42 : 42 + + if (isString) { +>isString : boolean + + let s: string = obj.x; // Not narrowed because of is assigned in function body +>s : string +>obj.x : string | number +>obj : { readonly x: string | number; } +>x : string | number + } +} + +function f17(obj: readonly [string | number]) { +>f17 : (obj: readonly [string | number]) => void +>obj : readonly [string | number] + + const isString = typeof obj[0] === 'string'; +>isString : boolean +>typeof obj[0] === 'string' : boolean +>typeof obj[0] : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>obj[0] : string | number +>obj : readonly [string | number] +>0 : 0 +>'string' : "string" + + if (isString) { +>isString : boolean + + let s: string = obj[0]; +>s : string +>obj[0] : string +>obj : readonly [string | number] +>0 : 0 + } +} + +function f18(obj: readonly [string | number]) { +>f18 : (obj: readonly [string | number]) => void +>obj : readonly [string | number] + + const isString = typeof obj[0] === 'string'; +>isString : boolean +>typeof obj[0] === 'string' : boolean +>typeof obj[0] : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>obj[0] : string | number +>obj : readonly [string | number] +>0 : 0 +>'string' : "string" + + obj = [42]; +>obj = [42] : [number] +>obj : readonly [string | number] +>[42] : [number] +>42 : 42 + + if (isString) { +>isString : boolean + + let s: string = obj[0]; // Not narrowed because of is assigned in function body +>s : string +>obj[0] : string | number +>obj : readonly [string | number] +>0 : 0 + } +} + function f20(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { >f20 : (obj: { kind: 'foo'; foo: string;} | { kind: 'bar'; bar: number;}) => void >obj : { kind: 'foo'; foo: string; } | { kind: 'bar'; bar: number; } From 6f86803827a388d2d7b26f979fdf8ce6e070df33 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Date: Mon, 28 Jun 2021 22:39:34 +0000 Subject: [PATCH 4/5] Added test cases for parameter properties. --- .../controlFlow/controlFlowAliasing.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts index 2e16fa29eb78c..b8d2a81fb1a09 100644 --- a/tests/cases/conformance/controlFlow/controlFlowAliasing.ts +++ b/tests/cases/conformance/controlFlow/controlFlowAliasing.ts @@ -212,6 +212,36 @@ function f33(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { } } + +class C10 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + let s: string; + s = this.x; + s = x; + } + } +} + +class C11 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + // Some narrowings may be invalidated due to later assignments. + let s: string; + s = this.x; + s = x; + } + else { + this.x = 10; + x = 10; + } + } +} + // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) { From 3b12c042546aea831c2a2b8df096a7bca31df552 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Date: Mon, 28 Jun 2021 22:41:52 +0000 Subject: [PATCH 5/5] Accepted baselines. --- .../reference/controlFlowAliasing.errors.txt | 51 ++++- .../reference/controlFlowAliasing.js | 69 +++++++ .../reference/controlFlowAliasing.symbols | 175 +++++++++++++----- .../reference/controlFlowAliasing.types | 105 +++++++++++ 4 files changed, 351 insertions(+), 49 deletions(-) diff --git a/tests/baselines/reference/controlFlowAliasing.errors.txt b/tests/baselines/reference/controlFlowAliasing.errors.txt index 93bb7936eeebb..a29ae9e2faf52 100644 --- a/tests/baselines/reference/controlFlowAliasing.errors.txt +++ b/tests/baselines/reference/controlFlowAliasing.errors.txt @@ -22,13 +22,19 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(154,19): error TS2339 Property 'foo' does not exist on type '{ kind: "bar"; bar: number; }'. tests/cases/conformance/controlFlow/controlFlowAliasing.ts(157,19): error TS2339: Property 'bar' does not exist on type '{ kind: "foo"; foo: string; } | { kind: "bar"; bar: number; }'. Property 'bar' does not exist on type '{ kind: "foo"; foo: string; }'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(237,13): error TS2322: Type 'string | number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(219,13): error TS2322: Type 'string | number' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/controlFlow/controlFlowAliasing.ts(240,13): error TS2322: Type 'string | number' is not assignable to type 'number'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(232,13): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(233,13): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(267,13): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/controlFlow/controlFlowAliasing.ts(270,13): error TS2322: Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'. -==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (14 errors) ==== +==== tests/cases/conformance/controlFlow/controlFlowAliasing.ts (17 errors) ==== // Narrowing by aliased conditional expressions function f10(x: string | number) { @@ -276,6 +282,45 @@ tests/cases/conformance/controlFlow/controlFlowAliasing.ts(240,13): error TS2322 } } + + class C10 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + let s: string; + s = this.x; + ~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + s = x; + } + } + } + + class C11 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + // Some narrowings may be invalidated due to later assignments. + let s: string; + s = this.x; + ~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + s = x; + ~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + else { + this.x = 10; + x = 10; + } + } + } + // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) { diff --git a/tests/baselines/reference/controlFlowAliasing.js b/tests/baselines/reference/controlFlowAliasing.js index 6f663d2daf71c..4ed26e586c3f6 100644 --- a/tests/baselines/reference/controlFlowAliasing.js +++ b/tests/baselines/reference/controlFlowAliasing.js @@ -210,6 +210,36 @@ function f33(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { } } + +class C10 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + let s: string; + s = this.x; + s = x; + } + } +} + +class C11 { + constructor(readonly x: string | number) { + const thisX_isString = typeof this.x === 'string'; + const xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + // Some narrowings may be invalidated due to later assignments. + let s: string; + s = this.x; + s = x; + } + else { + this.x = 10; + x = 10; + } + } +} + // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) { @@ -436,6 +466,37 @@ function f33(obj) { break; } } +var C10 = /** @class */ (function () { + function C10(x) { + this.x = x; + var thisX_isString = typeof this.x === 'string'; + var xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + var s = void 0; + s = this.x; + s = x; + } + } + return C10; +}()); +var C11 = /** @class */ (function () { + function C11(x) { + this.x = x; + var thisX_isString = typeof this.x === 'string'; + var xIsString = typeof x === 'string'; + if (thisX_isString && xIsString) { + // Some narrowings may be invalidated due to later assignments. + var s = void 0; + s = this.x; + s = x; + } + else { + this.x = 10; + x = 10; + } + } + return C11; +}()); // Mixing of aliased discriminants and conditionals function f40(obj) { var kind = obj.kind; @@ -572,6 +633,14 @@ declare function f33(obj: { kind: 'bar'; bar: number; }): void; +declare class C10 { + readonly x: string | number; + constructor(x: string | number); +} +declare class C11 { + readonly x: string | number; + constructor(x: string | number); +} declare function f40(obj: { kind: 'foo'; foo?: string; diff --git a/tests/baselines/reference/controlFlowAliasing.symbols b/tests/baselines/reference/controlFlowAliasing.symbols index efe11532c9b24..6fb00b3428182 100644 --- a/tests/baselines/reference/controlFlowAliasing.symbols +++ b/tests/baselines/reference/controlFlowAliasing.symbols @@ -603,89 +603,172 @@ function f33(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { } } + +class C10 { +>C10 : Symbol(C10, Decl(controlFlowAliasing.ts, 209, 1)) + + constructor(readonly x: string | number) { +>x : Symbol(C10.x, Decl(controlFlowAliasing.ts, 213, 16)) + + const thisX_isString = typeof this.x === 'string'; +>thisX_isString : Symbol(thisX_isString, Decl(controlFlowAliasing.ts, 214, 13)) +>this.x : Symbol(C10.x, Decl(controlFlowAliasing.ts, 213, 16)) +>this : Symbol(C10, Decl(controlFlowAliasing.ts, 209, 1)) +>x : Symbol(C10.x, Decl(controlFlowAliasing.ts, 213, 16)) + + const xIsString = typeof x === 'string'; +>xIsString : Symbol(xIsString, Decl(controlFlowAliasing.ts, 215, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 213, 16)) + + if (thisX_isString && xIsString) { +>thisX_isString : Symbol(thisX_isString, Decl(controlFlowAliasing.ts, 214, 13)) +>xIsString : Symbol(xIsString, Decl(controlFlowAliasing.ts, 215, 13)) + + let s: string; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 217, 15)) + + s = this.x; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 217, 15)) +>this.x : Symbol(C10.x, Decl(controlFlowAliasing.ts, 213, 16)) +>this : Symbol(C10, Decl(controlFlowAliasing.ts, 209, 1)) +>x : Symbol(C10.x, Decl(controlFlowAliasing.ts, 213, 16)) + + s = x; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 217, 15)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 213, 16)) + } + } +} + +class C11 { +>C11 : Symbol(C11, Decl(controlFlowAliasing.ts, 222, 1)) + + constructor(readonly x: string | number) { +>x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) + + const thisX_isString = typeof this.x === 'string'; +>thisX_isString : Symbol(thisX_isString, Decl(controlFlowAliasing.ts, 226, 13)) +>this.x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) +>this : Symbol(C11, Decl(controlFlowAliasing.ts, 222, 1)) +>x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) + + const xIsString = typeof x === 'string'; +>xIsString : Symbol(xIsString, Decl(controlFlowAliasing.ts, 227, 13)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 225, 16)) + + if (thisX_isString && xIsString) { +>thisX_isString : Symbol(thisX_isString, Decl(controlFlowAliasing.ts, 226, 13)) +>xIsString : Symbol(xIsString, Decl(controlFlowAliasing.ts, 227, 13)) + + // Some narrowings may be invalidated due to later assignments. + let s: string; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 230, 15)) + + s = this.x; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 230, 15)) +>this.x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) +>this : Symbol(C11, Decl(controlFlowAliasing.ts, 222, 1)) +>x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) + + s = x; +>s : Symbol(s, Decl(controlFlowAliasing.ts, 230, 15)) +>x : Symbol(x, Decl(controlFlowAliasing.ts, 225, 16)) + } + else { + this.x = 10; +>this.x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) +>this : Symbol(C11, Decl(controlFlowAliasing.ts, 222, 1)) +>x : Symbol(C11.x, Decl(controlFlowAliasing.ts, 225, 16)) + + x = 10; +>x : Symbol(x, Decl(controlFlowAliasing.ts, 225, 16)) + } + } +} + // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) { ->f40 : Symbol(f40, Decl(controlFlowAliasing.ts, 209, 1)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 213, 19)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 213, 51)) ->bar : Symbol(bar, Decl(controlFlowAliasing.ts, 213, 64)) +>f40 : Symbol(f40, Decl(controlFlowAliasing.ts, 239, 1)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 243, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 243, 19)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 243, 32)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 243, 51)) +>bar : Symbol(bar, Decl(controlFlowAliasing.ts, 243, 64)) const { kind } = obj; ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 214, 11)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 244, 11)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 243, 13)) const isFoo = kind == 'foo'; ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 215, 9)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 214, 11)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 245, 9)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 244, 11)) if (isFoo && obj.foo) { ->isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 215, 9)) ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) +>isFoo : Symbol(isFoo, Decl(controlFlowAliasing.ts, 245, 9)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 243, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 243, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 243, 32)) let t: string = obj.foo; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 217, 11)) ->obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 213, 13)) ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 213, 32)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 247, 11)) +>obj.foo : Symbol(foo, Decl(controlFlowAliasing.ts, 243, 32)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 243, 13)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 243, 32)) } } // Unsupported narrowing of destructured payload by destructured discriminant type Data = { kind: 'str', payload: string } | { kind: 'num', payload: number }; ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 48)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 249, 1)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 253, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 26)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 253, 48)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 61)) function gg2(obj: Data) { ->gg2 : Symbol(gg2, Decl(controlFlowAliasing.ts, 223, 80)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) +>gg2 : Symbol(gg2, Decl(controlFlowAliasing.ts, 253, 80)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 255, 13)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 249, 1)) if (obj.kind === 'str') { ->obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13), Decl(controlFlowAliasing.ts, 223, 48)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 223, 13), Decl(controlFlowAliasing.ts, 223, 48)) +>obj.kind : Symbol(kind, Decl(controlFlowAliasing.ts, 253, 13), Decl(controlFlowAliasing.ts, 253, 48)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 255, 13)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 253, 13), Decl(controlFlowAliasing.ts, 253, 48)) let t: string = obj.payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 227, 11)) ->obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 26)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 257, 11)) +>obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 26)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 255, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 26)) } else { let t: number = obj.payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 230, 11)) ->obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) ->obj : Symbol(obj, Decl(controlFlowAliasing.ts, 225, 13)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 223, 61)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 260, 11)) +>obj.payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 61)) +>obj : Symbol(obj, Decl(controlFlowAliasing.ts, 255, 13)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 253, 61)) } } function foo({ kind, payload }: Data) { ->foo : Symbol(foo, Decl(controlFlowAliasing.ts, 232, 1)) ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 234, 14)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) ->Data : Symbol(Data, Decl(controlFlowAliasing.ts, 219, 1)) +>foo : Symbol(foo, Decl(controlFlowAliasing.ts, 262, 1)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 264, 14)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 264, 20)) +>Data : Symbol(Data, Decl(controlFlowAliasing.ts, 249, 1)) if (kind === 'str') { ->kind : Symbol(kind, Decl(controlFlowAliasing.ts, 234, 14)) +>kind : Symbol(kind, Decl(controlFlowAliasing.ts, 264, 14)) let t: string = payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 236, 11)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 266, 11)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 264, 20)) } else { let t: number = payload; ->t : Symbol(t, Decl(controlFlowAliasing.ts, 239, 11)) ->payload : Symbol(payload, Decl(controlFlowAliasing.ts, 234, 20)) +>t : Symbol(t, Decl(controlFlowAliasing.ts, 269, 11)) +>payload : Symbol(payload, Decl(controlFlowAliasing.ts, 264, 20)) } } diff --git a/tests/baselines/reference/controlFlowAliasing.types b/tests/baselines/reference/controlFlowAliasing.types index 5db01a1cc0498..aced9845a07d6 100644 --- a/tests/baselines/reference/controlFlowAliasing.types +++ b/tests/baselines/reference/controlFlowAliasing.types @@ -701,6 +701,111 @@ function f33(obj: { kind: 'foo', foo: string } | { kind: 'bar', bar: number }) { } } + +class C10 { +>C10 : C10 + + constructor(readonly x: string | number) { +>x : string | number + + const thisX_isString = typeof this.x === 'string'; +>thisX_isString : boolean +>typeof this.x === 'string' : boolean +>typeof this.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>this.x : string | number +>this : this +>x : string | number +>'string' : "string" + + const xIsString = typeof x === 'string'; +>xIsString : boolean +>typeof x === 'string' : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number +>'string' : "string" + + if (thisX_isString && xIsString) { +>thisX_isString && xIsString : boolean +>thisX_isString : boolean +>xIsString : boolean + + let s: string; +>s : string + + s = this.x; +>s = this.x : string | number +>s : string +>this.x : string | number +>this : this +>x : string | number + + s = x; +>s = x : string +>s : string +>x : string + } + } +} + +class C11 { +>C11 : C11 + + constructor(readonly x: string | number) { +>x : string | number + + const thisX_isString = typeof this.x === 'string'; +>thisX_isString : boolean +>typeof this.x === 'string' : boolean +>typeof this.x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>this.x : string | number +>this : this +>x : string | number +>'string' : "string" + + const xIsString = typeof x === 'string'; +>xIsString : boolean +>typeof x === 'string' : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number +>'string' : "string" + + if (thisX_isString && xIsString) { +>thisX_isString && xIsString : boolean +>thisX_isString : boolean +>xIsString : boolean + + // Some narrowings may be invalidated due to later assignments. + let s: string; +>s : string + + s = this.x; +>s = this.x : string | number +>s : string +>this.x : string | number +>this : this +>x : string | number + + s = x; +>s = x : string | number +>s : string +>x : string | number + } + else { + this.x = 10; +>this.x = 10 : 10 +>this.x : string | number +>this : this +>x : string | number +>10 : 10 + + x = 10; +>x = 10 : 10 +>x : string | number +>10 : 10 + } + } +} + // Mixing of aliased discriminants and conditionals function f40(obj: { kind: 'foo', foo?: string } | { kind: 'bar', bar?: number }) {