blob: 004e56ed75bc9dacaa03f45b75bd347b02d2ed4e [file] [log] [blame]
"""'Runtime subtype' check for RTypes.
A type S is a runtime subtype of T if a value of type S can be used at runtime
when a value of type T is expected without requiring any runtime conversions.
For boxed types, runtime subtyping is the same as regular subtyping.
Unboxed subtypes, on the other hand, are not runtime subtypes of object
(since they require boxing to be used as an object), but short ints
are runtime subtypes of int.
Subtyping is used to determine whether an object can be in a
particular place and runtime subtyping is used to determine whether a
coercion is necessary first.
"""
from __future__ import annotations
from mypyc.ir.rtypes import (
RArray,
RInstance,
RPrimitive,
RStruct,
RTuple,
RType,
RTypeVisitor,
RUnion,
RVoid,
is_bit_rprimitive,
is_bool_rprimitive,
is_int_rprimitive,
is_short_int_rprimitive,
)
from mypyc.subtype import is_subtype
def is_runtime_subtype(left: RType, right: RType) -> bool:
return left.accept(RTSubtypeVisitor(right))
class RTSubtypeVisitor(RTypeVisitor[bool]):
"""Is left a runtime subtype of right?
A few special cases such as right being 'object' are handled in
is_runtime_subtype and don't need to be covered here.
"""
def __init__(self, right: RType) -> None:
self.right = right
def visit_rinstance(self, left: RInstance) -> bool:
return is_subtype(left, self.right)
def visit_runion(self, left: RUnion) -> bool:
return not self.right.is_unboxed and is_subtype(left, self.right)
def visit_rprimitive(self, left: RPrimitive) -> bool:
if is_short_int_rprimitive(left) and is_int_rprimitive(self.right):
return True
if is_bit_rprimitive(left) and is_bool_rprimitive(self.right):
return True
return left is self.right
def visit_rtuple(self, left: RTuple) -> bool:
if isinstance(self.right, RTuple):
return len(self.right.types) == len(left.types) and all(
is_runtime_subtype(t1, t2) for t1, t2 in zip(left.types, self.right.types)
)
return False
def visit_rstruct(self, left: RStruct) -> bool:
return isinstance(self.right, RStruct) and self.right.name == left.name
def visit_rarray(self, left: RArray) -> bool:
return left == self.right
def visit_rvoid(self, left: RVoid) -> bool:
return isinstance(self.right, RVoid)