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