mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-23 19:07:27 -06:00
Merge pull request #10028 from Microsoft/fixDiscriminantInLoop
Fix discriminant in loop
This commit is contained in:
commit
36b611334d
@ -7764,16 +7764,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isMatchingReference(source: Node, target: Node): boolean {
|
||||
if (source.kind === target.kind) {
|
||||
switch (source.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target);
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return true;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return (<PropertyAccessExpression>source).name.text === (<PropertyAccessExpression>target).name.text &&
|
||||
isMatchingReference((<PropertyAccessExpression>source).expression, (<PropertyAccessExpression>target).expression);
|
||||
}
|
||||
switch (source.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||
|
||||
(target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement) &&
|
||||
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>source)) === getSymbolOfNode(target);
|
||||
case SyntaxKind.ThisKeyword:
|
||||
return target.kind === SyntaxKind.ThisKeyword;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return target.kind === SyntaxKind.PropertyAccessExpression &&
|
||||
(<PropertyAccessExpression>source).name.text === (<PropertyAccessExpression>target).name.text &&
|
||||
isMatchingReference((<PropertyAccessExpression>source).expression, (<PropertyAccessExpression>target).expression);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -7788,6 +7789,10 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function rootContainsMatchingReference(source: Node, target: Node) {
|
||||
return target.kind === SyntaxKind.PropertyAccessExpression && containsMatchingReference(source, (<PropertyAccessExpression>target).expression);
|
||||
}
|
||||
|
||||
function isOrContainsMatchingReference(source: Node, target: Node) {
|
||||
return isMatchingReference(source, target) || containsMatchingReference(source, target);
|
||||
}
|
||||
@ -8031,6 +8036,12 @@ namespace ts {
|
||||
getInitialTypeOfBindingElement(<BindingElement>node);
|
||||
}
|
||||
|
||||
function getInitialOrAssignedType(node: VariableDeclaration | BindingElement | Expression) {
|
||||
return node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ?
|
||||
getInitialType(<VariableDeclaration | BindingElement>node) :
|
||||
getAssignedType(<Expression>node);
|
||||
}
|
||||
|
||||
function getReferenceCandidate(node: Expression): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
@ -8153,19 +8164,9 @@ namespace ts {
|
||||
const node = flow.node;
|
||||
// Assignments only narrow the computed type if the declared type is a union type. Thus, we
|
||||
// only need to evaluate the assigned type if the declared type is a union type.
|
||||
if ((node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) &&
|
||||
reference.kind === SyntaxKind.Identifier &&
|
||||
getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(<Identifier>reference)) === getSymbolOfNode(node)) {
|
||||
return declaredType.flags & TypeFlags.Union ?
|
||||
getAssignmentReducedType(<UnionType>declaredType, getInitialType(<VariableDeclaration | BindingElement>node)) :
|
||||
declaredType;
|
||||
}
|
||||
// If the node is not a variable declaration or binding element, it is an identifier
|
||||
// or a dotted name that is the target of an assignment. If we have a match, reduce
|
||||
// the declared type by the assigned type.
|
||||
if (isMatchingReference(reference, node)) {
|
||||
return declaredType.flags & TypeFlags.Union ?
|
||||
getAssignmentReducedType(<UnionType>declaredType, getAssignedType(<Expression>node)) :
|
||||
getAssignmentReducedType(<UnionType>declaredType, getInitialOrAssignedType(node)) :
|
||||
declaredType;
|
||||
}
|
||||
// We didn't have a direct match. However, if the reference is a dotted name, this
|
||||
@ -8297,6 +8298,9 @@ namespace ts {
|
||||
if (isMatchingPropertyAccess(expr)) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>expr, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy));
|
||||
}
|
||||
if (rootContainsMatchingReference(reference, expr)) {
|
||||
return declaredType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -8329,6 +8333,9 @@ namespace ts {
|
||||
if (isMatchingPropertyAccess(right)) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>right, t => narrowTypeByEquality(t, operator, left, assumeTrue));
|
||||
}
|
||||
if (rootContainsMatchingReference(reference, left) || rootContainsMatchingReference(reference, right)) {
|
||||
return declaredType;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.InstanceOfKeyword:
|
||||
return narrowTypeByInstanceof(type, expr, assumeTrue);
|
||||
|
||||
139
tests/baselines/reference/narrowingByDiscriminantInLoop.js
Normal file
139
tests/baselines/reference/narrowingByDiscriminantInLoop.js
Normal file
@ -0,0 +1,139 @@
|
||||
//// [narrowingByDiscriminantInLoop.ts]
|
||||
|
||||
// Repro from #9977
|
||||
|
||||
type IDLMemberTypes = OperationMemberType | ConstantMemberType;
|
||||
|
||||
interface IDLTypeDescription {
|
||||
origin: string;
|
||||
}
|
||||
|
||||
interface InterfaceType {
|
||||
members: IDLMemberTypes[];
|
||||
}
|
||||
|
||||
interface OperationMemberType {
|
||||
type: "operation";
|
||||
idlType: IDLTypeDescription;
|
||||
}
|
||||
|
||||
interface ConstantMemberType {
|
||||
type: "const";
|
||||
idlType: string;
|
||||
}
|
||||
|
||||
function insertInterface(callbackType: InterfaceType) {
|
||||
for (const memberType of callbackType.members) {
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
(memberType.idlType as IDLTypeDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertInterface2(callbackType: InterfaceType) {
|
||||
for (const memberType of callbackType.members) {
|
||||
if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function foo(memberType: IDLMemberTypes) {
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
|
||||
// Repro for issue similar to #8383
|
||||
|
||||
interface A {
|
||||
kind: true;
|
||||
prop: { a: string; };
|
||||
}
|
||||
|
||||
interface B {
|
||||
kind: false;
|
||||
prop: { b: string; }
|
||||
}
|
||||
|
||||
function f1(x: A | B) {
|
||||
while (true) {
|
||||
x.prop;
|
||||
if (x.kind === true) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (x.kind === false) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: A | B) {
|
||||
while (true) {
|
||||
if (x.kind) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (!x.kind) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// [narrowingByDiscriminantInLoop.js]
|
||||
// Repro from #9977
|
||||
function insertInterface(callbackType) {
|
||||
for (var _i = 0, _a = callbackType.members; _i < _a.length; _i++) {
|
||||
var memberType = _a[_i];
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
memberType.idlType;
|
||||
}
|
||||
}
|
||||
}
|
||||
function insertInterface2(callbackType) {
|
||||
for (var _i = 0, _a = callbackType.members; _i < _a.length; _i++) {
|
||||
var memberType = _a[_i];
|
||||
if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
}
|
||||
function foo(memberType) {
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
function f1(x) {
|
||||
while (true) {
|
||||
x.prop;
|
||||
if (x.kind === true) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (x.kind === false) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
function f2(x) {
|
||||
while (true) {
|
||||
if (x.kind) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (!x.kind) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
238
tests/baselines/reference/narrowingByDiscriminantInLoop.symbols
Normal file
238
tests/baselines/reference/narrowingByDiscriminantInLoop.symbols
Normal file
@ -0,0 +1,238 @@
|
||||
=== tests/cases/compiler/narrowingByDiscriminantInLoop.ts ===
|
||||
|
||||
// Repro from #9977
|
||||
|
||||
type IDLMemberTypes = OperationMemberType | ConstantMemberType;
|
||||
>IDLMemberTypes : Symbol(IDLMemberTypes, Decl(narrowingByDiscriminantInLoop.ts, 0, 0))
|
||||
>OperationMemberType : Symbol(OperationMemberType, Decl(narrowingByDiscriminantInLoop.ts, 11, 1))
|
||||
>ConstantMemberType : Symbol(ConstantMemberType, Decl(narrowingByDiscriminantInLoop.ts, 16, 1))
|
||||
|
||||
interface IDLTypeDescription {
|
||||
>IDLTypeDescription : Symbol(IDLTypeDescription, Decl(narrowingByDiscriminantInLoop.ts, 3, 63))
|
||||
|
||||
origin: string;
|
||||
>origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
}
|
||||
|
||||
interface InterfaceType {
|
||||
>InterfaceType : Symbol(InterfaceType, Decl(narrowingByDiscriminantInLoop.ts, 7, 1))
|
||||
|
||||
members: IDLMemberTypes[];
|
||||
>members : Symbol(InterfaceType.members, Decl(narrowingByDiscriminantInLoop.ts, 9, 25))
|
||||
>IDLMemberTypes : Symbol(IDLMemberTypes, Decl(narrowingByDiscriminantInLoop.ts, 0, 0))
|
||||
}
|
||||
|
||||
interface OperationMemberType {
|
||||
>OperationMemberType : Symbol(OperationMemberType, Decl(narrowingByDiscriminantInLoop.ts, 11, 1))
|
||||
|
||||
type: "operation";
|
||||
>type : Symbol(OperationMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31))
|
||||
|
||||
idlType: IDLTypeDescription;
|
||||
>idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>IDLTypeDescription : Symbol(IDLTypeDescription, Decl(narrowingByDiscriminantInLoop.ts, 3, 63))
|
||||
}
|
||||
|
||||
interface ConstantMemberType {
|
||||
>ConstantMemberType : Symbol(ConstantMemberType, Decl(narrowingByDiscriminantInLoop.ts, 16, 1))
|
||||
|
||||
type: "const";
|
||||
>type : Symbol(ConstantMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
|
||||
idlType: string;
|
||||
>idlType : Symbol(ConstantMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 19, 18))
|
||||
}
|
||||
|
||||
function insertInterface(callbackType: InterfaceType) {
|
||||
>insertInterface : Symbol(insertInterface, Decl(narrowingByDiscriminantInLoop.ts, 21, 1))
|
||||
>callbackType : Symbol(callbackType, Decl(narrowingByDiscriminantInLoop.ts, 23, 25))
|
||||
>InterfaceType : Symbol(InterfaceType, Decl(narrowingByDiscriminantInLoop.ts, 7, 1))
|
||||
|
||||
for (const memberType of callbackType.members) {
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>callbackType.members : Symbol(InterfaceType.members, Decl(narrowingByDiscriminantInLoop.ts, 9, 25))
|
||||
>callbackType : Symbol(callbackType, Decl(narrowingByDiscriminantInLoop.ts, 23, 25))
|
||||
>members : Symbol(InterfaceType.members, Decl(narrowingByDiscriminantInLoop.ts, 9, 25))
|
||||
|
||||
if (memberType.type === "const") {
|
||||
>memberType.type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
|
||||
memberType.idlType; // string
|
||||
>memberType.idlType : Symbol(ConstantMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 19, 18))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>idlType : Symbol(ConstantMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 19, 18))
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
>memberType.type : Symbol(OperationMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>type : Symbol(OperationMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31))
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
>memberType.idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
|
||||
(memberType.idlType as IDLTypeDescription);
|
||||
>memberType.idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 24, 14))
|
||||
>idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>IDLTypeDescription : Symbol(IDLTypeDescription, Decl(narrowingByDiscriminantInLoop.ts, 3, 63))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertInterface2(callbackType: InterfaceType) {
|
||||
>insertInterface2 : Symbol(insertInterface2, Decl(narrowingByDiscriminantInLoop.ts, 33, 1))
|
||||
>callbackType : Symbol(callbackType, Decl(narrowingByDiscriminantInLoop.ts, 35, 26))
|
||||
>InterfaceType : Symbol(InterfaceType, Decl(narrowingByDiscriminantInLoop.ts, 7, 1))
|
||||
|
||||
for (const memberType of callbackType.members) {
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 36, 14))
|
||||
>callbackType.members : Symbol(InterfaceType.members, Decl(narrowingByDiscriminantInLoop.ts, 9, 25))
|
||||
>callbackType : Symbol(callbackType, Decl(narrowingByDiscriminantInLoop.ts, 35, 26))
|
||||
>members : Symbol(InterfaceType.members, Decl(narrowingByDiscriminantInLoop.ts, 9, 25))
|
||||
|
||||
if (memberType.type === "operation") {
|
||||
>memberType.type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 36, 14))
|
||||
>type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
>memberType.idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 36, 14))
|
||||
>idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function foo(memberType: IDLMemberTypes) {
|
||||
>foo : Symbol(foo, Decl(narrowingByDiscriminantInLoop.ts, 41, 1))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 43, 13))
|
||||
>IDLMemberTypes : Symbol(IDLMemberTypes, Decl(narrowingByDiscriminantInLoop.ts, 0, 0))
|
||||
|
||||
if (memberType.type === "const") {
|
||||
>memberType.type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 43, 13))
|
||||
>type : Symbol(type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31), Decl(narrowingByDiscriminantInLoop.ts, 18, 30))
|
||||
|
||||
memberType.idlType; // string
|
||||
>memberType.idlType : Symbol(ConstantMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 19, 18))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 43, 13))
|
||||
>idlType : Symbol(ConstantMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 19, 18))
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
>memberType.type : Symbol(OperationMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 43, 13))
|
||||
>type : Symbol(OperationMemberType.type, Decl(narrowingByDiscriminantInLoop.ts, 13, 31))
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
>memberType.idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>memberType : Symbol(memberType, Decl(narrowingByDiscriminantInLoop.ts, 43, 13))
|
||||
>idlType : Symbol(OperationMemberType.idlType, Decl(narrowingByDiscriminantInLoop.ts, 14, 22))
|
||||
>origin : Symbol(IDLTypeDescription.origin, Decl(narrowingByDiscriminantInLoop.ts, 5, 30))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro for issue similar to #8383
|
||||
|
||||
interface A {
|
||||
>A : Symbol(A, Decl(narrowingByDiscriminantInLoop.ts, 50, 1))
|
||||
|
||||
kind: true;
|
||||
>kind : Symbol(A.kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13))
|
||||
|
||||
prop: { a: string; };
|
||||
>prop : Symbol(A.prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15))
|
||||
>a : Symbol(a, Decl(narrowingByDiscriminantInLoop.ts, 56, 11))
|
||||
}
|
||||
|
||||
interface B {
|
||||
>B : Symbol(B, Decl(narrowingByDiscriminantInLoop.ts, 57, 1))
|
||||
|
||||
kind: false;
|
||||
>kind : Symbol(B.kind, Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
|
||||
prop: { b: string; }
|
||||
>prop : Symbol(B.prop, Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>b : Symbol(b, Decl(narrowingByDiscriminantInLoop.ts, 61, 11))
|
||||
}
|
||||
|
||||
function f1(x: A | B) {
|
||||
>f1 : Symbol(f1, Decl(narrowingByDiscriminantInLoop.ts, 62, 1))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>A : Symbol(A, Decl(narrowingByDiscriminantInLoop.ts, 50, 1))
|
||||
>B : Symbol(B, Decl(narrowingByDiscriminantInLoop.ts, 57, 1))
|
||||
|
||||
while (true) {
|
||||
x.prop;
|
||||
>x.prop : Symbol(prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15), Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>prop : Symbol(prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15), Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
|
||||
if (x.kind === true) {
|
||||
>x.kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
|
||||
x.prop.a;
|
||||
>x.prop.a : Symbol(a, Decl(narrowingByDiscriminantInLoop.ts, 56, 11))
|
||||
>x.prop : Symbol(A.prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>prop : Symbol(A.prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15))
|
||||
>a : Symbol(a, Decl(narrowingByDiscriminantInLoop.ts, 56, 11))
|
||||
}
|
||||
if (x.kind === false) {
|
||||
>x.kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
|
||||
x.prop.b;
|
||||
>x.prop.b : Symbol(b, Decl(narrowingByDiscriminantInLoop.ts, 61, 11))
|
||||
>x.prop : Symbol(B.prop, Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 64, 12))
|
||||
>prop : Symbol(B.prop, Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>b : Symbol(b, Decl(narrowingByDiscriminantInLoop.ts, 61, 11))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: A | B) {
|
||||
>f2 : Symbol(f2, Decl(narrowingByDiscriminantInLoop.ts, 74, 1))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 76, 12))
|
||||
>A : Symbol(A, Decl(narrowingByDiscriminantInLoop.ts, 50, 1))
|
||||
>B : Symbol(B, Decl(narrowingByDiscriminantInLoop.ts, 57, 1))
|
||||
|
||||
while (true) {
|
||||
if (x.kind) {
|
||||
>x.kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 76, 12))
|
||||
>kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
|
||||
x.prop.a;
|
||||
>x.prop.a : Symbol(a, Decl(narrowingByDiscriminantInLoop.ts, 56, 11))
|
||||
>x.prop : Symbol(A.prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 76, 12))
|
||||
>prop : Symbol(A.prop, Decl(narrowingByDiscriminantInLoop.ts, 55, 15))
|
||||
>a : Symbol(a, Decl(narrowingByDiscriminantInLoop.ts, 56, 11))
|
||||
}
|
||||
if (!x.kind) {
|
||||
>x.kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 76, 12))
|
||||
>kind : Symbol(kind, Decl(narrowingByDiscriminantInLoop.ts, 54, 13), Decl(narrowingByDiscriminantInLoop.ts, 59, 13))
|
||||
|
||||
x.prop.b;
|
||||
>x.prop.b : Symbol(b, Decl(narrowingByDiscriminantInLoop.ts, 61, 11))
|
||||
>x.prop : Symbol(B.prop, Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>x : Symbol(x, Decl(narrowingByDiscriminantInLoop.ts, 76, 12))
|
||||
>prop : Symbol(B.prop, Decl(narrowingByDiscriminantInLoop.ts, 60, 16))
|
||||
>b : Symbol(b, Decl(narrowingByDiscriminantInLoop.ts, 61, 11))
|
||||
}
|
||||
}
|
||||
}
|
||||
261
tests/baselines/reference/narrowingByDiscriminantInLoop.types
Normal file
261
tests/baselines/reference/narrowingByDiscriminantInLoop.types
Normal file
@ -0,0 +1,261 @@
|
||||
=== tests/cases/compiler/narrowingByDiscriminantInLoop.ts ===
|
||||
|
||||
// Repro from #9977
|
||||
|
||||
type IDLMemberTypes = OperationMemberType | ConstantMemberType;
|
||||
>IDLMemberTypes : IDLMemberTypes
|
||||
>OperationMemberType : OperationMemberType
|
||||
>ConstantMemberType : ConstantMemberType
|
||||
|
||||
interface IDLTypeDescription {
|
||||
>IDLTypeDescription : IDLTypeDescription
|
||||
|
||||
origin: string;
|
||||
>origin : string
|
||||
}
|
||||
|
||||
interface InterfaceType {
|
||||
>InterfaceType : InterfaceType
|
||||
|
||||
members: IDLMemberTypes[];
|
||||
>members : IDLMemberTypes[]
|
||||
>IDLMemberTypes : IDLMemberTypes
|
||||
}
|
||||
|
||||
interface OperationMemberType {
|
||||
>OperationMemberType : OperationMemberType
|
||||
|
||||
type: "operation";
|
||||
>type : "operation"
|
||||
|
||||
idlType: IDLTypeDescription;
|
||||
>idlType : IDLTypeDescription
|
||||
>IDLTypeDescription : IDLTypeDescription
|
||||
}
|
||||
|
||||
interface ConstantMemberType {
|
||||
>ConstantMemberType : ConstantMemberType
|
||||
|
||||
type: "const";
|
||||
>type : "const"
|
||||
|
||||
idlType: string;
|
||||
>idlType : string
|
||||
}
|
||||
|
||||
function insertInterface(callbackType: InterfaceType) {
|
||||
>insertInterface : (callbackType: InterfaceType) => void
|
||||
>callbackType : InterfaceType
|
||||
>InterfaceType : InterfaceType
|
||||
|
||||
for (const memberType of callbackType.members) {
|
||||
>memberType : IDLMemberTypes
|
||||
>callbackType.members : IDLMemberTypes[]
|
||||
>callbackType : InterfaceType
|
||||
>members : IDLMemberTypes[]
|
||||
|
||||
if (memberType.type === "const") {
|
||||
>memberType.type === "const" : boolean
|
||||
>memberType.type : "operation" | "const"
|
||||
>memberType : IDLMemberTypes
|
||||
>type : "operation" | "const"
|
||||
>"const" : "const"
|
||||
|
||||
memberType.idlType; // string
|
||||
>memberType.idlType : string
|
||||
>memberType : ConstantMemberType
|
||||
>idlType : string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
>memberType.type === "operation" : boolean
|
||||
>memberType.type : "operation"
|
||||
>memberType : OperationMemberType
|
||||
>type : "operation"
|
||||
>"operation" : "operation"
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : string
|
||||
>memberType.idlType : IDLTypeDescription
|
||||
>memberType : OperationMemberType
|
||||
>idlType : IDLTypeDescription
|
||||
>origin : string
|
||||
|
||||
(memberType.idlType as IDLTypeDescription);
|
||||
>(memberType.idlType as IDLTypeDescription) : IDLTypeDescription
|
||||
>memberType.idlType as IDLTypeDescription : IDLTypeDescription
|
||||
>memberType.idlType : IDLTypeDescription
|
||||
>memberType : OperationMemberType
|
||||
>idlType : IDLTypeDescription
|
||||
>IDLTypeDescription : IDLTypeDescription
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertInterface2(callbackType: InterfaceType) {
|
||||
>insertInterface2 : (callbackType: InterfaceType) => void
|
||||
>callbackType : InterfaceType
|
||||
>InterfaceType : InterfaceType
|
||||
|
||||
for (const memberType of callbackType.members) {
|
||||
>memberType : IDLMemberTypes
|
||||
>callbackType.members : IDLMemberTypes[]
|
||||
>callbackType : InterfaceType
|
||||
>members : IDLMemberTypes[]
|
||||
|
||||
if (memberType.type === "operation") {
|
||||
>memberType.type === "operation" : boolean
|
||||
>memberType.type : "operation" | "const"
|
||||
>memberType : IDLMemberTypes
|
||||
>type : "operation" | "const"
|
||||
>"operation" : "operation"
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : string
|
||||
>memberType.idlType : IDLTypeDescription
|
||||
>memberType : OperationMemberType
|
||||
>idlType : IDLTypeDescription
|
||||
>origin : string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function foo(memberType: IDLMemberTypes) {
|
||||
>foo : (memberType: IDLMemberTypes) => void
|
||||
>memberType : IDLMemberTypes
|
||||
>IDLMemberTypes : IDLMemberTypes
|
||||
|
||||
if (memberType.type === "const") {
|
||||
>memberType.type === "const" : boolean
|
||||
>memberType.type : "operation" | "const"
|
||||
>memberType : IDLMemberTypes
|
||||
>type : "operation" | "const"
|
||||
>"const" : "const"
|
||||
|
||||
memberType.idlType; // string
|
||||
>memberType.idlType : string
|
||||
>memberType : ConstantMemberType
|
||||
>idlType : string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
>memberType.type === "operation" : boolean
|
||||
>memberType.type : "operation"
|
||||
>memberType : OperationMemberType
|
||||
>type : "operation"
|
||||
>"operation" : "operation"
|
||||
|
||||
memberType.idlType.origin; // string
|
||||
>memberType.idlType.origin : string
|
||||
>memberType.idlType : IDLTypeDescription
|
||||
>memberType : OperationMemberType
|
||||
>idlType : IDLTypeDescription
|
||||
>origin : string
|
||||
}
|
||||
}
|
||||
|
||||
// Repro for issue similar to #8383
|
||||
|
||||
interface A {
|
||||
>A : A
|
||||
|
||||
kind: true;
|
||||
>kind : true
|
||||
>true : true
|
||||
|
||||
prop: { a: string; };
|
||||
>prop : { a: string; }
|
||||
>a : string
|
||||
}
|
||||
|
||||
interface B {
|
||||
>B : B
|
||||
|
||||
kind: false;
|
||||
>kind : false
|
||||
>false : false
|
||||
|
||||
prop: { b: string; }
|
||||
>prop : { b: string; }
|
||||
>b : string
|
||||
}
|
||||
|
||||
function f1(x: A | B) {
|
||||
>f1 : (x: A | B) => void
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
|
||||
while (true) {
|
||||
>true : boolean
|
||||
|
||||
x.prop;
|
||||
>x.prop : { a: string; } | { b: string; }
|
||||
>x : A | B
|
||||
>prop : { a: string; } | { b: string; }
|
||||
|
||||
if (x.kind === true) {
|
||||
>x.kind === true : boolean
|
||||
>x.kind : boolean
|
||||
>x : A | B
|
||||
>kind : boolean
|
||||
>true : true
|
||||
|
||||
x.prop.a;
|
||||
>x.prop.a : string
|
||||
>x.prop : { a: string; }
|
||||
>x : A
|
||||
>prop : { a: string; }
|
||||
>a : string
|
||||
}
|
||||
if (x.kind === false) {
|
||||
>x.kind === false : boolean
|
||||
>x.kind : boolean
|
||||
>x : A | B
|
||||
>kind : boolean
|
||||
>false : false
|
||||
|
||||
x.prop.b;
|
||||
>x.prop.b : string
|
||||
>x.prop : { b: string; }
|
||||
>x : B
|
||||
>prop : { b: string; }
|
||||
>b : string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: A | B) {
|
||||
>f2 : (x: A | B) => void
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
|
||||
while (true) {
|
||||
>true : boolean
|
||||
|
||||
if (x.kind) {
|
||||
>x.kind : boolean
|
||||
>x : A | B
|
||||
>kind : boolean
|
||||
|
||||
x.prop.a;
|
||||
>x.prop.a : string
|
||||
>x.prop : { a: string; }
|
||||
>x : A
|
||||
>prop : { a: string; }
|
||||
>a : string
|
||||
}
|
||||
if (!x.kind) {
|
||||
>!x.kind : boolean
|
||||
>x.kind : boolean
|
||||
>x : A | B
|
||||
>kind : boolean
|
||||
|
||||
x.prop.b;
|
||||
>x.prop.b : string
|
||||
>x.prop : { b: string; }
|
||||
>x : B
|
||||
>prop : { b: string; }
|
||||
>b : string
|
||||
}
|
||||
}
|
||||
}
|
||||
87
tests/cases/compiler/narrowingByDiscriminantInLoop.ts
Normal file
87
tests/cases/compiler/narrowingByDiscriminantInLoop.ts
Normal file
@ -0,0 +1,87 @@
|
||||
// @strictNullChecks: true
|
||||
|
||||
// Repro from #9977
|
||||
|
||||
type IDLMemberTypes = OperationMemberType | ConstantMemberType;
|
||||
|
||||
interface IDLTypeDescription {
|
||||
origin: string;
|
||||
}
|
||||
|
||||
interface InterfaceType {
|
||||
members: IDLMemberTypes[];
|
||||
}
|
||||
|
||||
interface OperationMemberType {
|
||||
type: "operation";
|
||||
idlType: IDLTypeDescription;
|
||||
}
|
||||
|
||||
interface ConstantMemberType {
|
||||
type: "const";
|
||||
idlType: string;
|
||||
}
|
||||
|
||||
function insertInterface(callbackType: InterfaceType) {
|
||||
for (const memberType of callbackType.members) {
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
(memberType.idlType as IDLTypeDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertInterface2(callbackType: InterfaceType) {
|
||||
for (const memberType of callbackType.members) {
|
||||
if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function foo(memberType: IDLMemberTypes) {
|
||||
if (memberType.type === "const") {
|
||||
memberType.idlType; // string
|
||||
}
|
||||
else if (memberType.type === "operation") {
|
||||
memberType.idlType.origin; // string
|
||||
}
|
||||
}
|
||||
|
||||
// Repro for issue similar to #8383
|
||||
|
||||
interface A {
|
||||
kind: true;
|
||||
prop: { a: string; };
|
||||
}
|
||||
|
||||
interface B {
|
||||
kind: false;
|
||||
prop: { b: string; }
|
||||
}
|
||||
|
||||
function f1(x: A | B) {
|
||||
while (true) {
|
||||
x.prop;
|
||||
if (x.kind === true) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (x.kind === false) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: A | B) {
|
||||
while (true) {
|
||||
if (x.kind) {
|
||||
x.prop.a;
|
||||
}
|
||||
if (!x.kind) {
|
||||
x.prop.b;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user