Skip to content

Commit 624539f

Browse files
committed
Fix generic function overloading with tuple types
Fixes #1595. There were actually two issues: * Erasing tuple types was incorrect, as the fallback type was not erased. * Some tuple types got generated without a type argument, even though a uniform tuple type is internally represented as instance type tuple[t]. Similar issues might still arise in other contexts but at least this is improves things a little. Also, we generate fallback types that are like Tuple[Any, ...]. We could potentially generate a more precise fallback type, but that would potentially require joins and I'm not sure if we can use them during semantic analysis.
1 parent a9aeacc commit 624539f

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

mypy/erasetype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def visit_overloaded(self, t: Overloaded) -> Type:
6767
return t.items()[0].accept(self)
6868

6969
def visit_tuple_type(self, t: TupleType) -> Type:
70-
return t.fallback
70+
return t.fallback.accept(self)
7171

7272
def visit_union_type(self, t: UnionType) -> Type:
7373
return AnyType() # XXX: return underlying type if only one?

mypy/test/data/check-overloading.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,20 @@ def f(x: int) -> None: pass
678678
def f(x: B) -> str: pass # E: Overloaded function signatures 2 and 3 overlap with incompatible return types
679679
@overload
680680
def f(x: A) -> int: pass
681+
682+
[case testOverloadWithTupleMatchingTypeVar]
683+
from typing import TypeVar, Generic, Tuple, overload
684+
685+
T = TypeVar('T')
686+
687+
class A(Generic[T]):
688+
@overload
689+
def f(self, arg: T) -> None:
690+
pass
691+
@overload
692+
def f(self, arg: T, default: int) -> None:
693+
pass
694+
695+
b = A() # type: A[Tuple[int, int]]
696+
b.f((0, 0))
697+
b.f((0, '')) # E: Argument 1 to "f" of "A" has incompatible type "Tuple[int, str]"; expected "Tuple[int, int]"

mypy/typeanal.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type:
100100
node = self.lookup_fqn_func('builtins.tuple')
101101
info = cast(TypeInfo, node.node)
102102
return Instance(info, [t.args[0].accept(self)], t.line)
103-
return TupleType(self.anal_array(t.args),
104-
self.builtin_type('builtins.tuple'))
103+
return self.tuple_type(self.anal_array(t.args))
105104
elif fullname == 'typing.Union':
106105
items = self.anal_array(t.args)
107106
items = [item for item in items if not isinstance(item, Void)]
@@ -191,7 +190,7 @@ def visit_tuple_type(self, t: TupleType) -> Type:
191190
if star_count > 1:
192191
self.fail('At most one star type allowed in a tuple', t)
193192
return AnyType()
194-
fallback = t.fallback if t.fallback else self.builtin_type('builtins.tuple')
193+
fallback = t.fallback if t.fallback else self.builtin_type('builtins.tuple', [AnyType()])
195194
return TupleType(self.anal_array(t.items), fallback, t.line)
196195

197196
def visit_star_type(self, t: StarType) -> Type:
@@ -257,10 +256,13 @@ def anal_var_defs(self, var_defs: List[TypeVarDef]) -> List[TypeVarDef]:
257256
vd.line))
258257
return a
259258

260-
def builtin_type(self, fully_qualified_name: str) -> Instance:
259+
def builtin_type(self, fully_qualified_name: str, args: List[Type] = None) -> Instance:
261260
node = self.lookup_fqn_func(fully_qualified_name)
262261
info = cast(TypeInfo, node.node)
263-
return Instance(info, [])
262+
return Instance(info, args or [])
263+
264+
def tuple_type(self, items: List[Type]) -> TupleType:
265+
return TupleType(items, fallback=self.builtin_type('builtins.tuple', [AnyType()]))
264266

265267

266268
class TypeAnalyserPass3(TypeVisitor[None]):

0 commit comments

Comments
 (0)