diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 54d21cf16f2cb..3b3d4256fecfc 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -39347,20 +39347,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
- function getNonGenericReturnTypeOfSingleCallSignature(funcType: Type) {
+ function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
const signature = getSingleCallSignature(funcType);
- if (signature) {
- const returnType = getReturnTypeOfSignature(signature);
- if (!signature.typeParameters || !couldContainTypeVariables(returnType)) {
- return returnType;
- }
+ if (signature && !signature.typeParameters) {
+ return getReturnTypeOfSignature(signature);
}
}
function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
const funcType = checkExpression(expr.expression);
const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
- const returnType = getNonGenericReturnTypeOfSingleCallSignature(funcType);
+ const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
}
@@ -39409,7 +39406,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) :
- getNonGenericReturnTypeOfSingleCallSignature(checkNonNullExpression(expr.expression));
+ getReturnTypeOfSingleNonGenericCallSignature(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 b3189e4ef57a3..dda3f91d2698f 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) => Iterable | ArrayLike
+>getEither : (in1: Iterable, in2: ArrayLike) => ArrayLike | Iterable
>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) => Iterable | ArrayLike
+>getEither : (in1: Iterable, in2: ArrayLike) => ArrayLike | Iterable
>in1 : Iterable
>in2 : ArrayLike
return Math.random() > 0.5 ? in1 : in2;
->Math.random() > 0.5 ? in1 : in2 : Iterable | ArrayLike
+>Math.random() > 0.5 ? in1 : in2 : ArrayLike | Iterable
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
diff --git a/tests/baselines/reference/circularReferenceInReturnType.errors.txt b/tests/baselines/reference/circularReferenceInReturnType.errors.txt
new file mode 100644
index 0000000000000..d90cf8523f5a4
--- /dev/null
+++ b/tests/baselines/reference/circularReferenceInReturnType.errors.txt
@@ -0,0 +1,19 @@
+circularReferenceInReturnType.ts(3,7): error TS7022: 'res1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+circularReferenceInReturnType.ts(9,7): error TS7022: 'res3' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+
+
+==== circularReferenceInReturnType.ts (2 errors) ====
+ // inference fails for res1 and res2, but ideally should not
+ declare function fn1(cb: () => T): string;
+ const res1 = fn1(() => res1);
+ ~~~~
+!!! error TS7022: 'res1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+
+ 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);
+ ~~~~
+!!! error TS7022: 'res3' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+
\ No newline at end of file
diff --git a/tests/baselines/reference/circularReferenceInReturnType.symbols b/tests/baselines/reference/circularReferenceInReturnType.symbols
index 7baad0aa81c5e..d126adc332884 100644
--- a/tests/baselines/reference/circularReferenceInReturnType.symbols
+++ b/tests/baselines/reference/circularReferenceInReturnType.symbols
@@ -1,41 +1,42 @@
//// [tests/cases/compiler/circularReferenceInReturnType.ts] ////
=== circularReferenceInReturnType.ts ===
+// inference fails for res1 and res2, but ideally should not
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))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 1, 21))
+>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 1, 24))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 1, 21))
const res1 = fn1(() => res1);
->res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5))
+>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 2, 5))
>fn1 : Symbol(fn1, Decl(circularReferenceInReturnType.ts, 0, 0))
->res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 1, 5))
+>res1 : Symbol(res1, Decl(circularReferenceInReturnType.ts, 2, 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))
+>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 2, 29))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 4, 21))
+>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 4, 28))
+>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 4, 47))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 4, 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))
+>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 5, 5))
+>fn2 : Symbol(fn2, Decl(circularReferenceInReturnType.ts, 2, 29))
+>res2 : Symbol(res2, Decl(circularReferenceInReturnType.ts, 5, 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))
+>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 5, 31))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 7, 21))
+>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 7, 28))
+>cb : Symbol(cb, Decl(circularReferenceInReturnType.ts, 7, 32))
+>arg : Symbol(arg, Decl(circularReferenceInReturnType.ts, 7, 37))
+>T2 : Symbol(T2, Decl(circularReferenceInReturnType.ts, 7, 28))
+>a : Symbol(a, Decl(circularReferenceInReturnType.ts, 7, 58))
+>T : Symbol(T, Decl(circularReferenceInReturnType.ts, 7, 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))
+>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 8, 5))
+>fn3 : Symbol(fn3, Decl(circularReferenceInReturnType.ts, 5, 31))
+>res3 : Symbol(res3, Decl(circularReferenceInReturnType.ts, 8, 5))
diff --git a/tests/baselines/reference/circularReferenceInReturnType.types b/tests/baselines/reference/circularReferenceInReturnType.types
index 68fb3d2bd653f..a1c4fd9e0a1ab 100644
--- a/tests/baselines/reference/circularReferenceInReturnType.types
+++ b/tests/baselines/reference/circularReferenceInReturnType.types
@@ -1,16 +1,17 @@
//// [tests/cases/compiler/circularReferenceInReturnType.ts] ////
=== circularReferenceInReturnType.ts ===
+// inference fails for res1 and res2, but ideally should not
declare function fn1(cb: () => T): string;
>fn1 : (cb: () => T) => string
>cb : () => T
const res1 = fn1(() => res1);
->res1 : string
+>res1 : any
>fn1(() => res1) : string
>fn1 : (cb: () => T) => string
->() => res1 : () => string
->res1 : string
+>() => res1 : () => any
+>res1 : any
declare function fn2(): (cb: () => any) => (a: T) => void;
>fn2 : () => (cb: () => any) => (a: T) => void
@@ -32,10 +33,10 @@ declare function fn3(): (cb: (arg: T2) => any) => (a: T) => void;
>a : T
const res3 = fn3()(() => res3);
->res3 : (a: unknown) => void
+>res3 : any
>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
+>() => res3 : () => any
+>res3 : any
diff --git a/tests/baselines/reference/circularReferenceInReturnType2.errors.txt b/tests/baselines/reference/circularReferenceInReturnType2.errors.txt
new file mode 100644
index 0000000000000..4f075e69a6814
--- /dev/null
+++ b/tests/baselines/reference/circularReferenceInReturnType2.errors.txt
@@ -0,0 +1,58 @@
+circularReferenceInReturnType2.ts(39,7): error TS7022: 'A' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+
+
+==== circularReferenceInReturnType2.ts (1 errors) ====
+ 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 };
+
+ // inference fails here, but ideally should not
+ const A = object()({
+ ~
+!!! error TS7022: 'A' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
+ name: "A",
+ fields: () => ({
+ a: field({
+ type: A,
+ resolve() {
+ return {
+ foo: 100,
+ };
+ },
+ }),
+ }),
+ });
+
\ No newline at end of file
diff --git a/tests/baselines/reference/circularReferenceInReturnType2.symbols b/tests/baselines/reference/circularReferenceInReturnType2.symbols
index 119e9245ea0e2..beb82053ac663 100644
--- a/tests/baselines/reference/circularReferenceInReturnType2.symbols
+++ b/tests/baselines/reference/circularReferenceInReturnType2.symbols
@@ -126,31 +126,32 @@ type Something = { foo: number };
>Something : Symbol(Something, Decl(circularReferenceInReturnType2.ts, 33, 24))
>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 35, 18))
+// inference fails here, but ideally should not
const A = object()({
->A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 37, 5))
+>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 38, 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))
+>name : Symbol(name, Decl(circularReferenceInReturnType2.ts, 38, 31))
fields: () => ({
->fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 38, 12))
+>fields : Symbol(fields, Decl(circularReferenceInReturnType2.ts, 39, 12))
a: field({
->a : Symbol(a, Decl(circularReferenceInReturnType2.ts, 39, 18))
+>a : Symbol(a, Decl(circularReferenceInReturnType2.ts, 40, 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))
+>type : Symbol(type, Decl(circularReferenceInReturnType2.ts, 41, 14))
+>A : Symbol(A, Decl(circularReferenceInReturnType2.ts, 38, 5))
resolve() {
->resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 41, 14))
+>resolve : Symbol(resolve, Decl(circularReferenceInReturnType2.ts, 42, 14))
return {
foo: 100,
->foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 43, 16))
+>foo : Symbol(foo, Decl(circularReferenceInReturnType2.ts, 44, 16))
};
},
diff --git a/tests/baselines/reference/circularReferenceInReturnType2.types b/tests/baselines/reference/circularReferenceInReturnType2.types
index 49096d1921ff4..de202f7c8cad9 100644
--- a/tests/baselines/reference/circularReferenceInReturnType2.types
+++ b/tests/baselines/reference/circularReferenceInReturnType2.types
@@ -79,8 +79,9 @@ type Something = { foo: number };
>Something : { foo: number; }
>foo : number
+// inference fails here, but ideally should not
const A = object()({
->A : ObjectType
+>A : any
>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
@@ -100,11 +101,11 @@ const A = object()({
>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, resolve() { return { foo: 100, }; }, } : { type: any; resolve(): { foo: number; }; }
type: A,
->type : ObjectType
->A : ObjectType
+>type : any
+>A : any
resolve() {
>resolve : () => { foo: number; }
diff --git a/tests/cases/compiler/circularReferenceInReturnType.ts b/tests/cases/compiler/circularReferenceInReturnType.ts
index 05ed1a56f509c..50f82f9e37156 100644
--- a/tests/cases/compiler/circularReferenceInReturnType.ts
+++ b/tests/cases/compiler/circularReferenceInReturnType.ts
@@ -1,6 +1,7 @@
// @strict: true
// @noEmit: true
+// inference fails for res1 and res2, but ideally should not
declare function fn1(cb: () => T): string;
const res1 = fn1(() => res1);
diff --git a/tests/cases/compiler/circularReferenceInReturnType2.ts b/tests/cases/compiler/circularReferenceInReturnType2.ts
index f9fa8fef33c7e..3fb431ffc44a4 100644
--- a/tests/cases/compiler/circularReferenceInReturnType2.ts
+++ b/tests/cases/compiler/circularReferenceInReturnType2.ts
@@ -38,6 +38,7 @@ declare const field: , Key extends string>(
type Something = { foo: number };
+// inference fails here, but ideally should not
const A = object()({
name: "A",
fields: () => ({