Skip to content

Commit a56118f

Browse files
committed
Fix subtyping checks for type constructors
1 parent 0a35901 commit a56118f

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

src/ir/types.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,31 @@ def is_type_constructor(self):
472472
return True
473473

474474
def is_subtype(self, other: Type):
475-
return other in self.get_supertypes()
475+
supertypes = self.get_supertypes()
476+
matched_supertype = None
477+
for supertype in supertypes:
478+
if other == supertype:
479+
matched_supertype = supertype
480+
break
481+
if matched_supertype is None:
482+
# This type constructor is not subtype of other
483+
return False
484+
if not other.is_parameterized():
485+
return True
486+
487+
# The rationale here is the following: there might be collision
488+
# in the type variables introduced by the type constructor and
489+
# the type variables that appear in the type arguments of the given
490+
# parameterized type. See the following example:
491+
#
492+
# class Bar<T> extends Foo<Float, T> {}
493+
# fun <T> foo(Foo<Float, T> x) {
494+
# In this context, the type constructor Bar<T> is not a subtype
495+
# of Foo<Float, T>.
496+
# }
497+
type_vars = set(
498+
matched_supertype.get_type_variable_assignments().values())
499+
return not bool(type_vars.intersection(self.type_parameters))
476500

477501
def new(self, type_args: List[Type]):
478502
type_map = {tp: type_args[i]

tests/test_types.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,29 @@ def test_parameterized_with_bound_abstract():
142142
[type_param, tp.TypeParameter("K", bound=type_param)]
143143

144144

145+
def test_subtype_type_constructor_regular():
146+
type_param = tp.TypeParameter("T1")
147+
bar = tp.Classifier("Bar")
148+
foo = tp.TypeConstructor("Foo", [type_param], [bar])
149+
assert foo.is_subtype(bar)
150+
151+
152+
def test_subtype_type_constructor_paramerized():
153+
type_param1 = tp.TypeParameter("T1")
154+
type_param2 = tp.TypeParameter("T2")
155+
foo = tp.TypeConstructor("Foo", [type_param1, type_param2])
156+
bar = tp.TypeConstructor("Bar", [type_param1],
157+
[foo.new([kt.String, type_param1])])
158+
159+
foo_type = foo.new([kt.String, type_param1])
160+
assert not bar.is_subtype(foo_type)
161+
162+
bar = tp.TypeConstructor("Bar", [type_param1],
163+
[foo.new([kt.String, kt.Integer])])
164+
foo_type = foo.new([kt.String, kt.Integer])
165+
assert bar.is_subtype(foo_type)
166+
167+
145168
def test_subtype_covariant_parameterized():
146169
type_param = tp.TypeParameter("T", tp.Covariant)
147170
type_param2 = tp.TypeParameter("K", tp.Covariant)

0 commit comments

Comments
 (0)