Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypedDictType,
Expand Down Expand Up @@ -935,12 +936,20 @@ def analyze_var(
return result


def expand_tuplegetter_type_if_needed(typ: Type) -> Type:
proper = get_proper_type(typ)
if isinstance(proper, TupleGetterType):
return proper.typ
return typ


def expand_without_binding(
typ: Type, var: Var, itype: Instance, original_itype: Instance, mx: MemberContext
) -> Type:
if not mx.preserve_type_var_ids:
typ = freshen_all_functions_type_vars(typ)
typ = expand_self_type_if_needed(typ, mx, var, original_itype)
typ = expand_tuplegetter_type_if_needed(typ)
expanded = expand_type_by_instance(typ, itype)
freeze_all_type_vars(expanded)
return expanded
Expand Down
4 changes: 4 additions & 0 deletions mypy/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -1244,6 +1245,9 @@ def infer_against_overloaded(
item = find_matching_overload_item(overloaded, template)
return infer_constraints(template, item, self.direction)

def visit_tuplegetter_type(self, template: TupleGetterType) -> list[Constraint]:
raise NotImplementedError

def visit_tuple_type(self, template: TupleType) -> list[Constraint]:
actual = self.actual
unpack_index = find_unpack_in_list(template.items)
Expand Down
4 changes: 4 additions & 0 deletions mypy/copytype.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
TypeAliasType,
TypedDictType,
Expand Down Expand Up @@ -103,6 +104,9 @@ def visit_partial_type(self, t: PartialType) -> ProperType:
def visit_callable_type(self, t: CallableType) -> ProperType:
return self.copy_common(t, t.copy_modified())

def visit_tuplegetter_type(self, t: TupleGetterType) -> ProperType:
return self.copy_common(t, TupleGetterType(t.typ))

def visit_tuple_type(self, t: TupleType) -> ProperType:
return self.copy_common(t, TupleType(t.items, t.partial_fallback, implicit=t.implicit))

Expand Down
4 changes: 4 additions & 0 deletions mypy/erasetype.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -115,6 +116,9 @@ def visit_callable_type(self, t: CallableType) -> ProperType:
def visit_overloaded(self, t: Overloaded) -> ProperType:
return t.fallback.accept(self)

def visit_tuplegetter_type(self, t: TupleGetterType) -> ProperType:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> ProperType:
return t.partial_fallback.accept(self)

Expand Down
4 changes: 4 additions & 0 deletions mypy/expandtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
PartialType,
ProperType,
TrivialSyntheticTypeTranslator,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -456,6 +457,9 @@ def expand_type_tuple_with_unpack(self, typs: tuple[Type, ...]) -> list[Type]:
items.append(item.accept(self))
return items

def visit_tuplegetter_type(self, t: TupleGetterType) -> Type:
return TupleGetterType(t.typ.accept(self))

def visit_tuple_type(self, t: TupleType) -> Type:
items = self.expand_type_list_with_unpack(t.items)
if len(items) == 1:
Expand Down
4 changes: 4 additions & 0 deletions mypy/fixup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
Overloaded,
Parameters,
ParamSpecType,
TupleGetterType,
TupleType,
TypeAliasType,
TypedDictType,
Expand Down Expand Up @@ -296,6 +297,9 @@ def visit_uninhabited_type(self, o: Any) -> None:
def visit_partial_type(self, o: Any) -> None:
raise RuntimeError("Shouldn't get here", o)

def visit_tuplegetter_type(self, tgt: TupleGetterType) -> None:
tgt.typ.accept(self)

def visit_tuple_type(self, tt: TupleType) -> None:
if tt.items:
for it in tt.items:
Expand Down
3 changes: 3 additions & 0 deletions mypy/indirection.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ def visit_overloaded(self, t: types.Overloaded) -> None:
self._visit_type_list(list(t.items))
self._visit(t.fallback)

def visit_tuplegetter_type(self, t: types.TupleGetterType) -> None:
self._visit(t.typ)

def visit_tuple_type(self, t: types.TupleType) -> None:
self._visit_type_list(t.items)
self._visit(t.partial_fallback)
Expand Down
4 changes: 4 additions & 0 deletions mypy/join.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -559,6 +560,9 @@ def join_tuples(self, s: TupleType, t: TupleType) -> list[Type] | None:
items.append(join_types(fi, vi))
return items

def visit_tuplegetter_type(self, t: TupleGetterType) -> ProperType:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> ProperType:
# When given two fixed-length tuples:
# * If they have the same length, join their subtypes item-wise:
Expand Down
4 changes: 4 additions & 0 deletions mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -1039,6 +1040,9 @@ def meet_tuples(self, s: TupleType, t: TupleType) -> list[Type] | None:
items.append(self.meet(fi, vi))
return items

def visit_tuplegetter_type(self, t: TupleGetterType) -> ProperType:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> ProperType:
if isinstance(self.s, TupleType):
items = self.meet_tuples(self.s, t)
Expand Down
3 changes: 3 additions & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -2664,6 +2665,8 @@ def format_literal_value(typ: LiteralType) -> str:
else:
# TODO: better disambiguate ParamSpec name clashes.
return typ.name_with_suffix()
elif isinstance(typ, TupleGetterType):
return f"TupleGetterType[{typ.typ}]"
elif isinstance(typ, TupleType):
# Prefer the name of the fallback class (if not tuple), as it's more informative.
if typ.partial_fallback.type.fullname != "builtins.tuple":
Expand Down
3 changes: 2 additions & 1 deletion mypy/semanal_namedtuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
AnyType,
CallableType,
LiteralType,
TupleGetterType,
TupleType,
Type,
TypeOfAny,
Expand Down Expand Up @@ -552,7 +553,7 @@ def add_field(
var._fullname = f"{info.fullname}.{var.name}"
info.names[var.name] = SymbolTableNode(MDEF, var)

fields = [Var(item, typ) for item, typ in zip(items, types)]
fields = [Var(item, TupleGetterType(typ)) for item, typ in zip(items, types)]
for var in fields:
add_field(var, is_property=True)
# We can't share Vars between fields and method arguments, since they
Expand Down
4 changes: 4 additions & 0 deletions mypy/semanal_typeargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Instance,
Parameters,
ParamSpecType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -103,6 +104,9 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None:
# the expansion, most likely it will result in the same kind of error.
get_proper_type(t).accept(self)

def visit_tuplegetter_type(self, t: TupleGetterType) -> None:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> None:
t.items = flatten_nested_tuples(t.items)
# We could also normalize Tuple[*tuple[X, ...]] -> tuple[X, ...] like in
Expand Down
4 changes: 4 additions & 0 deletions mypy/server/astdiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class level -- these are handled at attribute level (say, 'mod.Cls.method'
Parameters,
ParamSpecType,
PartialType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -481,6 +482,9 @@ def normalize_callable_variables(self, typ: CallableType) -> CallableType:
with state.strict_optional_set(True):
return expand_type(typ, tvmap).copy_modified(variables=tvs)

def visit_tuplegetter_type(self, typ: TupleGetterType) -> SnapshotItem:
return ("TupleGetterType", snapshot_type(typ.typ))

def visit_tuple_type(self, typ: TupleType) -> SnapshotItem:
return ("TupleType", snapshot_types(typ.items))

Expand Down
4 changes: 4 additions & 0 deletions mypy/server/astmerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
PlaceholderType,
RawExpressionType,
SyntheticTypeVisitor,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -470,6 +471,9 @@ def visit_deleted_type(self, typ: DeletedType) -> None:
def visit_partial_type(self, typ: PartialType) -> None:
raise RuntimeError("Cannot handle partial type")

def visit_tuplegetter_type(self, typ: TupleGetterType) -> None:
typ.typ.accept(self)

def visit_tuple_type(self, typ: TupleType) -> None:
for item in typ.items:
item.accept(self)
Expand Down
4 changes: 4 additions & 0 deletions mypy/server/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class 'mod.Cls'. This can also refer to an attribute inherited from a
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -1017,6 +1018,9 @@ def visit_deleted_type(self, typ: DeletedType) -> list[str]:
def visit_partial_type(self, typ: PartialType) -> list[str]:
assert False, "Should not see a partial type here"

def visit_tuplegetter_type(self, typ: TupleGetterType) -> list[str]:
return typ.typ.accept(self)

def visit_tuple_type(self, typ: TupleType) -> list[str]:
triggers = []
for item in typ.items:
Expand Down
9 changes: 9 additions & 0 deletions mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
ParamSpecType,
PartialType,
ProperType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -759,6 +760,14 @@ def visit_callable_type(self, left: CallableType) -> bool:
else:
return False

def visit_tuplegetter_type(self, left: TupleGetterType) -> bool:
right = self.right
if isinstance(right, TupleGetterType):
return left.typ == right.typ
elif isinstance(right, Instance):
return self.is_top_type(right)
return False

def visit_tuple_type(self, left: TupleType) -> bool:
right = self.right
if isinstance(right, Instance):
Expand Down
14 changes: 14 additions & 0 deletions mypy/type_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
PartialType,
PlaceholderType,
RawExpressionType,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -114,6 +115,10 @@ def visit_callable_type(self, t: CallableType, /) -> T:
def visit_overloaded(self, t: Overloaded, /) -> T:
pass

@abstractmethod
def visit_tuplegetter_type(self, t: TupleGetterType, /) -> T:
pass

@abstractmethod
def visit_tuple_type(self, t: TupleType, /) -> T:
pass
Expand Down Expand Up @@ -260,6 +265,9 @@ def visit_callable_type(self, t: CallableType, /) -> Type:
variables=self.translate_variables(t.variables),
)

def visit_tuplegetter_type(self, t: TupleGetterType, /) -> Type:
return TupleGetterType(t.typ.accept(self))

def visit_tuple_type(self, t: TupleType, /) -> Type:
return TupleType(
self.translate_types(t.items),
Expand Down Expand Up @@ -412,6 +420,9 @@ def visit_callable_type(self, t: CallableType, /) -> T:
def visit_tuple_type(self, t: TupleType, /) -> T:
return self.query_types([t.partial_fallback] + t.items)

def visit_tuplegetter_type(self, t: TupleGetterType, /) -> T:
return self.query_types([t.typ])

def visit_typeddict_type(self, t: TypedDictType, /) -> T:
return self.query_types(t.items.values())

Expand Down Expand Up @@ -549,6 +560,9 @@ def visit_callable_type(self, t: CallableType, /) -> bool:
else:
return args and ret

def visit_tuplegetter_type(self, t: TupleGetterType, /) -> bool:
return self.default

def visit_tuple_type(self, t: TupleType, /) -> bool:
return self.query_types([t.partial_fallback] + t.items)

Expand Down
7 changes: 7 additions & 0 deletions mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
RequiredType,
SyntheticTypeVisitor,
TrivialSyntheticTypeTranslator,
TupleGetterType,
TupleType,
Type,
TypeAliasType,
Expand Down Expand Up @@ -1261,6 +1262,9 @@ def visit_overloaded(self, t: Overloaded) -> Type:
# fine to just return it as-is.
return t

def visit_tuplegetter_type(self, t: TupleGetterType) -> Type:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> Type:
# Types such as (t1, t2, ...) only allowed in assignment statements. They'll
# generate errors elsewhere, and Tuple[t1, t2, ...] must be used instead.
Expand Down Expand Up @@ -2637,6 +2641,9 @@ def visit_callable_type(self, t: CallableType) -> None:
self.process_types(t.arg_types)
t.ret_type.accept(self)

def visit_tuplegetter_type(self, t: TupleGetterType) -> None:
raise NotImplementedError

def visit_tuple_type(self, t: TupleType) -> None:
self.process_types(t.items)

Expand Down
Loading