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,
+ };
+ },
+ }),
+ }),
+});