Skip to content

Commit

Permalink
Defer processing of nested generic calls that return constructor types (
Browse files Browse the repository at this point in the history
microsoft#54813)

Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
  • Loading branch information
Andarist and sandersn committed Nov 30, 2023
1 parent eb2046d commit 8d1fa44
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 3 deletions.
10 changes: 7 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -34776,7 +34776,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// use the resolvingSignature singleton to indicate that we deferred processing. This result will be
// propagated out and eventually turned into silentNeverType (a type that is assignable to anything and
// from which we never make inferences).
if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) {
if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunctionOrConstructor)) {
skippedGenericFunction(node, checkMode);
return resolvingSignature;
}
Expand All @@ -34789,8 +34789,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags);
}

function isGenericFunctionReturningFunction(signature: Signature) {
return !!(signature.typeParameters && isFunctionType(getReturnTypeOfSignature(signature)));
function isGenericFunctionReturningFunctionOrConstructor(signature: Signature) {
if (!signature.typeParameters) {
return false;
}
const returnType = getReturnTypeOfSignature(signature);
return isFunctionType(returnType) || isConstructorType(returnType);
}

/**
Expand Down
@@ -0,0 +1,72 @@
//// [tests/cases/compiler/inferenceGenericNestedCallReturningConstructor.ts] ////

=== inferenceGenericNestedCallReturningConstructor.ts ===
interface Action<TContext> {
>Action : Symbol(Action, Decl(inferenceGenericNestedCallReturningConstructor.ts, 0, 0))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 0, 17))

new (ctx: TContext): void;
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 1, 7))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 0, 17))
}

declare class AssignAction<TContext> {
>AssignAction : Symbol(AssignAction, Decl(inferenceGenericNestedCallReturningConstructor.ts, 2, 1))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 4, 27))

constructor(ctx: TContext);
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 5, 14))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 4, 27))
}

declare function assign<TContext>(
>assign : Symbol(assign, Decl(inferenceGenericNestedCallReturningConstructor.ts, 6, 1))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 8, 24))

assigner: (ctx: TContext) => void
>assigner : Symbol(assigner, Decl(inferenceGenericNestedCallReturningConstructor.ts, 8, 34))
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 9, 13))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 8, 24))

): {
new (ctx: TContext): AssignAction<TContext>;
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 11, 7))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 8, 24))
>AssignAction : Symbol(AssignAction, Decl(inferenceGenericNestedCallReturningConstructor.ts, 2, 1))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 8, 24))
}

declare function createMachine<TContext>(config: {
>createMachine : Symbol(createMachine, Decl(inferenceGenericNestedCallReturningConstructor.ts, 12, 1))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 14, 31))
>config : Symbol(config, Decl(inferenceGenericNestedCallReturningConstructor.ts, 14, 41))

context: TContext;
>context : Symbol(context, Decl(inferenceGenericNestedCallReturningConstructor.ts, 14, 50))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 14, 31))

entry: Action<TContext>;
>entry : Symbol(entry, Decl(inferenceGenericNestedCallReturningConstructor.ts, 15, 20))
>Action : Symbol(Action, Decl(inferenceGenericNestedCallReturningConstructor.ts, 0, 0))
>TContext : Symbol(TContext, Decl(inferenceGenericNestedCallReturningConstructor.ts, 14, 31))

}): void;

createMachine({
>createMachine : Symbol(createMachine, Decl(inferenceGenericNestedCallReturningConstructor.ts, 12, 1))

context: { count: 0 },
>context : Symbol(context, Decl(inferenceGenericNestedCallReturningConstructor.ts, 19, 15))
>count : Symbol(count, Decl(inferenceGenericNestedCallReturningConstructor.ts, 20, 12))

entry: assign((ctx) => {
>entry : Symbol(entry, Decl(inferenceGenericNestedCallReturningConstructor.ts, 20, 24))
>assign : Symbol(assign, Decl(inferenceGenericNestedCallReturningConstructor.ts, 6, 1))
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 21, 17))

ctx // { count: number }
>ctx : Symbol(ctx, Decl(inferenceGenericNestedCallReturningConstructor.ts, 21, 17))

}),
});

@@ -0,0 +1,63 @@
//// [tests/cases/compiler/inferenceGenericNestedCallReturningConstructor.ts] ////

=== inferenceGenericNestedCallReturningConstructor.ts ===
interface Action<TContext> {
new (ctx: TContext): void;
>ctx : TContext
}

declare class AssignAction<TContext> {
>AssignAction : AssignAction<TContext>

constructor(ctx: TContext);
>ctx : TContext
}

declare function assign<TContext>(
>assign : <TContext>(assigner: (ctx: TContext) => void) => new (ctx: TContext) => AssignAction<TContext>

assigner: (ctx: TContext) => void
>assigner : (ctx: TContext) => void
>ctx : TContext

): {
new (ctx: TContext): AssignAction<TContext>;
>ctx : TContext
}

declare function createMachine<TContext>(config: {
>createMachine : <TContext>(config: { context: TContext; entry: Action<TContext>;}) => void
>config : { context: TContext; entry: Action<TContext>; }

context: TContext;
>context : TContext

entry: Action<TContext>;
>entry : Action<TContext>

}): void;

createMachine({
>createMachine({ context: { count: 0 }, entry: assign((ctx) => { ctx // { count: number } }),}) : void
>createMachine : <TContext>(config: { context: TContext; entry: Action<TContext>; }) => void
>{ context: { count: 0 }, entry: assign((ctx) => { ctx // { count: number } }),} : { context: { count: number; }; entry: new (ctx: { count: number; }) => AssignAction<{ count: number; }>; }

context: { count: 0 },
>context : { count: number; }
>{ count: 0 } : { count: number; }
>count : number
>0 : 0

entry: assign((ctx) => {
>entry : new (ctx: { count: number; }) => AssignAction<{ count: number; }>
>assign((ctx) => { ctx // { count: number } }) : new (ctx: { count: number; }) => AssignAction<{ count: number; }>
>assign : <TContext>(assigner: (ctx: TContext) => void) => new (ctx: TContext) => AssignAction<TContext>
>(ctx) => { ctx // { count: number } } : (ctx: { count: number; }) => void
>ctx : { count: number; }

ctx // { count: number }
>ctx : { count: number; }

}),
});

@@ -0,0 +1,28 @@
// @strict: true
// @noEmit: true

interface Action<TContext> {
new (ctx: TContext): void;
}

declare class AssignAction<TContext> {
constructor(ctx: TContext);
}

declare function assign<TContext>(
assigner: (ctx: TContext) => void
): {
new (ctx: TContext): AssignAction<TContext>;
}

declare function createMachine<TContext>(config: {
context: TContext;
entry: Action<TContext>;
}): void;

createMachine({
context: { count: 0 },
entry: assign((ctx) => {
ctx // { count: number }
}),
});

0 comments on commit 8d1fa44

Please sign in to comment.