diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2d4239f578e..51eeb0fdb48 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21699,15 +21699,19 @@ namespace ts { * to cache the result. */ function getTypeOfExpression(node: Expression, cache?: boolean) { + const expr = skipParentheses(node); // Optimize for the common case of a call to a function with a single non-generic call // signature where we can just fetch the return type without checking the arguments. - if (node.kind === SyntaxKind.CallExpression && (node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) { - const funcType = checkNonNullExpression((node).expression); + if (expr.kind === SyntaxKind.CallExpression && (expr).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { + const funcType = checkNonNullExpression((expr).expression); const signature = getSingleCallSignature(funcType); if (signature && !signature.typeParameters) { return getReturnTypeOfSignature(signature); } } + else if (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) { + return getTypeFromTypeNode((expr).type); + } // Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions // should have a parameter that indicates whether full error checking is required such that // we can perform the optimizations locally. diff --git a/tests/baselines/reference/controlFlowSelfReferentialLoop.errors.txt b/tests/baselines/reference/controlFlowSelfReferentialLoop.errors.txt index 69f670359af..b36d991f114 100644 --- a/tests/baselines/reference/controlFlowSelfReferentialLoop.errors.txt +++ b/tests/baselines/reference/controlFlowSelfReferentialLoop.errors.txt @@ -184,4 +184,24 @@ tests/cases/compiler/controlFlowSelfReferentialLoop.ts(17,29): error TS7006: Par b=II(b,c,d,a,x[k+9], S44,0xEB86D391); } } - export default md5; \ No newline at end of file + export default md5; + + // Repro from #26655 + + interface DataShape { + message: { id: string } + } + + function getObject(id: string | number) { + return {} as any + } + + ;(() => { + let id: string | number = 'a' + while (1) { + const data = getObject(id) as DataShape + const message = data.message + id = message.id + } + })() + \ No newline at end of file diff --git a/tests/baselines/reference/controlFlowSelfReferentialLoop.js b/tests/baselines/reference/controlFlowSelfReferentialLoop.js index 4781f2776fb..a6efecb7e2a 100644 --- a/tests/baselines/reference/controlFlowSelfReferentialLoop.js +++ b/tests/baselines/reference/controlFlowSelfReferentialLoop.js @@ -98,7 +98,27 @@ function md5(string:string): void { b=II(b,c,d,a,x[k+9], S44,0xEB86D391); } } -export default md5; +export default md5; + +// Repro from #26655 + +interface DataShape { + message: { id: string } +} + +function getObject(id: string | number) { + return {} as any +} + +;(() => { + let id: string | number = 'a' + while (1) { + const data = getObject(id) as DataShape + const message = data.message + id = message.id + } +})() + //// [controlFlowSelfReferentialLoop.js] "use strict"; @@ -204,3 +224,15 @@ function md5(string) { } } exports["default"] = md5; +function getObject(id) { + return {}; +} +; +(function () { + var id = 'a'; + while (1) { + var data = getObject(id); + var message = data.message; + id = message.id; + } +})(); diff --git a/tests/baselines/reference/controlFlowSelfReferentialLoop.symbols b/tests/baselines/reference/controlFlowSelfReferentialLoop.symbols index ac857a13f43..6247d792c19 100644 --- a/tests/baselines/reference/controlFlowSelfReferentialLoop.symbols +++ b/tests/baselines/reference/controlFlowSelfReferentialLoop.symbols @@ -831,3 +831,45 @@ function md5(string:string): void { export default md5; >md5 : Symbol(md5, Decl(controlFlowSelfReferentialLoop.ts, 0, 0)) +// Repro from #26655 + +interface DataShape { +>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19)) + + message: { id: string } +>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21)) +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12)) +} + +function getObject(id: string | number) { +>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1)) +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 107, 19)) + + return {} as any +} + +;(() => { + let id: string | number = 'a' +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5)) + + while (1) { + const data = getObject(id) as DataShape +>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9)) +>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1)) +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5)) +>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19)) + + const message = data.message +>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9)) +>data.message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21)) +>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9)) +>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21)) + + id = message.id +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5)) +>message.id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12)) +>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9)) +>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12)) + } +})() + diff --git a/tests/baselines/reference/controlFlowSelfReferentialLoop.types b/tests/baselines/reference/controlFlowSelfReferentialLoop.types index 202286e2eb5..6dba558bd71 100644 --- a/tests/baselines/reference/controlFlowSelfReferentialLoop.types +++ b/tests/baselines/reference/controlFlowSelfReferentialLoop.types @@ -1260,3 +1260,54 @@ function md5(string:string): void { export default md5; >md5 : (string: string) => void +// Repro from #26655 + +interface DataShape { + message: { id: string } +>message : { id: string; } +>id : string +} + +function getObject(id: string | number) { +>getObject : (id: string | number) => any +>id : string | number + + return {} as any +>{} as any : any +>{} : {} +} + +;(() => { +>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }})() : void +>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }}) : () => void +>() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }} : () => void + + let id: string | number = 'a' +>id : string | number +>'a' : "a" + + while (1) { +>1 : 1 + + const data = getObject(id) as DataShape +>data : DataShape +>getObject(id) as DataShape : DataShape +>getObject(id) : any +>getObject : (id: string | number) => any +>id : string + + const message = data.message +>message : { id: string; } +>data.message : { id: string; } +>data : DataShape +>message : { id: string; } + + id = message.id +>id = message.id : string +>id : string | number +>message.id : string +>message : { id: string; } +>id : string + } +})() + diff --git a/tests/cases/compiler/controlFlowSelfReferentialLoop.ts b/tests/cases/compiler/controlFlowSelfReferentialLoop.ts index 361d3a557b4..0be51effc80 100644 --- a/tests/cases/compiler/controlFlowSelfReferentialLoop.ts +++ b/tests/cases/compiler/controlFlowSelfReferentialLoop.ts @@ -99,4 +99,23 @@ function md5(string:string): void { b=II(b,c,d,a,x[k+9], S44,0xEB86D391); } } -export default md5; \ No newline at end of file +export default md5; + +// Repro from #26655 + +interface DataShape { + message: { id: string } +} + +function getObject(id: string | number) { + return {} as any +} + +;(() => { + let id: string | number = 'a' + while (1) { + const data = getObject(id) as DataShape + const message = data.message + id = message.id + } +})()