Skip to content

Commit 31333d8

Browse files
elazargJukkaL
authored andcommitted
Treat varargs as legal context in default lambda argument (Take 2) (#2796)
* treat varargs as legal context * add test for #2790 and fix crash * check vararg without type_override * return the parameter for type_override
1 parent 41bae63 commit 31333d8

File tree

3 files changed

+26
-8
lines changed

3 files changed

+26
-8
lines changed

mypy/checker.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ def is_implicit_any(t: Type) -> bool:
614614
.format(erased, ref_type), defn)
615615
elif isinstance(arg_type, TypeVarType):
616616
# Refuse covariant parameter type variables
617-
# TODO: check recuresively for inner type variables
617+
# TODO: check recursively for inner type variables
618618
if arg_type.variance == COVARIANT:
619619
self.fail(messages.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, arg_type)
620620
if typ.arg_kinds[i] == nodes.ARG_STAR:

mypy/checkexpr.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,7 @@ def visit_dict_expr(self, e: DictExpr) -> Type:
17421742

17431743
def visit_func_expr(self, e: FuncExpr) -> Type:
17441744
"""Type check lambda expression."""
1745-
inferred_type = self.infer_lambda_type_using_context(e)
1745+
inferred_type, type_override = self.infer_lambda_type_using_context(e)
17461746
if not inferred_type:
17471747
# No useful type context.
17481748
ret_type = self.accept(e.expr())
@@ -1752,7 +1752,7 @@ def visit_func_expr(self, e: FuncExpr) -> Type:
17521752
return callable_type(e, fallback, ret_type)
17531753
else:
17541754
# Type context available.
1755-
self.chk.check_func_item(e, type_override=inferred_type)
1755+
self.chk.check_func_item(e, type_override=type_override)
17561756
if e.expr() not in self.chk.type_map:
17571757
self.accept(e.expr())
17581758
ret_type = self.chk.type_map[e.expr()]
@@ -1763,10 +1763,12 @@ def visit_func_expr(self, e: FuncExpr) -> Type:
17631763
return inferred_type
17641764
return replace_callable_return_type(inferred_type, ret_type)
17651765

1766-
def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType]:
1766+
def infer_lambda_type_using_context(self, e: FuncExpr) -> Tuple[Optional[CallableType],
1767+
Optional[CallableType]]:
17671768
"""Try to infer lambda expression type using context.
17681769
17691770
Return None if could not infer type.
1771+
The second item in the return type is the type_override parameter for check_func_item.
17701772
"""
17711773
# TODO also accept 'Any' context
17721774
ctx = self.chk.type_context[-1]
@@ -1777,7 +1779,7 @@ def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType]
17771779
ctx = callables[0]
17781780

17791781
if not ctx or not isinstance(ctx, CallableType):
1780-
return None
1782+
return None, None
17811783

17821784
# The context may have function type variables in it. We replace them
17831785
# since these are the type variables we are ultimately trying to infer;
@@ -1799,13 +1801,13 @@ def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType]
17991801

18001802
if ARG_STAR in arg_kinds or ARG_STAR2 in arg_kinds:
18011803
# TODO treat this case appropriately
1802-
return None
1804+
return callable_ctx, None
18031805
if callable_ctx.arg_kinds != arg_kinds:
18041806
# Incompatible context; cannot use it to infer types.
18051807
self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e)
1806-
return None
1808+
return None, None
18071809

1808-
return callable_ctx
1810+
return callable_ctx, callable_ctx
18091811

18101812
def visit_super_expr(self, e: SuperExpr) -> Type:
18111813
"""Type check a super expression (non-lvalue)."""

test-data/unit/check-inference.test

+16
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,22 @@ b = lambda: None # type: Callable[[], None]
10331033
f(b)
10341034
g(b) # E: Argument 1 to "g" has incompatible type Callable[[], None]; expected Callable[[], int]
10351035

1036+
[case testLambdaDefaultContext]
1037+
# flags: --strict-optional
1038+
from typing import Callable
1039+
def f(a: Callable[..., None] = lambda *a, **k: None):
1040+
pass
1041+
1042+
def g(a: Callable[..., None] = lambda *a, **k: 1): # E: Incompatible types in assignment (expression has type Callable[[StarArg(Any), KwArg(Any)], int], variable has type Callable[..., None])
1043+
pass
1044+
[builtins fixtures/dict.pyi]
1045+
1046+
[case testLambdaVarargContext]
1047+
# Should not crash
1048+
from typing import Callable
1049+
def f(a: Callable[[int, int, int], int] = lambda *a, **k: 1):
1050+
pass
1051+
[builtins fixtures/dict.pyi]
10361052

10371053
-- Boolean operators
10381054
-- -----------------

0 commit comments

Comments
 (0)