|
45 | 45 | from mypy import nodes |
46 | 46 | from mypy.config_parser import parse_config_file |
47 | 47 | from mypy.evalexpr import UNKNOWN, evaluate_expression |
| 48 | +from mypy.maptype import map_instance_to_supertype |
48 | 49 | from mypy.options import Options |
49 | 50 | from mypy.util import FancyFormatter, bytes_to_human_readable_repr, is_dunder, plural_s |
50 | 51 |
|
@@ -1852,10 +1853,39 @@ def describe_runtime_callable(signature: inspect.Signature, *, is_async: bool) - |
1852 | 1853 | return f'{"async " if is_async else ""}def {signature}' |
1853 | 1854 |
|
1854 | 1855 |
|
| 1856 | +class _TypeCheckOnlyBaseMapper(mypy.types.TypeTranslator): |
| 1857 | + """Rewrites @type_check_only instances to the nearest runtime-visible base class.""" |
| 1858 | + |
| 1859 | + def visit_instance(self, t: mypy.types.Instance, /) -> mypy.types.Type: |
| 1860 | + instance = mypy.types.get_proper_type(super().visit_instance(t)) |
| 1861 | + assert isinstance(instance, mypy.types.Instance) |
| 1862 | + |
| 1863 | + if instance.type.is_type_check_only: |
| 1864 | + # find the nearest non-@type_check_only base class |
| 1865 | + for base_info in instance.type.mro[1:]: |
| 1866 | + if not base_info.is_type_check_only: |
| 1867 | + return map_instance_to_supertype(instance, base_info) |
| 1868 | + |
| 1869 | + msg = f"all base classes of {instance.type.fullname!r} are @type_check_only" |
| 1870 | + assert False, msg |
| 1871 | + |
| 1872 | + return instance |
| 1873 | + |
| 1874 | + def visit_type_alias_type(self, t: mypy.types.TypeAliasType, /) -> mypy.types.Type: |
| 1875 | + return t |
| 1876 | + |
| 1877 | + |
| 1878 | +_TYPE_CHECK_ONLY_BASE_MAPPER = _TypeCheckOnlyBaseMapper() |
| 1879 | + |
| 1880 | + |
| 1881 | +def _relax_type_check_only_type(typ: mypy.types.ProperType) -> mypy.types.ProperType: |
| 1882 | + return mypy.types.get_proper_type(typ.accept(_TYPE_CHECK_ONLY_BASE_MAPPER)) |
| 1883 | + |
| 1884 | + |
1855 | 1885 | def is_subtype_helper(left: mypy.types.Type, right: mypy.types.Type) -> bool: |
1856 | 1886 | """Checks whether ``left`` is a subtype of ``right``.""" |
1857 | | - left = mypy.types.get_proper_type(left) |
1858 | | - right = mypy.types.get_proper_type(right) |
| 1887 | + left = _relax_type_check_only_type(mypy.types.get_proper_type(left)) |
| 1888 | + right = _relax_type_check_only_type(mypy.types.get_proper_type(right)) |
1859 | 1889 | if ( |
1860 | 1890 | isinstance(left, mypy.types.LiteralType) |
1861 | 1891 | and isinstance(left.value, int) |
|
0 commit comments