Skip to content

Commit 5cd1dab

Browse files
authored
Untangle most of the big import cycle (#7397)
Currently mypy has a 47 module import cycle, which is not great. This untangles things, leaving the following cycles: * Size 2: mypy.build, mypy.semanal_main * Size 2: mypy.plugin, mypy.interpreted_plugin * Size 4: mypy.checker, mypy.checkexpr, mypy.checkmember, mypy.checkstrformat. The type checker itself. This could be untangled by having the sub-checkers operate on an interface of the checker, like the semantic analyzer does. * Size 5: mypy.nodes, mypy.types, mypy.type_visitor, mypy.visitors, mypy.strconv. This can't really be untangled. * Size 14: mypy.messages, mypy.expandtype, mypy.erasetype, mypy.typevars, mypy.maptype, mypy.typeops, mypy.sametypes, mypy.subtypes, mypy.constraints, mypy.applytype, mypy.join, mypy.meet, mypy.solve, mypy.infer. The "typeops tangle". Untangling a little further is probably possible but will require some thought and actual logic changes to code. Messages can definitely be removed. The untangling done here is pretty simple and consists of two main parts: * Remove `mypy.types`'s dependency on the type ops tangle by moving all of its functions that depend on it into `mypy.typeops`. * Remove the dependency of the type ops tangle on the type checker by moving some functions from `mypy.checkmember` to `mypy.typeops`. Fixes #93. Fixes #6329.
1 parent ddec163 commit 5cd1dab

20 files changed

+482
-435
lines changed

mypy/build.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from mypy.nodes import MypyFile, ImportBase, Import, ImportFrom, ImportAll, SymbolTable
3232
from mypy.semanal_pass1 import SemanticAnalyzerPreAnalysis
3333
from mypy.semanal import SemanticAnalyzer
34-
from mypy.semanal_main import semantic_analysis_for_scc
34+
import mypy.semanal_main
3535
from mypy.checker import TypeChecker
3636
from mypy.indirection import TypeIndirectionVisitor
3737
from mypy.errors import Errors, CompileError, ErrorInfo, report_internal_error
@@ -2961,7 +2961,7 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No
29612961
# SemanticAnalyzerPass2.add_builtin_aliases for details.
29622962
typing_mod = graph['typing'].tree
29632963
assert typing_mod, "The typing module was not parsed"
2964-
semantic_analysis_for_scc(graph, scc, manager.errors)
2964+
mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
29652965

29662966
# Track what modules aren't yet done so we can finish them as soon
29672967
# as possible, saving memory.

mypy/checker.py

+23-19
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
Type, AnyType, CallableType, FunctionLike, Overloaded, TupleType, TypedDictType,
3535
Instance, NoneType, strip_type, TypeType, TypeOfAny,
3636
UnionType, TypeVarId, TypeVarType, PartialType, DeletedType, UninhabitedType, TypeVarDef,
37-
true_only, false_only, function_type, is_named_instance, union_items, TypeQuery, LiteralType,
37+
function_type, is_named_instance, union_items, TypeQuery, LiteralType,
3838
is_optional, remove_optional, TypeTranslator, StarType, get_proper_type, ProperType,
3939
get_proper_types, is_literal_type
4040
)
@@ -45,8 +45,12 @@
4545
)
4646
import mypy.checkexpr
4747
from mypy.checkmember import (
48-
map_type_from_supertype, bind_self, erase_to_bound, type_object_type,
49-
analyze_descriptor_access,
48+
analyze_descriptor_access, type_object_type,
49+
)
50+
from mypy.typeops import (
51+
map_type_from_supertype, bind_self, erase_to_bound, make_simplified_union,
52+
erase_def_to_union_or_bound, erase_to_union_or_bound,
53+
true_only, false_only,
5054
)
5155
from mypy import message_registry
5256
from mypy.subtypes import (
@@ -1539,7 +1543,7 @@ def get_op_other_domain(self, tp: FunctionLike) -> Optional[Type]:
15391543
raw_items = [self.get_op_other_domain(it) for it in tp.items()]
15401544
items = [it for it in raw_items if it]
15411545
if items:
1542-
return UnionType.make_simplified_union(items)
1546+
return make_simplified_union(items)
15431547
return None
15441548
else:
15451549
assert False, "Need to check all FunctionLike subtypes here"
@@ -1973,7 +1977,7 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
19731977
if not self.current_node_deferred:
19741978
# Partial type can't be final, so strip any literal values.
19751979
rvalue_type = remove_instance_last_known_values(rvalue_type)
1976-
inferred_type = UnionType.make_simplified_union(
1980+
inferred_type = make_simplified_union(
19771981
[rvalue_type, NoneType()])
19781982
self.set_inferred_type(var, lvalue, inferred_type)
19791983
else:
@@ -2417,7 +2421,7 @@ def check_multi_assignment_from_union(self, lvalues: List[Expression], rvalue: E
24172421
rv_type=item, undefined_rvalue=True)
24182422
for t, lv in zip(transposed, self.flatten_lvalues(lvalues)):
24192423
t.append(self.type_map.pop(lv, AnyType(TypeOfAny.special_form)))
2420-
union_types = tuple(UnionType.make_simplified_union(col) for col in transposed)
2424+
union_types = tuple(make_simplified_union(col) for col in transposed)
24212425
for expr, items in assignments.items():
24222426
# Bind a union of types collected in 'assignments' to every expression.
24232427
if isinstance(expr, StarExpr):
@@ -2432,8 +2436,8 @@ def check_multi_assignment_from_union(self, lvalues: List[Expression], rvalue: E
24322436

24332437
types, declared_types = zip(*clean_items)
24342438
self.binder.assign_type(expr,
2435-
UnionType.make_simplified_union(list(types)),
2436-
UnionType.make_simplified_union(list(declared_types)),
2439+
make_simplified_union(list(types)),
2440+
make_simplified_union(list(declared_types)),
24372441
False)
24382442
for union, lv in zip(union_types, self.flatten_lvalues(lvalues)):
24392443
# Properly store the inferred types.
@@ -2856,9 +2860,9 @@ def try_infer_partial_type_from_indexed_assignment(
28562860
# TODO: Don't infer things twice.
28572861
key_type = self.expr_checker.accept(lvalue.index)
28582862
value_type = self.expr_checker.accept(rvalue)
2859-
full_key_type = UnionType.make_simplified_union(
2863+
full_key_type = make_simplified_union(
28602864
[key_type, var.type.inner_types[0]])
2861-
full_value_type = UnionType.make_simplified_union(
2865+
full_value_type = make_simplified_union(
28622866
[value_type, var.type.inner_types[1]])
28632867
if (is_valid_inferred_type(full_key_type) and
28642868
is_valid_inferred_type(full_value_type)):
@@ -3176,7 +3180,7 @@ def check_except_handler_test(self, n: Expression) -> Type:
31763180

31773181
all_types.append(exc_type)
31783182

3179-
return UnionType.make_simplified_union(all_types)
3183+
return make_simplified_union(all_types)
31803184

31813185
def get_types_from_except_handler(self, typ: Type, n: Expression) -> List[Type]:
31823186
"""Helper for check_except_handler_test to retrieve handler types."""
@@ -3524,7 +3528,7 @@ def partition_by_callable(self, typ: Type,
35243528
# do better.
35253529
# If it is possible for the false branch to execute, return the original
35263530
# type to avoid losing type information.
3527-
callables, uncallables = self.partition_by_callable(typ.erase_to_union_or_bound(),
3531+
callables, uncallables = self.partition_by_callable(erase_to_union_or_bound(typ),
35283532
unsound_partition)
35293533
uncallables = [typ] if len(uncallables) else []
35303534
return callables, uncallables
@@ -4087,7 +4091,7 @@ def conditional_type_map(expr: Expression,
40874091
if it was not the proposed type, if any. None means bot, {} means top"""
40884092
if proposed_type_ranges:
40894093
proposed_items = [type_range.item for type_range in proposed_type_ranges]
4090-
proposed_type = UnionType.make_simplified_union(proposed_items)
4094+
proposed_type = make_simplified_union(proposed_items)
40914095
if current_type:
40924096
if isinstance(proposed_type, AnyType):
40934097
# We don't really know much about the proposed type, so we shouldn't
@@ -4170,7 +4174,7 @@ def builtin_item_type(tp: Type) -> Optional[Type]:
41704174
return tp.args[0]
41714175
elif isinstance(tp, TupleType) and all(not isinstance(it, AnyType)
41724176
for it in get_proper_types(tp.items)):
4173-
return UnionType.make_simplified_union(tp.items) # this type is not externally visible
4177+
return make_simplified_union(tp.items) # this type is not externally visible
41744178
elif isinstance(tp, TypedDictType):
41754179
# TypedDict always has non-optional string keys. Find the key type from the Mapping
41764180
# base class.
@@ -4221,7 +4225,7 @@ def or_conditional_maps(m1: TypeMap, m2: TypeMap) -> TypeMap:
42214225
for n1 in m1:
42224226
for n2 in m2:
42234227
if literal_hash(n1) == literal_hash(n2):
4224-
result[n1] = UnionType.make_simplified_union([m1[n1], m2[n2]])
4228+
result[n1] = make_simplified_union([m1[n1], m2[n2]])
42254229
return result
42264230

42274231

@@ -4435,7 +4439,7 @@ def overload_can_never_match(signature: CallableType, other: CallableType) -> bo
44354439
# the below subtype check and (surprisingly?) `is_proper_subtype(Any, Any)`
44364440
# returns `True`.
44374441
# TODO: find a cleaner solution instead of this ad-hoc erasure.
4438-
exp_signature = expand_type(signature, {tvar.id: tvar.erase_to_union_or_bound()
4442+
exp_signature = expand_type(signature, {tvar.id: erase_def_to_union_or_bound(tvar)
44394443
for tvar in signature.variables})
44404444
assert isinstance(exp_signature, CallableType)
44414445
return is_callable_compatible(exp_signature, other,
@@ -4689,7 +4693,7 @@ class Status(Enum):
46894693

46904694
if isinstance(typ, UnionType):
46914695
items = [try_expanding_enum_to_union(item, target_fullname) for item in typ.items]
4692-
return UnionType.make_simplified_union(items)
4696+
return make_simplified_union(items)
46934697
elif isinstance(typ, Instance) and typ.type.is_enum and typ.type.fullname() == target_fullname:
46944698
new_items = []
46954699
for name, symbol in typ.type.names.items():
@@ -4704,7 +4708,7 @@ class Status(Enum):
47044708
# only using CPython, but we might as well for the sake of full correctness.
47054709
if sys.version_info < (3, 7):
47064710
new_items.sort(key=lambda lit: lit.value)
4707-
return UnionType.make_simplified_union(new_items)
4711+
return make_simplified_union(new_items)
47084712
else:
47094713
return typ
47104714

@@ -4716,7 +4720,7 @@ def coerce_to_literal(typ: Type) -> ProperType:
47164720
typ = get_proper_type(typ)
47174721
if isinstance(typ, UnionType):
47184722
new_items = [coerce_to_literal(item) for item in typ.items]
4719-
return UnionType.make_simplified_union(new_items)
4723+
return make_simplified_union(new_items)
47204724
elif isinstance(typ, Instance) and typ.last_known_value:
47214725
return typ.last_known_value
47224726
else:

0 commit comments

Comments
 (0)