@@ -2140,6 +2140,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2140
2140
var inferenceContexts: (InferenceContext | undefined)[] = [];
2141
2141
var inferenceContextCount = 0;
2142
2142
2143
+ var intraExpressionInferenceSites: InferenceContext["intraExpressionInferenceSites"][] = [];
2144
+ var intraExpressionInferenceSitesLengths: number[] = [];
2145
+ var intraExpressionInferenceSitesCount = 0;
2146
+
2143
2147
var emptyStringType = getStringLiteralType("");
2144
2148
var zeroType = getNumberLiteralType(0);
2145
2149
var zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" });
@@ -23956,6 +23960,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
23956
23960
}
23957
23961
23958
23962
function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) {
23963
+ const stored = intraExpressionInferenceSites[intraExpressionInferenceSitesCount];
23964
+ if (stored && stored === context.intraExpressionInferenceSites) {
23965
+ // if the `context.intraExpressionInferenceSites` are still the same as when we last stored into `intraExpressionInferenceSites`
23966
+ // then we can just shrink the array and push to it since items that were pushed since then are guaranteed to be inside the node
23967
+ // and we only need to keep the outermost site until it's pulled from and resetted by `inferFromIntraExpressionSites`
23968
+ stored.length = intraExpressionInferenceSitesLengths[intraExpressionInferenceSitesCount];
23969
+ stored.push({ node, type });
23970
+ return;
23971
+ }
23959
23972
(context.intraExpressionInferenceSites ??= []).push({ node, type });
23960
23973
}
23961
23974
@@ -29611,6 +29624,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29611
29624
}
29612
29625
}
29613
29626
29627
+ function pushIntraExpressionInferenceSites(node: ObjectLiteralExpression | ArrayLiteralExpression | JsxAttributes, contextualType: Type | undefined, checkMode: CheckMode) {
29628
+ const inIntraExpressionInferenceContext = !!(contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive));
29629
+ const sites = inIntraExpressionInferenceContext ? getInferenceContext(node)!.intraExpressionInferenceSites : undefined;
29630
+ intraExpressionInferenceSites[intraExpressionInferenceSitesCount] = sites;
29631
+ intraExpressionInferenceSitesLengths[intraExpressionInferenceSitesCount] = sites?.length || 0;
29632
+ intraExpressionInferenceSitesCount++;
29633
+ return inIntraExpressionInferenceContext;
29634
+ }
29635
+
29636
+ function popIntraExpressionInferenceSites() {
29637
+ intraExpressionInferenceSitesCount--;
29638
+ }
29639
+
29614
29640
function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) {
29615
29641
if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) {
29616
29642
const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags);
@@ -29936,7 +29962,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29936
29962
(node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken);
29937
29963
}
29938
29964
29939
- function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined , forceTuple: boolean | undefined): Type {
29965
+ function checkArrayLiteral(node: ArrayLiteralExpression, checkMode = CheckMode.Normal , forceTuple: boolean | undefined): Type {
29940
29966
const elements = node.elements;
29941
29967
const elementCount = elements.length;
29942
29968
const elementTypes: Type[] = [];
@@ -29946,6 +29972,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29946
29972
const isSpreadIntoCallOrNew = isSpreadElement(node.parent) && isCallOrNewExpression(node.parent.parent);
29947
29973
const inConstContext = isSpreadIntoCallOrNew || isConstContext(node);
29948
29974
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
29975
+ const inIntraExpressionInferenceContext = pushIntraExpressionInferenceSites(node, contextualType, checkMode);
29949
29976
const inTupleContext = isSpreadIntoCallOrNew || !!contextualType && someType(contextualType, isTupleLikeType);
29950
29977
let hasOmittedExpression = false;
29951
29978
for (let i = 0; i < elementCount; i++) {
@@ -29992,14 +30019,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
29992
30019
const type = checkExpressionForMutableLocation(e, checkMode, forceTuple);
29993
30020
elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression));
29994
30021
elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required);
29995
- if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) {
30022
+ if (inTupleContext && inIntraExpressionInferenceContext && isContextSensitive(e)) {
29996
30023
const inferenceContext = getInferenceContext(node);
29997
30024
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
29998
30025
addIntraExpressionInferenceSite(inferenceContext, e, type);
29999
30026
}
30000
30027
}
30001
30028
}
30002
30029
popContextualType();
30030
+ popIntraExpressionInferenceSites();
30003
30031
if (inDestructuringPattern) {
30004
30032
return createTupleType(elementTypes, elementFlags);
30005
30033
}
@@ -30129,6 +30157,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30129
30157
const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined);
30130
30158
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
30131
30159
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
30160
+ const inIntraExpressionInferenceContext = pushIntraExpressionInferenceSites(node, contextualType, checkMode);
30132
30161
const inConstContext = isConstContext(node);
30133
30162
const checkFlags = inConstContext ? CheckFlags.Readonly : 0;
30134
30163
const isInJavascript = isInJSFile(node) && !isInJsonFile(node);
@@ -30217,8 +30246,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30217
30246
member = prop;
30218
30247
allPropertiesTable?.set(prop.escapedName, prop);
30219
30248
30220
- if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) &&
30221
- (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) {
30249
+ if (inIntraExpressionInferenceContext && (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) {
30222
30250
const inferenceContext = getInferenceContext(node);
30223
30251
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
30224
30252
const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl;
@@ -30287,6 +30315,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30287
30315
propertiesArray.push(member);
30288
30316
}
30289
30317
popContextualType();
30318
+ popIntraExpressionInferenceSites();
30290
30319
30291
30320
// If object literal is contextually typed by the implied type of a binding pattern, augment the result
30292
30321
// type with those properties for which the binding pattern specifies a default value.
@@ -30440,6 +30469,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30440
30469
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode = CheckMode.Normal) {
30441
30470
const attributes = openingLikeElement.attributes;
30442
30471
const contextualType = getContextualType(attributes, ContextFlags.None);
30472
+ const inIntraExpressionInferenceContext = pushIntraExpressionInferenceSites(attributes, contextualType, checkMode);
30443
30473
const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined;
30444
30474
let attributesTable = createSymbolTable();
30445
30475
let spread: Type = emptyJsxObjectType;
@@ -30474,7 +30504,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30474
30504
addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string);
30475
30505
}
30476
30506
}
30477
- if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) {
30507
+ if (inIntraExpressionInferenceContext && isContextSensitive(attributeDecl)) {
30478
30508
const inferenceContext = getInferenceContext(attributes);
30479
30509
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
30480
30510
const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!;
@@ -30543,6 +30573,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
30543
30573
}
30544
30574
}
30545
30575
30576
+ popIntraExpressionInferenceSites();
30577
+
30546
30578
if (hasSpreadAnyType) {
30547
30579
return anyType;
30548
30580
}
0 commit comments