forked from python/mypy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubtype.py
88 lines (73 loc) · 2.69 KB
/
subtype.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""Subtype check for RTypes."""
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_fixed_width_rtype,
is_int_rprimitive,
is_object_rprimitive,
is_short_int_rprimitive,
is_tagged,
is_tuple_rprimitive,
)
def is_subtype(left: RType, right: RType) -> bool:
if is_object_rprimitive(right):
return True
elif isinstance(right, RUnion):
if isinstance(left, RUnion):
for left_item in left.items:
if not any(is_subtype(left_item, right_item) for right_item in right.items):
return False
return True
else:
return any(is_subtype(left, item) for item in right.items)
return left.accept(SubtypeVisitor(right))
class SubtypeVisitor(RTypeVisitor[bool]):
"""Is left a subtype of right?
A few special cases such as right being 'object' are handled in
is_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 isinstance(self.right, RInstance) and self.right.class_ir in left.class_ir.mro
def visit_runion(self, left: RUnion) -> bool:
return all(is_subtype(item, self.right) for item in left.items)
def visit_rprimitive(self, left: RPrimitive) -> bool:
right = self.right
if is_bool_rprimitive(left):
if is_tagged(right) or is_fixed_width_rtype(right):
return True
elif is_bit_rprimitive(left):
if is_bool_rprimitive(right) or is_tagged(right) or is_fixed_width_rtype(right):
return True
elif is_short_int_rprimitive(left):
if is_int_rprimitive(right):
return True
elif is_fixed_width_rtype(left):
if is_int_rprimitive(right):
return True
return left is right
def visit_rtuple(self, left: RTuple) -> bool:
if is_tuple_rprimitive(self.right):
return True
if isinstance(self.right, RTuple):
return len(self.right.types) == len(left.types) and all(
is_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)