From 5f2647a3ccb63b964dd0b191c2d9c73e863763c5 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 4 Dec 2018 18:17:07 +0000 Subject: [PATCH] Mitigate a regression in the external context --- mypy/checkexpr.py | 6 ++--- mypy/types.py | 4 ++++ test-data/unit/check-inference-context.test | 26 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 45e302f6595b..2b67d232a90d 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -20,7 +20,7 @@ TupleType, TypedDictType, Instance, TypeVarType, ErasedType, UnionType, PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, true_only, false_only, is_named_instance, function_type, callable_type, FunctionLike, - StarType, is_optional, remove_optional, is_invariant_instance + StarType, is_optional, remove_optional, is_generic_instance ) from mypy.nodes import ( NameExpr, RefExpr, Var, FuncDef, OverloadedFuncDef, TypeInfo, CallExpr, @@ -885,13 +885,13 @@ def infer_function_type_arguments_using_context( # variables in an expression are inferred at the same time. # (And this is hard, also we need to be careful with lambdas that require # two passes.) - if isinstance(ret_type, TypeVarType) and not is_invariant_instance(ctx): + if isinstance(ret_type, TypeVarType) and not is_generic_instance(ctx): # Another special case: the return type is a type variable. If it's unrestricted, # we could infer a too general type for the type variable if we use context, # and this could result in confusing and spurious type errors elsewhere. # # Give up and just use function arguments for type inference. As an exception, - # if the context is an invariant instance type, actually use it as context, as + # if the context is a generic instance type, actually use it as context, as # this *seems* to usually be the reasonable thing to do. # # See also github issues #462 and #360. diff --git a/mypy/types.py b/mypy/types.py index 201c40b30045..4e89cc0a7b04 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -2057,6 +2057,10 @@ def union_items(typ: Type) -> List[Type]: return [typ] +def is_generic_instance(tp: Type) -> bool: + return isinstance(tp, Instance) and bool(tp.args) + + def is_invariant_instance(tp: Type) -> bool: if not isinstance(tp, Instance) or not tp.args: return False diff --git a/test-data/unit/check-inference-context.test b/test-data/unit/check-inference-context.test index e4ac2300ff9c..20e1b04b77fe 100644 --- a/test-data/unit/check-inference-context.test +++ b/test-data/unit/check-inference-context.test @@ -1283,3 +1283,29 @@ def f(x: Optional[T] = None) -> List[T]: ... y: List[str] = f() # E: Incompatible types in assignment (expression has type "List[]", variable has type "List[str]") [builtins fixtures/list.pyi] + +[case testUseCovariantGenericOuterContext] +from typing import TypeVar, Callable, Tuple + +T = TypeVar('T') + +def f(x: Callable[..., T]) -> T: + return x() + +x: Tuple[str, ...] = f(tuple) +[builtins fixtures/tuple.pyi] +[out] + +[case testUseCovariantGenericOuterContextUserDefined] +from typing import TypeVar, Callable, Generic + +T_co = TypeVar('T_co', covariant=True) +T = TypeVar('T') + +class G(Generic[T_co]): ... + +def f(x: Callable[..., T]) -> T: + return x() + +x: G[str] = f(G) +[out]