Skip to content

Commit 393e9ab

Browse files
authored
Mitigate a regression in the external context (#6006)
Mitigates #5738 by reverting heuristics for type variable return vs instance type outer context changed in #5699. Both versions are kind of unprincipled, but the old one _seems_ to work better in real codebases. This doesn't touch the core fixes in #5699
1 parent 8dafdc8 commit 393e9ab

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

mypy/checkexpr.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
TupleType, TypedDictType, Instance, TypeVarType, ErasedType, UnionType,
2121
PartialType, DeletedType, UninhabitedType, TypeType, TypeOfAny, LiteralType,
2222
true_only, false_only, is_named_instance, function_type, callable_type, FunctionLike,
23-
StarType, is_optional, remove_optional, is_invariant_instance
23+
StarType, is_optional, remove_optional, is_generic_instance
2424
)
2525
from mypy.nodes import (
2626
NameExpr, RefExpr, Var, FuncDef, OverloadedFuncDef, TypeInfo, CallExpr,
@@ -885,13 +885,13 @@ def infer_function_type_arguments_using_context(
885885
# variables in an expression are inferred at the same time.
886886
# (And this is hard, also we need to be careful with lambdas that require
887887
# two passes.)
888-
if isinstance(ret_type, TypeVarType) and not is_invariant_instance(ctx):
888+
if isinstance(ret_type, TypeVarType) and not is_generic_instance(ctx):
889889
# Another special case: the return type is a type variable. If it's unrestricted,
890890
# we could infer a too general type for the type variable if we use context,
891891
# and this could result in confusing and spurious type errors elsewhere.
892892
#
893893
# Give up and just use function arguments for type inference. As an exception,
894-
# if the context is an invariant instance type, actually use it as context, as
894+
# if the context is a generic instance type, actually use it as context, as
895895
# this *seems* to usually be the reasonable thing to do.
896896
#
897897
# See also github issues #462 and #360.

mypy/types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,10 @@ def union_items(typ: Type) -> List[Type]:
20562056
return [typ]
20572057

20582058

2059+
def is_generic_instance(tp: Type) -> bool:
2060+
return isinstance(tp, Instance) and bool(tp.args)
2061+
2062+
20592063
def is_invariant_instance(tp: Type) -> bool:
20602064
if not isinstance(tp, Instance) or not tp.args:
20612065
return False

test-data/unit/check-inference-context.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,3 +1283,29 @@ def f(x: Optional[T] = None) -> List[T]: ...
12831283

12841284
y: List[str] = f() # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[str]")
12851285
[builtins fixtures/list.pyi]
1286+
1287+
[case testUseCovariantGenericOuterContext]
1288+
from typing import TypeVar, Callable, Tuple
1289+
1290+
T = TypeVar('T')
1291+
1292+
def f(x: Callable[..., T]) -> T:
1293+
return x()
1294+
1295+
x: Tuple[str, ...] = f(tuple)
1296+
[builtins fixtures/tuple.pyi]
1297+
[out]
1298+
1299+
[case testUseCovariantGenericOuterContextUserDefined]
1300+
from typing import TypeVar, Callable, Generic
1301+
1302+
T_co = TypeVar('T_co', covariant=True)
1303+
T = TypeVar('T')
1304+
1305+
class G(Generic[T_co]): ...
1306+
1307+
def f(x: Callable[..., T]) -> T:
1308+
return x()
1309+
1310+
x: G[str] = f(G)
1311+
[out]

0 commit comments

Comments
 (0)