Skip to content

Commit acee628

Browse files
committed
Fix discriminant checking in contextual types to avoid infinite recursion
1 parent 83bc70d commit acee628

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15036,6 +15036,26 @@ namespace ts {
1503615036
}
1503715037
}
1503815038

15039+
// Return true if the given expression is possibly a discriminant value. We limit the kinds of
15040+
// expressions we check to those that don't depend on their contextual type in order not to cause
15041+
// recursive (and possibly infinite) invocations of getContextualType.
15042+
function isPossiblyDiscriminantValue(node: Expression): boolean {
15043+
switch (node.kind) {
15044+
case SyntaxKind.StringLiteral:
15045+
case SyntaxKind.NumericLiteral:
15046+
case SyntaxKind.NoSubstitutionTemplateLiteral:
15047+
case SyntaxKind.TrueKeyword:
15048+
case SyntaxKind.FalseKeyword:
15049+
case SyntaxKind.NullKeyword:
15050+
case SyntaxKind.Identifier:
15051+
return true;
15052+
case SyntaxKind.PropertyAccessExpression:
15053+
case SyntaxKind.ParenthesizedExpression:
15054+
return isPossiblyDiscriminantValue((<PropertyAccessExpression | ParenthesizedExpression>node).expression);
15055+
}
15056+
return false;
15057+
}
15058+
1503915059
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
1504015060
// be "pushed" onto a node using the contextualType property.
1504115061
function getApparentTypeOfContextualType(node: Expression): Type {
@@ -15049,8 +15069,8 @@ namespace ts {
1504915069
propLoop: for (const prop of node.properties) {
1505015070
if (!prop.symbol) continue;
1505115071
if (prop.kind !== SyntaxKind.PropertyAssignment) continue;
15052-
if (isDiscriminantProperty(contextualType, prop.symbol.escapedName)) {
15053-
const discriminatingType = getTypeOfNode(prop.initializer);
15072+
if (isPossiblyDiscriminantValue(prop.initializer) && isDiscriminantProperty(contextualType, prop.symbol.escapedName)) {
15073+
const discriminatingType = checkExpression(prop.initializer);
1505415074
for (const type of (contextualType as UnionType).types) {
1505515075
const targetType = getTypeOfPropertyOfType(type, prop.symbol.escapedName);
1505615076
if (targetType && checkTypeAssignableTo(discriminatingType, targetType, /*errorNode*/ undefined)) {

0 commit comments

Comments
 (0)