|
57 | 57 | UninhabitedType,
|
58 | 58 | UnionType,
|
59 | 59 | UnpackType,
|
| 60 | + _flattened, |
60 | 61 | get_proper_type,
|
61 | 62 | is_named_instance,
|
62 | 63 | )
|
@@ -891,6 +892,35 @@ def visit_union_type(self, left: UnionType) -> bool:
|
891 | 892 | if not self._is_subtype(item, self.orig_right):
|
892 | 893 | return False
|
893 | 894 | return True
|
| 895 | + |
| 896 | + elif isinstance(self.right, UnionType): |
| 897 | + # prune literals early to avoid nasty quadratic behavior which would otherwise arise when checking |
| 898 | + # subtype relationships between slightly different narrowings of an Enum |
| 899 | + # we achieve O(N+M) instead of O(N*M) |
| 900 | + |
| 901 | + fast_check: set[ProperType] = set() |
| 902 | + |
| 903 | + for item in _flattened(self.right.relevant_items()): |
| 904 | + p_item = get_proper_type(item) |
| 905 | + if isinstance(p_item, LiteralType): |
| 906 | + fast_check.add(p_item) |
| 907 | + elif isinstance(p_item, Instance): |
| 908 | + if p_item.last_known_value is None: |
| 909 | + fast_check.add(p_item) |
| 910 | + else: |
| 911 | + fast_check.add(p_item.last_known_value) |
| 912 | + |
| 913 | + for item in left.relevant_items(): |
| 914 | + p_item = get_proper_type(item) |
| 915 | + if p_item in fast_check: |
| 916 | + continue |
| 917 | + lit_type = mypy.typeops.simple_literal_type(p_item) |
| 918 | + if lit_type in fast_check: |
| 919 | + continue |
| 920 | + if not self._is_subtype(item, self.orig_right): |
| 921 | + return False |
| 922 | + return True |
| 923 | + |
894 | 924 | return all(self._is_subtype(item, self.orig_right) for item in left.items)
|
895 | 925 |
|
896 | 926 | def visit_partial_type(self, left: PartialType) -> bool:
|
|
0 commit comments