diff --git a/mypy/checker.py b/mypy/checker.py index bde5d7fc9ad0..ecc5d9473e45 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -614,7 +614,7 @@ def is_implicit_any(t: Type) -> bool: .format(erased, ref_type), defn) elif isinstance(arg_type, TypeVarType): # Refuse covariant parameter type variables - # TODO: check recuresively for inner type variables + # TODO: check recursively for inner type variables if arg_type.variance == COVARIANT: self.fail(messages.FUNCTION_PARAMETER_CANNOT_BE_COVARIANT, arg_type) if typ.arg_kinds[i] == nodes.ARG_STAR: diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 79454d029ee2..fa77425db204 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1742,7 +1742,7 @@ def visit_dict_expr(self, e: DictExpr) -> Type: def visit_func_expr(self, e: FuncExpr) -> Type: """Type check lambda expression.""" - inferred_type = self.infer_lambda_type_using_context(e) + inferred_type, type_override = self.infer_lambda_type_using_context(e) if not inferred_type: # No useful type context. ret_type = self.accept(e.expr()) @@ -1752,7 +1752,7 @@ def visit_func_expr(self, e: FuncExpr) -> Type: return callable_type(e, fallback, ret_type) else: # Type context available. - self.chk.check_func_item(e, type_override=inferred_type) + self.chk.check_func_item(e, type_override=type_override) if e.expr() not in self.chk.type_map: self.accept(e.expr()) ret_type = self.chk.type_map[e.expr()] @@ -1763,10 +1763,12 @@ def visit_func_expr(self, e: FuncExpr) -> Type: return inferred_type return replace_callable_return_type(inferred_type, ret_type) - def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType]: + def infer_lambda_type_using_context(self, e: FuncExpr) -> Tuple[Optional[CallableType], + Optional[CallableType]]: """Try to infer lambda expression type using context. Return None if could not infer type. + The second item in the return type is the type_override parameter for check_func_item. """ # TODO also accept 'Any' context ctx = self.chk.type_context[-1] @@ -1777,7 +1779,7 @@ def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType] ctx = callables[0] if not ctx or not isinstance(ctx, CallableType): - return None + return None, None # The context may have function type variables in it. We replace them # 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] if ARG_STAR in arg_kinds or ARG_STAR2 in arg_kinds: # TODO treat this case appropriately - return None + return callable_ctx, None if callable_ctx.arg_kinds != arg_kinds: # Incompatible context; cannot use it to infer types. self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e) - return None + return None, None - return callable_ctx + return callable_ctx, callable_ctx def visit_super_expr(self, e: SuperExpr) -> Type: """Type check a super expression (non-lvalue).""" diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 799fb3525d70..0585f70ea78a 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1033,6 +1033,22 @@ b = lambda: None # type: Callable[[], None] f(b) g(b) # E: Argument 1 to "g" has incompatible type Callable[[], None]; expected Callable[[], int] +[case testLambdaDefaultContext] +# flags: --strict-optional +from typing import Callable +def f(a: Callable[..., None] = lambda *a, **k: None): + pass + +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]) + pass +[builtins fixtures/dict.pyi] + +[case testLambdaVarargContext] +# Should not crash +from typing import Callable +def f(a: Callable[[int, int, int], int] = lambda *a, **k: 1): + pass +[builtins fixtures/dict.pyi] -- Boolean operators -- -----------------