Repository: microsoft/typescript-go (go)

Issue:
Condition in body removes contextual type of later return statement
```ts
declare function useMemo<T>(func: () => T): T;

function getPredicate(alwaysTrue: boolean) {
    const predicate: ((input: string) => boolean) = useMemo(() => {
        if (alwaysTrue) {
            return () => true;
        }

        return input => input.length > 0;
    });

    return predicate;
}
```

`tsc` issues no error, `tsgo` issues:

```
src/index.ts:8:12 - error TS7006: Parameter 'input' implicitly has an 'any' type.

8     return input => input.length > 0;
             ~~~~~
```

Pull request description:
Make `anyFunctionType` a supertype in strict subtype relation
Fixes #849.

Patch:
diff --git a/internal/checker/relater.go b/internal/checker/relater.go
index 907307ed7..56dfb8cdd 100644
--- a/internal/checker/relater.go
+++ b/internal/checker/relater.go
@@ -4357,7 +4357,7 @@ func (r *Relater) signaturesRelatedTo(source *Type, target *Type, kind Signature
 	if r.relation == r.c.identityRelation {
 		return r.signaturesIdenticalTo(source, target, kind)
 	}
-	if target == r.c.anyFunctionType || source == r.c.anyFunctionType {
+	if target == r.c.anyFunctionType || r.relation != r.c.strictSubtypeRelation && source == r.c.anyFunctionType {
 		return TernaryTrue
 	}
 	sourceSignatures := r.c.getSignaturesOfType(source, kind)


Test patch:
diff --git a/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.symbols b/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.symbols
new file mode 100644
index 000000000..8785b54ad
--- /dev/null
+++ b/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.symbols
@@ -0,0 +1,37 @@
+//// [tests/cases/compiler/subtypeReductionWithAnyFunctionType.ts] ////
+
+=== subtypeReductionWithAnyFunctionType.ts ===
+// https://github.com/microsoft/typescript-go/issues/849
+
+declare function useMemo<T>(func: () => T): T;
+>useMemo : Symbol(useMemo, Decl(subtypeReductionWithAnyFunctionType.ts, 0, 0))
+>T : Symbol(T, Decl(subtypeReductionWithAnyFunctionType.ts, 2, 25))
+>func : Symbol(func, Decl(subtypeReductionWithAnyFunctionType.ts, 2, 28))
+>T : Symbol(T, Decl(subtypeReductionWithAnyFunctionType.ts, 2, 25))
+>T : Symbol(T, Decl(subtypeReductionWithAnyFunctionType.ts, 2, 25))
+
+function getPredicate(alwaysTrue: boolean) {
+>getPredicate : Symbol(getPredicate, Decl(subtypeReductionWithAnyFunctionType.ts, 2, 46))
+>alwaysTrue : Symbol(alwaysTrue, Decl(subtypeReductionWithAnyFunctionType.ts, 4, 22))
+
+    const predicate: (input: string) => boolean = useMemo(() => {
+>predicate : Symbol(predicate, Decl(subtypeReductionWithAnyFunctionType.ts, 5, 9))
+>input : Symbol(input, Decl(subtypeReductionWithAnyFunctionType.ts, 5, 22))
+>useMemo : Symbol(useMemo, Decl(subtypeReductionWithAnyFunctionType.ts, 0, 0))
+
+        if (alwaysTrue) {
+>alwaysTrue : Symbol(alwaysTrue, Decl(subtypeReductionWithAnyFunctionType.ts, 4, 22))
+
+            return () => true;
+        }
+        return x => x.length > 0;
+>x : Symbol(x, Decl(subtypeReductionWithAnyFunctionType.ts, 9, 14))
+>x.length : Symbol(length, Decl(lib.es5.d.ts, --, --))
+>x : Symbol(x, Decl(subtypeReductionWithAnyFunctionType.ts, 9, 14))
+>length : Symbol(length, Decl(lib.es5.d.ts, --, --))
+
+    });
+    return predicate;
+>predicate : Symbol(predicate, Decl(subtypeReductionWithAnyFunctionType.ts, 5, 9))
+}
+
diff --git a/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.types b/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.types
new file mode 100644
index 000000000..d95779c66
--- /dev/null
+++ b/testdata/baselines/reference/compiler/subtypeReductionWithAnyFunctionType.types
@@ -0,0 +1,41 @@
+//// [tests/cases/compiler/subtypeReductionWithAnyFunctionType.ts] ////
+
+=== subtypeReductionWithAnyFunctionType.ts ===
+// https://github.com/microsoft/typescript-go/issues/849
+
+declare function useMemo<T>(func: () => T): T;
+>useMemo : <T>(func: () => T) => T
+>func : () => T
+
+function getPredicate(alwaysTrue: boolean) {
+>getPredicate : (alwaysTrue: boolean) => (input: string) => boolean
+>alwaysTrue : boolean
+
+    const predicate: (input: string) => boolean = useMemo(() => {
+>predicate : (input: string) => boolean
+>input : string
+>useMemo(() => {        if (alwaysTrue) {            return () => true;        }        return x => x.length > 0;    }) : (x: string) => boolean
+>useMemo : <T>(func: () => T) => T
+>() => {        if (alwaysTrue) {            return () => true;        }        return x => x.length > 0;    } : () => (x: string) => boolean
+
+        if (alwaysTrue) {
+>alwaysTrue : boolean
+
+            return () => true;
+>() => true : () => true
+>true : true
+        }
+        return x => x.length > 0;
+>x => x.length > 0 : (x: string) => boolean
+>x : string
+>x.length > 0 : boolean
+>x.length : number
+>x : string
+>length : number
+>0 : 0
+
+    });
+    return predicate;
+>predicate : (input: string) => boolean
+}
+
diff --git a/testdata/tests/cases/compiler/subtypeReductionWithAnyFunctionType.ts b/testdata/tests/cases/compiler/subtypeReductionWithAnyFunctionType.ts
new file mode 100644
index 000000000..8a69da0f2
--- /dev/null
+++ b/testdata/tests/cases/compiler/subtypeReductionWithAnyFunctionType.ts
@@ -0,0 +1,17 @@
+// @strict: true
+// @target: esnext
+// @noEmit: true
+
+// https://github.com/microsoft/typescript-go/issues/849
+
+declare function useMemo<T>(func: () => T): T;
+
+function getPredicate(alwaysTrue: boolean) {
+    const predicate: (input: string) => boolean = useMemo(() => {
+        if (alwaysTrue) {
+            return () => true;
+        }
+        return x => x.length > 0;
+    });
+    return predicate;
+}