Skip to content

Commit a2d654b

Browse files
ilevkivskyiJukkaL
authored andcommitted
Fix meta level on member access (#2809)
Fixes #2804 The problem is that analyze_member_access calls freshen_function_type_vars if the member is a function (i.e. method). This is necessary to not mix the type variables during type inference of generic methods inside generic functions. However, if the method does not participate in type inference, type variables are left in meta_level = 1 state. This causes the error, since the types could not be serialized in the middle of type inference. In this PR I propose to restore meta_level = 0 on member access, this is safe, since anyway, check_call always calls freshen_function_type_vars on callee (for generic functions, generic methods, etc).
1 parent b4492b7 commit a2d654b

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

mypy/checkexpr.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,13 @@ def analyze_ordinary_member_access(self, e: MemberExpr,
993993
e.name, original_type, e, is_lvalue, False, False,
994994
self.named_type, self.not_ready_callback, self.msg,
995995
original_type=original_type, chk=self.chk)
996+
if isinstance(member_type, CallableType):
997+
for v in member_type.variables:
998+
v.id.meta_level = 0
999+
if isinstance(member_type, Overloaded):
1000+
for it in member_type.items():
1001+
for v in it.variables:
1002+
v.id.meta_level = 0
9961003
if is_lvalue:
9971004
return member_type
9981005
else:

test-data/unit/check-incremental.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,25 @@ main:2: error: Revealed type is 'TypedDict(x=builtins.int, _fallback=typing.Mapp
17671767
main:3: error: Revealed type is 'TypedDict(x=builtins.int, _fallback=ntcrash.C.A@4)'
17681768
main:4: error: Revealed type is 'def () -> ntcrash.C.A@4'
17691769

1770+
[case testGenericMethodRestoreMetaLevel]
1771+
from typing import Dict
1772+
1773+
d = {} # type: Dict[str, int]
1774+
g = d.get # This should not crash: see https://github.com/python/mypy/issues/2804
1775+
[builtins fixtures/dict.pyi]
1776+
1777+
[case testGenericMethodRestoreMetaLevel2]
1778+
from typing import TypeVar
1779+
1780+
T = TypeVar('T')
1781+
1782+
class D:
1783+
def m(self, x: T) -> T:
1784+
return x
1785+
1786+
g = D().m # This should not crash: see https://github.com/python/mypy/issues/2804
1787+
[builtins fixtures/dict.pyi]
1788+
17701789
[case testIncrementalPerFileFlags]
17711790
# flags: --config-file tmp/mypy.ini
17721791
import a

test-data/unit/fixtures/dict.pyi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Builtins stub used in dictionary-related test cases.
22

3-
from typing import TypeVar, Generic, Iterable, Iterator, Mapping, Tuple, overload
3+
from typing import TypeVar, Generic, Iterable, Iterator, Mapping, Tuple, overload, Optional, Union
44

55
T = TypeVar('T')
66
KT = TypeVar('KT')
@@ -19,6 +19,10 @@ class dict(Iterable[KT], Mapping[KT, VT], Generic[KT, VT]):
1919
def __setitem__(self, k: KT, v: VT) -> None: pass
2020
def __iter__(self) -> Iterator[KT]: pass
2121
def update(self, a: Mapping[KT, VT]) -> None: pass
22+
@overload
23+
def get(self, k: KT) -> Optional[VT]: pass
24+
@overload
25+
def get(self, k: KT, default: Union[KT, T]) -> Union[VT, T]: pass
2226

2327
class int: # for convenience
2428
def __add__(self, x: int) -> int: pass

0 commit comments

Comments
 (0)