Skip to content

Commit 741543f

Browse files
rwbartonddfisher
authored andcommitted
Improve handling of "lambda: None" (#1557)
"lambda: None" might be used either where a function returning an Optional[T] is expected, or where a function not returning a value is expected. Previously it would always treated as the former; now the context is used to decide. When no context is available, mypy continues to treat the lambda as returning the value None, rather than no value at all. When the other meaning is desired, it is generally possible to provide a context, or in any case to use a function defined with `def`. Fixes #1425.
1 parent 584f8f3 commit 741543f

File tree

3 files changed

+23
-0
lines changed

3 files changed

+23
-0
lines changed

Diff for: mypy/checkexpr.py

+5
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,11 @@ def visit_func_expr(self, e: FuncExpr) -> Type:
13471347
if e.expr() not in self.chk.type_map:
13481348
self.accept(e.expr())
13491349
ret_type = self.chk.type_map[e.expr()]
1350+
if isinstance(ret_type, NoneTyp):
1351+
# For "lambda ...: None", just use type from the context.
1352+
# Important when the context is Callable[..., None] which
1353+
# really means Void. See #1425.
1354+
return inferred_type
13501355
return replace_callable_return_type(inferred_type, ret_type)
13511356

13521357
def infer_lambda_type_using_context(self, e: FuncExpr) -> CallableType:

Diff for: test-data/unit/check-inference-context.test

+7
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,13 @@ T = TypeVar('T')
611611
def foo(arg: Callable[..., T]) -> None: pass
612612
foo(lambda: 1)
613613

614+
[case testLambdaNoneInContext]
615+
from typing import Callable
616+
def f(x: Callable[[], None]) -> None: pass
617+
def g(x: Callable[[], int]) -> None: pass
618+
f(lambda: None)
619+
g(lambda: None)
620+
614621

615622
-- Overloads + generic functions
616623
-- -----------------------------

Diff for: test-data/unit/check-inference.test

+11
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,17 @@ y = f(lambda x: x, 1) # Fail
10411041
main:4: error: Cannot infer type argument 1 of "f"
10421042
main:4: error: Argument 2 to "f" has incompatible type "int"; expected "str"
10431043

1044+
[case testInferLambdaNone]
1045+
from typing import Callable
1046+
def f(x: Callable[[], None]) -> None: pass
1047+
def g(x: Callable[[], int]) -> None: pass
1048+
a = lambda: None
1049+
f(a) # E: Argument 1 to "f" has incompatible type Callable[[], None]; expected Callable[[], None]
1050+
g(a)
1051+
b = lambda: None # type: Callable[[], None]
1052+
f(b)
1053+
g(b) # E: Argument 1 to "g" has incompatible type Callable[[], None]; expected Callable[[], int]
1054+
10441055

10451056
-- Boolean operators
10461057
-- -----------------

0 commit comments

Comments
 (0)