Skip to content

Commit 9e748b7

Browse files
committed
prefer inferring from non-context sensitive type
1 parent b5c6ef4 commit 9e748b7

File tree

5 files changed

+352
-5
lines changed

5 files changed

+352
-5
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26454,6 +26454,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2645426454
const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter;
2645526455
const templateType = getTemplateTypeFromMappedType(target);
2645626456
const inference = createInferenceInfo(typeParameter);
26457+
if (sourceValueDeclaration && getObjectFlags(sourceType) & ObjectFlags.NonInferrableType) {
26458+
const scopeNode = sourceValueDeclaration.parent;
26459+
const nonContextSensitiveScopeType = getNodeLinks(scopeNode).nonContextSensitiveType;
26460+
if (nonContextSensitiveScopeType) {
26461+
const name = getSymbolOfDeclaration(sourceValueDeclaration).escapedName;
26462+
const prop = getPropertyOfType(nonContextSensitiveScopeType, name);
26463+
if (prop) {
26464+
sourceType = getTypeOfSymbol(prop);
26465+
}
26466+
}
26467+
}
2645726468
inferTypes([inference], sourceType, templateType);
2645826469
if (sourceValueDeclaration && getObjectFlags(sourceType) & ObjectFlags.NonInferrableType) {
2645926470
const scopeNode = sourceValueDeclaration.parent;
@@ -33488,6 +33499,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3348833499
}
3348933500

3349033501
const intraExpressionInferenceContext = contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) ? getInferenceContext(node) : undefined;
33502+
const isReverseMappedScopeNode = (intraExpressionInferenceContext && some(intraExpressionInferenceContext.inferences, hasReverseMappedCandidate)) || false;
3349133503

3349233504
let offset = 0;
3349333505
for (const memberDecl of node.properties) {
@@ -33500,23 +33512,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3350033512
isObjectLiteralMethod(memberDecl)
3350133513
) {
3350233514
const isIntraExpressionInferenceSource = intraExpressionInferenceContext && (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl);
33503-
if (isIntraExpressionInferenceSource) {
33515+
if (isReverseMappedScopeNode) {
3350433516
// this object literal is a potential source for reverse mapped type inference
3350533517
// so we push it onto the reverse mapped intra-expression inference scope stack
3350633518
// that makes `addIntraExpressionInferenceSite` called when checking expressions *contained in* this member
3350733519
// to collect intra-expression inference sites for the potential reverse mapped type symbol originating from this member
3350833520
// the member's type itself wouldn't contribute to intra-expression inference
3350933521
// as there wouldn't be any "earlier" (in source order) expressions able to "consume" this type through contextual parameter assignment
33510-
pushReverseMappedTypeIntraExpressionInferenceScope(intraExpressionInferenceContext, node);
33522+
pushReverseMappedTypeIntraExpressionInferenceScope(intraExpressionInferenceContext!, node);
3351133523
}
3351233524
let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) :
3351333525
// avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring
3351433526
// for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`.
3351533527
// we don't want to say "could not find 'a'".
3351633528
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) :
3351733529
checkObjectLiteralMethod(memberDecl, checkMode);
33518-
if (isIntraExpressionInferenceSource) {
33519-
popReverseMappedTypeIntraExpressionInferenceScope(intraExpressionInferenceContext);
33530+
if (isReverseMappedScopeNode) {
33531+
popReverseMappedTypeIntraExpressionInferenceScope(intraExpressionInferenceContext!);
3352033532
}
3352133533
if (isInJavascript) {
3352233534
const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl);
@@ -33649,7 +33661,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3364933661
return mapType(spread, t => t === emptyObjectType ? createObjectLiteralType() : t);
3365033662
}
3365133663

33652-
return createObjectLiteralType();
33664+
const type = createObjectLiteralType();
33665+
33666+
if (isReverseMappedScopeNode) {
33667+
getNodeLinks(node).nonContextSensitiveType = type;
33668+
}
33669+
33670+
return type;
3365333671

3365433672
function createObjectLiteralType() {
3365533673
const indexInfos = [];
@@ -41571,6 +41589,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4157141589
return !!(info.candidates || info.contraCandidates || hasTypeParameterDefault(info.typeParameter));
4157241590
}
4157341591

41592+
function hasReverseMappedCandidate(info: InferenceInfo) {
41593+
return some(info.candidates, t => !!(getObjectFlags(t) & ObjectFlags.ReverseMapped));
41594+
}
41595+
4157441596
function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) {
4157541597
for (let i = 0; i < a.length; i++) {
4157641598
if (hasInferenceCandidates(a[i]) && hasInferenceCandidates(b[i])) {

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6308,6 +6308,7 @@ export interface NodeLinks {
63086308
externalHelpersModule?: Symbol; // Resolved symbol for the external helpers module
63096309
instantiationExpressionTypes?: Map<number, Type>; // Cache of instantiation expression types for the node
63106310
nonExistentPropCheckCache?: Set<string>;
6311+
nonContextSensitiveType?: Type;
63116312
}
63126313

63136314
/** @internal */
@@ -7156,6 +7157,7 @@ export interface InferenceContext {
71567157
outerReturnMapper?: TypeMapper; // Type mapper for inferences from return types of outer function (if any)
71577158
inferredTypeParameters?: readonly TypeParameter[]; // Inferred type parameters for function result
71587159
intraExpressionInferenceSites?: IntraExpressionInferenceSite[];
7160+
reverseMappedScopeNodes?: Set<Node>;
71597161
reverseMappedIntraExpressionInferenceScopeNodes?: Node[];
71607162
reverseMappedIntraExpressionInferenceSites?: IntraExpressionInferenceSite[][];
71617163
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//// [tests/cases/compiler/reverseMappedPartiallyInferableTypes3.ts] ////
2+
3+
=== reverseMappedPartiallyInferableTypes3.ts ===
4+
declare function setup<TAction = {}>(arg: {
5+
>setup : Symbol(setup, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 0))
6+
>TAction : Symbol(TAction, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 23))
7+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 37))
8+
9+
actions?: {
10+
>actions : Symbol(actions, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 43))
11+
12+
[K in keyof TAction]: (
13+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes3.ts, 2, 5))
14+
>TAction : Symbol(TAction, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 23))
15+
16+
params: TAction[K],
17+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 2, 27))
18+
>TAction : Symbol(TAction, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 23))
19+
>K : Symbol(K, Decl(reverseMappedPartiallyInferableTypes3.ts, 2, 5))
20+
21+
exec: (arg: TAction) => void,
22+
>exec : Symbol(exec, Decl(reverseMappedPartiallyInferableTypes3.ts, 3, 25))
23+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes3.ts, 4, 13))
24+
>TAction : Symbol(TAction, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 23))
25+
26+
) => void;
27+
};
28+
}): TAction;
29+
>TAction : Symbol(TAction, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 23))
30+
31+
const result1 = setup({
32+
>result1 : Symbol(result1, Decl(reverseMappedPartiallyInferableTypes3.ts, 9, 5))
33+
>setup : Symbol(setup, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 0))
34+
35+
actions: {
36+
>actions : Symbol(actions, Decl(reverseMappedPartiallyInferableTypes3.ts, 9, 23))
37+
38+
first: (params: { count: number }, enqueue) => {},
39+
>first : Symbol(first, Decl(reverseMappedPartiallyInferableTypes3.ts, 10, 12))
40+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 11, 12))
41+
>count : Symbol(count, Decl(reverseMappedPartiallyInferableTypes3.ts, 11, 21))
42+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 11, 38))
43+
44+
second: (params: { foo: string }, enqueue) => {},
45+
>second : Symbol(second, Decl(reverseMappedPartiallyInferableTypes3.ts, 11, 54))
46+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 12, 13))
47+
>foo : Symbol(foo, Decl(reverseMappedPartiallyInferableTypes3.ts, 12, 22))
48+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 12, 37))
49+
50+
},
51+
});
52+
53+
const result2 = setup({
54+
>result2 : Symbol(result2, Decl(reverseMappedPartiallyInferableTypes3.ts, 16, 5))
55+
>setup : Symbol(setup, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 0))
56+
57+
actions: {
58+
>actions : Symbol(actions, Decl(reverseMappedPartiallyInferableTypes3.ts, 16, 23))
59+
60+
foo: (params: { count: number }) => {},
61+
>foo : Symbol(foo, Decl(reverseMappedPartiallyInferableTypes3.ts, 17, 12))
62+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 18, 10))
63+
>count : Symbol(count, Decl(reverseMappedPartiallyInferableTypes3.ts, 18, 19))
64+
65+
first: (params: { count: number }, enqueue) => {},
66+
>first : Symbol(first, Decl(reverseMappedPartiallyInferableTypes3.ts, 18, 43))
67+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 19, 12))
68+
>count : Symbol(count, Decl(reverseMappedPartiallyInferableTypes3.ts, 19, 21))
69+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 19, 38))
70+
71+
second: (params: { foo: string }, enqueue) => {},
72+
>second : Symbol(second, Decl(reverseMappedPartiallyInferableTypes3.ts, 19, 54))
73+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 20, 13))
74+
>foo : Symbol(foo, Decl(reverseMappedPartiallyInferableTypes3.ts, 20, 22))
75+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 20, 37))
76+
77+
},
78+
});
79+
80+
const result3 = setup({
81+
>result3 : Symbol(result3, Decl(reverseMappedPartiallyInferableTypes3.ts, 24, 5))
82+
>setup : Symbol(setup, Decl(reverseMappedPartiallyInferableTypes3.ts, 0, 0))
83+
84+
actions: {
85+
>actions : Symbol(actions, Decl(reverseMappedPartiallyInferableTypes3.ts, 24, 23))
86+
87+
foo: (params: { count: number }) => {},
88+
>foo : Symbol(foo, Decl(reverseMappedPartiallyInferableTypes3.ts, 25, 12))
89+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 26, 10))
90+
>count : Symbol(count, Decl(reverseMappedPartiallyInferableTypes3.ts, 26, 19))
91+
92+
first: (params: { count: number }, enqueue: (arg: never) => void) => {},
93+
>first : Symbol(first, Decl(reverseMappedPartiallyInferableTypes3.ts, 26, 43))
94+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 27, 12))
95+
>count : Symbol(count, Decl(reverseMappedPartiallyInferableTypes3.ts, 27, 21))
96+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 27, 38))
97+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes3.ts, 27, 49))
98+
99+
second: (params: { foo: string }, enqueue: (arg: never) => void) => {},
100+
>second : Symbol(second, Decl(reverseMappedPartiallyInferableTypes3.ts, 27, 76))
101+
>params : Symbol(params, Decl(reverseMappedPartiallyInferableTypes3.ts, 28, 13))
102+
>foo : Symbol(foo, Decl(reverseMappedPartiallyInferableTypes3.ts, 28, 22))
103+
>enqueue : Symbol(enqueue, Decl(reverseMappedPartiallyInferableTypes3.ts, 28, 37))
104+
>arg : Symbol(arg, Decl(reverseMappedPartiallyInferableTypes3.ts, 28, 48))
105+
106+
},
107+
});
108+

0 commit comments

Comments
 (0)