Skip to content

Commit ac0d5da

Browse files
authored
Merge pull request microsoft#26679 from Microsoft/improveGetTypeOfExpression
Improve control flow analysis of type assertions
2 parents bd40583 + a1c373c commit ac0d5da

6 files changed

+173
-5
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21699,15 +21699,19 @@ namespace ts {
2169921699
* to cache the result.
2170021700
*/
2170121701
function getTypeOfExpression(node: Expression, cache?: boolean) {
21702+
const expr = skipParentheses(node);
2170221703
// Optimize for the common case of a call to a function with a single non-generic call
2170321704
// signature where we can just fetch the return type without checking the arguments.
21704-
if (node.kind === SyntaxKind.CallExpression && (<CallExpression>node).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(node, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(node)) {
21705-
const funcType = checkNonNullExpression((<CallExpression>node).expression);
21705+
if (expr.kind === SyntaxKind.CallExpression && (<CallExpression>expr).expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
21706+
const funcType = checkNonNullExpression((<CallExpression>expr).expression);
2170621707
const signature = getSingleCallSignature(funcType);
2170721708
if (signature && !signature.typeParameters) {
2170821709
return getReturnTypeOfSignature(signature);
2170921710
}
2171021711
}
21712+
else if (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
21713+
return getTypeFromTypeNode((<TypeAssertion>expr).type);
21714+
}
2171121715
// Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions
2171221716
// should have a parameter that indicates whether full error checking is required such that
2171321717
// we can perform the optimizations locally.

tests/baselines/reference/controlFlowSelfReferentialLoop.errors.txt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,24 @@ tests/cases/compiler/controlFlowSelfReferentialLoop.ts(17,29): error TS7006: Par
184184
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
185185
}
186186
}
187-
export default md5;
187+
export default md5;
188+
189+
// Repro from #26655
190+
191+
interface DataShape {
192+
message: { id: string }
193+
}
194+
195+
function getObject(id: string | number) {
196+
return {} as any
197+
}
198+
199+
;(() => {
200+
let id: string | number = 'a'
201+
while (1) {
202+
const data = getObject(id) as DataShape
203+
const message = data.message
204+
id = message.id
205+
}
206+
})()
207+

tests/baselines/reference/controlFlowSelfReferentialLoop.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,27 @@ function md5(string:string): void {
9898
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
9999
}
100100
}
101-
export default md5;
101+
export default md5;
102+
103+
// Repro from #26655
104+
105+
interface DataShape {
106+
message: { id: string }
107+
}
108+
109+
function getObject(id: string | number) {
110+
return {} as any
111+
}
112+
113+
;(() => {
114+
let id: string | number = 'a'
115+
while (1) {
116+
const data = getObject(id) as DataShape
117+
const message = data.message
118+
id = message.id
119+
}
120+
})()
121+
102122

103123
//// [controlFlowSelfReferentialLoop.js]
104124
"use strict";
@@ -204,3 +224,15 @@ function md5(string) {
204224
}
205225
}
206226
exports["default"] = md5;
227+
function getObject(id) {
228+
return {};
229+
}
230+
;
231+
(function () {
232+
var id = 'a';
233+
while (1) {
234+
var data = getObject(id);
235+
var message = data.message;
236+
id = message.id;
237+
}
238+
})();

tests/baselines/reference/controlFlowSelfReferentialLoop.symbols

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,3 +831,45 @@ function md5(string:string): void {
831831
export default md5;
832832
>md5 : Symbol(md5, Decl(controlFlowSelfReferentialLoop.ts, 0, 0))
833833

834+
// Repro from #26655
835+
836+
interface DataShape {
837+
>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19))
838+
839+
message: { id: string }
840+
>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
841+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
842+
}
843+
844+
function getObject(id: string | number) {
845+
>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1))
846+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 107, 19))
847+
848+
return {} as any
849+
}
850+
851+
;(() => {
852+
let id: string | number = 'a'
853+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
854+
855+
while (1) {
856+
const data = getObject(id) as DataShape
857+
>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9))
858+
>getObject : Symbol(getObject, Decl(controlFlowSelfReferentialLoop.ts, 105, 1))
859+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
860+
>DataShape : Symbol(DataShape, Decl(controlFlowSelfReferentialLoop.ts, 99, 19))
861+
862+
const message = data.message
863+
>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9))
864+
>data.message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
865+
>data : Symbol(data, Decl(controlFlowSelfReferentialLoop.ts, 114, 9))
866+
>message : Symbol(DataShape.message, Decl(controlFlowSelfReferentialLoop.ts, 103, 21))
867+
868+
id = message.id
869+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 112, 5))
870+
>message.id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
871+
>message : Symbol(message, Decl(controlFlowSelfReferentialLoop.ts, 115, 9))
872+
>id : Symbol(id, Decl(controlFlowSelfReferentialLoop.ts, 104, 12))
873+
}
874+
})()
875+

tests/baselines/reference/controlFlowSelfReferentialLoop.types

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,3 +1260,54 @@ function md5(string:string): void {
12601260
export default md5;
12611261
>md5 : (string: string) => void
12621262

1263+
// Repro from #26655
1264+
1265+
interface DataShape {
1266+
message: { id: string }
1267+
>message : { id: string; }
1268+
>id : string
1269+
}
1270+
1271+
function getObject(id: string | number) {
1272+
>getObject : (id: string | number) => any
1273+
>id : string | number
1274+
1275+
return {} as any
1276+
>{} as any : any
1277+
>{} : {}
1278+
}
1279+
1280+
;(() => {
1281+
>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }})() : void
1282+
>(() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }}) : () => void
1283+
>() => { let id: string | number = 'a' while (1) { const data = getObject(id) as DataShape const message = data.message id = message.id }} : () => void
1284+
1285+
let id: string | number = 'a'
1286+
>id : string | number
1287+
>'a' : "a"
1288+
1289+
while (1) {
1290+
>1 : 1
1291+
1292+
const data = getObject(id) as DataShape
1293+
>data : DataShape
1294+
>getObject(id) as DataShape : DataShape
1295+
>getObject(id) : any
1296+
>getObject : (id: string | number) => any
1297+
>id : string
1298+
1299+
const message = data.message
1300+
>message : { id: string; }
1301+
>data.message : { id: string; }
1302+
>data : DataShape
1303+
>message : { id: string; }
1304+
1305+
id = message.id
1306+
>id = message.id : string
1307+
>id : string | number
1308+
>message.id : string
1309+
>message : { id: string; }
1310+
>id : string
1311+
}
1312+
})()
1313+

tests/cases/compiler/controlFlowSelfReferentialLoop.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,23 @@ function md5(string:string): void {
9999
b=II(b,c,d,a,x[k+9], S44,0xEB86D391);
100100
}
101101
}
102-
export default md5;
102+
export default md5;
103+
104+
// Repro from #26655
105+
106+
interface DataShape {
107+
message: { id: string }
108+
}
109+
110+
function getObject(id: string | number) {
111+
return {} as any
112+
}
113+
114+
;(() => {
115+
let id: string | number = 'a'
116+
while (1) {
117+
const data = getObject(id) as DataShape
118+
const message = data.message
119+
id = message.id
120+
}
121+
})()

0 commit comments

Comments
 (0)