diff --git a/mypy/erasetype.py b/mypy/erasetype.py index be99acabc27b..f76533e2bafd 100644 --- a/mypy/erasetype.py +++ b/mypy/erasetype.py @@ -67,7 +67,7 @@ def visit_overloaded(self, t: Overloaded) -> Type: return t.items()[0].accept(self) def visit_tuple_type(self, t: TupleType) -> Type: - return t.fallback + return t.fallback.accept(self) def visit_union_type(self, t: UnionType) -> Type: return AnyType() # XXX: return underlying type if only one? diff --git a/mypy/test/data/check-overloading.test b/mypy/test/data/check-overloading.test index bf14a433a781..2d40a82e44f5 100644 --- a/mypy/test/data/check-overloading.test +++ b/mypy/test/data/check-overloading.test @@ -678,3 +678,20 @@ def f(x: int) -> None: pass def f(x: B) -> str: pass # E: Overloaded function signatures 2 and 3 overlap with incompatible return types @overload def f(x: A) -> int: pass + +[case testOverloadWithTupleMatchingTypeVar] +from typing import TypeVar, Generic, Tuple, overload + +T = TypeVar('T') + +class A(Generic[T]): + @overload + def f(self, arg: T) -> None: + pass + @overload + def f(self, arg: T, default: int) -> None: + pass + +b = A() # type: A[Tuple[int, int]] +b.f((0, 0)) +b.f((0, '')) # E: Argument 1 to "f" of "A" has incompatible type "Tuple[int, str]"; expected "Tuple[int, int]" diff --git a/mypy/test/data/check-tuples.test b/mypy/test/data/check-tuples.test index e57d6532186d..00592b6d64d6 100644 --- a/mypy/test/data/check-tuples.test +++ b/mypy/test/data/check-tuples.test @@ -594,16 +594,18 @@ b = bool() s = t.__len__() # E: Incompatible types in assignment (expression has type "int", variable has type "str") i = t.__str__() # E: Incompatible types in assignment (expression has type "str", variable has type "int") i = s in t # E: Incompatible types in assignment (expression has type "bool", variable has type "int") -t.foo # E: "tuple" has no attribute "foo" +t.foo # E: Tuple[Any, ...] has no attribute "foo" i = t.__len__() s = t.__str__() b = s in t [file builtins.py] +from typing import TypeVar, Generic +_T = TypeVar('_T') class object: def __init__(self) -> None: pass -class tuple: +class tuple(Generic[_T]): def __len__(self) -> int: pass def __str__(self) -> str: pass def __contains__(self, o: object) -> bool: pass @@ -669,6 +671,7 @@ class A(Tuple[int, str]): a, b = self b, a = self # Error self.f('') # Error +[builtins fixtures/tuple.py] [out] main:1: note: In module imported here: tmp/m.pyi: note: In member "f" of class "A": @@ -679,6 +682,7 @@ tmp/m.pyi:7: error: Argument 1 to "f" of "A" has incompatible type "str"; expect [case testInvalidTupleBaseClass] from typing import Tuple class A(Tuple[int, str]): pass # E: Tuple[...] not supported as a base class outside a stub file +[builtins fixtures/tuple.py] [out] [case testValidTupleBaseClass] @@ -704,6 +708,7 @@ from typing import TypeVar, Generic, Tuple T = TypeVar('T') class Test(Generic[T], Tuple[T]): pass x = Test() # type: Test[int] +[builtins fixtures/tuple.py] [out] main:3: error: Tuple[...] not supported as a base class outside a stub file main:4: error: Generic tuple types not supported diff --git a/mypy/test/data/semanal-classes.test b/mypy/test/data/semanal-classes.test index 5fc310077a00..43b1dc4c3a82 100644 --- a/mypy/test/data/semanal-classes.test +++ b/mypy/test/data/semanal-classes.test @@ -572,6 +572,7 @@ import m [file m.pyi] from typing import Tuple class A(Tuple[int, str]): pass +[builtins fixtures/tuple.py] [out] MypyFile:1( Import:1(m)) @@ -583,7 +584,7 @@ MypyFile:1( TupleType( Tuple[builtins.int, builtins.str]) BaseType( - builtins.tuple) + builtins.tuple[Any]) PassStmt:2())) [case testBaseClassFromIgnoredModule] diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 0ee10da7bd92..36644d18f16f 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -100,8 +100,7 @@ def visit_unbound_type(self, t: UnboundType) -> Type: node = self.lookup_fqn_func('builtins.tuple') info = cast(TypeInfo, node.node) return Instance(info, [t.args[0].accept(self)], t.line) - return TupleType(self.anal_array(t.args), - self.builtin_type('builtins.tuple')) + return self.tuple_type(self.anal_array(t.args)) elif fullname == 'typing.Union': items = self.anal_array(t.args) items = [item for item in items if not isinstance(item, Void)] @@ -191,7 +190,7 @@ def visit_tuple_type(self, t: TupleType) -> Type: if star_count > 1: self.fail('At most one star type allowed in a tuple', t) return AnyType() - fallback = t.fallback if t.fallback else self.builtin_type('builtins.tuple') + fallback = t.fallback if t.fallback else self.builtin_type('builtins.tuple', [AnyType()]) return TupleType(self.anal_array(t.items), fallback, t.line) def visit_star_type(self, t: StarType) -> Type: @@ -257,10 +256,13 @@ def anal_var_defs(self, var_defs: List[TypeVarDef]) -> List[TypeVarDef]: vd.line)) return a - def builtin_type(self, fully_qualified_name: str) -> Instance: + def builtin_type(self, fully_qualified_name: str, args: List[Type] = None) -> Instance: node = self.lookup_fqn_func(fully_qualified_name) info = cast(TypeInfo, node.node) - return Instance(info, []) + return Instance(info, args or []) + + def tuple_type(self, items: List[Type]) -> TupleType: + return TupleType(items, fallback=self.builtin_type('builtins.tuple', [AnyType()])) class TypeAnalyserPass3(TypeVisitor[None]):