Skip to content

Commit d8ef7b6

Browse files
committed
Make removeSubtypes resilient to reentry
1 parent 7a5804c commit d8ef7b6

File tree

5 files changed

+164
-0
lines changed

5 files changed

+164
-0
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,14 +3572,27 @@ module ts {
35723572
return false;
35733573
}
35743574

3575+
// Since removeSubtypes checks the subtype relation, and the subtype relation on a union
3576+
// may attempt to reduce a union, it is possible that removeSubtypes could be called
3577+
// recursively on the same set of types.
3578+
let removeSubtypesStack: string[] = [];
35753579
function removeSubtypes(types: Type[]) {
3580+
let typeListId = getTypeListId(types);
3581+
if (removeSubtypesStack.lastIndexOf(typeListId) >= 0) {
3582+
return;
3583+
}
3584+
3585+
removeSubtypesStack.push(typeListId);
3586+
35763587
let i = types.length;
35773588
while (i > 0) {
35783589
i--;
35793590
if (isSubtypeOfAny(types[i], types)) {
35803591
types.splice(i, 1);
35813592
}
35823593
}
3594+
3595+
removeSubtypesStack.pop();
35833596
}
35843597

35853598
function containsAnyType(types: Type[]) {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [unionTypeWithRecursiveSubtypeReduction.ts]
2+
class Module {
3+
public members: Class[];
4+
}
5+
6+
class Namespace {
7+
public members: (Class | Property)[];
8+
}
9+
10+
class Class {
11+
public parent: Namespace;
12+
}
13+
14+
class Property {
15+
public parent: Module | Class;
16+
}
17+
18+
var t: Class | Property;
19+
t.parent;
20+
21+
//// [unionTypeWithRecursiveSubtypeReduction.js]
22+
var Module = (function () {
23+
function Module() {
24+
}
25+
return Module;
26+
})();
27+
var Namespace = (function () {
28+
function Namespace() {
29+
}
30+
return Namespace;
31+
})();
32+
var Class = (function () {
33+
function Class() {
34+
}
35+
return Class;
36+
})();
37+
var Property = (function () {
38+
function Property() {
39+
}
40+
return Property;
41+
})();
42+
var t;
43+
t.parent;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/unionTypeWithRecursiveSubtypeReduction.ts ===
2+
class Module {
3+
>Module : Symbol(Module, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 0, 0))
4+
5+
public members: Class[];
6+
>members : Symbol(members, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 0, 14))
7+
>Class : Symbol(Class, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 6, 1))
8+
}
9+
10+
class Namespace {
11+
>Namespace : Symbol(Namespace, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 2, 1))
12+
13+
public members: (Class | Property)[];
14+
>members : Symbol(members, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 4, 17))
15+
>Class : Symbol(Class, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 6, 1))
16+
>Property : Symbol(Property, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 10, 1))
17+
}
18+
19+
class Class {
20+
>Class : Symbol(Class, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 6, 1))
21+
22+
public parent: Namespace;
23+
>parent : Symbol(parent, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 8, 13))
24+
>Namespace : Symbol(Namespace, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 2, 1))
25+
}
26+
27+
class Property {
28+
>Property : Symbol(Property, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 10, 1))
29+
30+
public parent: Module | Class;
31+
>parent : Symbol(parent, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 12, 16))
32+
>Module : Symbol(Module, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 0, 0))
33+
>Class : Symbol(Class, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 6, 1))
34+
}
35+
36+
var t: Class | Property;
37+
>t : Symbol(t, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 16, 3))
38+
>Class : Symbol(Class, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 6, 1))
39+
>Property : Symbol(Property, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 10, 1))
40+
41+
t.parent;
42+
>t.parent : Symbol(parent, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 8, 13), Decl(unionTypeWithRecursiveSubtypeReduction.ts, 12, 16))
43+
>t : Symbol(t, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 16, 3))
44+
>parent : Symbol(parent, Decl(unionTypeWithRecursiveSubtypeReduction.ts, 8, 13), Decl(unionTypeWithRecursiveSubtypeReduction.ts, 12, 16))
45+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/unionTypeWithRecursiveSubtypeReduction.ts ===
2+
class Module {
3+
>Module : Module
4+
5+
public members: Class[];
6+
>members : Class[]
7+
>Class : Class
8+
}
9+
10+
class Namespace {
11+
>Namespace : Namespace
12+
13+
public members: (Class | Property)[];
14+
>members : (Class | Property)[]
15+
>Class : Class
16+
>Property : Property
17+
}
18+
19+
class Class {
20+
>Class : Class
21+
22+
public parent: Namespace;
23+
>parent : Namespace
24+
>Namespace : Namespace
25+
}
26+
27+
class Property {
28+
>Property : Property
29+
30+
public parent: Module | Class;
31+
>parent : Module | Class
32+
>Module : Module
33+
>Class : Class
34+
}
35+
36+
var t: Class | Property;
37+
>t : Class | Property
38+
>Class : Class
39+
>Property : Property
40+
41+
t.parent;
42+
>t.parent : Class | Namespace
43+
>t : Class | Property
44+
>parent : Class | Namespace
45+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class Module {
2+
public members: Class[];
3+
}
4+
5+
class Namespace {
6+
public members: (Class | Property)[];
7+
}
8+
9+
class Class {
10+
public parent: Namespace;
11+
}
12+
13+
class Property {
14+
public parent: Module | Class;
15+
}
16+
17+
var t: Class | Property;
18+
t.parent;

0 commit comments

Comments
 (0)