Skip to content

Commit 4749c38

Browse files
authored
Only collect outermost intra expression inference sites (#54186)
1 parent 67299ed commit 4749c38

File tree

1 file changed

+23
-12
lines changed

1 file changed

+23
-12
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,9 +1254,10 @@ export const enum CheckMode {
12541254
Inferential = 1 << 1, // Inferential typing
12551255
SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions
12561256
SkipGenericFunctions = 1 << 3, // Skip single signature generic functions
1257-
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
1258-
IsForStringLiteralArgumentCompletions = 1 << 5, // Do not infer from the argument currently being typed
1259-
RestBindingElement = 1 << 6, // Checking a type that is going to be used to determine the type of a rest binding element
1257+
SkipAddingIntraExpressionSites = 1 << 4, // Skip adding intra expression sites in nested expressions since only the outermost one has to be added
1258+
IsForSignatureHelp = 1 << 5, // Call resolution for purposes of signature help
1259+
IsForStringLiteralArgumentCompletions = 1 << 6, // Do not infer from the argument currently being typed
1260+
RestBindingElement = 1 << 7, // Checking a type that is going to be used to determine the type of a rest binding element
12601261
// e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`,
12611262
// we need to preserve generic types instead of substituting them for constraints
12621263
TypeOnly = 1 << 7, // Called from getTypeOfExpression, diagnostics may be omitted
@@ -29979,10 +29980,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2997929980
elementFlags.push(ElementFlags.Optional);
2998029981
}
2998129982
else {
29982-
const type = checkExpressionForMutableLocation(e, checkMode, forceTuple);
29983+
const shouldAddAsIntraExpressionInferenceSite = inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & (CheckMode.SkipContextSensitive | CheckMode.SkipAddingIntraExpressionSites)) && isContextSensitive(e);
29984+
const elementCheckMode = (checkMode || CheckMode.Normal) | (shouldAddAsIntraExpressionInferenceSite ? CheckMode.SkipAddingIntraExpressionSites : 0);
29985+
29986+
const type = checkExpressionForMutableLocation(e, elementCheckMode, forceTuple);
2998329987
elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression));
2998429988
elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required);
29985-
if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) {
29989+
if (shouldAddAsIntraExpressionInferenceSite) {
2998629990
const inferenceContext = getInferenceContext(node);
2998729991
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
2998829992
addIntraExpressionInferenceSite(inferenceContext, e, type);
@@ -30147,12 +30151,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3014730151
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
3014830152
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
3014930153
isObjectLiteralMethod(memberDecl)) {
30150-
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) :
30154+
30155+
const shouldAddAsIntraExpressionInferenceSite = contextualType && checkMode & CheckMode.Inferential && !(checkMode & (CheckMode.SkipContextSensitive | CheckMode.SkipAddingIntraExpressionSites)) &&
30156+
(memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl);
30157+
const propCheckMode = checkMode | (shouldAddAsIntraExpressionInferenceSite ? CheckMode.SkipAddingIntraExpressionSites : 0);
30158+
30159+
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, propCheckMode) :
3015130160
// avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring
3015230161
// for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`.
3015330162
// we don't want to say "could not find 'a'".
30154-
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) :
30155-
checkObjectLiteralMethod(memberDecl, checkMode);
30163+
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, propCheckMode) :
30164+
checkObjectLiteralMethod(memberDecl, propCheckMode);
3015630165
if (isInJavascript) {
3015730166
const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl);
3015830167
if (jsDocType) {
@@ -30207,8 +30216,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3020730216
member = prop;
3020830217
allPropertiesTable?.set(prop.escapedName, prop);
3020930218

30210-
if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) &&
30211-
(memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) {
30219+
if (shouldAddAsIntraExpressionInferenceSite) {
3021230220
const inferenceContext = getInferenceContext(node);
3021330221
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
3021430222
const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl;
@@ -30442,7 +30450,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3044230450
for (const attributeDecl of attributes.properties) {
3044330451
const member = attributeDecl.symbol;
3044430452
if (isJsxAttribute(attributeDecl)) {
30445-
const exprType = checkJsxAttribute(attributeDecl, checkMode);
30453+
const shouldAddAsIntraExpressionInferenceSite = contextualType && checkMode & CheckMode.Inferential && !(checkMode & (CheckMode.SkipContextSensitive | CheckMode.SkipAddingIntraExpressionSites)) && isContextSensitive(attributeDecl);
30454+
const attributeCheckMode = checkMode | (shouldAddAsIntraExpressionInferenceSite ? CheckMode.SkipAddingIntraExpressionSites : 0);
30455+
30456+
const exprType = checkJsxAttribute(attributeDecl, attributeCheckMode);
3044630457
objectFlags |= getObjectFlags(exprType) & ObjectFlags.PropagatingFlags;
3044730458

3044830459
const attributeSymbol = createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
@@ -30464,7 +30475,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3046430475
addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string);
3046530476
}
3046630477
}
30467-
if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) {
30478+
if (shouldAddAsIntraExpressionInferenceSite) {
3046830479
const inferenceContext = getInferenceContext(attributes);
3046930480
Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context
3047030481
const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!;

0 commit comments

Comments
 (0)