Skip to content

Commit 5c2091a

Browse files
committed
Evolving array element ignores contextual type
Control flow analysis can easily hit circularities or exponential behaviour when requesting the contextual type of an expression. When adding an element type to an evolving array type, there is no point in checking the contextual type of the new element type because it is unknown -- it is exactly the type of the evolving array, which is in the middle of being found. Fixes #14628 This is code of the form: ```ts let x = [] x[0] = { contextual: 'no' } x[1] = { contextual: 'should not check' } x[2] = { contextual: 'contextual type' } // : // : ```
1 parent 3029b8f commit 5c2091a

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

src/compiler/checker.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10893,7 +10893,7 @@ namespace ts {
1089310893
// we defer subtype reduction until the evolving array type is finalized into a manifest
1089410894
// array type.
1089510895
function addEvolvingArrayElementType(evolvingArrayType: EvolvingArrayType, node: Expression): EvolvingArrayType {
10896-
const elementType = getBaseTypeOfLiteralType(getTypeOfExpression(node));
10896+
const elementType = getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node));
1089710897
return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType]));
1089810898
}
1089910899

@@ -17064,10 +17064,12 @@ namespace ts {
1706417064
return type;
1706517065
}
1706617066

17067-
// Returns the type of an expression. Unlike checkExpression, this function is simply concerned
17068-
// with computing the type and may not fully check all contained sub-expressions for errors.
17069-
// A cache argument of true indicates that if the function performs a full type check, it is ok
17070-
// to cache the result.
17067+
/**
17068+
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
17069+
* with computing the type and may not fully check all contained sub-expressions for errors.
17070+
* A cache argument of true indicates that if the function performs a full type check, it is ok
17071+
* to cache the result.
17072+
*/
1707117073
function getTypeOfExpression(node: Expression, cache?: boolean) {
1707217074
// Optimize for the common case of a call to a function with a single non-generic call
1707317075
// signature where we can just fetch the return type without checking the arguments.
@@ -17084,6 +17086,21 @@ namespace ts {
1708417086
return cache ? checkExpressionCached(node) : checkExpression(node);
1708517087
}
1708617088

17089+
/**
17090+
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
17091+
* with computing the type and may not fully check all contained sub-expressions for errors.
17092+
* It is intended for uses where you know there is no contextual type,
17093+
* and requesting the contextual type might cause a circularity or other bad behaviour.
17094+
* It sets the contextual type of the node to any before calling getTypeOfExpression.
17095+
*/
17096+
function getContextFreeTypeOfExpression(node: Expression) {
17097+
const saveContextualType = node.contextualType;
17098+
node.contextualType = anyType;
17099+
const type = getTypeOfExpression(node);
17100+
node.contextualType = saveContextualType;
17101+
return type;
17102+
}
17103+
1708717104
// Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When
1708817105
// contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the
1708917106
// expression is being inferentially typed (section 4.15.2 in spec) and provides the type mapper to use in

0 commit comments

Comments
 (0)