mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Fix self tail call return type inference in assigned anonymous functions (#58124)
This commit is contained in:
parent
30095a225c
commit
2b038ff64a
@ -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;
|
||||
|
||||
@ -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();
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
> : ^^^^^^^^^
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
34
tests/baselines/reference/simpleRecursionWithBaseCase3.types
Normal file
34
tests/baselines/reference/simpleRecursionWithBaseCase3.types
Normal file
@ -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
|
||||
> : ^
|
||||
}
|
||||
|
||||
@ -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))
|
||||
|
||||
74
tests/baselines/reference/simpleRecursionWithBaseCase4.types
Normal file
74
tests/baselines/reference/simpleRecursionWithBaseCase4.types
Normal file
@ -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
|
||||
> : ^^^
|
||||
|
||||
11
tests/cases/compiler/simpleRecursionWithBaseCase3.ts
Normal file
11
tests/cases/compiler/simpleRecursionWithBaseCase3.ts
Normal file
@ -0,0 +1,11 @@
|
||||
// @strict: true
|
||||
// @noImplicitAny: true
|
||||
// @lib: esnext
|
||||
// @noEmit: true
|
||||
|
||||
const fn1 = () => {
|
||||
if (Math.random() > 0.5) {
|
||||
return fn1()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
18
tests/cases/compiler/simpleRecursionWithBaseCase4.ts
Normal file
18
tests/cases/compiler/simpleRecursionWithBaseCase4.ts
Normal file
@ -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();
|
||||
Loading…
x
Reference in New Issue
Block a user