Skip to content

Commit e1d0515

Browse files
committed
Merge pull request #3071 from Microsoft/removeSubtypesRecursion
Make removeSubtypes resilient to reentry
2 parents ebb5a0d + 7a92282 commit e1d0515

8 files changed

+277
-0
lines changed

Diff for: src/compiler/checker.ts

+14
Original file line numberDiff line numberDiff line change
@@ -3572,14 +3572,28 @@ 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. The removeSubtypesStack is used to track which
3578+
// sets of types are currently undergoing subtype reduction.
3579+
let removeSubtypesStack: string[] = [];
35753580
function removeSubtypes(types: Type[]) {
3581+
let typeListId = getTypeListId(types);
3582+
if (removeSubtypesStack.lastIndexOf(typeListId) >= 0) {
3583+
return;
3584+
}
3585+
3586+
removeSubtypesStack.push(typeListId);
3587+
35763588
let i = types.length;
35773589
while (i > 0) {
35783590
i--;
35793591
if (isSubtypeOfAny(types[i], types)) {
35803592
types.splice(i, 1);
35813593
}
35823594
}
3595+
3596+
removeSubtypesStack.pop();
35833597
}
35843598

35853599
function containsAnyType(types: Type[]) {
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;
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+
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+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
tests/cases/compiler/unionTypeWithRecursiveSubtypeReduction2.ts(19,1): error TS2322: Type 'Property' is not assignable to type 'Class'.
2+
Types of property 'parent' are incompatible.
3+
Type 'Module | Class' is not assignable to type 'Namespace'.
4+
Type 'Class' is not assignable to type 'Namespace'.
5+
Property 'members' is missing in type 'Class'.
6+
tests/cases/compiler/unionTypeWithRecursiveSubtypeReduction2.ts(20,1): error TS2322: Type 'Class' is not assignable to type 'Property'.
7+
Types of property 'parent' are incompatible.
8+
Type 'Namespace' is not assignable to type 'Module | Class'.
9+
Type 'Namespace' is not assignable to type 'Class'.
10+
Property 'parent' is missing in type 'Namespace'.
11+
12+
13+
==== tests/cases/compiler/unionTypeWithRecursiveSubtypeReduction2.ts (2 errors) ====
14+
class Module {
15+
public members: Class[];
16+
}
17+
18+
class Namespace {
19+
public members: (Class | Property)[];
20+
}
21+
22+
class Class {
23+
public parent: Namespace;
24+
}
25+
26+
class Property {
27+
public parent: Module | Class;
28+
}
29+
30+
var c: Class;
31+
var p: Property;
32+
c = p;
33+
~
34+
!!! error TS2322: Type 'Property' is not assignable to type 'Class'.
35+
!!! error TS2322: Types of property 'parent' are incompatible.
36+
!!! error TS2322: Type 'Module | Class' is not assignable to type 'Namespace'.
37+
!!! error TS2322: Type 'Class' is not assignable to type 'Namespace'.
38+
!!! error TS2322: Property 'members' is missing in type 'Class'.
39+
p = c;
40+
~
41+
!!! error TS2322: Type 'Class' is not assignable to type 'Property'.
42+
!!! error TS2322: Types of property 'parent' are incompatible.
43+
!!! error TS2322: Type 'Namespace' is not assignable to type 'Module | Class'.
44+
!!! error TS2322: Type 'Namespace' is not assignable to type 'Class'.
45+
!!! error TS2322: Property 'parent' is missing in type 'Namespace'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [unionTypeWithRecursiveSubtypeReduction2.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 c: Class;
19+
var p: Property;
20+
c = p;
21+
p = c;
22+
23+
//// [unionTypeWithRecursiveSubtypeReduction2.js]
24+
var Module = (function () {
25+
function Module() {
26+
}
27+
return Module;
28+
})();
29+
var Namespace = (function () {
30+
function Namespace() {
31+
}
32+
return Namespace;
33+
})();
34+
var Class = (function () {
35+
function Class() {
36+
}
37+
return Class;
38+
})();
39+
var Property = (function () {
40+
function Property() {
41+
}
42+
return Property;
43+
})();
44+
var c;
45+
var p;
46+
c = p;
47+
p = c;
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;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 c: Class;
18+
var p: Property;
19+
c = p;
20+
p = c;

0 commit comments

Comments
 (0)