Skip to content

Commit

Permalink
Revert "Use class name as namespace for type variables (python#12590)"
Browse files Browse the repository at this point in the history
This reverts commit 20b0b9b.
  • Loading branch information
cdce8p committed Apr 23, 2022
1 parent d1c0616 commit 2c6e598
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 102 deletions.
3 changes: 2 additions & 1 deletion mypy/checkpattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,8 @@ def visit_mapping_pattern(self, o: MappingPattern) -> PatternType:
if is_subtype(current_type, mapping) and isinstance(current_type, Instance):
mapping_inst = map_instance_to_supertype(current_type, mapping.type)
dict_typeinfo = self.chk.lookup_typeinfo("builtins.dict")
rest_type = Instance(dict_typeinfo, mapping_inst.args)
dict_type = fill_typevars(dict_typeinfo)
rest_type = expand_type_by_instance(dict_type, mapping_inst)
else:
object_type = self.chk.named_type("builtins.object")
rest_type = self.chk.named_generic_type("builtins.dict",
Expand Down
3 changes: 1 addition & 2 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,8 +1116,7 @@ def check_decorated_function_is_method(self, decorator: str,
def visit_class_def(self, defn: ClassDef) -> None:
self.statement = defn
self.incomplete_type_stack.append(not defn.info)
namespace = self.qualified_name(defn.name)
with self.tvar_scope_frame(self.tvar_scope.class_frame(namespace)):
with self.tvar_scope_frame(self.tvar_scope.class_frame()):
self.analyze_class(defn)
self.incomplete_type_stack.pop()

Expand Down
21 changes: 6 additions & 15 deletions mypy/tvar_scope.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from typing import Optional, Dict, Union
from mypy.types import (
TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarId, TypeVarTupleType,
)
from mypy.nodes import (
ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode, TypeVarTupleExpr,
)
from mypy.types import TypeVarLikeType, TypeVarType, ParamSpecType, ParamSpecFlavor, TypeVarTupleType
from mypy.nodes import ParamSpecExpr, TypeVarExpr, TypeVarLikeExpr, SymbolTableNode, TypeVarTupleExpr


class TypeVarLikeScope:
Expand All @@ -16,8 +12,7 @@ class TypeVarLikeScope:
def __init__(self,
parent: 'Optional[TypeVarLikeScope]' = None,
is_class_scope: bool = False,
prohibited: 'Optional[TypeVarLikeScope]' = None,
namespace: str = '') -> None:
prohibited: 'Optional[TypeVarLikeScope]' = None) -> None:
"""Initializer for TypeVarLikeScope
Parameters:
Expand All @@ -32,7 +27,6 @@ def __init__(self,
self.class_id = 0
self.is_class_scope = is_class_scope
self.prohibited = prohibited
self.namespace = namespace
if parent is not None:
self.func_id = parent.func_id
self.class_id = parent.class_id
Expand All @@ -57,25 +51,22 @@ def method_frame(self) -> 'TypeVarLikeScope':
"""A new scope frame for binding a method"""
return TypeVarLikeScope(self, False, None)

def class_frame(self, namespace: str) -> 'TypeVarLikeScope':
def class_frame(self) -> 'TypeVarLikeScope':
"""A new scope frame for binding a class. Prohibits *this* class's tvars"""
return TypeVarLikeScope(self.get_function_scope(), True, self, namespace=namespace)
return TypeVarLikeScope(self.get_function_scope(), True, self)

def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
if self.is_class_scope:
self.class_id += 1
i = self.class_id
namespace = self.namespace
else:
self.func_id -= 1
i = self.func_id
# TODO: Consider also using namespaces for functions
namespace = ''
if isinstance(tvar_expr, TypeVarExpr):
tvar_def: TypeVarLikeType = TypeVarType(
name,
tvar_expr.fullname,
TypeVarId(i, namespace=namespace),
i,
values=tvar_expr.values,
upper_bound=tvar_expr.upper_bound,
variance=tvar_expr.variance,
Expand Down
16 changes: 4 additions & 12 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,15 +426,9 @@ class TypeVarId:
# Class variable used for allocating fresh ids for metavariables.
next_raw_id: ClassVar[int] = 1

# Fullname of class (or potentially function in the future) which
# declares this type variable (not the fullname of the TypeVar
# definition!), or ''
namespace: str

def __init__(self, raw_id: int, meta_level: int = 0, *, namespace: str = '') -> None:
def __init__(self, raw_id: int, meta_level: int = 0) -> None:
self.raw_id = raw_id
self.meta_level = meta_level
self.namespace = namespace

@staticmethod
def new(meta_level: int) -> 'TypeVarId':
Expand All @@ -448,16 +442,15 @@ def __repr__(self) -> str:
def __eq__(self, other: object) -> bool:
if isinstance(other, TypeVarId):
return (self.raw_id == other.raw_id and
self.meta_level == other.meta_level and
self.namespace == other.namespace)
self.meta_level == other.meta_level)
else:
return False

def __ne__(self, other: object) -> bool:
return not (self == other)

def __hash__(self) -> int:
return hash((self.raw_id, self.meta_level, self.namespace))
return hash((self.raw_id, self.meta_level))

def is_meta_var(self) -> bool:
return self.meta_level > 0
Expand Down Expand Up @@ -531,7 +524,6 @@ def serialize(self) -> JsonDict:
'name': self.name,
'fullname': self.fullname,
'id': self.id.raw_id,
'namespace': self.id.namespace,
'values': [v.serialize() for v in self.values],
'upper_bound': self.upper_bound.serialize(),
'variance': self.variance,
Expand All @@ -543,7 +535,7 @@ def deserialize(cls, data: JsonDict) -> 'TypeVarType':
return TypeVarType(
data['name'],
data['fullname'],
TypeVarId(data['id'], namespace=data['namespace']),
data['id'],
[deserialize_type(v) for v in data['values']],
deserialize_type(data['upper_bound']),
data['variance'],
Expand Down
73 changes: 1 addition & 72 deletions test-data/unit/check-selftype.test
Original file line number Diff line number Diff line change
Expand Up @@ -893,14 +893,11 @@ from typing import Generic, TypeVar, Tuple
T = TypeVar('T')
S = TypeVar('S')
U = TypeVar('U')
V = TypeVar('V')

class C(Generic[T]):
def magic(self: C[Tuple[S, U]]) -> Tuple[T, S, U]: ...

class D(Generic[V]):
def f(self) -> None:
reveal_type(C[Tuple[V, str]]().magic()) # N: Revealed type is "Tuple[Tuple[V`1, builtins.str], V`1, builtins.str]"
reveal_type(C[Tuple[int, str]]().magic()) # N: Revealed type is "Tuple[Tuple[builtins.int, builtins.str], builtins.int, builtins.str]"
[builtins fixtures/tuple.pyi]

[case testSelfTypeOnUnion]
Expand Down Expand Up @@ -1170,71 +1167,3 @@ def build_wrapper_non_gen(descriptor: Descriptor[int]) -> BaseWrapper[str]:
def build_sub_wrapper_non_gen(descriptor: Descriptor[int]) -> SubWrapper[str]:
return SubWrapper.create_wrapper(descriptor) # E: Argument 1 to "create_wrapper" of "BaseWrapper" has incompatible type "Descriptor[int]"; expected "Descriptor[str]"
[builtins fixtures/classmethod.pyi]

[case testSelfTypeInGenericClassUsedFromAnotherGenericClass1]
from typing import TypeVar, Generic, Iterator, List, Tuple

_T_co = TypeVar("_T_co", covariant=True)
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
S = TypeVar("S")

class Z(Iterator[_T_co]):
def __new__(cls,
__iter1: List[_T1],
__iter2: List[_T2]) -> Z[Tuple[_T1, _T2]]: ...
def __iter__(self: S) -> S: ...
def __next__(self) -> _T_co: ...

T = TypeVar('T')

class C(Generic[T]):
a: List[T]
b: List[str]

def f(self) -> None:
for x, y in Z(self.a, self.b):
reveal_type((x, y)) # N: Revealed type is "Tuple[T`1, builtins.str]"
[builtins fixtures/tuple.pyi]

[case testEnumerateReturningSelfFromIter]
from typing import Generic, Iterable, Iterator, TypeVar, Tuple

T = TypeVar("T")
KT = TypeVar("KT")
VT = TypeVar("VT")
Self = TypeVar("Self")

class enumerate(Iterator[Tuple[int, T]], Generic[T]):
def __init__(self, iterable: Iterable[T]) -> None: ...
def __iter__(self: Self) -> Self: ...
def __next__(self) -> Tuple[int, T]: ...

class Dict(Generic[KT, VT]):
def update(self, __m: Iterable[Tuple[KT, VT]]) -> None: ...

class ThingCollection(Generic[T]):
collection: Iterable[Tuple[float, T]]
index: Dict[int, T]

def do_thing(self) -> None:
self.index.update((idx, c) for idx, (k, c) in enumerate(self.collection))
[builtins fixtures/tuple.pyi]

[case testDequeReturningSelfFromCopy]
# Tests a bug with generic self types identified in issue #12641
from typing import Generic, Sequence, TypeVar

T = TypeVar("T")
Self = TypeVar("Self")

class deque(Sequence[T]):
def copy(self: Self) -> Self: ...

class List(Sequence[T]): ...

class Test(Generic[T]):
def test(self) -> None:
a: deque[List[T]]
# previously this failed with 'Incompatible types in assignment (expression has type "deque[List[List[T]]]", variable has type "deque[List[T]]")'
b: deque[List[T]] = a.copy()

0 comments on commit 2c6e598

Please sign in to comment.