Skip to content

Commit 7dc1952

Browse files
committed
Fix type mapper combination
1 parent 7e8c56c commit 7dc1952

6 files changed

+74
-5
lines changed

src/compiler/checker.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -21840,6 +21840,20 @@ namespace ts {
2184021840
return t;
2184121841
}
2184221842

21843+
function mapToInferredTypeIncludingReturnTypeInferences(context: InferenceContext, returnContext: InferenceContext, t: Type): Type {
21844+
const inferences = context.inferences;
21845+
for (let i = 0; i < inferences.length; i++) {
21846+
const inference = inferences[i];
21847+
if (t === inference.typeParameter) {
21848+
if (inference.inferredType || hasInferenceCandidates(inference)) {
21849+
return getInferredType(context, i);
21850+
}
21851+
return getMappedType(t, returnContext.mapper);
21852+
}
21853+
}
21854+
return t;
21855+
}
21856+
2184321857
function clearCachedInferences(inferences: InferenceInfo[]) {
2184421858
for (const inference of inferences) {
2184521859
if (!inference.isFixed) {
@@ -27055,12 +27069,10 @@ namespace ts {
2705527069
const inferenceContext = getInferenceContext(node);
2705627070
// If no inferences have been made, nothing is gained from instantiating as type parameters
2705727071
// would just be replaced with their defaults similar to the apparent type.
27058-
if (inferenceContext && contextFlags! & ContextFlags.Signature && (inferenceContext.returnMapper || some(inferenceContext.inferences, hasInferenceCandidates))) {
27072+
if (inferenceContext && contextFlags! & ContextFlags.Signature && (inferenceContext.combinedReturnMapper || some(inferenceContext.inferences, hasInferenceCandidates))) {
2705927073
// For contextual signatures we incorporate all inferences made so far, e.g. from return
2706027074
// types as well as arguments to the left in a function call.
27061-
return instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper
27062-
? combineTypeMappers(inferenceContext.nonFixingMapper, inferenceContext.returnMapper)
27063-
: inferenceContext.nonFixingMapper);
27075+
return instantiateInstantiableTypes(contextualType, inferenceContext.combinedReturnMapper || inferenceContext.nonFixingMapper);
2706427076
}
2706527077
if (inferenceContext?.returnMapper) {
2706627078
// For other purposes (e.g. determining whether to produce literal types) we only
@@ -29950,7 +29962,11 @@ namespace ts {
2995029962
const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags);
2995129963
const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper);
2995229964
inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType);
29953-
context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined;
29965+
if (some(returnContext.inferences, hasInferenceCandidates)) {
29966+
const clonedReturnContext = cloneInferredPartOfContext(returnContext)!;
29967+
context.returnMapper = getMapperFromContext(clonedReturnContext);
29968+
context.combinedReturnMapper = makeFunctionTypeMapper(t => mapToInferredTypeIncludingReturnTypeInferences(context, clonedReturnContext, t));
29969+
}
2995429970
}
2995529971
}
2995629972
}

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5922,6 +5922,7 @@ namespace ts {
59225922
mapper: TypeMapper; // Mapper that fixes inferences
59235923
nonFixingMapper: TypeMapper; // Mapper that doesn't fix inferences
59245924
returnMapper?: TypeMapper; // Type mapper for inferences from return types (if any)
5925+
combinedReturnMapper?: TypeMapper; // Non-fixing mapper combined with return mapper for contextual signature instantiation
59255926
inferredTypeParameters?: readonly TypeParameter[]; // Inferred type parameters for function result
59265927
intraExpressionInferenceSites?: IntraExpressionInferenceSite[];
59275928
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [objectBindingPatternContextuallyTypesArgument.ts]
2+
declare function id<T>(x: T): T;
3+
const { f = (x: string) => x.length } = id({ f: x => x.charAt });
4+
5+
6+
//// [objectBindingPatternContextuallyTypesArgument.js]
7+
var _a = id({ f: function (x) { return x.charAt; } }).f, f = _a === void 0 ? function (x) { return x.length; } : _a;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/objectBindingPatternContextuallyTypesArgument.ts ===
2+
declare function id<T>(x: T): T;
3+
>id : Symbol(id, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 0))
4+
>T : Symbol(T, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 20))
5+
>x : Symbol(x, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 23))
6+
>T : Symbol(T, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 20))
7+
>T : Symbol(T, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 20))
8+
9+
const { f = (x: string) => x.length } = id({ f: x => x.charAt });
10+
>f : Symbol(f, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 7))
11+
>x : Symbol(x, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 13))
12+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
13+
>x : Symbol(x, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 13))
14+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
15+
>id : Symbol(id, Decl(objectBindingPatternContextuallyTypesArgument.ts, 0, 0))
16+
>f : Symbol(f, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 44))
17+
>x : Symbol(x, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 47))
18+
>x.charAt : Symbol(String.charAt, Decl(lib.es5.d.ts, --, --))
19+
>x : Symbol(x, Decl(objectBindingPatternContextuallyTypesArgument.ts, 1, 47))
20+
>charAt : Symbol(String.charAt, Decl(lib.es5.d.ts, --, --))
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/compiler/objectBindingPatternContextuallyTypesArgument.ts ===
2+
declare function id<T>(x: T): T;
3+
>id : <T>(x: T) => T
4+
>x : T
5+
6+
const { f = (x: string) => x.length } = id({ f: x => x.charAt });
7+
>f : ((x: string) => number) | ((x: string) => (pos: number) => string)
8+
>(x: string) => x.length : (x: string) => number
9+
>x : string
10+
>x.length : number
11+
>x : string
12+
>length : number
13+
>id({ f: x => x.charAt }) : { f: (x: string) => (pos: number) => string; }
14+
>id : <T>(x: T) => T
15+
>{ f: x => x.charAt } : { f: (x: string) => (pos: number) => string; }
16+
>f : (x: string) => (pos: number) => string
17+
>x => x.charAt : (x: string) => (pos: number) => string
18+
>x : string
19+
>x.charAt : (pos: number) => string
20+
>x : string
21+
>charAt : (pos: number) => string
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare function id<T>(x: T): T;
2+
const { f = (x: string) => x.length } = id({ f: x => x.charAt });

0 commit comments

Comments
 (0)