Repository: python/mypy (Python)

Issue:
Crash with nested partial type
**Crash Report**

Stumbled across this one while testing the latest master commit on Home Assistant (with dependencies).
A dependency (https://github.com/caronc/apprise) uses the pattern below which results in a crash.

I bisected the issue to the changes in #13494.

Direct link to the line which causes the crash:
https://github.com/caronc/apprise/blob/v1.0.0/apprise/decorators/CustomNotifyPlugin.py#L148

**Traceback**

```
(venv-39) $ mypy --show-traceback --no-incremental test.py
test.py:9: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.980+dev.be495c72f551fe94748edafacc747eb07b252f5c
Traceback (most recent call last):
  ...
  File ".../mypy/mypy/subtypes.py", line 888, in visit_partial_type
    raise RuntimeError(f'Partial type "{left}" cannot be checked with "issubtype()"')
RuntimeError: Partial type "<partial dict[?, ?]>" cannot be checked with "issubtype()"
test.py:9: : note: use --pdb to drop into pdb
```

<details>
<summary>Full traceback</summary>

```
(venv-39) $ mypy --show-traceback --no-incremental test.py
test.py:9: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.980+dev.be495c72f551fe94748edafacc747eb07b252f5c
Traceback (most recent call last):
  File ".../venv-39/bin/mypy", line 8, in <module>
    sys.exit(console_entry())
  File ".../mypy/mypy/__main__.py", line 15, in console_entry
    main()
  File ".../mypy/mypy/main.py", line 95, in main
    res, messages, blockers = run_build(sources, options, fscache, t0, stdout, stderr)
  File ".../mypy/mypy/main.py", line 174, in run_build
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File ".../mypy/mypy/build.py", line 186, in build
    result = _build(
  File ".../mypy/mypy/build.py", line 269, in _build
    graph = dispatch(sources, manager, stdout)
  File ".../mypy/mypy/build.py", line 2875, in dispatch
    process_graph(graph, manager)
  File ".../mypy/mypy/build.py", line 3259, in process_graph
    process_stale_scc(graph, scc, manager)
  File ".../mypy/mypy/build.py", line 3360, in process_stale_scc
    graph[id].type_check_first_pass()
  File ".../mypy/mypy/build.py", line 2302, in type_check_first_pass
    self.type_checker().check_first_pass()
  File ".../mypy/mypy/checker.py", line 461, in check_first_pass
    self.accept(d)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1131, in accept
    return visitor.visit_class_def(self)
  File ".../mypy/mypy/checker.py", line 2035, in visit_class_def
    self.accept(defn.defs)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1206, in accept
    return visitor.visit_block(self)
  File ".../mypy/mypy/checker.py", line 2415, in visit_block
    self.accept(s)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 908, in accept
    return visitor.visit_decorator(self)
  File ".../mypy/mypy/checker.py", line 4333, in visit_decorator
    self.check_func_item(e.func, name=e.func.name)
  File ".../mypy/mypy/checker.py", line 1000, in check_func_item
    self.check_func_def(defn, typ, name)
  File ".../mypy/mypy/checker.py", line 1186, in check_func_def
    self.accept(item.body)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1206, in accept
    return visitor.visit_block(self)
  File ".../mypy/mypy/checker.py", line 2415, in visit_block
    self.accept(s)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1131, in accept
    return visitor.visit_class_def(self)
  File ".../mypy/mypy/checker.py", line 2035, in visit_class_def
    self.accept(defn.defs)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1206, in accept
    return visitor.visit_block(self)
  File ".../mypy/mypy/checker.py", line 2415, in visit_block
    self.accept(s)
  File ".../mypy/mypy/checker.py", line 569, in accept
    stmt.accept(self)
  File ".../mypy/mypy/nodes.py", line 1289, in accept
    return visitor.visit_assignment_stmt(self)
  File ".../mypy/mypy/checker.py", line 2462, in visit_assignment_stmt
    self.check_assignment(s.lvalues[-1], s.rvalue, s.type is None, s.new_syntax)
  File ".../mypy/mypy/checker.py", line 2683, in check_assignment
    type_context = self.get_variable_type_context(inferred)
  File ".../mypy/mypy/checker.py", line 2712, in get_variable_type_context
    elif not is_subtype(candidate, other):
  File ".../mypy/mypy/subtypes.py", line 178, in is_subtype
    return _is_subtype(left, right, subtype_context, proper_subtype=False)
  File ".../mypy/mypy/subtypes.py", line 328, in _is_subtype
    return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype))
  File ".../mypy/mypy/types.py", line 2618, in accept
    return visitor.visit_partial_type(self)
  File ".../mypy/mypy/subtypes.py", line 888, in visit_partial_type
    raise RuntimeError(f'Partial type "{left}" cannot be checked with "issubtype()"')
RuntimeError: Partial type "<partial dict[?, ?]>" cannot be checked with "issubtype()"
test.py:9: : note: use --pdb to drop into pdb
```
</details>

**To Reproduce**

```py
class A:
    args = {}

    @staticmethod
    def f():
        value = {1: "Hello"}

        class B(A):
            args = value  # <-- crash
```

**Expected**
```
test.py:2: error: Need type annotation for "args" (hint: "args: Dict[<type>, <type>] = ...")
```

**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: `mypy 0.980+dev.09b8b550abe3982726047cc0ed68a9b6fa91745c (compiled: no)` (latest master)
- Python version used: `3.9`


Hints:

Patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -2709,8 +2709,10 @@ def get_variable_type_context(self, inferred: Var) -> Type | None:
         if inferred.info:
             for base in inferred.info.mro[1:]:
                 base_type, base_node = self.lvalue_type_from_base(inferred, base)
-                if base_type and not (
-                    isinstance(base_node, Var) and base_node.invalid_partial_type
+                if (
+                    base_type
+                    and not (isinstance(base_node, Var) and base_node.invalid_partial_type)
+                    and not isinstance(base_type, PartialType)
                 ):
                     type_contexts.append(base_type)
         # Use most derived supertype as type context if available.
@@ -2813,6 +2815,8 @@ def check_compatibility_all_supers(
                     continue
 
                 base_type, base_node = self.lvalue_type_from_base(lvalue_node, base)
+                if isinstance(base_type, PartialType):
+                    base_type = None
 
                 if base_type:
                     assert base_node is not None


Test patch:
diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test
--- a/test-data/unit/check-inference.test
+++ b/test-data/unit/check-inference.test
@@ -3328,3 +3328,12 @@ class C(P, M):
     x = []  # E: Need type annotation for "x" (hint: "x: List[<type>] = ...")
 reveal_type(C.x)  # N: Revealed type is "builtins.list[Any]"
 [builtins fixtures/list.pyi]
+
+[case testNoPartialInSupertypeAsContext]
+class A:
+    args = {}  # E: Need type annotation for "args" (hint: "args: Dict[<type>, <type>] = ...")
+    def f(self) -> None:
+        value = {1: "Hello"}
+        class B(A):
+            args = value
+[builtins fixtures/dict.pyi]