diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 189d82eeab97e..0a05ffacbe944 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -38856,17 +38856,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) { + function getNonGenericReturnTypeOfSingleCallSignature(funcType: Type) { const signature = getSingleCallSignature(funcType); - if (signature && !signature.typeParameters) { - return getReturnTypeOfSignature(signature); + if (signature) { + const returnType = getReturnTypeOfSignature(signature); + if (!signature.typeParameters || !couldContainTypeVariables(returnType)) { + return returnType; + } } } function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) { const funcType = checkExpression(expr.expression); const nonOptionalType = getOptionalExpressionType(funcType, expr.expression); - const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType); + const returnType = getNonGenericReturnTypeOfSingleCallSignature(funcType); return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType); } @@ -38915,7 +38918,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // signature where we can just fetch the return type without checking the arguments. if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr)) { return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : - getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); + getNonGenericReturnTypeOfSingleCallSignature(checkNonNullExpression(expr.expression)); } else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { return getTypeFromTypeNode((expr as TypeAssertion).type); diff --git a/tests/baselines/reference/arrayFrom.types b/tests/baselines/reference/arrayFrom.types index dda3f91d2698f..b3189e4ef57a3 100644 --- a/tests/baselines/reference/arrayFrom.types +++ b/tests/baselines/reference/arrayFrom.types @@ -31,7 +31,7 @@ const inputALike: ArrayLike = { length: 0 }; const inputARand = getEither(inputA, inputALike); >inputARand : ArrayLike | Iterable >getEither(inputA, inputALike) : ArrayLike | Iterable ->getEither : (in1: Iterable, in2: ArrayLike) => ArrayLike | Iterable +>getEither : (in1: Iterable, in2: ArrayLike) => Iterable | ArrayLike >inputA : A[] >inputALike : ArrayLike @@ -163,12 +163,12 @@ const result11: B[] = Array.from(inputASet, ({ a }): B => ({ b: a })); // the ?: as always taking the false branch, narrowing to ArrayLike, // even when the type is written as : Iterable|ArrayLike function getEither (in1: Iterable, in2: ArrayLike) { ->getEither : (in1: Iterable, in2: ArrayLike) => ArrayLike | Iterable +>getEither : (in1: Iterable, in2: ArrayLike) => Iterable | ArrayLike >in1 : Iterable >in2 : ArrayLike return Math.random() > 0.5 ? in1 : in2; ->Math.random() > 0.5 ? in1 : in2 : ArrayLike | Iterable +>Math.random() > 0.5 ? in1 : in2 : Iterable | ArrayLike >Math.random() > 0.5 : boolean >Math.random() : number >Math.random : () => number diff --git a/tests/baselines/reference/circularReferenceInReturnType.symbols b/tests/baselines/reference/circularReferenceInReturnType.symbols new file mode 100644 index 0000000000000..7baad0aa81c5e --- /dev/null +++ b/tests/baselines/reference/circularReferenceInReturnType.symbols @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/circularReferenceInReturnType.ts] //// + +=== circularReferenceInReturnType.ts === +declare function fn1(cb: () => T): string; +>fn1 : Symbol(fn1, Decl(circularReferenceInReturnType.ts, 0, 0)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 0, 21)) +>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 0, 24)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 0, 21)) + +const res1 = fn1(() => res1); +>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5)) +>fn1 : Symbol(fn1, Decl(circularReferenceInReturnType.ts, 0, 0)) +>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5)) + +declare function fn2(): (cb: () => any) => (a: T) => void; +>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 1, 29)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 3, 21)) +>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 3, 28)) +>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 3, 47)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 3, 21)) + +const res2 = fn2()(() => res2); +>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 4, 5)) +>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 1, 29)) +>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 4, 5)) + +declare function fn3(): (cb: (arg: T2) => any) => (a: T) => void; +>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 4, 31)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 6, 21)) +>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 6, 28)) +>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 6, 32)) +>arg : Symbol(arg, Decl(circularReferenceInReturnType.ts, 6, 37)) +>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 6, 28)) +>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 6, 58)) +>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 6, 21)) + +const res3 = fn3()(() => res3); +>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 7, 5)) +>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 4, 31)) +>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 7, 5)) + diff --git a/tests/baselines/reference/circularReferenceInReturnType.types b/tests/baselines/reference/circularReferenceInReturnType.types new file mode 100644 index 0000000000000..68fb3d2bd653f --- /dev/null +++ b/tests/baselines/reference/circularReferenceInReturnType.types @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/circularReferenceInReturnType.ts] //// + +=== circularReferenceInReturnType.ts === +declare function fn1(cb: () => T): string; +>fn1 : (cb: () => T) => string +>cb : () => T + +const res1 = fn1(() => res1); +>res1 : string +>fn1(() => res1) : string +>fn1 : (cb: () => T) => string +>() => res1 : () => string +>res1 : string + +declare function fn2(): (cb: () => any) => (a: T) => void; +>fn2 : () => (cb: () => any) => (a: T) => void +>cb : () => any +>a : T + +const res2 = fn2()(() => res2); +>res2 : (a: unknown) => void +>fn2()(() => res2) : (a: unknown) => void +>fn2() : (cb: () => any) => (a: unknown) => void +>fn2 : () => (cb: () => any) => (a: T) => void +>() => res2 : () => (a: unknown) => void +>res2 : (a: unknown) => void + +declare function fn3(): (cb: (arg: T2) => any) => (a: T) => void; +>fn3 : () => (cb: (arg: T2) => any) => (a: T) => void +>cb : (arg: T2) => any +>arg : T2 +>a : T + +const res3 = fn3()(() => res3); +>res3 : (a: unknown) => void +>fn3()(() => res3) : (a: unknown) => void +>fn3() : (cb: (arg: T2) => any) => (a: unknown) => void +>fn3 : () => (cb: (arg: T2) => any) => (a: T) => void +>() => res3 : () => (a: unknown) => void +>res3 : (a: unknown) => void + diff --git a/tests/baselines/reference/circularReferenceInReturnType2.symbols b/tests/baselines/reference/circularReferenceInReturnType2.symbols new file mode 100644 index 0000000000000..119e9245ea0e2 --- /dev/null +++ b/tests/baselines/reference/circularReferenceInReturnType2.symbols @@ -0,0 +1,160 @@ +//// [tests/cases/compiler/circularReferenceInReturnType2.ts] //// + +=== circularReferenceInReturnType2.ts === +type ObjectType = { +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 0, 16)) + + kind: "object"; +>kind : Symbol(kind, Decl(circularReferenceInReturnType2.ts, 0, 27)) + + __source: (source: Source) => void; +>__source : Symbol(__source, Decl(circularReferenceInReturnType2.ts, 1, 17)) +>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 2, 13)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 0, 16)) + +}; + +type Field = { +>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 5, 11)) +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 5, 18)) + + __key: (key: Key) => void; +>__key : Symbol(__key, Decl(circularReferenceInReturnType2.ts, 5, 42)) +>key : Symbol(key, Decl(circularReferenceInReturnType2.ts, 6, 10)) +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 5, 18)) + + __source: (source: Source) => void; +>__source : Symbol(__source, Decl(circularReferenceInReturnType2.ts, 6, 28)) +>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 7, 13)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 5, 11)) + +}; + +declare const object: () => < +>object : Symbol(object, Decl(circularReferenceInReturnType2.ts, 10, 13)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23)) + + Fields extends { +>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37)) + + [Key in keyof Fields]: Field; +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 12, 5)) +>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37)) +>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23)) +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 12, 5)) + } +>(config: { +>config : Symbol(config, Decl(circularReferenceInReturnType2.ts, 14, 2)) + + name: string; +>name : Symbol(name, Decl(circularReferenceInReturnType2.ts, 14, 11)) + + fields: Fields | (() => Fields); +>fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 15, 15)) +>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37)) +>Fields : Symbol(Fields, Decl(circularReferenceInReturnType2.ts, 10, 37)) + +}) => ObjectType; +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 10, 23)) + +type InferValueFromObjectType> = +>InferValueFromObjectType : Symbol(InferValueFromObjectType, Decl(circularReferenceInReturnType2.ts, 17, 25)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 19, 30)) +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) + + Type extends ObjectType ? Source : never; +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 19, 30)) +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 20, 31)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 20, 31)) + +type FieldResolver> = ( +>FieldResolver : Symbol(FieldResolver, Decl(circularReferenceInReturnType2.ts, 20, 57)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 22, 19)) +>TType : Symbol(TType, Decl(circularReferenceInReturnType2.ts, 22, 26)) +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) + + source: Source +>source : Symbol(source, Decl(circularReferenceInReturnType2.ts, 22, 61)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 22, 19)) + +) => InferValueFromObjectType; +>InferValueFromObjectType : Symbol(InferValueFromObjectType, Decl(circularReferenceInReturnType2.ts, 17, 25)) +>TType : Symbol(TType, Decl(circularReferenceInReturnType2.ts, 22, 26)) + +type FieldFuncArgs> = { +>FieldFuncArgs : Symbol(FieldFuncArgs, Decl(circularReferenceInReturnType2.ts, 24, 37)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 26, 19)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26)) +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) + + type: Type; +>type : Symbol(type, Decl(circularReferenceInReturnType2.ts, 26, 60)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26)) + + resolve: FieldResolver; +>resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 27, 13)) +>FieldResolver : Symbol(FieldResolver, Decl(circularReferenceInReturnType2.ts, 20, 57)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 26, 19)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 26, 26)) + +}; + +declare const field: , Key extends string>( +>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 13)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 31, 29)) +>ObjectType : Symbol(ObjectType, Decl(circularReferenceInReturnType2.ts, 0, 0)) +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 31, 59)) + + field: FieldFuncArgs +>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 80)) +>FieldFuncArgs : Symbol(FieldFuncArgs, Decl(circularReferenceInReturnType2.ts, 24, 37)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22)) +>Type : Symbol(Type, Decl(circularReferenceInReturnType2.ts, 31, 29)) + +) => Field; +>Field : Symbol(Field, Decl(circularReferenceInReturnType2.ts, 3, 2)) +>Source : Symbol(Source, Decl(circularReferenceInReturnType2.ts, 31, 22)) +>Key : Symbol(Key, Decl(circularReferenceInReturnType2.ts, 31, 59)) + +type Something = { foo: number }; +>Something : Symbol(Something, Decl(circularReferenceInReturnType2.ts, 33, 24)) +>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 35, 18)) + +const A = object()({ +>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 37, 5)) +>object : Symbol(object, Decl(circularReferenceInReturnType2.ts, 10, 13)) +>Something : Symbol(Something, Decl(circularReferenceInReturnType2.ts, 33, 24)) + + name: "A", +>name : Symbol(name, Decl(circularReferenceInReturnType2.ts, 37, 31)) + + fields: () => ({ +>fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 38, 12)) + + a: field({ +>a : Symbol(a, Decl(circularReferenceInReturnType2.ts, 39, 18)) +>field : Symbol(field, Decl(circularReferenceInReturnType2.ts, 31, 13)) + + type: A, +>type : Symbol(type, Decl(circularReferenceInReturnType2.ts, 40, 14)) +>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 37, 5)) + + resolve() { +>resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 41, 14)) + + return { + foo: 100, +>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 43, 16)) + + }; + }, + }), + }), +}); + diff --git a/tests/baselines/reference/circularReferenceInReturnType2.types b/tests/baselines/reference/circularReferenceInReturnType2.types new file mode 100644 index 0000000000000..49096d1921ff4 --- /dev/null +++ b/tests/baselines/reference/circularReferenceInReturnType2.types @@ -0,0 +1,124 @@ +//// [tests/cases/compiler/circularReferenceInReturnType2.ts] //// + +=== circularReferenceInReturnType2.ts === +type ObjectType = { +>ObjectType : ObjectType + + kind: "object"; +>kind : "object" + + __source: (source: Source) => void; +>__source : (source: Source) => void +>source : Source + +}; + +type Field = { +>Field : Field + + __key: (key: Key) => void; +>__key : (key: Key) => void +>key : Key + + __source: (source: Source) => void; +>__source : (source: Source) => void +>source : Source + +}; + +declare const object: () => < +>object : () => ; }>(config: { name: string; fields: Fields | (() => Fields);}) => ObjectType + + Fields extends { + [Key in keyof Fields]: Field; + } +>(config: { +>config : { name: string; fields: Fields | (() => Fields); } + + name: string; +>name : string + + fields: Fields | (() => Fields); +>fields : Fields | (() => Fields) + +}) => ObjectType; + +type InferValueFromObjectType> = +>InferValueFromObjectType : InferValueFromObjectType + + Type extends ObjectType ? Source : never; + +type FieldResolver> = ( +>FieldResolver : FieldResolver + + source: Source +>source : Source + +) => InferValueFromObjectType; + +type FieldFuncArgs> = { +>FieldFuncArgs : FieldFuncArgs + + type: Type; +>type : Type + + resolve: FieldResolver; +>resolve : FieldResolver + +}; + +declare const field: , Key extends string>( +>field : , Key extends string>(field: FieldFuncArgs) => Field + + field: FieldFuncArgs +>field : FieldFuncArgs + +) => Field; + +type Something = { foo: number }; +>Something : { foo: number; } +>foo : number + +const A = object()({ +>A : ObjectType +>object()({ name: "A", fields: () => ({ a: field({ type: A, resolve() { return { foo: 100, }; }, }), }),}) : ObjectType +>object() : ; }>(config: { name: string; fields: Fields | (() => Fields); }) => ObjectType +>object : () => ; }>(config: { name: string; fields: Fields | (() => Fields); }) => ObjectType +>{ name: "A", fields: () => ({ a: field({ type: A, resolve() { return { foo: 100, }; }, }), }),} : { name: string; fields: () => { a: Field; }; } + + name: "A", +>name : string +>"A" : "A" + + fields: () => ({ +>fields : () => { a: Field; } +>() => ({ a: field({ type: A, resolve() { return { foo: 100, }; }, }), }) : () => { a: Field; } +>({ a: field({ type: A, resolve() { return { foo: 100, }; }, }), }) : { a: Field; } +>{ a: field({ type: A, resolve() { return { foo: 100, }; }, }), } : { a: Field; } + + a: field({ +>a : Field +>field({ type: A, resolve() { return { foo: 100, }; }, }) : Field +>field : , Key extends string>(field: FieldFuncArgs) => Field +>{ type: A, resolve() { return { foo: 100, }; }, } : { type: ObjectType; resolve(): { foo: number; }; } + + type: A, +>type : ObjectType +>A : ObjectType + + resolve() { +>resolve : () => { foo: number; } + + return { +>{ foo: 100, } : { foo: number; } + + foo: 100, +>foo : number +>100 : 100 + + }; + }, + }), + }), +}); + diff --git a/tests/cases/compiler/circularReferenceInReturnType.ts b/tests/cases/compiler/circularReferenceInReturnType.ts new file mode 100644 index 0000000000000..05ed1a56f509c --- /dev/null +++ b/tests/cases/compiler/circularReferenceInReturnType.ts @@ -0,0 +1,11 @@ +// @strict: true +// @noEmit: true + +declare function fn1(cb: () => T): string; +const res1 = fn1(() => res1); + +declare function fn2(): (cb: () => any) => (a: T) => void; +const res2 = fn2()(() => res2); + +declare function fn3(): (cb: (arg: T2) => any) => (a: T) => void; +const res3 = fn3()(() => res3); diff --git a/tests/cases/compiler/circularReferenceInReturnType2.ts b/tests/cases/compiler/circularReferenceInReturnType2.ts new file mode 100644 index 0000000000000..f9fa8fef33c7e --- /dev/null +++ b/tests/cases/compiler/circularReferenceInReturnType2.ts @@ -0,0 +1,53 @@ +// @strict: true +// @noEmit: true + +type ObjectType = { + kind: "object"; + __source: (source: Source) => void; +}; + +type Field = { + __key: (key: Key) => void; + __source: (source: Source) => void; +}; + +declare const object: () => < + Fields extends { + [Key in keyof Fields]: Field; + } +>(config: { + name: string; + fields: Fields | (() => Fields); +}) => ObjectType; + +type InferValueFromObjectType> = + Type extends ObjectType ? Source : never; + +type FieldResolver> = ( + source: Source +) => InferValueFromObjectType; + +type FieldFuncArgs> = { + type: Type; + resolve: FieldResolver; +}; + +declare const field: , Key extends string>( + field: FieldFuncArgs +) => Field; + +type Something = { foo: number }; + +const A = object()({ + name: "A", + fields: () => ({ + a: field({ + type: A, + resolve() { + return { + foo: 100, + }; + }, + }), + }), +});