Repository: python/mypy

Issue:
New semantic analyzer: support recursive TypedDicts and NamedTuples
These have (limited) support in old analyzer, with new semantic analyzer they just crash.


Discussion:
There are some tests skipped with `--no-new-semantic-analyzer` that needs to be fixed.
Recursive type aliases are similar.
I will take care of this issue.
I have a work-in-progress branch that turns these into blocking errors.
I think that this is now mostly resolved. Added #7111 as a follow-up issue.
@JukkaL 
> I think that this is now mostly resolved. Added #7111 as a follow-up issue.

There are 7 tests that refer to this issue as an excuse, should we enable them first?
```
test-data/unit/check-classes.test:4358:# FIXME: #6445
test-data/unit/check-classes.test:4367:# FIXME: #6445
test-data/unit/check-classes.test:4375:# FIXME: #6445
test-data/unit/check-classes.test:4390:# FIXME: #6445
test-data/unit/check-unions.test:960:# https://github.com/python/mypy/issues/6445
test-data/unit/check-flags.test:1056:# Crashes on new semantic analyzer: https://github.com/python/mypy/issues/6445
test-data/unit/check-flags.test:1065:# Crashes on new semantic analyzer: https://github.com/python/mypy/issues/6445
```
Yeah, let's go through all of those issues firs.

Resolving patch:
diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py
--- a/mypy/newsemanal/semanal.py
+++ b/mypy/newsemanal/semanal.py
@@ -2398,13 +2398,14 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
                 # Otherwise just replace existing placeholder with type alias.
                 existing.node = alias_node
                 updated = True
-            if self.final_iteration:
-                self.cannot_resolve_name(lvalue.name, 'name', s)
-                return True
-            elif updated:
-                self.progress = True
-                # We need to defer so that this change can get propagated to base classes.
-                self.defer()
+            if updated:
+                if self.final_iteration:
+                    self.cannot_resolve_name(lvalue.name, 'name', s)
+                    return True
+                else:
+                    self.progress = True
+                    # We need to defer so that this change can get propagated to base classes.
+                    self.defer()
         else:
             self.add_symbol(lvalue.name, alias_node, s)
         if isinstance(rvalue, RefExpr) and isinstance(rvalue.node, TypeAlias):


Test patch:
diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test
--- a/test-data/unit/check-classes.test
+++ b/test-data/unit/check-classes.test
@@ -4355,7 +4355,6 @@ class A(Tuple[int, str]): pass
 -- -----------------------
 
 [case testCrashOnSelfRecursiveNamedTupleVar]
-# FIXME: #6445
 # flags: --new-semantic-analyzer
 from typing import NamedTuple
 
@@ -4364,7 +4363,6 @@ n: N
 reveal_type(n) # N: Revealed type is 'Tuple[Any, fallback=__main__.N]'
 
 [case testCrashOnSelfRecursiveTypedDictVar]
-# FIXME: #6445
 from mypy_extensions import TypedDict
 
 A = TypedDict('A', {'a': 'A'})  # type: ignore
@@ -4372,7 +4370,6 @@ a: A
 [builtins fixtures/isinstancelist.pyi]
 
 [case testCrashInJoinOfSelfRecursiveNamedTuples]
-# FIXME: #6445
 # flags: --new-semantic-analyzer
 from typing import NamedTuple
 
@@ -4387,7 +4384,6 @@ lst = [n, m]
 [builtins fixtures/isinstancelist.pyi]
 
 [case testCorrectJoinOfSelfRecursiveTypedDicts]
-# FIXME: #6445
 # flags: --new-semantic-analyzer
 from mypy_extensions import TypedDict
 
diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test
--- a/test-data/unit/check-flags.test
+++ b/test-data/unit/check-flags.test
@@ -1053,8 +1053,7 @@ always_false = BLAH, BLAH1
 [builtins fixtures/bool.pyi]
 
 [case testCheckDisallowAnyGenericsNamedTuple]
-# Crashes on new semantic analyzer: https://github.com/python/mypy/issues/6445
-# flags: --disallow-any-generics --no-new-semantic-analyzer
+# flags: --disallow-any-generics --new-semantic-analyzer
 from typing import NamedTuple
 
 N = NamedTuple('N', [('x', N)])  # type: ignore
@@ -1062,23 +1061,21 @@ n: N
 [out]
 
 [case testCheckDisallowAnyGenericsTypedDict]
-# Crashes on new semantic analyzer: https://github.com/python/mypy/issues/6445
-# flags: --disallow-any-generics --no-new-semantic-analyzer
+# flags: --disallow-any-generics --new-semantic-analyzer
 from typing import Dict, Any, Optional
 from mypy_extensions import TypedDict
 
 VarsDict = Dict[str, Any]
 HostsDict = Dict[str, Optional[VarsDict]]
 
-GroupDataDict = TypedDict(  # type: ignore
-    "GroupDataDict", {"children": "GroupsDict",
+GroupDataDict = TypedDict(
+    "GroupDataDict", {"children": "GroupsDict",  # type: ignore
                       "vars": VarsDict,
                       "hosts": HostsDict}, total=False
 )
 
 GroupsDict = Dict[str, GroupDataDict]  # type: ignore
 [builtins fixtures/dict.pyi]
-[out]
 
 [case testCheckDefaultAllowAnyGeneric]
 from typing import TypeVar, Callable
diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test
--- a/test-data/unit/check-unions.test
+++ b/test-data/unit/check-unions.test
@@ -957,13 +957,10 @@ def takes_int(arg: int) -> None: pass
 takes_int(x)  # E: Argument 1 to "takes_int" has incompatible type <union: 6 items>; expected "int"
 
 [case testRecursiveForwardReferenceInUnion]
-# https://github.com/python/mypy/issues/6445
 # flags: --new-semantic-analyzer
 from typing import List, Union
-MYTYPE = List[Union[str, "MYTYPE"]]
+MYTYPE = List[Union[str, "MYTYPE"]] # E: Cannot resolve name "MYTYPE" (possible cyclic definition)
 [builtins fixtures/list.pyi]
-[out]
-main:4: error: Cannot resolve name "MYTYPE" (possible cyclic definition)
 
 [case testNonStrictOptional]
 from typing import Optional, List