From 44aa28893f45536bf80dbcabbb98ca1a3c0fb11e Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 18 Sep 2018 14:10:31 +0100 Subject: [PATCH 1/3] Don't crash on aliases like C = C --- mypy/fixup.py | 5 +- mypy/semanal.py | 4 ++ test-data/unit/check-incremental.test | 84 ++++++++++++++++++++++++++ test-data/unit/check-type-aliases.test | 38 ++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/mypy/fixup.py b/mypy/fixup.py index 281f5fc4a0ae..947f3bbb7afc 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -236,7 +236,10 @@ def lookup_qualified_typeinfo(modules: Dict[str, MypyFile], name: str, return node else: # Looks like a missing TypeInfo in quick mode, put something there - assert quick_and_dirty, "Should never get here in normal mode" + assert quick_and_dirty, "Should never get here in normal mode," \ + " got {}:{} instead of TypeInfo".format(type(node).__name__, + node.fullname() if node + else '') return stale_info(modules) diff --git a/mypy/semanal.py b/mypy/semanal.py index 1e24dd3ea1c1..3facb72cb729 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1931,6 +1931,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> None: res, alias_tvars, depends_on, qualified_tvars = self.analyze_alias(rvalue) if not res: return + if (isinstance(res, Instance) and res.type.name() == lvalue.name and + res.type.module_name == self.cur_mod_id): + # Aliases like C = C is a no-op. + return s.is_alias_def = True node = self.lookup(lvalue.name, lvalue) assert node is not None diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index a902a25d5ed3..3374d2df3499 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5193,3 +5193,87 @@ def f(x: str) -> None: pass [out] [out2] tmp/main.py:2: error: Argument 1 to "f" has incompatible type "int"; expected "str" + +[case testOverrideByIdemAlias] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +C = C +class C: # type: ignore + pass +[out] +[out2] + +[case testOverrideByIdemAliasReversed] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +class C: + pass +C = C # type: ignore +x: C +[out] +[out2] + +[case testOverrideByIdemAliasGeneric] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +from typing import Generic, TypeVar + +T = TypeVar('T') + +class C(Generic[T]): + pass +C = C[int] # type: ignore +x: C +[out] +[out2] + +[case testOverrideByIdemAliasImported] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +from other import C +C = C # type: ignore +x: C +[file other.py] +class C: + pass +[out] + +[case testOverrideByIdemAliasImportedReversed] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +C = C # type: ignore +from other import C +[file other.py] +class C: + pass +[out] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 44377d584cd8..5e0702e35a3e 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -518,3 +518,41 @@ def foo(x: Bogus[int]) -> None: reveal_type(x) # E: Revealed type is 'builtins.int' [builtins fixtures/dict.pyi] + +[case testOverrideByIdemAliasCorrectType] +C = C +class C: # type: ignore + pass +x: C +reveal_type(x) # E: Revealed type is '__main__.C' +[out] + +[case testOverrideByIdemAliasCorrectTypeReversed] +class C: + pass +C = C # type: ignore +x: C +reveal_type(x) # E: Revealed type is '__main__.C' +[out] + +[case testOverrideByIdemAliasCorrectTypeImported] +from other import C as B +C = B +x: C +reveal_type(x) # E: Revealed type is 'other.C' +[file other.py] +class C: + pass +[out] + +[case testConditionalExceptionAlias] +try: + E = E +except BaseException: + class E(BaseException): pass # type: ignore + +try: + pass +except E as e: + reveal_type(e) # E: Revealed type is '__main__.E' +[builtins fixtures/exception.pyi] From 8667ccf5727ec3001360fa284511b0d5348c8ac7 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 18 Sep 2018 15:22:10 +0100 Subject: [PATCH 2/3] Add a test --- test-data/unit/check-incremental.test | 20 ++++++++++++++++++++ test-data/unit/fixtures/exception.pyi | 1 + 2 files changed, 21 insertions(+) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 3374d2df3499..eff4a0930178 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5277,3 +5277,23 @@ from other import C class C: pass [out] + +[case testConditionalExceptionAliasOverride] +import a +[file a.py] +import lib +x = 1 +[file a.py.2] +import lib +x = 2 +[file lib.py] +try: + Exception = Exception +except BaseException: + class Exception(BaseException): pass # type: ignore + +try: + pass +except Exception as e: + pass +[builtins fixtures/exception.pyi] diff --git a/test-data/unit/fixtures/exception.pyi b/test-data/unit/fixtures/exception.pyi index b6810d41fd1f..f9bda1b2a042 100644 --- a/test-data/unit/fixtures/exception.pyi +++ b/test-data/unit/fixtures/exception.pyi @@ -14,3 +14,4 @@ class bool: pass class ellipsis: pass class BaseException: pass +class Exception(BaseException): pass From f533d8de5ba35d882c855389603cf4aa1858469c Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 18 Sep 2018 15:33:57 +0100 Subject: [PATCH 3/3] Tweak tests --- test-data/unit/check-incremental.test | 14 ++++++++++++-- test-data/unit/check-type-aliases.test | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index eff4a0930178..f386890280b4 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5261,6 +5261,7 @@ x: C class C: pass [out] +[out2] [case testOverrideByIdemAliasImportedReversed] import a @@ -5277,15 +5278,22 @@ from other import C class C: pass [out] +[out2] [case testConditionalExceptionAliasOverride] import a [file a.py] import lib -x = 1 +try: + x = 1 +except lib.Exception as e: + pass [file a.py.2] import lib -x = 2 +try: + x = 2 +except lib.Exception as e: + pass [file lib.py] try: Exception = Exception @@ -5297,3 +5305,5 @@ try: except Exception as e: pass [builtins fixtures/exception.pyi] +[out] +[out2] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 5e0702e35a3e..b8ebe8105213 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -556,3 +556,4 @@ try: except E as e: reveal_type(e) # E: Revealed type is '__main__.E' [builtins fixtures/exception.pyi] +[out]