Skip to content

Commit a7d38ba

Browse files
committed
Update type var assignments only when upper bound is not respected
1 parent a5830e2 commit a7d38ba

File tree

2 files changed

+68
-4
lines changed

2 files changed

+68
-4
lines changed

src/ir/type_utils.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,9 @@ def _get_type_arg_variance(t_param, variance_choices):
494494
return utils.random.choice(variances)
495495

496496

497-
def _update_type_var_bound_rec(t_param, t, t_args, indexes, type_var_map):
497+
def update_type_var_bound_rec(t_param: tp.TypeParameter,
498+
t: tp.Type, t_args: list, indexes: list,
499+
type_var_map: dict):
498500
"""
499501
This method recursively updates the type assignment associated with the
500502
bound of a type variable.
@@ -510,11 +512,19 @@ def _update_type_var_bound_rec(t_param, t, t_args, indexes, type_var_map):
510512
the type assignment related to the bound of bounds.
511513
"""
512514
if not (t_param.is_type_var() and t_param.bound is not None):
515+
# Nothing to update. We don't encounter a type variable with an
516+
# upper bound.
513517
return
514518
bound = t_param.bound
515519
if not bound.is_type_var():
516520
return
517521
try:
522+
current_t = type_var_map[bound]
523+
if t.is_subtype(current_t):
524+
# The current assignment for the type variable corresponding to
525+
# the upper bound of 't_param' is supertype of 't'. So we don't
526+
# have to update anything.
527+
return
518528
t_args[indexes[bound]] = t
519529
type_var_map[bound] = t
520530
except KeyError:
@@ -523,7 +533,7 @@ def _update_type_var_bound_rec(t_param, t, t_args, indexes, type_var_map):
523533
# case the type variable of the type constructor should be already
524534
# instantiated with a type that cannot be changed.
525535
assert bound in type_var_map
526-
_update_type_var_bound_rec(bound, t, t_args, indexes, type_var_map)
536+
update_type_var_bound_rec(bound, t, t_args, indexes, type_var_map)
527537

528538

529539
def _compute_type_variable_assignments(
@@ -561,8 +571,8 @@ def _compute_type_variable_assignments(
561571

562572
if is_covariant and not for_type_constructor:
563573
t = tp.Nothing
564-
_update_type_var_bound_rec(t_param, t, t_args, indexes,
565-
type_var_map)
574+
update_type_var_bound_rec(t_param, t, t_args, indexes,
575+
type_var_map)
566576
else:
567577
a_types = []
568578
for k, v in type_var_map.items():

tests/test_type_utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from copy import deepcopy
2+
13
from src.ir import types as tp, kotlin_types as kt
24
from src.ir import ast, type_utils as tutils, context as ctx
35

@@ -1301,3 +1303,55 @@ def test_build_type_variable_dependencies():
13011303
baz.name: ["Baz.T1"],
13021304
"Foo.T1": ["Bar.T3"]
13031305
}
1306+
1307+
1308+
def test_update_type_var_bound_rec():
1309+
type_param1 = tp.TypeParameter("T1")
1310+
type_param2 = tp.TypeParameter("T2", bound=type_param1)
1311+
type_param3 = tp.TypeParameter("T3", bound=type_param2)
1312+
type_param4 = tp.TypeParameter("T4")
1313+
type_var_map = {
1314+
type_param1: kt.String
1315+
}
1316+
indexes = {
1317+
type_param1: 0,
1318+
type_param2: 1,
1319+
type_param3: 2,
1320+
type_param4: 3,
1321+
}
1322+
targs = [kt.String]
1323+
old_type_var_map = deepcopy(type_var_map)
1324+
old_targs = deepcopy(targs)
1325+
tutils.update_type_var_bound_rec(tp.Classifier("Foo"), kt.String,
1326+
targs, indexes, type_var_map)
1327+
assert old_targs == targs
1328+
assert old_type_var_map == type_var_map
1329+
1330+
tutils.update_type_var_bound_rec(type_param4, kt.Integer,
1331+
targs, indexes, type_var_map)
1332+
assert old_targs == targs
1333+
assert old_type_var_map == type_var_map
1334+
1335+
1336+
tutils.update_type_var_bound_rec(type_param2, kt.Integer,
1337+
targs, indexes, type_var_map)
1338+
assert type_var_map == {type_param1: kt.Integer}
1339+
assert targs == [kt.Integer]
1340+
1341+
type_var_map = deepcopy(old_type_var_map)
1342+
type_var_map[type_param2] = kt.Boolean
1343+
targs = deepcopy(old_targs)
1344+
targs.append(kt.Boolean)
1345+
1346+
tutils.update_type_var_bound_rec(type_param3, kt.Integer,
1347+
targs, indexes, type_var_map)
1348+
assert type_var_map == {type_param1: kt.Integer, type_param2: kt.Integer}
1349+
assert targs == [kt.Integer, kt.Integer]
1350+
1351+
type_var_map[type_param1] = kt.Number
1352+
type_var_map[type_param2] = kt.Number
1353+
targs = [kt.Number, kt.Number]
1354+
tutils.update_type_var_bound_rec(type_param3, kt.Integer,
1355+
targs, indexes, type_var_map)
1356+
assert type_var_map == {type_param1: kt.Number, type_param2: kt.Number}
1357+
assert targs == [kt.Number, kt.Number]

0 commit comments

Comments
 (0)