Skip to content

Commit

Permalink
Fixed regression in generic signature instantiation with default type…
Browse files Browse the repository at this point in the history
… args (#59510)
  • Loading branch information
Andarist committed Aug 9, 2024
1 parent 278cb94 commit 1bb1d2a
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16040,8 16040,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true);
}

function getTypeParametersForMapper(signature: Signature) {
return sameMap(signature.typeParameters, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp);
}

function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper {
return createTypeMapper(sameMap(signature.typeParameters!, tp => tp.mapper ? instantiateType(tp, tp.mapper) : tp), typeArguments);
return createTypeMapper(getTypeParametersForMapper(signature)!, typeArguments);
}

function getErasedSignature(signature: Signature): Signature {
Expand Down Expand Up @@ -34930,7 34934,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature {
const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes);
const context = createInferenceContext(getTypeParametersForMapper(signature)!, signature, InferenceFlags.None, compareTypes);
// We clone the inferenceContext to avoid fixing. For example, when the source signature is <T>(x: T) => T[] and
// the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any')
// for T but leave it possible to later infer '[any]' back to A.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 1,85 @@
//// [tests/cases/compiler/genericCallInferenceConditionalType2.ts] ////

=== genericCallInferenceConditionalType2.ts ===
// https://github.com/microsoft/TypeScript/issues/86390

type ComponentProps<T> = T extends (props: infer P) => unknown ? P : never;
>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceConditionalType2.ts, 0, 0))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 2, 20))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 2, 20))
>props : Symbol(props, Decl(genericCallInferenceConditionalType2.ts, 2, 36))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 2, 48))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 2, 48))

declare function wrapComponent<P>(
>wrapComponent : Symbol(wrapComponent, Decl(genericCallInferenceConditionalType2.ts, 2, 75))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 4, 31))

component: (props: P) => unknown,
>component : Symbol(component, Decl(genericCallInferenceConditionalType2.ts, 4, 34))
>props : Symbol(props, Decl(genericCallInferenceConditionalType2.ts, 5, 14))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 4, 31))

): (props: P) => unknown;
>props : Symbol(props, Decl(genericCallInferenceConditionalType2.ts, 6, 4))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 4, 31))

const WrappedComponent = wrapComponent(
>WrappedComponent : Symbol(WrappedComponent, Decl(genericCallInferenceConditionalType2.ts, 8, 5))
>wrapComponent : Symbol(wrapComponent, Decl(genericCallInferenceConditionalType2.ts, 2, 75))

<T extends string = "span">(props: {
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 9, 3))
>props : Symbol(props, Decl(genericCallInferenceConditionalType2.ts, 9, 30))

as?: T | undefined;
>as : Symbol(as, Decl(genericCallInferenceConditionalType2.ts, 9, 38))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 9, 3))

className?: string;
>className : Symbol(className, Decl(genericCallInferenceConditionalType2.ts, 10, 23))

}) => {
return null;
},
);

type RetrievedProps = ComponentProps<typeof WrappedComponent>;
>RetrievedProps : Symbol(RetrievedProps, Decl(genericCallInferenceConditionalType2.ts, 15, 2))
>ComponentProps : Symbol(ComponentProps, Decl(genericCallInferenceConditionalType2.ts, 0, 0))
>WrappedComponent : Symbol(WrappedComponent, Decl(genericCallInferenceConditionalType2.ts, 8, 5))

declare const f: <T>(f: (x: T) => unknown) => (x: T) => unknown
>f : Symbol(f, Decl(genericCallInferenceConditionalType2.ts, 19, 13))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 19, 18))
>f : Symbol(f, Decl(genericCallInferenceConditionalType2.ts, 19, 21))
>x : Symbol(x, Decl(genericCallInferenceConditionalType2.ts, 19, 25))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 19, 18))
>x : Symbol(x, Decl(genericCallInferenceConditionalType2.ts, 19, 47))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 19, 18))

declare const g: <T extends unknown = string>(x: { foo: T }) => unknown
>g : Symbol(g, Decl(genericCallInferenceConditionalType2.ts, 20, 13))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 20, 18))
>x : Symbol(x, Decl(genericCallInferenceConditionalType2.ts, 20, 46))
>foo : Symbol(foo, Decl(genericCallInferenceConditionalType2.ts, 20, 50))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 20, 18))

const h = f(g)
>h : Symbol(h, Decl(genericCallInferenceConditionalType2.ts, 22, 5))
>f : Symbol(f, Decl(genericCallInferenceConditionalType2.ts, 19, 13))
>g : Symbol(g, Decl(genericCallInferenceConditionalType2.ts, 20, 13))

type FirstParameter<T> = T extends (x: infer P) => unknown ? P : unknown
>FirstParameter : Symbol(FirstParameter, Decl(genericCallInferenceConditionalType2.ts, 22, 14))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 24, 20))
>T : Symbol(T, Decl(genericCallInferenceConditionalType2.ts, 24, 20))
>x : Symbol(x, Decl(genericCallInferenceConditionalType2.ts, 24, 36))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 24, 44))
>P : Symbol(P, Decl(genericCallInferenceConditionalType2.ts, 24, 44))

type X = FirstParameter<typeof h>['foo']
>X : Symbol(X, Decl(genericCallInferenceConditionalType2.ts, 24, 72))
>FirstParameter : Symbol(FirstParameter, Decl(genericCallInferenceConditionalType2.ts, 22, 14))
>h : Symbol(h, Decl(genericCallInferenceConditionalType2.ts, 22, 5))

Original file line number Diff line number Diff line change
@@ -0,0 1,98 @@
//// [tests/cases/compiler/genericCallInferenceConditionalType2.ts] ////

=== genericCallInferenceConditionalType2.ts ===
// https://github.com/microsoft/TypeScript/issues/86390

type ComponentProps<T> = T extends (props: infer P) => unknown ? P : never;
>ComponentProps : ComponentProps<T>
> : ^^^^^^^^^^^^^^^^^
>props : P
> : ^

declare function wrapComponent<P>(
>wrapComponent : <P>(component: (props: P) => unknown) => (props: P) => unknown
> : ^ ^^ ^^ ^^^^^

component: (props: P) => unknown,
>component : (props: P) => unknown
> : ^ ^^ ^^^^^
>props : P
> : ^

): (props: P) => unknown;
>props : P
> : ^

const WrappedComponent = wrapComponent(
>WrappedComponent : <T extends string = "span">(props: { as?: T | undefined; className?: string; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^
>wrapComponent( <T extends string = "span">(props: { as?: T | undefined; className?: string; }) => { return null; },) : <T extends string = "span">(props: { as?: T | undefined; className?: string; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^
>wrapComponent : <P>(component: (props: P) => unknown) => (props: P) => unknown
> : ^ ^^ ^^ ^^^^^

<T extends string = "span">(props: {
><T extends string = "span">(props: { as?: T | undefined; className?: string; }) => { return null; } : <T extends string = "span">(props: { as?: T | undefined; className?: string; }) => null
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^^^^^
>props : { as?: T | undefined; className?: string; }
> : ^^^^^^^ ^^^^^^^^^^^^^^ ^^^

as?: T | undefined;
>as : T | undefined
> : ^^^^^^^^^^^^^

className?: string;
>className : string | undefined
> : ^^^^^^^^^^^^^^^^^^

}) => {
return null;
},
);

type RetrievedProps = ComponentProps<typeof WrappedComponent>;
>RetrievedProps : { as?: string | undefined; className?: string; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^
>WrappedComponent : <T extends string = "span">(props: { as?: T | undefined; className?: string; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^

declare const f: <T>(f: (x: T) => unknown) => (x: T) => unknown
>f : <T>(f: (x: T) => unknown) => (x: T) => unknown
> : ^ ^^ ^^ ^^^^^
>f : (x: T) => unknown
> : ^ ^^ ^^^^^
>x : T
> : ^
>x : T
> : ^

declare const g: <T extends unknown = string>(x: { foo: T }) => unknown
>g : <T extends unknown = string>(x: { foo: T; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^
>x : { foo: T; }
> : ^^^^^^^ ^^^
>foo : T
> : ^

const h = f(g)
>h : <T extends unknown = string>(x: { foo: T; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^
>f(g) : <T extends unknown = string>(x: { foo: T; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^
>f : <T>(f: (x: T) => unknown) => (x: T) => unknown
> : ^ ^^ ^^ ^^^^^
>g : <T extends unknown = string>(x: { foo: T; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^^^^

type FirstParameter<T> = T extends (x: infer P) => unknown ? P : unknown
>FirstParameter : FirstParameter<T>
> : ^^^^^^^^^^^^^^^^^
>x : P
> : ^

type X = FirstParameter<typeof h>['foo']
>X : unknown
> : ^^^^^^^
>h : <T extends unknown = string>(x: { foo: T; }) => unknown
> : ^ ^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^

29 changes: 29 additions & 0 deletions tests/cases/compiler/genericCallInferenceConditionalType2.ts
Original file line number Diff line number Diff line change
@@ -0,0 1,29 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/86390

type ComponentProps<T> = T extends (props: infer P) => unknown ? P : never;

declare function wrapComponent<P>(
component: (props: P) => unknown,
): (props: P) => unknown;

const WrappedComponent = wrapComponent(
<T extends string = "span">(props: {
as?: T | undefined;
className?: string;
}) => {
return null;
},
);

type RetrievedProps = ComponentProps<typeof WrappedComponent>;

declare const f: <T>(f: (x: T) => unknown) => (x: T) => unknown
declare const g: <T extends unknown = string>(x: { foo: T }) => unknown

const h = f(g)

type FirstParameter<T> = T extends (x: infer P) => unknown ? P : unknown
type X = FirstParameter<typeof h>['foo']

0 comments on commit 1bb1d2a

Please sign in to comment.