From 16bf5bdcb91deefdb48abcea634381417ad82032 Mon Sep 17 00:00:00 2001 From: elazar Date: Sat, 28 Jan 2017 21:40:13 +0200 Subject: [PATCH 1/4] treat varargs as legal context --- mypy/checkexpr.py | 2 +- test-data/unit/check-inference.test | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 79454d029ee2..af9eea0dee44 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1799,7 +1799,7 @@ 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 if callable_ctx.arg_kinds != arg_kinds: # Incompatible context; cannot use it to infer types. self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 799fb3525d70..9eb49926cd49 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1033,7 +1033,18 @@ 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 return value type (got "int", expected None) + pass +[out] +main:6: error: Incompatible types in assignment (expression has type Callable[[StarArg(Any), KwArg(Any)], int], variable has type Callable[..., None]) +[builtins fixtures/dict.pyi] -- Boolean operators -- ----------------- From 08237f580b0fdada656e22adaeafcbf3dd418643 Mon Sep 17 00:00:00 2001 From: elazar Date: Thu, 2 Feb 2017 23:29:00 +0200 Subject: [PATCH 2/4] add test for #2790 and fix crash --- mypy/checker.py | 2 +- mypy/checkexpr.py | 2 +- test-data/unit/check-inference.test | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) 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 af9eea0dee44..fc631e72987b 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1752,7 +1752,6 @@ 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) if e.expr() not in self.chk.type_map: self.accept(e.expr()) ret_type = self.chk.type_map[e.expr()] @@ -1805,6 +1804,7 @@ def infer_lambda_type_using_context(self, e: FuncExpr) -> Optional[CallableType] self.chk.fail(messages.CANNOT_INFER_LAMBDA_TYPE, e) return None + self.chk.check_func_item(e, type_override=callable_ctx) return callable_ctx def visit_super_expr(self, e: SuperExpr) -> Type: diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 9eb49926cd49..565fcf125dbd 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1039,10 +1039,14 @@ 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 return value type (got "int", expected None) +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 + +[case testLambdaVarargContext] +# Should not crash +from typing import Callable +def f(a: Callable[[int, int, int], int] = lambda *a, **k: 1): pass -[out] -main:6: error: Incompatible types in assignment (expression has type Callable[[StarArg(Any), KwArg(Any)], int], variable has type Callable[..., None]) [builtins fixtures/dict.pyi] -- Boolean operators From b3318c04b91076b98a52b8dcc47a03b4cd9f193d Mon Sep 17 00:00:00 2001 From: elazar Date: Thu, 2 Feb 2017 23:31:48 +0200 Subject: [PATCH 3/4] check vararg without type_override --- mypy/checkexpr.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index fc631e72987b..9d02578659c6 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1798,6 +1798,7 @@ 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 + self.chk.check_func_item(e) return callable_ctx if callable_ctx.arg_kinds != arg_kinds: # Incompatible context; cannot use it to infer types. From 85d696f25077524a1c388a704d6725c6e9dfc316 Mon Sep 17 00:00:00 2001 From: elazar Date: Thu, 2 Feb 2017 23:45:35 +0200 Subject: [PATCH 4/4] return the parameter for type_override --- mypy/checkexpr.py | 17 +++++++++-------- test-data/unit/check-inference.test | 3 ++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 9d02578659c6..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,6 +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=type_override) if e.expr() not in self.chk.type_map: self.accept(e.expr()) ret_type = self.chk.type_map[e.expr()] @@ -1762,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] @@ -1776,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; @@ -1798,15 +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 - self.chk.check_func_item(e) - return callable_ctx + 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 - self.chk.check_func_item(e, type_override=callable_ctx) - 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 565fcf125dbd..0585f70ea78a 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1041,14 +1041,15 @@ def f(a: Callable[..., None] = lambda *a, **k: None): 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 -- -----------------