Skip to content

Commit

Permalink
stop redundant inference from returns of non-context sensitive functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Jan 3, 2025
1 parent 37af847 commit 4aa5ca7
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 6 deletions.
10 changes: 4 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38952,7 +38952,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!signature) {
return;
}
if (isContextSensitive(node)) {
const isNodeContextSensitive = isContextSensitive(node);
if (isNodeContextSensitive) {
if (contextualSignature) {
const inferenceContext = getInferenceContext(node);
let instantiatedContextualSignature: Signature | undefined;
Expand Down Expand Up @@ -38982,7 +38983,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
let contextualReturnType: Type;
let returnType: Type;

if (checkMode & CheckMode.Inferential && couldContainTypeVariables(contextualReturnType = getReturnTypeOfSignature(contextualSignature))) {
if (isNodeContextSensitive && checkMode & CheckMode.Inferential && couldContainTypeVariables(contextualReturnType = getReturnTypeOfSignature(contextualSignature))) {
const inferenceContext = getInferenceContext(node);
const isReturnContextSensitive = !!node.body && (node.body.kind === SyntaxKind.Block ? forEachReturnStatement(node.body as Block, statement => !!statement.expression && isContextSensitive(statement.expression)) : isContextSensitive(node.body));
returnType = getReturnTypeFromBody(node, checkMode | (isReturnContextSensitive ? CheckMode.SkipContextSensitive : 0));
Expand All @@ -38994,10 +38995,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
else {
returnType = getReturnTypeFromBody(node, checkMode);
}

if (!signature.resolvedReturnType) {
signature.resolvedReturnType = returnType;
}
signature.resolvedReturnType ??= returnType;
}
checkSignatureDeclaration(node);
}
Expand Down
111 changes: 111 additions & 0 deletions tests/baselines/reference/genericFunctionInference3.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//// [tests/cases/compiler/genericFunctionInference3.ts] ////

=== genericFunctionInference3.ts ===
const enum SyntaxKind {
>SyntaxKind : Symbol(SyntaxKind, Decl(genericFunctionInference3.ts, 0, 0))

JSDocAllType,
>JSDocAllType : Symbol(SyntaxKind.JSDocAllType, Decl(genericFunctionInference3.ts, 0, 23))

JSDocUnknownType,
>JSDocUnknownType : Symbol(SyntaxKind.JSDocUnknownType, Decl(genericFunctionInference3.ts, 1, 15))
}

interface Node {
>Node : Symbol(Node, Decl(genericFunctionInference3.ts, 3, 1))

readonly kind: SyntaxKind;
>kind : Symbol(Node.kind, Decl(genericFunctionInference3.ts, 5, 16))
>SyntaxKind : Symbol(SyntaxKind, Decl(genericFunctionInference3.ts, 0, 0))
}

interface TypeNode extends Node {
>TypeNode : Symbol(TypeNode, Decl(genericFunctionInference3.ts, 7, 1))
>Node : Symbol(Node, Decl(genericFunctionInference3.ts, 3, 1))

_typeNodeBrand: any;
>_typeNodeBrand : Symbol(TypeNode._typeNodeBrand, Decl(genericFunctionInference3.ts, 9, 33))
}

interface JSDocType extends TypeNode {
>JSDocType : Symbol(JSDocType, Decl(genericFunctionInference3.ts, 11, 1))
>TypeNode : Symbol(TypeNode, Decl(genericFunctionInference3.ts, 7, 1))

_jsDocTypeBrand: any;
>_jsDocTypeBrand : Symbol(JSDocType._jsDocTypeBrand, Decl(genericFunctionInference3.ts, 13, 38))
}

export interface JSDocAllType extends JSDocType {
>JSDocAllType : Symbol(JSDocAllType, Decl(genericFunctionInference3.ts, 15, 1))
>JSDocType : Symbol(JSDocType, Decl(genericFunctionInference3.ts, 11, 1))

readonly kind: SyntaxKind.JSDocAllType;
>kind : Symbol(JSDocAllType.kind, Decl(genericFunctionInference3.ts, 17, 49))
>SyntaxKind : Symbol(SyntaxKind, Decl(genericFunctionInference3.ts, 0, 0))
>JSDocAllType : Symbol(SyntaxKind.JSDocAllType, Decl(genericFunctionInference3.ts, 0, 23))
}

export interface JSDocUnknownType extends JSDocType {
>JSDocUnknownType : Symbol(JSDocUnknownType, Decl(genericFunctionInference3.ts, 19, 1))
>JSDocType : Symbol(JSDocType, Decl(genericFunctionInference3.ts, 11, 1))

readonly kind: SyntaxKind.JSDocUnknownType;
>kind : Symbol(JSDocUnknownType.kind, Decl(genericFunctionInference3.ts, 21, 53))
>SyntaxKind : Symbol(SyntaxKind, Decl(genericFunctionInference3.ts, 0, 0))
>JSDocUnknownType : Symbol(SyntaxKind.JSDocUnknownType, Decl(genericFunctionInference3.ts, 1, 15))
}

type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] };
>Mutable : Symbol(Mutable, Decl(genericFunctionInference3.ts, 23, 1))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 25, 13))
>K : Symbol(K, Decl(genericFunctionInference3.ts, 25, 46))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 25, 13))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 25, 13))
>K : Symbol(K, Decl(genericFunctionInference3.ts, 25, 46))

declare function createJSDocPrimaryTypeWorker<T extends JSDocType>(
>createJSDocPrimaryTypeWorker : Symbol(createJSDocPrimaryTypeWorker, Decl(genericFunctionInference3.ts, 25, 68))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 27, 46))
>JSDocType : Symbol(JSDocType, Decl(genericFunctionInference3.ts, 11, 1))

kind: T["kind"],
>kind : Symbol(kind, Decl(genericFunctionInference3.ts, 27, 67))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 27, 46))

): Mutable<T>;
>Mutable : Symbol(Mutable, Decl(genericFunctionInference3.ts, 23, 1))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 27, 46))

declare function memoizeOne<A extends string | number | boolean | undefined, T>(
>memoizeOne : Symbol(memoizeOne, Decl(genericFunctionInference3.ts, 29, 14))
>A : Symbol(A, Decl(genericFunctionInference3.ts, 31, 28))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 31, 76))

callback: (arg: A) => T,
>callback : Symbol(callback, Decl(genericFunctionInference3.ts, 31, 80))
>arg : Symbol(arg, Decl(genericFunctionInference3.ts, 32, 13))
>A : Symbol(A, Decl(genericFunctionInference3.ts, 31, 28))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 31, 76))

): (arg: A) => T;
>arg : Symbol(arg, Decl(genericFunctionInference3.ts, 33, 4))
>A : Symbol(A, Decl(genericFunctionInference3.ts, 31, 28))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 31, 76))

export const getJSDocPrimaryTypeCreateFunction = memoizeOne(
>getJSDocPrimaryTypeCreateFunction : Symbol(getJSDocPrimaryTypeCreateFunction, Decl(genericFunctionInference3.ts, 35, 12))
>memoizeOne : Symbol(memoizeOne, Decl(genericFunctionInference3.ts, 29, 14))

<T extends JSDocType>(kind: T["kind"]) =>
>T : Symbol(T, Decl(genericFunctionInference3.ts, 36, 3))
>JSDocType : Symbol(JSDocType, Decl(genericFunctionInference3.ts, 11, 1))
>kind : Symbol(kind, Decl(genericFunctionInference3.ts, 36, 24))
>T : Symbol(T, Decl(genericFunctionInference3.ts, 36, 3))

() =>
createJSDocPrimaryTypeWorker(kind),
>createJSDocPrimaryTypeWorker : Symbol(createJSDocPrimaryTypeWorker, Decl(genericFunctionInference3.ts, 25, 68))
>kind : Symbol(kind, Decl(genericFunctionInference3.ts, 36, 24))

);

104 changes: 104 additions & 0 deletions tests/baselines/reference/genericFunctionInference3.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//// [tests/cases/compiler/genericFunctionInference3.ts] ////

=== genericFunctionInference3.ts ===
const enum SyntaxKind {
>SyntaxKind : SyntaxKind
> : ^^^^^^^^^^

JSDocAllType,
>JSDocAllType : SyntaxKind.JSDocAllType
> : ^^^^^^^^^^^^^^^^^^^^^^^

JSDocUnknownType,
>JSDocUnknownType : SyntaxKind.JSDocUnknownType
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

interface Node {
readonly kind: SyntaxKind;
>kind : SyntaxKind
> : ^^^^^^^^^^
}

interface TypeNode extends Node {
_typeNodeBrand: any;
>_typeNodeBrand : any
}

interface JSDocType extends TypeNode {
_jsDocTypeBrand: any;
>_jsDocTypeBrand : any
}

export interface JSDocAllType extends JSDocType {
readonly kind: SyntaxKind.JSDocAllType;
>kind : SyntaxKind.JSDocAllType
> : ^^^^^^^^^^^^^^^^^^^^^^^
>SyntaxKind : any
> : ^^^
}

export interface JSDocUnknownType extends JSDocType {
readonly kind: SyntaxKind.JSDocUnknownType;
>kind : SyntaxKind.JSDocUnknownType
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^
>SyntaxKind : any
> : ^^^
}

type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] };
>Mutable : Mutable<T>
> : ^^^^^^^^^^

declare function createJSDocPrimaryTypeWorker<T extends JSDocType>(
>createJSDocPrimaryTypeWorker : <T extends JSDocType>(kind: T["kind"]) => Mutable<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^

kind: T["kind"],
>kind : T["kind"]
> : ^^^^^^^^^

): Mutable<T>;

declare function memoizeOne<A extends string | number | boolean | undefined, T>(
>memoizeOne : <A extends string | number | boolean | undefined, T>(callback: (arg: A) => T) => (arg: A) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^

callback: (arg: A) => T,
>callback : (arg: A) => T
> : ^ ^^ ^^^^^
>arg : A
> : ^

): (arg: A) => T;
>arg : A
> : ^

export const getJSDocPrimaryTypeCreateFunction = memoizeOne(
>getJSDocPrimaryTypeCreateFunction : <T extends JSDocType>(arg: T["kind"]) => () => Mutable<T>
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>memoizeOne( <T extends JSDocType>(kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind),) : <T extends JSDocType>(arg: T["kind"]) => () => Mutable<T>
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>memoizeOne : <A extends string | number | boolean | undefined, T>(callback: (arg: A) => T) => (arg: A) => T
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^

<T extends JSDocType>(kind: T["kind"]) =>
><T extends JSDocType>(kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind) : <T extends JSDocType>(kind: T["kind"]) => () => Mutable<T>
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^
>kind : T["kind"]
> : ^^^^^^^^^

() =>
>() => createJSDocPrimaryTypeWorker(kind) : () => Mutable<T>
> : ^^^^^^^^^^^^^^^^

createJSDocPrimaryTypeWorker(kind),
>createJSDocPrimaryTypeWorker(kind) : Mutable<T>
> : ^^^^^^^^^^
>createJSDocPrimaryTypeWorker : <T_1 extends JSDocType>(kind: T_1["kind"]) => Mutable<T_1>
> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^
>kind : T["kind"]
> : ^^^^^^^^^

);

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

const enum SyntaxKind {
JSDocAllType,
JSDocUnknownType,
}

interface Node {
readonly kind: SyntaxKind;
}

interface TypeNode extends Node {
_typeNodeBrand: any;
}

interface JSDocType extends TypeNode {
_jsDocTypeBrand: any;
}

export interface JSDocAllType extends JSDocType {
readonly kind: SyntaxKind.JSDocAllType;
}

export interface JSDocUnknownType extends JSDocType {
readonly kind: SyntaxKind.JSDocUnknownType;
}

type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] };

declare function createJSDocPrimaryTypeWorker<T extends JSDocType>(
kind: T["kind"],
): Mutable<T>;

declare function memoizeOne<A extends string | number | boolean | undefined, T>(
callback: (arg: A) => T,
): (arg: A) => T;

export const getJSDocPrimaryTypeCreateFunction = memoizeOne(
<T extends JSDocType>(kind: T["kind"]) =>
() =>
createJSDocPrimaryTypeWorker(kind),
);

0 comments on commit 4aa5ca7

Please sign in to comment.