Skip to content

Commit 6a261ad

Browse files
committed
Consult cached contextual types only when no contextFlags
1 parent ddadea1 commit 6a261ad

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

src/compiler/checker.ts

+22-15
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21102110

21112111
const contextualTypeNodes: Node[] = [];
21122112
const contextualTypes: (Type | undefined)[] = [];
2113+
const contextualIsCache: boolean[] = [];
21132114
let contextualTypeCount = 0;
21142115

21152116
const inferenceContextNodes: Node[] = [];
@@ -19199,7 +19200,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1919919200
}
1920019201

1920119202
function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) {
19202-
pushContextualType(next, sourcePropType);
19203+
pushContextualType(next, sourcePropType, /*isCache*/ false);
1920319204
const result = checkExpressionForMutableLocation(next, CheckMode.Contextual);
1920419205
popContextualType();
1920519206
return result;
@@ -19516,7 +19517,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1951619517
}
1951719518
// recreate a tuple from the elements, if possible
1951819519
// Since we're re-doing the expression type, we need to reapply the contextual type
19519-
pushContextualType(node, target);
19520+
pushContextualType(node, target, /*isCache*/ false);
1952019521
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
1952119522
popContextualType();
1952219523
if (isTupleLikeType(tupleizedType)) {
@@ -29035,10 +29036,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2903529036
// We cannot answer semantic questions within a with block, do not proceed any further
2903629037
return undefined;
2903729038
}
29038-
const index = findContextualNode(node);
29039+
// Cached contextual types are obtained with no ContextFlags, so we can only consult them for
29040+
// requests with no ContextFlags.
29041+
const index = findContextualNode(node, /*includeCaches*/ !contextFlags);
2903929042
if (index >= 0) {
29040-
const cached = contextualTypes[index];
29041-
if (cached || !contextFlags) return cached;
29043+
return contextualTypes[index];
2904229044
}
2904329045
const { parent } = node;
2904429046
switch (parent.kind) {
@@ -29111,19 +29113,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2911129113
return undefined;
2911229114
}
2911329115

29114-
function pushContextualType(node: Node, type: Type | undefined) {
29116+
function pushCachedContextualType(node: Expression) {
29117+
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined), /*isCache*/ true);
29118+
}
29119+
29120+
function pushContextualType(node: Expression, type: Type | undefined, isCache: boolean) {
2911529121
contextualTypeNodes[contextualTypeCount] = node;
2911629122
contextualTypes[contextualTypeCount] = type;
29123+
contextualIsCache[contextualTypeCount] = isCache;
2911729124
contextualTypeCount++;
2911829125
}
2911929126

2912029127
function popContextualType() {
2912129128
contextualTypeCount--;
2912229129
}
2912329130

29124-
function findContextualNode(node: Node) {
29131+
function findContextualNode(node: Node, includeCaches: boolean) {
2912529132
for (let i = contextualTypeCount - 1; i >= 0; i--) {
29126-
if (node === contextualTypeNodes[i]) {
29133+
if (node === contextualTypeNodes[i] && (includeCaches || !contextualIsCache[i])) {
2912729134
return i;
2912829135
}
2912929136
}
@@ -29150,7 +29157,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2915029157

2915129158
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
2915229159
if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) {
29153-
const index = findContextualNode(node.parent);
29160+
const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags);
2915429161
if (index >= 0) {
2915529162
// Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit
2915629163
// _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type
@@ -29486,7 +29493,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2948629493
const elementCount = elements.length;
2948729494
const elementTypes: Type[] = [];
2948829495
const elementFlags: ElementFlags[] = [];
29489-
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined));
29496+
pushCachedContextualType(node);
2949029497
const inDestructuringPattern = isAssignmentTarget(node);
2949129498
const inConstContext = isConstContext(node);
2949229499
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
@@ -29669,7 +29676,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2966929676
let propertiesArray: Symbol[] = [];
2967029677
let spread: Type = emptyObjectType;
2967129678

29672-
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined));
29679+
pushCachedContextualType(node);
2967329680
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
2967429681
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
2967529682
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@@ -36828,16 +36835,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3682836835
type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike));
3682936836
}
3683036837

36831-
function getContextNode(node: Expression): Node {
36832-
if (node.kind === SyntaxKind.JsxAttributes && !isJsxSelfClosingElement(node.parent)) {
36838+
function getContextNode(node: Expression): Expression {
36839+
if (isJsxAttributes(node) && !isJsxSelfClosingElement(node.parent)) {
3683336840
return node.parent.parent; // Needs to be the root JsxElement, so it encompasses the attributes _and_ the children (which are essentially part of the attributes)
3683436841
}
3683536842
return node;
3683636843
}
3683736844

3683836845
function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type {
3683936846
const contextNode = getContextNode(node);
36840-
pushContextualType(contextNode, contextualType);
36847+
pushContextualType(contextNode, contextualType, /*isCache*/ false);
3684136848
pushInferenceContext(contextNode, inferenceContext);
3684236849
const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0));
3684336850
// In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type
@@ -37228,7 +37235,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3722837235
if (links.contextFreeType) {
3722937236
return links.contextFreeType;
3723037237
}
37231-
pushContextualType(node, anyType);
37238+
pushContextualType(node, anyType, /*isCache*/ false);
3723237239
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
3723337240
popContextualType();
3723437241
return type;

0 commit comments

Comments
 (0)