Skip to content

Commit e385331

Browse files
alexisthedevtheosotr
authored andcommitted
Add more unit tests for type unification, solve bugs in the type unification algorithm
1 parent 832c73a commit e385331

File tree

3 files changed

+42
-5
lines changed

3 files changed

+42
-5
lines changed

src/ir/typescript_types.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ def unify_types(self, t1, factory, same_type=True):
532532
# Hence, we only substitute necessary types in T2
533533
# by ensuring that the T1 type we will subtitute
534534
# is NOT a subtype of any other types in the T1 union type.
535-
for t1_t in t1_types:
535+
for t1_t in list(add_to_t2):
536536
if any(t1_t.is_subtype(other_t1_t)
537537
and t1_t is not other_t1_t
538538
for other_t1_t in t1_types):
@@ -665,7 +665,7 @@ def assign_types_to_type_vars(self, possible_subs):
665665
while possible_subs:
666666
# Sort the possible_subs dict, in order to first find a substitution for the T1
667667
# type with the fewest compatible T2 type variables.
668-
sorted_type_subs = sorted(possible_subs.items(), key=lambda x: len(x), reverse=True)
668+
sorted_type_subs = sorted(list(possible_subs.items()), key=lambda x: len(x[1]), reverse=False)
669669

670670
# Get the first (T1 type, T2 type variable) pair (sorted_type_subs is a tuples list)
671671
type_to_substitute, compatible_tvars = sorted_type_subs[0]
@@ -686,7 +686,7 @@ def assign_types_to_type_vars(self, possible_subs):
686686
# of all other T1 types.
687687
for k in list(possible_subs.keys()):
688688
if chosen_tvar in possible_subs[k]:
689-
possible_subs.remove(chosen_tvar)
689+
possible_subs[k].remove(chosen_tvar)
690690

691691
# Delete the possible substitutions of the T1 type we just substituted in T2
692692
del possible_subs[type_to_substitute]
@@ -698,6 +698,9 @@ def assign_types_to_type_vars(self, possible_subs):
698698
def get_name(self):
699699
return self.name
700700

701+
def __str__(self):
702+
return f'UnionType(TS)({" | ".join([str(t) for t in self.types])})'
703+
701704
def __eq__(self, other):
702705
return (self.__class__ == other.__class__ and
703706
self.name == other.name and

src/resources/typescript_keywords

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ Delete
66
debugger
77
arguments
88
let
9-
export
9+
export
10+
symbol

tests/test_typescript.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from src.ir.builtins import NumberType
12
import src.ir.typescript_types as tst
23
import src.ir.typescript_ast as ts_ast
34
import src.ir.types as tp
@@ -130,7 +131,7 @@ def test_union_type_unification_type_var():
130131
assert type_var_map == {type_param: union}
131132

132133

133-
def test_unify_two_union_types():
134+
def test_union_type_unification():
134135
type_param = tp.TypeParameter("T")
135136
union1 = tst.UnionType([tst.NumberLiteralType(1410), tst.NumberType(), tst.StringType()])
136137
union2 = tst.UnionType([type_param, tst.NumberType(), tst.StringType()])
@@ -147,3 +148,35 @@ def test_unify_two_union_types():
147148
assert len(type_var_map) == 2
148149
assert type_param, type_param2 in type_var_map
149150
assert union1.types[1], union1.types[2] in type_var_map.values()
151+
152+
def test_union_type_unification2():
153+
union = tst.UnionType([tst.NumberType(), tst.StringType()])
154+
assert tu.unify_types(tst.BooleanType(), union, tst.TypeScriptBuiltinFactory()) == {}
155+
156+
t1 = tst.NumberType()
157+
t2 = tst.UnionType([tst.NumberType(), tp.TypeParameter("T")])
158+
res = tu.unify_types(t1, t2, tst.TypeScriptBuiltinFactory())
159+
assert len(res) == 1 and res[t2.types[1]] == t1
160+
161+
t1 = tst.UnionType([tst.NumberType(), tst.StringType()])
162+
res = tu.unify_types(t1, t2, tst.TypeScriptBuiltinFactory())
163+
assert len(res) == 1 and res[t2.types[1]] == t1.types[1]
164+
165+
t1 = tst.UnionType([tst.NumberType(), tst.StringLiteralType("foo"), tst.StringType()])
166+
res = tu.unify_types(t1, t2, tst.TypeScriptBuiltinFactory())
167+
assert len(res) == 1 and res[t2.types[1]] == t1.types[2]
168+
169+
t1 = tst.UnionType([tst.NumberType(), tst.NumberLiteralType(100), tst.BooleanType(), tst.StringLiteralType("foo"), tst.StringType()])
170+
171+
t_param1 = tp.TypeParameter("T", bound=tst.StringType())
172+
helper_union = tst.UnionType([tst.BooleanType(), tst.StringType()])
173+
t_param2 = tp.TypeParameter("G", bound=helper_union)
174+
t2 = tst.UnionType([tst.NumberType(), t_param1, t_param2])
175+
176+
# Unify t1: number | 100 | boolean | "foo" | string
177+
# with t2: number | T extends string | G extends (boolean | string)
178+
# Result should be {T: StringType, G: BooleanType}
179+
res = tu.unify_types(t1, t2, tst.TypeScriptBuiltinFactory())
180+
assert (len(res) == 2 and
181+
res[t2.types[1]] == t1.types[4] and
182+
res[t2.types[2]] == t1.types[2])

0 commit comments

Comments
 (0)