Skip to content

Commit dc63432

Browse files
committed
Fix generic functions with Callable[..., T]
1 parent 77b9429 commit dc63432

File tree

4 files changed

+23
-9
lines changed

4 files changed

+23
-9
lines changed

mypy/constraints.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,15 @@ def visit_callable_type(self, template: CallableType) -> List[Constraint]:
211211
# FIX verify argument counts
212212
# FIX what if one of the functions is generic
213213
res = [] # type: List[Constraint]
214-
for i in range(len(template.arg_types)):
215-
# Negate constraints due function argument type contravariance.
216-
res.extend(negate_constraints(infer_constraints(
217-
template.arg_types[i], cactual.arg_types[i],
218-
self.direction)))
214+
215+
# We can't infer constraints from arguments if the template is Callable[..., T] (with
216+
# literal '...').
217+
if not template.is_ellipsis_args():
218+
for i in range(len(template.arg_types)):
219+
# Negate constraints due function argument type contravariance.
220+
res.extend(negate_constraints(infer_constraints(
221+
template.arg_types[i], cactual.arg_types[i],
222+
self.direction)))
219223
res.extend(infer_constraints(template.ret_type, cactual.ret_type,
220224
self.direction))
221225
return res

mypy/messages.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
Type, CallableType, Instance, TypeVarType, TupleType, UnionType, Void, NoneTyp, AnyType,
1313
Overloaded, FunctionLike
1414
)
15-
from mypy.nodes import (
16-
TypeInfo, Context, op_methods, FuncDef, reverse_type_aliases, ARG_STAR, ARG_STAR2
17-
)
15+
from mypy.nodes import TypeInfo, Context, op_methods, FuncDef, reverse_type_aliases
1816

1917

2018
# Constants that represent simple type checker error message, i.e. messages
@@ -144,7 +142,7 @@ def format(self, typ: Type, verbose: bool = False) -> str:
144142
return result
145143
elif isinstance(func, CallableType):
146144
return_type = strip_quotes(self.format(func.ret_type))
147-
if func.arg_kinds == [ARG_STAR, ARG_STAR2]:
145+
if func.is_ellipsis_args():
148146
return 'Callable[..., {}]'.format(return_type)
149147
arg_types = [strip_quotes(self.format(t)) for t in func.arg_types]
150148
return 'Callable[[{}], {}]'.format(", ".join(arg_types), return_type)

mypy/test/data/check-functions.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,3 +802,12 @@ def f(x: Callable[..., int]) -> None:
802802
x = 1 # E: Incompatible types in assignment (expression has type "int", variable has type Callable[..., int])
803803
[out]
804804
main: In function "f":
805+
806+
[case testCallableWithArbitraryArgsInGenericFunction]
807+
from typing import Callable, TypeVar
808+
T = TypeVar('T')
809+
def f(x: Callable[..., T]) -> T: pass
810+
def g(*x: int) -> str: pass
811+
x = f(g)
812+
x + 1 # E: Unsupported left operand type for + ("str")
813+
[builtins fixtures/list.py]

mypy/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ def items(self) -> List['CallableType']:
313313
def is_generic(self) -> bool:
314314
return bool(self.variables)
315315

316+
def is_ellipsis_args(self) -> bool:
317+
return self.arg_kinds == [mypy.nodes.ARG_STAR, mypy.nodes.ARG_STAR2]
318+
316319
def type_var_ids(self) -> List[int]:
317320
a = [] # type: List[int]
318321
for tv in self.variables:

0 commit comments

Comments
 (0)