Skip to content

Commit c54c226

Browse files
authored
Move some utils that use get_proper_type away from types.py (#15204)
This is a pure refactor to improve code organization.
1 parent 6283516 commit c54c226

File tree

12 files changed

+215
-197
lines changed

12 files changed

+215
-197
lines changed

mypy/checker.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,8 @@
212212
get_proper_types,
213213
is_literal_type,
214214
is_named_instance,
215-
is_optional,
216-
remove_optional,
217-
store_argument_type,
218-
strip_type,
219215
)
216+
from mypy.types_utils import is_optional, remove_optional, store_argument_type, strip_type
220217
from mypy.typetraverser import TypeTraverserVisitor
221218
from mypy.typevars import fill_typevars, fill_typevars_with_any, has_no_typevars
222219
from mypy.util import is_dunder, is_sunder, is_typeshed_file
@@ -1542,9 +1539,20 @@ def check_reverse_op_method(
15421539
opt_meta = item.type.metaclass_type
15431540
if opt_meta is not None:
15441541
forward_inst = opt_meta
1542+
1543+
def has_readable_member(typ: Union[UnionType, Instance], name: str) -> bool:
1544+
# TODO: Deal with attributes of TupleType etc.
1545+
if isinstance(typ, Instance):
1546+
return typ.type.has_readable_member(name)
1547+
return all(
1548+
(isinstance(x, UnionType) and has_readable_member(x, name))
1549+
or (isinstance(x, Instance) and x.type.has_readable_member(name))
1550+
for x in get_proper_types(typ.relevant_items())
1551+
)
1552+
15451553
if not (
15461554
isinstance(forward_inst, (Instance, UnionType))
1547-
and forward_inst.has_readable_member(forward_name)
1555+
and has_readable_member(forward_inst, forward_name)
15481556
):
15491557
return
15501558
forward_base = reverse_type.arg_types[1]

mypy/checkexpr.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,9 @@
155155
get_proper_type,
156156
get_proper_types,
157157
has_recursive_types,
158-
is_generic_instance,
159158
is_named_instance,
160-
is_optional,
161-
is_self_type_like,
162-
remove_optional,
163159
)
160+
from mypy.types_utils import is_generic_instance, is_optional, is_self_type_like, remove_optional
164161
from mypy.typestate import type_state
165162
from mypy.typevars import fill_typevars
166163
from mypy.typevartuples import find_unpack_in_list

mypy/constraints.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
has_recursive_types,
4747
has_type_vars,
4848
is_named_instance,
49-
is_union_with_any,
5049
)
50+
from mypy.types_utils import is_union_with_any
5151
from mypy.typestate import type_state
5252
from mypy.typevartuples import (
5353
extract_unpack,

mypy/expandtype.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing_extensions import Final
55

66
from mypy.nodes import ARG_POS, ARG_STAR, ArgKind, Var
7+
from mypy.state import state
78
from mypy.type_visitor import TypeTranslator
89
from mypy.types import (
910
ANY_STRATEGY,
@@ -38,7 +39,6 @@
3839
expand_param_spec,
3940
flatten_nested_unions,
4041
get_proper_type,
41-
remove_trivial,
4242
)
4343
from mypy.typevartuples import (
4444
find_unpack_in_list,
@@ -549,3 +549,33 @@ def expand_self_type(var: Var, typ: Type, replacement: Type) -> Type:
549549
if var.info.self_type is not None and not var.is_property:
550550
return expand_type(typ, {var.info.self_type.id: replacement})
551551
return typ
552+
553+
554+
def remove_trivial(types: Iterable[Type]) -> list[Type]:
555+
"""Make trivial simplifications on a list of types without calling is_subtype().
556+
557+
This makes following simplifications:
558+
* Remove bottom types (taking into account strict optional setting)
559+
* Remove everything else if there is an `object`
560+
* Remove strict duplicate types
561+
"""
562+
removed_none = False
563+
new_types = []
564+
all_types = set()
565+
for t in types:
566+
p_t = get_proper_type(t)
567+
if isinstance(p_t, UninhabitedType):
568+
continue
569+
if isinstance(p_t, NoneType) and not state.strict_optional:
570+
removed_none = True
571+
continue
572+
if isinstance(p_t, Instance) and p_t.type.fullname == "builtins.object":
573+
return [p_t]
574+
if p_t not in all_types:
575+
new_types.append(t)
576+
all_types.add(p_t)
577+
if new_types:
578+
return new_types
579+
if removed_none:
580+
return [NoneType()]
581+
return [UninhabitedType()]

mypy/plugins/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
TypeVarType,
4545
deserialize_type,
4646
get_proper_type,
47-
is_optional,
4847
)
48+
from mypy.types_utils import is_optional
4949
from mypy.typevars import fill_typevars
5050
from mypy.util import get_unique_redefinition_name
5151

mypy/semanal.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,9 @@
274274
UnpackType,
275275
get_proper_type,
276276
get_proper_types,
277-
invalid_recursive_alias,
278277
is_named_instance,
279-
store_argument_type,
280278
)
279+
from mypy.types_utils import is_invalid_recursive_alias, store_argument_type
281280
from mypy.typevars import fill_typevars
282281
from mypy.util import (
283282
correct_relative_import,
@@ -3605,7 +3604,7 @@ def disable_invalid_recursive_aliases(
36053604
) -> None:
36063605
"""Prohibit and fix recursive type aliases that are invalid/unsupported."""
36073606
messages = []
3608-
if invalid_recursive_alias({current_node}, current_node.target):
3607+
if is_invalid_recursive_alias({current_node}, current_node.target):
36093608
messages.append("Invalid recursive alias: a union item of itself")
36103609
if detect_diverging_alias(
36113610
current_node, current_node.target, self.lookup_qualified, self.tvar_scope

mypy/subtypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@
5858
UninhabitedType,
5959
UnionType,
6060
UnpackType,
61-
_flattened,
6261
get_proper_type,
6362
is_named_instance,
6463
)
64+
from mypy.types_utils import flatten_types
6565
from mypy.typestate import SubtypeKind, type_state
6666
from mypy.typevars import fill_typevars_with_any
6767
from mypy.typevartuples import extract_unpack, fully_split_with_mapped_and_template
@@ -913,7 +913,7 @@ def visit_union_type(self, left: UnionType) -> bool:
913913

914914
fast_check: set[ProperType] = set()
915915

916-
for item in _flattened(self.right.relevant_items()):
916+
for item in flatten_types(self.right.relevant_items()):
917917
p_item = get_proper_type(item)
918918
fast_check.add(p_item)
919919
if isinstance(p_item, Instance) and p_item.last_known_value is not None:

mypy/suggestions.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@
7878
UninhabitedType,
7979
UnionType,
8080
get_proper_type,
81-
is_optional,
82-
remove_optional,
8381
)
82+
from mypy.types_utils import is_optional, remove_optional
8483
from mypy.util import split_target
8584

8685

mypy/test/testtypes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,7 @@ def make_call(*items: tuple[str, str | None]) -> CallExpr:
14441444
class TestExpandTypeLimitGetProperType(TestCase):
14451445
# WARNING: do not increase this number unless absolutely necessary,
14461446
# and you understand what you are doing.
1447-
ALLOWED_GET_PROPER_TYPES = 7
1447+
ALLOWED_GET_PROPER_TYPES = 8
14481448

14491449
@skipUnless(mypy.expandtype.__file__.endswith(".py"), "Skip for compiled mypy")
14501450
def test_count_get_proper_type(self) -> None:

mypy/typeanal.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@
8181
UninhabitedType,
8282
UnionType,
8383
UnpackType,
84-
bad_type_type_item,
8584
callable_with_ellipsis,
8685
flatten_nested_unions,
8786
get_proper_type,
8887
has_type_vars,
8988
)
89+
from mypy.types_utils import is_bad_type_type_item
9090
from mypy.typetraverser import TypeTraverserVisitor
9191
from mypy.typevars import fill_typevars
9292

@@ -564,7 +564,7 @@ def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Typ
564564
type_str + " must have exactly one type argument", t, code=codes.VALID_TYPE
565565
)
566566
item = self.anal_type(t.args[0])
567-
if bad_type_type_item(item):
567+
if is_bad_type_type_item(item):
568568
self.fail("Type[...] can't contain another Type[...]", t, code=codes.VALID_TYPE)
569569
item = AnyType(TypeOfAny.from_error)
570570
return TypeType.make_normalized(item, line=t.line, column=t.column)

0 commit comments

Comments
 (0)