From 3e4a60348ac48b8b71c8e1c5aa9076f769f26f12 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Mon, 1 Jul 2019 11:56:54 +0100 Subject: [PATCH] New analyzer: use placeholder type full name correctly --- mypy/newsemanal/semanal.py | 4 +-- mypy/newsemanal/typeanal.py | 4 +-- mypy/types.py | 4 +-- test-data/unit/check-newsemanal.test | 50 ++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py index 9b5e613ddc80d..6470261f4a7cd 100644 --- a/mypy/newsemanal/semanal.py +++ b/mypy/newsemanal/semanal.py @@ -2828,7 +2828,7 @@ def process_typevar_parameters(self, args: List[Expression], # T = TypeVar('T', bound=Custom[Any]) # class Custom(Generic[T]): # ... - analyzed = PlaceholderType('', [], context.line) + analyzed = PlaceholderType(None, [], context.line) upper_bound = analyzed if isinstance(upper_bound, AnyType) and upper_bound.is_from_error: self.fail("TypeVar 'bound' must be a type", param_value) @@ -2893,7 +2893,7 @@ def analyze_value_types(self, items: List[Expression]) -> List[Type]: # Type variables are special: we need to place them in the symbol table # soon, even if some value is not ready yet, see process_typevar_parameters() # for an example. - analyzed = PlaceholderType('', [], node.line) + analyzed = PlaceholderType(None, [], node.line) result.append(analyzed) except TypeTranslationError: self.fail('Type expected', node) diff --git a/mypy/newsemanal/typeanal.py b/mypy/newsemanal/typeanal.py index 7a8b503fc875d..8cacc3fd0ae41 100644 --- a/mypy/newsemanal/typeanal.py +++ b/mypy/newsemanal/typeanal.py @@ -540,8 +540,8 @@ def visit_forwardref_type(self, t: ForwardRef) -> Type: return t def visit_placeholder_type(self, t: PlaceholderType) -> Type: - n = self.api.lookup_fully_qualified(t.fullname) - if isinstance(n.node, PlaceholderNode): + n = None if t.fullname is None else self.api.lookup_fully_qualified(t.fullname) + if not n or isinstance(n.node, PlaceholderNode): self.api.defer() # Still incomplete return t else: diff --git a/mypy/types.py b/mypy/types.py index ca2f4e085bc43..c3fe681623172 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -1871,9 +1871,9 @@ class str(Sequence[str]): ... exist. """ - def __init__(self, fullname: str, args: List[Type], line: int) -> None: + def __init__(self, fullname: Optional[str], args: List[Type], line: int) -> None: super().__init__(line) - self.fullname = fullname # Only used for debugging + self.fullname = fullname # Must be a valid full name of an actual node (or None). self.args = args def accept(self, visitor: 'TypeVisitor[T]') -> T: diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 02b1ea52097ba..b871f18b3ab06 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -2795,3 +2795,53 @@ S = TypeVar('S', covariant=True, contravariant=True) # E: TypeVar cannot be bot class Yes: ... [builtins fixtures/bool.pyi] + +[case testNewAnalyzerVarTypeVarNoCrash] +from typing import Callable, TypeVar + +FooT = TypeVar('FooT', bound='Foo') +class Foo: ... + +f = lambda x: True # type: Callable[[FooT], bool] +reveal_type(f) # N: Revealed type is 'def [FooT <: __main__.Foo] (FooT`-1) -> builtins.bool' +[builtins fixtures/bool.pyi] + +[case testNewAnalyzerVarTypeVarNoCrashImportCycle] +import a + +[file a.py] +from b import B +from typing import TypeVar + +FooT = TypeVar('FooT', bound='Foo') +class Foo: ... + +[file b.py] +from a import FooT +from typing import Callable + +f = lambda x: True # type: Callable[[FooT], bool] +reveal_type(f) # N: Revealed type is 'def [FooT <: a.Foo] (FooT`-1) -> builtins.bool' + +class B: ... +[builtins fixtures/bool.pyi] + +[case testNewAnalyzerFuncTypeVarNoCrashImportCycle] +import a + +[file a.py] +from b import B +from typing import TypeVar + +FooT = TypeVar('FooT', bound='Foo') +class Foo: ... + +[file b.py] +from a import FooT +from typing import Callable + +def f(x: FooT) -> bool: ... +reveal_type(f) # N: Revealed type is 'def [FooT <: a.Foo] (x: FooT`-1) -> builtins.bool' + +class B: ... +[builtins fixtures/bool.pyi]