diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3774bccd78e..1360a884bc9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28086,7 +28086,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return isConstantVariable(symbol) || isParameterOrMutableLocalVariable(symbol) && !isSymbolAssigned(symbol); + return isConstantVariable(symbol) + || isParameterOrMutableLocalVariable(symbol) && !isSymbolAssigned(symbol) + || !!symbol.valueDeclaration && isFunctionExpression(symbol.valueDeclaration); } break; case SyntaxKind.PropertyAccessExpression: @@ -37796,7 +37798,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ( expr.kind === SyntaxKind.CallExpression && (expr as CallExpression).expression.kind === SyntaxKind.Identifier && - checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol + checkExpressionCached((expr as CallExpression).expression).symbol === getMergedSymbol(func.symbol) && + (!isFunctionExpressionOrArrowFunction(func.symbol.valueDeclaration!) || isConstantReference((expr as CallExpression).expression)) ) { hasReturnOfTypeNever = true; return; diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt index dd2f4cc3af5..29986db55f3 100644 --- a/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt +++ b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt @@ -2,13 +2,14 @@ implicitAnyFromCircularInference.ts(2,5): error TS2502: 'a' is referenced direct implicitAnyFromCircularInference.ts(5,5): error TS2502: 'b' is referenced directly or indirectly in its own type annotation. implicitAnyFromCircularInference.ts(6,5): error TS2502: 'c' is referenced directly or indirectly in its own type annotation. implicitAnyFromCircularInference.ts(9,5): error TS2502: 'd' is referenced directly or indirectly in its own type annotation. +implicitAnyFromCircularInference.ts(17,5): error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. implicitAnyFromCircularInference.ts(22,5): error TS7023: 'f2' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. implicitAnyFromCircularInference.ts(25,10): error TS7023: 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. implicitAnyFromCircularInference.ts(27,14): error TS7023: 'foo' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. implicitAnyFromCircularInference.ts(44,9): error TS7023: 'x' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. -==== implicitAnyFromCircularInference.ts (8 errors) ==== +==== implicitAnyFromCircularInference.ts (9 errors) ==== // Error expected var a: typeof a; ~ @@ -34,6 +35,8 @@ implicitAnyFromCircularInference.ts(44,9): error TS7023: 'x' implicitly has retu // Error expected var f1 = function () { + ~~ +!!! error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. return f1(); }; diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.types b/tests/baselines/reference/implicitAnyFromCircularInference.types index 1309591c1d8..a065bc09763 100644 --- a/tests/baselines/reference/implicitAnyFromCircularInference.types +++ b/tests/baselines/reference/implicitAnyFromCircularInference.types @@ -45,16 +45,16 @@ function g() { return g(); } // Error expected var f1 = function () { ->f1 : () => never -> : ^^^^^^^^^^^ ->function () { return f1();} : () => never -> : +>f1 : () => any +> : ^^^^^^^^^ +>function () { return f1();} : () => any +> : return f1(); ->f1() : never -> : ^^^^^ ->f1 : () => never -> : ^^^^^^^^^^^ +>f1() : any +> : ^^^ +>f1 : () => any +> : ^^^^^^^^^ }; diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase3.symbols b/tests/baselines/reference/simpleRecursionWithBaseCase3.symbols new file mode 100644 index 00000000000..625eed9966b --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase3.symbols @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/simpleRecursionWithBaseCase3.ts] //// + +=== simpleRecursionWithBaseCase3.ts === +const fn1 = () => { +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase3.ts, 0, 5)) + + if (Math.random() > 0.5) { +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) + + return fn1() +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase3.ts, 0, 5)) + } + return 0 +} + diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase3.types b/tests/baselines/reference/simpleRecursionWithBaseCase3.types new file mode 100644 index 00000000000..56525aab76c --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase3.types @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/simpleRecursionWithBaseCase3.ts] //// + +=== simpleRecursionWithBaseCase3.ts === +const fn1 = () => { +>fn1 : () => number +> : ^^^^^^^^^^^^ +>() => { if (Math.random() > 0.5) { return fn1() } return 0} : () => number +> : + + if (Math.random() > 0.5) { +>Math.random() > 0.5 : boolean +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^^^^^^^ +>0.5 : 0.5 +> : ^^^ + + return fn1() +>fn1() : number +> : ^^^^^^ +>fn1 : () => number +> : ^^^^^^^^^^^^ + } + return 0 +>0 : 0 +> : ^ +} + diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase4.symbols b/tests/baselines/reference/simpleRecursionWithBaseCase4.symbols new file mode 100644 index 00000000000..290c57575b7 --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase4.symbols @@ -0,0 +1,43 @@ +//// [tests/cases/compiler/simpleRecursionWithBaseCase4.ts] //// + +=== simpleRecursionWithBaseCase4.ts === +var fn2 = function(name) { +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase4.ts, 0, 3)) +>name : Symbol(name, Decl(simpleRecursionWithBaseCase4.ts, 0, 19)) + + fn2 = compose(this, 0, 1) +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase4.ts, 0, 3)) +>compose : Symbol(compose, Decl(simpleRecursionWithBaseCase4.ts, 2, 18)) + + return fn2(name) +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase4.ts, 0, 3)) +>name : Symbol(name, Decl(simpleRecursionWithBaseCase4.ts, 0, 19)) + + function compose(child, level, find) { +>compose : Symbol(compose, Decl(simpleRecursionWithBaseCase4.ts, 2, 18)) +>child : Symbol(child, Decl(simpleRecursionWithBaseCase4.ts, 4, 19)) +>level : Symbol(level, Decl(simpleRecursionWithBaseCase4.ts, 4, 25)) +>find : Symbol(find, Decl(simpleRecursionWithBaseCase4.ts, 4, 32)) + + if (child === find) { +>child : Symbol(child, Decl(simpleRecursionWithBaseCase4.ts, 4, 19)) +>find : Symbol(find, Decl(simpleRecursionWithBaseCase4.ts, 4, 32)) + + return level +>level : Symbol(level, Decl(simpleRecursionWithBaseCase4.ts, 4, 25)) + } + return compose(child, level + 1, find) +>compose : Symbol(compose, Decl(simpleRecursionWithBaseCase4.ts, 2, 18)) +>child : Symbol(child, Decl(simpleRecursionWithBaseCase4.ts, 4, 19)) +>level : Symbol(level, Decl(simpleRecursionWithBaseCase4.ts, 4, 25)) +>find : Symbol(find, Decl(simpleRecursionWithBaseCase4.ts, 4, 32)) + } +} + +var d = fn2(1); // d: any +>d : Symbol(d, Decl(simpleRecursionWithBaseCase4.ts, 12, 3)) +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase4.ts, 0, 3)) + +d.redefined(); +>d : Symbol(d, Decl(simpleRecursionWithBaseCase4.ts, 12, 3)) + diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase4.types b/tests/baselines/reference/simpleRecursionWithBaseCase4.types new file mode 100644 index 00000000000..637ae735011 --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase4.types @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/simpleRecursionWithBaseCase4.ts] //// + +=== simpleRecursionWithBaseCase4.ts === +var fn2 = function(name) { +>fn2 : (name: any) => any +> : ^ ^^^^^^^^^^^^^ +>function(name) { fn2 = compose(this, 0, 1) return fn2(name) function compose(child, level, find) { if (child === find) { return level } return compose(child, level + 1, find) }} : (name: any) => any +> : +>name : any + + fn2 = compose(this, 0, 1) +>fn2 = compose(this, 0, 1) : any +>fn2 : (name: any) => any +> : ^ ^^^^^^^^^^^^^ +>compose(this, 0, 1) : any +>compose : (child: any, level: any, find: any) => any +> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^ +>this : any +>0 : 0 +> : ^ +>1 : 1 +> : ^ + + return fn2(name) +>fn2(name) : any +>fn2 : (name: any) => any +> : ^ ^^^^^^^^^^^^^ +>name : any + + function compose(child, level, find) { +>compose : (child: any, level: any, find: any) => any +> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^ +>child : any +>level : any +>find : any + + if (child === find) { +>child === find : boolean +> : ^^^^^^^ +>child : any +>find : any + + return level +>level : any + } + return compose(child, level + 1, find) +>compose(child, level + 1, find) : any +>compose : (child: any, level: any, find: any) => any +> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^ +>child : any +>level + 1 : any +>level : any +>1 : 1 +> : ^ +>find : any + } +} + +var d = fn2(1); // d: any +>d : any +>fn2(1) : any +>fn2 : (name: any) => any +> : ^ ^^^^^^^^^^^^^ +>1 : 1 +> : ^ + +d.redefined(); +>d.redefined() : any +>d.redefined : any +>d : any +> : ^^^ +>redefined : any +> : ^^^ + diff --git a/tests/cases/compiler/simpleRecursionWithBaseCase3.ts b/tests/cases/compiler/simpleRecursionWithBaseCase3.ts new file mode 100644 index 00000000000..a7abf187517 --- /dev/null +++ b/tests/cases/compiler/simpleRecursionWithBaseCase3.ts @@ -0,0 +1,11 @@ +// @strict: true +// @noImplicitAny: true +// @lib: esnext +// @noEmit: true + +const fn1 = () => { + if (Math.random() > 0.5) { + return fn1() + } + return 0 +} diff --git a/tests/cases/compiler/simpleRecursionWithBaseCase4.ts b/tests/cases/compiler/simpleRecursionWithBaseCase4.ts new file mode 100644 index 00000000000..96aeea4e2e5 --- /dev/null +++ b/tests/cases/compiler/simpleRecursionWithBaseCase4.ts @@ -0,0 +1,18 @@ +// @checkJs: true +// @noEmit: true +// @strict: false + +var fn2 = function(name) { + fn2 = compose(this, 0, 1) + return fn2(name) + + function compose(child, level, find) { + if (child === find) { + return level + } + return compose(child, level + 1, find) + } +} + +var d = fn2(1); // d: any +d.redefined();