Skip to content

Commit 4a957b7

Browse files
authored
Fixed control flow Analysis of aliased discriminants with parenthesized initializers (#61788)
1 parent 48244d8 commit 4a957b7

File tree

4 files changed

+1002
-10
lines changed

4 files changed

+1002
-10
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29379,26 +29379,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2937929379
const symbol = getResolvedSymbol(expr);
2938029380
if (isConstantVariable(symbol)) {
2938129381
const declaration = symbol.valueDeclaration!;
29382+
let initializer = getCandidateVariableDeclarationInitializer(declaration);
2938229383
// Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind'
29383-
if (
29384-
isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) &&
29385-
isMatchingReference(reference, declaration.initializer.expression)
29386-
) {
29387-
return declaration.initializer;
29384+
if (initializer && isAccessExpression(initializer) && isMatchingReference(reference, initializer.expression)) {
29385+
return initializer;
2938829386
}
2938929387
// Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind'
2939029388
if (isBindingElement(declaration) && !declaration.initializer) {
29391-
const parent = declaration.parent.parent;
29392-
if (
29393-
isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) &&
29394-
isMatchingReference(reference, parent.initializer)
29395-
) {
29389+
initializer = getCandidateVariableDeclarationInitializer(declaration.parent.parent);
29390+
if (initializer && (isIdentifier(initializer) || isAccessExpression(initializer)) && isMatchingReference(reference, initializer)) {
2939629391
return declaration;
2939729392
}
2939829393
}
2939929394
}
2940029395
}
2940129396
return undefined;
29397+
29398+
function getCandidateVariableDeclarationInitializer(node: Node) {
29399+
return isVariableDeclaration(node) && !node.type && node.initializer ? skipParentheses(node.initializer) : undefined;
29400+
}
2940229401
}
2940329402

2940429403
function getDiscriminantPropertyAccess(expr: Expression, computedType: Type) {
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
//// [tests/cases/conformance/controlFlow/controlFlowAliasing2.ts] ////
2+
3+
=== controlFlowAliasing2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/61784
5+
6+
type Test = TestA | TestB;
7+
>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0))
8+
>TestA : Symbol(TestA, Decl(controlFlowAliasing2.ts, 2, 26))
9+
>TestB : Symbol(TestB, Decl(controlFlowAliasing2.ts, 7, 1))
10+
11+
interface TestA {
12+
>TestA : Symbol(TestA, Decl(controlFlowAliasing2.ts, 2, 26))
13+
14+
type: 'a';
15+
>type : Symbol(TestA.type, Decl(controlFlowAliasing2.ts, 4, 17))
16+
17+
name: string;
18+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
19+
}
20+
21+
interface TestB {
22+
>TestB : Symbol(TestB, Decl(controlFlowAliasing2.ts, 7, 1))
23+
24+
type: 'b';
25+
>type : Symbol(TestB.type, Decl(controlFlowAliasing2.ts, 9, 17))
26+
27+
value: number;
28+
>value : Symbol(TestB.value, Decl(controlFlowAliasing2.ts, 10, 12))
29+
}
30+
31+
function _tcb1(this: { test: Test }) {
32+
>_tcb1 : Symbol(_tcb1, Decl(controlFlowAliasing2.ts, 12, 1))
33+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
34+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
35+
>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0))
36+
37+
// TS generated by Angular's Type Check block
38+
const _t1 = (((((this).test)).type));
39+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 16, 7))
40+
>(((this).test)).type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
41+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
42+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
43+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
44+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
45+
46+
if (_t1 === "a") {
47+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 16, 7))
48+
49+
(((((this).test)).name));
50+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
51+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
52+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
53+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
54+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
55+
}
56+
57+
// Same as above, without the parenthesis
58+
const _t2 = this.test.type;
59+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 22, 7))
60+
>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
61+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
62+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
63+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
64+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
65+
66+
if (_t2 === "a") {
67+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 22, 7))
68+
69+
(((((this).test)).name));
70+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
71+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
72+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
73+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
74+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
75+
}
76+
77+
// Same as above without parenthesis at both places
78+
const testType = this.test.type;
79+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 28, 7))
80+
>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
81+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
82+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
83+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
84+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
85+
86+
if (testType === "a") {
87+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 28, 7))
88+
89+
this.test.name;
90+
>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
91+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
92+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 14, 15))
93+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 14, 22))
94+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
95+
}
96+
}
97+
98+
function _tcb2(this: { test: Test }) {
99+
>_tcb2 : Symbol(_tcb2, Decl(controlFlowAliasing2.ts, 32, 1))
100+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
101+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
102+
>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0))
103+
104+
// TS generated by Angular's Type Check block
105+
const _t1 = (((((this).test)).type));
106+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 36, 7))
107+
>(((this).test)).type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
108+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
109+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
110+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
111+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
112+
113+
if ("a" === _t1) {
114+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 36, 7))
115+
116+
(((((this).test)).name));
117+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
118+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
119+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
120+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
121+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
122+
}
123+
124+
// Same as above, without the parenthesis
125+
const _t2 = this.test.type;
126+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 42, 7))
127+
>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
128+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
129+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
130+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
131+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
132+
133+
if ("a" === _t2) {
134+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 42, 7))
135+
136+
(((((this).test)).name));
137+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
138+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
139+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
140+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
141+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
142+
}
143+
144+
// Same as above without parenthesis at both places
145+
const testType = this.test.type;
146+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 48, 7))
147+
>this.test.type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
148+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
149+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
150+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
151+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
152+
153+
if ("a" === testType) {
154+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 48, 7))
155+
156+
this.test.name;
157+
>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
158+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
159+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 34, 15))
160+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 34, 22))
161+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
162+
}
163+
}
164+
165+
function _tcb3(this: { test: Test }) {
166+
>_tcb3 : Symbol(_tcb3, Decl(controlFlowAliasing2.ts, 52, 1))
167+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
168+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
169+
>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0))
170+
171+
const { type: _t1 } = (((((this).test))));
172+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
173+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 55, 9))
174+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
175+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
176+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
177+
178+
if (_t1 === "a") {
179+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 55, 9))
180+
181+
(((((this).test)).name));
182+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
183+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
184+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
185+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
186+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
187+
}
188+
189+
// Same as above, without the parenthesis
190+
const { type: _t2 } = this.test;
191+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
192+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 61, 9))
193+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
194+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
195+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
196+
197+
if (_t2 === "a") {
198+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 61, 9))
199+
200+
(((((this).test)).name));
201+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
202+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
203+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
204+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
205+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
206+
}
207+
208+
// Same as above without parenthesis at both places
209+
const { type: testType } = this.test;
210+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
211+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 67, 9))
212+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
213+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
214+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
215+
216+
if (testType === "a") {
217+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 67, 9))
218+
219+
this.test.name;
220+
>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
221+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
222+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 54, 15))
223+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 54, 22))
224+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
225+
}
226+
}
227+
228+
function _tcb4(this: { test: Test }) {
229+
>_tcb4 : Symbol(_tcb4, Decl(controlFlowAliasing2.ts, 71, 1))
230+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
231+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
232+
>Test : Symbol(Test, Decl(controlFlowAliasing2.ts, 0, 0))
233+
234+
const { type: _t1 } = (((((this).test))));
235+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
236+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 74, 9))
237+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
238+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
239+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
240+
241+
if ("a" === _t1) {
242+
>_t1 : Symbol(_t1, Decl(controlFlowAliasing2.ts, 74, 9))
243+
244+
(((((this).test)).name));
245+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
246+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
247+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
248+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
249+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
250+
}
251+
252+
// Same as above, without the parenthesis
253+
const { type: _t2 } = this.test;
254+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
255+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 80, 9))
256+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
257+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
258+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
259+
260+
if ("a" === _t2) {
261+
>_t2 : Symbol(_t2, Decl(controlFlowAliasing2.ts, 80, 9))
262+
263+
(((((this).test)).name));
264+
>(((this).test)).name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
265+
>(this).test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
266+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
267+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
268+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
269+
}
270+
271+
// Same as above without parenthesis at both places
272+
const { type: testType } = this.test;
273+
>type : Symbol(type, Decl(controlFlowAliasing2.ts, 4, 17), Decl(controlFlowAliasing2.ts, 9, 17))
274+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 86, 9))
275+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
276+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
277+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
278+
279+
if ("a" === testType) {
280+
>testType : Symbol(testType, Decl(controlFlowAliasing2.ts, 86, 9))
281+
282+
this.test.name;
283+
>this.test.name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
284+
>this.test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
285+
>this : Symbol(this, Decl(controlFlowAliasing2.ts, 73, 15))
286+
>test : Symbol(test, Decl(controlFlowAliasing2.ts, 73, 22))
287+
>name : Symbol(TestA.name, Decl(controlFlowAliasing2.ts, 5, 12))
288+
}
289+
}
290+
291+
export {};
292+

0 commit comments

Comments
 (0)