Repository: python/mypy

Issue:
[1.16 regression] Internal error: must never apply partial type
<!--
  Use this form only if mypy reports an "INTERNAL ERROR" and/or gives a traceback.
  Please include the traceback and all other messages below (use `mypy --show-traceback`).
-->

**Crash Report**

mypy crash with message:

    Internal error: must never apply partial type

**Traceback**

```
main.py:19: 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: 1.16.0
Traceback (most recent call last):
  File "mypy/checkexpr.py", line 5926, in accept
  File "mypy/nodes.py", line 2018, in accept
  File "mypy/checkexpr.py", line 488, in visit_call_expr
  File "mypy/checkexpr.py", line 622, in visit_call_expr_inner
  File "mypy/checkexpr.py", line 1478, in check_call_expr_with_callee_type
  File "mypy/checkexpr.py", line 1591, in check_call
  File "mypy/checkexpr.py", line 2724, in check_overload_call
  File "mypy/checkexpr.py", line 2885, in infer_overload_return_type
  File "mypy/checkexpr.py", line 1580, in check_call
  File "mypy/checkexpr.py", line 1752, in check_callable_call
  File "mypy/checkexpr.py", line 2054, in infer_function_type_arguments_using_context
  File "mypy/checkexpr.py", line 3260, in apply_generic_arguments
  File "mypy/applytype.py", line 112, in apply_generic_arguments
AssertionError: Internal error: must never apply partial type
main.py:19: : note: use --pdb to drop into pdb
```

**To Reproduce**

main.py:

    from typing import overload, TypeVar, Optional, Protocol

    T = TypeVar('T')


    class DbManager(Protocol):
        @overload
        def get(self, key: str) -> Optional[T]:
            pass

        @overload
        def get(self, key: str, default: T) -> T:
            pass


    class Foo:
        def __init__(self, db: DbManager, bar: bool):
            if bar:
                self.qux = db.get('qux')
            else:
                self.qux = {}

run mypy:

    mypy --show-traceback main.py

**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 1.16.0
- Mypy command-line flags:
- Mypy configuration options from `mypy.ini` (and other config files):
- Python version used: 3.11.1
- Operating system and version: Ubuntu 20.04.6 LTS

<!--
You can freely edit this text, please remove all the lines
you believe are unnecessary.
-->

with mypy 1.15.0, I got error:

    main.py:21: error: Need type annotation for "qux" (hint: "qux: dict[<type>, <type>] = ...")  [var-annotated]
    Found 1 error in 1 file (checked 1 source file)

But with mypy 1.16.0, I got error:

    main.py:19: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
    https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
    If this issue continues with mypy master, please report a bug at https://github.com/python/mypy/issues
    version: 1.16.0
    main.py:19: : note: please use --show-traceback to print a traceback when reporting a bug


Discussion:
Thanks for the report, bisects to #18847
The snippet has obvious typing error, but hard crash is certainly too much... MRE without overload:

```python
from typing import TypeVar, Protocol

T = TypeVar('T')

class DbManager(Protocol):
    def get(self, key: str) -> T | None:
        pass

class Foo:
    def __init__(self, db: DbManager) -> None:
        self.qux = db.get('qux')
```

Note that `T` instead of `T | None` prevents crash.
@sterliakov Essentially the crash happens in the case where the outer (return) type context is used. I used the original example in the test before seeing your comment, but I think it is OK.



Patch:
diff --git a/mypy/checker.py b/mypy/checker.py
index e83473492f01..5201037242ac 100644
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -3427,7 +3427,9 @@ def check_compatibility_all_supers(self, lvalue: RefExpr, rvalue: Expression) ->
             # store the rvalue type on the variable.
             actual_lvalue_type = None
             if lvalue_node.is_inferred and not lvalue_node.explicit_self_type:
-                rvalue_type = self.expr_checker.accept(rvalue, lvalue_node.type)
+                # Don't use partial types as context, similar to regular code path.
+                ctx = lvalue_node.type if not isinstance(lvalue_node.type, PartialType) else None
+                rvalue_type = self.expr_checker.accept(rvalue, ctx)
                 actual_lvalue_type = lvalue_node.type
                 lvalue_node.type = rvalue_type
             lvalue_type, _ = self.node_type_from_base(lvalue_node.name, lvalue_node.info, lvalue)


Test patch:
diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test
index 4a3930533954..b563eef0f8aa 100644
--- a/test-data/unit/check-inference.test
+++ b/test-data/unit/check-inference.test
@@ -4128,3 +4128,24 @@ T = TypeVar("T")
 def f(x: Optional[T]) -> T: ...
 reveal_type(f(a))  # N: Revealed type is "Any"
 reveal_type(f(oa))  # N: Revealed type is "Any"
+
+[case testNoCrashOnPartialTypeAsContext]
+from typing import overload, TypeVar, Optional, Protocol
+
+T = TypeVar("T")
+class DbManager(Protocol):
+    @overload
+    def get(self, key: str) -> Optional[T]:
+        pass
+
+    @overload
+    def get(self, key: str, default: T) -> T:
+        pass
+
+class Foo:
+    def __init__(self, db: DbManager, bar: bool) -> None:
+        if bar:
+            self.qux = db.get("qux")
+        else:
+            self.qux = {}  # E: Need type annotation for "qux" (hint: "qux: dict[<type>, <type>] = ...")
+[builtins fixtures/dict.pyi]