Skip to content

Commit dc8e6a8

Browse files
authored
Fix over-eager isMatchingConstructorReference function (#4691)
1 parent cc49daf commit dc8e6a8

4 files changed

Lines changed: 160 additions & 5 deletions

File tree

internal/checker/flow.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -736,12 +736,13 @@ func (c *Checker) narrowTypeByDiscriminant(t *Type, access *ast.Node, narrowType
736736
}
737737

738738
func (c *Checker) isMatchingConstructorReference(f *FlowState, expr *ast.Node) bool {
739-
if ast.IsAccessExpression(expr) {
740-
if accessedName, ok := c.getAccessedPropertyName(expr); ok && accessedName == "constructor" && c.isMatchingReference(f.reference, expr.Expression()) {
741-
return true
742-
}
739+
var name *ast.Node
740+
if ast.IsPropertyAccessExpression(expr) {
741+
name = expr.AsPropertyAccessExpression().Name()
742+
} else if ast.IsElementAccessExpression(expr) && ast.IsStringLiteralLike(expr.AsElementAccessExpression().ArgumentExpression) {
743+
name = expr.AsElementAccessExpression().ArgumentExpression
743744
}
744-
return false
745+
return name != nil && name.Text() == "constructor" && c.isMatchingReference(f.reference, expr.Expression())
745746
}
746747

747748
func (c *Checker) narrowTypeByConstructor(t *Type, operator ast.Kind, identifier *ast.Node, assumeTrue bool) *Type {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//// [tests/cases/compiler/controlFlowNoCircularity.ts] ////
2+
3+
=== controlFlowNoCircularity.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/4673
5+
6+
export function repro(board: number[][], pos: number | undefined): void {
7+
>repro : Symbol(repro, Decl(controlFlowNoCircularity.ts, 0, 0))
8+
>board : Symbol(board, Decl(controlFlowNoCircularity.ts, 2, 22))
9+
>pos : Symbol(pos, Decl(controlFlowNoCircularity.ts, 2, 40))
10+
11+
if (!pos) return;
12+
>pos : Symbol(pos, Decl(controlFlowNoCircularity.ts, 2, 40))
13+
14+
for (const pattern of [{ target: [-1, -1], intermediate: [-1, 0] }]) {
15+
>pattern : Symbol(pattern, Decl(controlFlowNoCircularity.ts, 4, 12))
16+
>target : Symbol(target, Decl(controlFlowNoCircularity.ts, 4, 26))
17+
>intermediate : Symbol(intermediate, Decl(controlFlowNoCircularity.ts, 4, 44))
18+
19+
const targetR = pos + pattern.target[0];
20+
>targetR : Symbol(targetR, Decl(controlFlowNoCircularity.ts, 5, 9))
21+
>pos : Symbol(pos, Decl(controlFlowNoCircularity.ts, 2, 40))
22+
>pattern.target : Symbol(target, Decl(controlFlowNoCircularity.ts, 4, 26))
23+
>pattern : Symbol(pattern, Decl(controlFlowNoCircularity.ts, 4, 12))
24+
>target : Symbol(target, Decl(controlFlowNoCircularity.ts, 4, 26))
25+
26+
const targetC = pos + pattern.target[1];
27+
>targetC : Symbol(targetC, Decl(controlFlowNoCircularity.ts, 6, 9))
28+
>pos : Symbol(pos, Decl(controlFlowNoCircularity.ts, 2, 40))
29+
>pattern.target : Symbol(target, Decl(controlFlowNoCircularity.ts, 4, 26))
30+
>pattern : Symbol(pattern, Decl(controlFlowNoCircularity.ts, 4, 12))
31+
>target : Symbol(target, Decl(controlFlowNoCircularity.ts, 4, 26))
32+
33+
if (board[targetR][targetC] !== 0) {}
34+
>board : Symbol(board, Decl(controlFlowNoCircularity.ts, 2, 22))
35+
>targetR : Symbol(targetR, Decl(controlFlowNoCircularity.ts, 5, 9))
36+
>targetC : Symbol(targetC, Decl(controlFlowNoCircularity.ts, 6, 9))
37+
38+
const [ir, ic] = pattern.intermediate;
39+
>ir : Symbol(ir, Decl(controlFlowNoCircularity.ts, 8, 11))
40+
>ic : Symbol(ic, Decl(controlFlowNoCircularity.ts, 8, 14))
41+
>pattern.intermediate : Symbol(intermediate, Decl(controlFlowNoCircularity.ts, 4, 44))
42+
>pattern : Symbol(pattern, Decl(controlFlowNoCircularity.ts, 4, 12))
43+
>intermediate : Symbol(intermediate, Decl(controlFlowNoCircularity.ts, 4, 44))
44+
45+
const midC = ic;
46+
>midC : Symbol(midC, Decl(controlFlowNoCircularity.ts, 9, 9))
47+
>ic : Symbol(ic, Decl(controlFlowNoCircularity.ts, 8, 14))
48+
49+
if (board[ir][midC] === 0) {
50+
>board : Symbol(board, Decl(controlFlowNoCircularity.ts, 2, 22))
51+
>ir : Symbol(ir, Decl(controlFlowNoCircularity.ts, 8, 11))
52+
>midC : Symbol(midC, Decl(controlFlowNoCircularity.ts, 9, 9))
53+
}
54+
}
55+
}
56+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//// [tests/cases/compiler/controlFlowNoCircularity.ts] ////
2+
3+
=== controlFlowNoCircularity.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/4673
5+
6+
export function repro(board: number[][], pos: number | undefined): void {
7+
>repro : (board: number[][], pos: number | undefined) => void
8+
>board : number[][]
9+
>pos : number | undefined
10+
11+
if (!pos) return;
12+
>!pos : boolean
13+
>pos : number | undefined
14+
15+
for (const pattern of [{ target: [-1, -1], intermediate: [-1, 0] }]) {
16+
>pattern : { target: number[]; intermediate: number[]; }
17+
>[{ target: [-1, -1], intermediate: [-1, 0] }] : { target: number[]; intermediate: number[]; }[]
18+
>{ target: [-1, -1], intermediate: [-1, 0] } : { target: number[]; intermediate: number[]; }
19+
>target : number[]
20+
>[-1, -1] : number[]
21+
>-1 : -1
22+
>1 : 1
23+
>-1 : -1
24+
>1 : 1
25+
>intermediate : number[]
26+
>[-1, 0] : number[]
27+
>-1 : -1
28+
>1 : 1
29+
>0 : 0
30+
31+
const targetR = pos + pattern.target[0];
32+
>targetR : number
33+
>pos + pattern.target[0] : number
34+
>pos : number
35+
>pattern.target[0] : number
36+
>pattern.target : number[]
37+
>pattern : { target: number[]; intermediate: number[]; }
38+
>target : number[]
39+
>0 : 0
40+
41+
const targetC = pos + pattern.target[1];
42+
>targetC : number
43+
>pos + pattern.target[1] : number
44+
>pos : number
45+
>pattern.target[1] : number
46+
>pattern.target : number[]
47+
>pattern : { target: number[]; intermediate: number[]; }
48+
>target : number[]
49+
>1 : 1
50+
51+
if (board[targetR][targetC] !== 0) {}
52+
>board[targetR][targetC] !== 0 : boolean
53+
>board[targetR][targetC] : number
54+
>board[targetR] : number[]
55+
>board : number[][]
56+
>targetR : number
57+
>targetC : number
58+
>0 : 0
59+
60+
const [ir, ic] = pattern.intermediate;
61+
>ir : number
62+
>ic : number
63+
>pattern.intermediate : number[]
64+
>pattern : { target: number[]; intermediate: number[]; }
65+
>intermediate : number[]
66+
67+
const midC = ic;
68+
>midC : number
69+
>ic : number
70+
71+
if (board[ir][midC] === 0) {
72+
>board[ir][midC] === 0 : boolean
73+
>board[ir][midC] : number
74+
>board[ir] : number[]
75+
>board : number[][]
76+
>ir : number
77+
>midC : number
78+
>0 : 0
79+
}
80+
}
81+
}
82+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @noEmit: true
2+
3+
// https://github.com/microsoft/typescript-go/issues/4673
4+
5+
export function repro(board: number[][], pos: number | undefined): void {
6+
if (!pos) return;
7+
for (const pattern of [{ target: [-1, -1], intermediate: [-1, 0] }]) {
8+
const targetR = pos + pattern.target[0];
9+
const targetC = pos + pattern.target[1];
10+
if (board[targetR][targetC] !== 0) {}
11+
const [ir, ic] = pattern.intermediate;
12+
const midC = ic;
13+
if (board[ir][midC] === 0) {
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)