Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def __init__(self) -> None:
false_only,
fixup_partial_type,
function_type,
get_tuple_item_types,
is_literal_type_like,
is_singleton_equality_type,
is_singleton_identity_type,
Expand Down Expand Up @@ -9037,19 +9038,7 @@ def builtin_item_type(tp: Type) -> Type | None:
if not isinstance(get_proper_type(tp.args[0]), AnyType):
return tp.args[0]
elif isinstance(tp, TupleType):
normalized_items = []
for it in tp.items:
# This use case is probably rare, but not handling unpacks here can cause crashes.
if isinstance(it, UnpackType):
unpacked = get_proper_type(it.type)
if isinstance(unpacked, TypeVarTupleType):
unpacked = get_proper_type(unpacked.upper_bound)
assert (
isinstance(unpacked, Instance) and unpacked.type.fullname == "builtins.tuple"
)
normalized_items.append(unpacked.args[0])
else:
normalized_items.append(it)
normalized_items = get_tuple_item_types(tp)
if all(not isinstance(it, AnyType) for it in get_proper_types(normalized_items)):
return make_simplified_union(normalized_items) # this type is not externally visible
elif isinstance(tp, TypedDictType):
Expand Down
22 changes: 2 additions & 20 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
fixup_partial_type,
freeze_all_type_vars,
get_all_type_vars,
get_tuple_item_types,
get_type_vars,
is_literal_type_like,
make_simplified_union,
Expand Down Expand Up @@ -4823,30 +4824,11 @@ def try_getting_int_literals(self, index: Expression) -> list[int] | None:
def nonliteral_tuple_index_helper(self, left_type: TupleType, index: Expression) -> Type:
self.check_method_call_by_name("__getitem__", left_type, [index], [ARG_POS], context=index)
# We could return the return type from above, but unions are often better than the join
union = self.union_tuple_fallback_item(left_type)
union = make_simplified_union(get_tuple_item_types(left_type))
if isinstance(index, SliceExpr):
return self.chk.named_generic_type("builtins.tuple", [union])
return union

def union_tuple_fallback_item(self, left_type: TupleType) -> Type:
# TODO: this duplicates logic in typeops.tuple_fallback().
items = []
for item in left_type.items:
if isinstance(item, UnpackType):
unpacked_type = get_proper_type(item.type)
if isinstance(unpacked_type, TypeVarTupleType):
unpacked_type = get_proper_type(unpacked_type.upper_bound)
if (
isinstance(unpacked_type, Instance)
and unpacked_type.type.fullname == "builtins.tuple"
):
items.append(unpacked_type.args[0])
else:
raise NotImplementedError
else:
items.append(item)
return make_simplified_union(items)

def visit_typeddict_index_expr(
self, td_type: TypedDictType, index: Expression, setitem: bool = False
) -> tuple[Type, set[str]]:
Expand Down
19 changes: 12 additions & 7 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ def tuple_fallback(typ: TupleType) -> Instance:
info = typ.partial_fallback.type
if info.fullname != "builtins.tuple":
return typ.partial_fallback
return Instance(
info,
# Note: flattening recursive unions is dangerous, since it can fool recursive
# types optimization in subtypes.py and go into infinite recursion.
[make_simplified_union(get_tuple_item_types(typ), handle_recursive=False)],
extra_attrs=typ.partial_fallback.extra_attrs,
)


def get_tuple_item_types(typ: TupleType) -> list[Type]:
"""Return tuple item types, replacing unpacks with their possible item types."""
items = []
for item in typ.items:
if isinstance(item, UnpackType):
Expand All @@ -124,13 +135,7 @@ def tuple_fallback(typ: TupleType) -> Instance:
raise NotImplementedError
else:
items.append(item)
return Instance(
info,
# Note: flattening recursive unions is dangerous, since it can fool recursive
# types optimization in subtypes.py and go into infinite recursion.
[make_simplified_union(items, handle_recursive=False)],
extra_attrs=typ.partial_fallback.extra_attrs,
)
return items


def get_self_type(func: CallableType, def_info: TypeInfo) -> Type | None:
Expand Down
Loading