Skip to content
Open
39 changes: 24 additions & 15 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38546,21 +38546,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType;
}

function inferFromAnnotatedParametersAndReturn(signature: Signature, context: Signature, inferenceContext: InferenceContext) {
const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0);
for (let i = 0; i < len; i++) {
const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration;
const typeNode = getEffectiveTypeAnnotationNode(declaration);
if (typeNode) {
const source = addOptionality(getTypeFromTypeNode(typeNode), /*isProperty*/ false, isOptionalDeclaration(declaration));
const target = getTypeAtPosition(context, i);
inferTypes(inferenceContext.inferences, source, target);
function inferFromAnnotatedParametersAndReturn(node: FunctionExpression | ArrowFunction | MethodDeclaration, contextualSignature: Signature, inferenceContext: InferenceContext) {
if (node.parameters.length) {
const len = node.parameters.length - (last(node.parameters).dotDotDotToken ? 1 : 0);
const thisParameterOffset = first(node.parameters).symbol.escapedName === InternalSymbolName.This ? 1 : 0;
for (let i = thisParameterOffset; i < len; i++) {
const declaration = node.parameters[i];
const typeNode = getEffectiveTypeAnnotationNode(declaration);
if (typeNode) {
const source = addOptionality(getTypeFromTypeNode(typeNode), /*isProperty*/ false, isOptionalDeclaration(declaration));
const target = getTypeAtPosition(contextualSignature, i - thisParameterOffset);
inferTypes(inferenceContext.inferences, source, target);
}
}
}
const typeNode = signature.declaration && getEffectiveReturnTypeNode(signature.declaration);
if (typeNode) {
const source = getTypeFromTypeNode(typeNode);
const target = getReturnTypeOfSignature(context);
const returnTypeNode = node.type;
if (returnTypeNode) {
const source = getTypeFromTypeNode(returnTypeNode);
const target = getReturnTypeOfSignature(contextualSignature);
inferTypes(inferenceContext.inferences, source, target);
}
}
Expand Down Expand Up @@ -39536,6 +39539,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return links.contextFreeType = returnOnlyType;
}
}
if (checkMode & CheckMode.Inferential) {
const contextualSignature = getContextualSignature(node);
if (contextualSignature) {
inferFromAnnotatedParametersAndReturn(node, contextualSignature, getInferenceContext(node)!);
}
}
return anyFunctionType;
}

Expand Down Expand Up @@ -39569,7 +39578,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const inferenceContext = getInferenceContext(node);
let instantiatedContextualSignature: Signature | undefined;
if (checkMode && checkMode & CheckMode.Inferential) {
inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!);
inferFromAnnotatedParametersAndReturn(node, contextualSignature, inferenceContext!);
const restType = getEffectiveRestType(contextualSignature);
if (restType && restType.flags & TypeFlags.TypeParameter) {
instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper);
Expand All @@ -39587,7 +39596,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else if (contextualSignature && !node.typeParameters && contextualSignature.parameters.length > node.parameters.length) {
const inferenceContext = getInferenceContext(node);
if (checkMode && checkMode & CheckMode.Inferential) {
inferFromAnnotatedParametersAndReturn(signature, contextualSignature, inferenceContext!);
inferFromAnnotatedParametersAndReturn(node, contextualSignature, inferenceContext!);
}
}
if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//// [tests/cases/compiler/contextSensitiveAnnotatedParametersInference1.ts] ////

=== contextSensitiveAnnotatedParametersInference1.ts ===
declare function test<T, A, B>(obj: {
>test : Symbol(test, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 0))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 22))
>A : Symbol(A, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 24))
>B : Symbol(B, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 27))
>obj : Symbol(obj, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 31))

ctx: T;
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 37))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 22))

a: (a: A, ctx: T) => void;
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 1, 9))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 2, 6))
>A : Symbol(A, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 24))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 2, 11))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 22))

b: (b: B, ctx: T, a: A) => void;
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 2, 28))
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 3, 6))
>B : Symbol(B, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 27))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 3, 11))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 22))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 3, 19))
>A : Symbol(A, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 24))

}): void;

test({
>test : Symbol(test, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 0))

ctx: 'foo',
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 6, 6))

a: (a: string, ctx) => {},
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 7, 13))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 8, 6))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 8, 16))

b: (b: string, ctx, a) => {},
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 8, 28))
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 9, 6))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 9, 16))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 9, 21))

});

test({
>test : Symbol(test, Decl(contextSensitiveAnnotatedParametersInference1.ts, 0, 0))

ctx: 'foo',
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 12, 6))

b: (b: string, ctx, a) => {},
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 13, 13))
>b : Symbol(b, Decl(contextSensitiveAnnotatedParametersInference1.ts, 14, 6))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 14, 16))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 14, 21))

a: (a: string, ctx) => {},
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 14, 31))
>a : Symbol(a, Decl(contextSensitiveAnnotatedParametersInference1.ts, 15, 6))
>ctx : Symbol(ctx, Decl(contextSensitiveAnnotatedParametersInference1.ts, 15, 16))

});

Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//// [tests/cases/compiler/contextSensitiveAnnotatedParametersInference1.ts] ////

=== contextSensitiveAnnotatedParametersInference1.ts ===
declare function test<T, A, B>(obj: {
>test : <T, A, B>(obj: { ctx: T; a: (a: A, ctx: T) => void; b: (b: B, ctx: T, a: A) => void; }) => void
> : ^ ^^ ^^ ^^ ^^ ^^^^^
>obj : { ctx: T; a: (a: A, ctx: T) => void; b: (b: B, ctx: T, a: A) => void; }
> : ^^^^^^^ ^^^^^ ^^^^^ ^^^

ctx: T;
>ctx : T
> : ^

a: (a: A, ctx: T) => void;
>a : (a: A, ctx: T) => void
> : ^ ^^ ^^ ^^ ^^^^^
>a : A
> : ^
>ctx : T
> : ^

b: (b: B, ctx: T, a: A) => void;
>b : (b: B, ctx: T, a: A) => void
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^
>b : B
> : ^
>ctx : T
> : ^
>a : A
> : ^

}): void;

test({
>test({ ctx: 'foo', a: (a: string, ctx) => {}, b: (b: string, ctx, a) => {},}) : void
> : ^^^^
>test : <T, A, B>(obj: { ctx: T; a: (a: A, ctx: T) => void; b: (b: B, ctx: T, a: A) => void; }) => void
> : ^ ^^ ^^ ^^ ^^ ^^^^^
>{ ctx: 'foo', a: (a: string, ctx) => {}, b: (b: string, ctx, a) => {},} : { ctx: string; a: (a: string, ctx: string) => void; b: (b: string, ctx: string, a: string) => void; }
> : ^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^

ctx: 'foo',
>ctx : string
> : ^^^^^^
>'foo' : "foo"
> : ^^^^^

a: (a: string, ctx) => {},
>a : (a: string, ctx: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^
>(a: string, ctx) => {} : (a: string, ctx: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^
>a : string
> : ^^^^^^
>ctx : string
> : ^^^^^^

b: (b: string, ctx, a) => {},
>b : (b: string, ctx: string, a: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
>(b: string, ctx, a) => {} : (b: string, ctx: string, a: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
>b : string
> : ^^^^^^
>ctx : string
> : ^^^^^^
>a : string
> : ^^^^^^

});

test({
>test({ ctx: 'foo', b: (b: string, ctx, a) => {}, a: (a: string, ctx) => {},}) : void
> : ^^^^
>test : <T, A, B>(obj: { ctx: T; a: (a: A, ctx: T) => void; b: (b: B, ctx: T, a: A) => void; }) => void
> : ^ ^^ ^^ ^^ ^^ ^^^^^
>{ ctx: 'foo', b: (b: string, ctx, a) => {}, a: (a: string, ctx) => {},} : { ctx: string; b: (b: string, ctx: string, a: string) => void; a: (a: string, ctx: string) => void; }
> : ^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^

ctx: 'foo',
>ctx : string
> : ^^^^^^
>'foo' : "foo"
> : ^^^^^

b: (b: string, ctx, a) => {},
>b : (b: string, ctx: string, a: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
>(b: string, ctx, a) => {} : (b: string, ctx: string, a: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
>b : string
> : ^^^^^^
>ctx : string
> : ^^^^^^
>a : string
> : ^^^^^^

a: (a: string, ctx) => {},
>a : (a: string, ctx: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^
>(a: string, ctx) => {} : (a: string, ctx: string) => void
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^
>a : string
> : ^^^^^^
>ctx : string
> : ^^^^^^

});

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//// [tests/cases/compiler/contextSensitiveAnnotatedParametersInference2.ts] ////

=== contextSensitiveAnnotatedParametersInference2.ts ===
// https://github.com/microsoft/TypeScript/issues/60047

type Map<T> = {
>Map : Symbol(Map, Decl(contextSensitiveAnnotatedParametersInference2.ts, 0, 0))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference2.ts, 2, 9))

[P in keyof T]: T[P] extends boolean ? "boolean" : "other";
>P : Symbol(P, Decl(contextSensitiveAnnotatedParametersInference2.ts, 3, 3))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference2.ts, 2, 9))
>T : Symbol(T, Decl(contextSensitiveAnnotatedParametersInference2.ts, 2, 9))
>P : Symbol(P, Decl(contextSensitiveAnnotatedParametersInference2.ts, 3, 3))

};

export function buildCommand<F extends Record<string, unknown>>(builderArgs: {
>buildCommand : Symbol(buildCommand, Decl(contextSensitiveAnnotatedParametersInference2.ts, 4, 2))
>F : Symbol(F, Decl(contextSensitiveAnnotatedParametersInference2.ts, 6, 29))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>builderArgs : Symbol(builderArgs, Decl(contextSensitiveAnnotatedParametersInference2.ts, 6, 64))

func: (p: F) => void;
>func : Symbol(func, Decl(contextSensitiveAnnotatedParametersInference2.ts, 6, 78))
>p : Symbol(p, Decl(contextSensitiveAnnotatedParametersInference2.ts, 7, 9))
>F : Symbol(F, Decl(contextSensitiveAnnotatedParametersInference2.ts, 6, 29))

params: Map<NoInfer<F>>;
>params : Symbol(params, Decl(contextSensitiveAnnotatedParametersInference2.ts, 7, 23))
>Map : Symbol(Map, Decl(contextSensitiveAnnotatedParametersInference2.ts, 0, 0))
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
>F : Symbol(F, Decl(contextSensitiveAnnotatedParametersInference2.ts, 6, 29))

}) {}

type Foo = { foo: boolean };
>Foo : Symbol(Foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 9, 5))
>foo : Symbol(foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 11, 12))

buildCommand({
>buildCommand : Symbol(buildCommand, Decl(contextSensitiveAnnotatedParametersInference2.ts, 4, 2))

func: function (p: Foo) {},
>func : Symbol(func, Decl(contextSensitiveAnnotatedParametersInference2.ts, 13, 14))
>p : Symbol(p, Decl(contextSensitiveAnnotatedParametersInference2.ts, 14, 18))
>Foo : Symbol(Foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 9, 5))

params: {
>params : Symbol(params, Decl(contextSensitiveAnnotatedParametersInference2.ts, 14, 29))

foo: "boolean",
>foo : Symbol(foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 15, 11))

},
});

buildCommand({
>buildCommand : Symbol(buildCommand, Decl(contextSensitiveAnnotatedParametersInference2.ts, 4, 2))

func(p: Foo) {},
>func : Symbol(func, Decl(contextSensitiveAnnotatedParametersInference2.ts, 20, 14))
>p : Symbol(p, Decl(contextSensitiveAnnotatedParametersInference2.ts, 21, 7))
>Foo : Symbol(Foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 9, 5))

params: {
>params : Symbol(params, Decl(contextSensitiveAnnotatedParametersInference2.ts, 21, 18))

foo: "boolean",
>foo : Symbol(foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 22, 11))

},
});

buildCommand({
>buildCommand : Symbol(buildCommand, Decl(contextSensitiveAnnotatedParametersInference2.ts, 4, 2))

func: (p: Foo) => {},
>func : Symbol(func, Decl(contextSensitiveAnnotatedParametersInference2.ts, 27, 14))
>p : Symbol(p, Decl(contextSensitiveAnnotatedParametersInference2.ts, 28, 9))
>Foo : Symbol(Foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 9, 5))

params: {
>params : Symbol(params, Decl(contextSensitiveAnnotatedParametersInference2.ts, 28, 23))

foo: "boolean",
>foo : Symbol(foo, Decl(contextSensitiveAnnotatedParametersInference2.ts, 29, 11))

},
});

Loading