Repository: python/mypy

Issue:
Yet another "AssertionError: Should never get here in normal mode"
Similar crash as in #5192; happening with current pip master.

```sh-session
$ # In a venv with only mypy installed.
$ git clone https://github.com/pypa/pip.git --depth=1
[...]
$ cd pip
$ git fetch origin deeb1e493d8947a957c86bf256e7f5fa91c92e52
$ git checkout deeb1e493d8947a957c86bf256e7f5fa91c92e52
$ # Populate the cache; there's 2 errors as expected.
$ mypy src
[...]
$ # This run will crash
$ mypy src
Traceback (most recent call last):
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/bin/mypy", line 11, in <module>
    sys.exit(console_entry())
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/__main__.py", line 7, in console_entry
    main(None)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/main.py", line 91, in main
    res = type_check_only(sources, bin_dir, options, flush_errors, fscache)  # noqa
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/main.py", line 148, in type_check_only
    fscache=fscache)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 183, in build
    flush_errors, fscache)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 356, in _build
    graph = dispatch(sources, manager)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 2543, in dispatch
    process_graph(graph, manager)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 2833, in process_graph
    process_fresh_modules(graph, prev_scc, manager)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 2919, in process_fresh_modules
    graph[id].fix_cross_refs()
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/build.py", line 1927, in fix_cross_refs
    self.options.use_fine_grained_cache)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/fixup.py", line 24, in fixup_module
    node_fixer.visit_symbol_table(tree.names)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/fixup.py", line 89, in visit_symbol_table
    value.node.accept(self)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/nodes.py", line 2582, in accept
    return visitor.visit_type_alias(self)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/fixup.py", line 135, in visit_type_alias
    a.target.accept(self.type_fixer)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/types.py", line 501, in accept
    return visitor.visit_instance(self)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/fixup.py", line 149, in visit_instance
    inst.type = lookup_qualified_typeinfo(self.modules, type_ref, self.quick_and_dirty)
  File "/Users/pradyunsg/.virtualenvs/tmp-646a2fd8b91d920/lib/python3.7/site-packages/mypy/fixup.py", line 239, in lookup_qualified_typeinfo
    assert quick_and_dirty, "Should never get here in normal mode"
AssertionError: Should never get here in normal mode
```

I haven't tested with master (internet access is patchy for me atm) but this does occur for mypy 0.630 on Python 3.7.0.


Discussion:
Doing `rm -r .mypy_cache/3.7/pip/_vendor/` before a second run prevents this crash.

I still see the crash on master. I am investigating now.
OK, it looks like the code causing the crash is also similar to the previous one (now in `urllib3`):
```python
try:  # Python 3:
    # Not a no-op, we're adding this to the namespace so it can be imported.
    ConnectionError = ConnectionError
except NameError:  # Python 2:
    class ConnectionError(Exception):
        pass
```
I will try to write a simple repro now.
OK, the minimal repro is as simple as this:
```
[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]
```
Also it looks like this is a regression since 0.620, caused by #5565

The fix is straightforward, the only question is does this warrant a bug-fix release 0.631?
> The fix is straightforward, the only question is does this warrant a bug-fix release 0.631?

Let's wait first if there are other reports of this issue. If not, we can release 0.640 in ~two weeks, on a slightly accelerated schedule. If there are other reports, a bug-fix release may make sense.

Resolving patch:
diff --git a/mypy/fixup.py b/mypy/fixup.py
--- 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
--- 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


Test patch:
diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test
--- a/test-data/unit/check-incremental.test
+++ b/test-data/unit/check-incremental.test
@@ -5193,3 +5193,117 @@ 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]
+[out2]
+
+[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]
+[out2]
+
+[case testConditionalExceptionAliasOverride]
+import a
+[file a.py]
+import lib
+try:
+    x = 1
+except lib.Exception as e:
+    pass
+[file a.py.2]
+import lib
+try:
+    x = 2
+except lib.Exception as e:
+    pass
+[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]
+[out]
+[out2]
diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test
--- a/test-data/unit/check-type-aliases.test
+++ b/test-data/unit/check-type-aliases.test
@@ -518,3 +518,42 @@ 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]
+[out]