Skip to content

Commit 09c1371

Browse files
committed
Make infer_lambda_type_using_context always set lambda fallback
Fixes #9234 This diff fixes a bug in `infer_lambda_type_using_context` where it blindly trusted and reused whatever fallback the context callable was using. This causes mypy to crash in the case where the context was a dynamic constructor. This is because... 1. The constructor has a fallback of `builtins.type` 2. The `infer_lambda_type_using_context` returns a CallableType with this fallback. 3. The join of the LHS and RHS of the ternary ends up being a `def (Any) -> Any` with a fallback of `builtins.type` -- see https://github.com/python/mypy/blob/7ffaf230a3984faaf848fe314cf275b854a0cdb0/mypy/join.py#L578 4. Later, we call `CallableType.is_type_obj()` and `CallableType.type_object()`. The former is supposed to be a guard for the former, but what happens instead is that the former succeeds due to the fallback and the latter fails an assert because the return type is Any, not an Instance: https://github.com/python/mypy/blob/7ffaf230a3984faaf848fe314cf275b854a0cdb0/mypy/types.py#L1771 I opted to fix this by modifying `infer_lambda_type_using_context` so it overrides the fallback to always be `builtins.function` -- I don't think it makes sense for it to be anything else.
1 parent 38eb6e8 commit 09c1371

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

mypy/checkexpr.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4230,6 +4230,10 @@ def infer_lambda_type_using_context(
42304230
callable_ctx = get_proper_type(replace_meta_vars(ctx, ErasedType()))
42314231
assert isinstance(callable_ctx, CallableType)
42324232

4233+
# The callable_ctx may have a fallback of builtins.type if the context
4234+
# is a constructor -- but this fallback doesn't make sense for lambdas.
4235+
callable_ctx = callable_ctx.copy_modified(fallback=self.named_type("builtins.function"))
4236+
42334237
if callable_ctx.type_guard is not None:
42344238
# Lambda's return type cannot be treated as a `TypeGuard`,
42354239
# because it is implicit. And `TypeGuard`s must be explicit.

test-data/unit/check-inference.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,21 @@ class A:
12761276
def h(x: Callable[[], int]) -> None:
12771277
pass
12781278

1279+
[case testLambdaJoinWithDynamicConstructor]
1280+
from typing import Any, Union
1281+
1282+
class Wrapper:
1283+
def __init__(self, x: Any) -> None: ...
1284+
1285+
def f(cond: bool) -> Any:
1286+
f = Wrapper if cond else lambda x: x
1287+
reveal_type(f) # N: Revealed type is "def (x: Any) -> Any"
1288+
return f(3)
1289+
1290+
def g(cond: bool) -> Any:
1291+
f = lambda x: x if cond else Wrapper
1292+
reveal_type(f) # N: Revealed type is "def (x: Any) -> Any"
1293+
return f(3)
12791294

12801295
-- Boolean operators
12811296
-- -----------------

0 commit comments

Comments
 (0)