Merge pull request #26679 from Microsoft/improveGetTypeOfExpression

Improve control flow analysis of type assertions
This commit is contained in:
Anders Hejlsberg
2018-08-27 18:30:16 -07:00
committed by GitHub
6 changed files with 173 additions and 5 deletions

View File

@@ -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 && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) {
const funcType = checkNonNullExpression((<CallExpression>node).expression);
if (expr.kind === SyntaxKind.CallExpression && (<CallExpression>expr).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
const funcType = checkNonNullExpression((<CallExpression>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((<TypeAssertion>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.

View File

@@ -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;
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
}
})()

View File

@@ -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;
}
})();

View File

@@ -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))
}
})()

View File

@@ -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
}
})()

View File

@@ -99,4 +99,23 @@ 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
}
})()