diff --git a/mypy/checker.py b/mypy/checker.py index c69b80a55fd9..35c883276029 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -8485,6 +8485,11 @@ def visit_type_var(self, t: TypeVarType) -> bool: # multi-step type inference. return t.id.is_meta_var() + def visit_tuple_type(self, t: TupleType, /) -> bool: + # Exclude fallback to avoid bogus "need type annotation" errors + # TODO: Maybe erase plain tuples used as fallback in TupleType constructor? + return self.query_types(t.items) + class SetNothingToAny(TypeTranslator): """Replace all ambiguous Uninhabited types with Any (to avoid spurious extra errors).""" diff --git a/mypy/type_visitor.py b/mypy/type_visitor.py index f62d67bc26cc..d935b9a47a51 100644 --- a/mypy/type_visitor.py +++ b/mypy/type_visitor.py @@ -410,7 +410,7 @@ def visit_callable_type(self, t: CallableType, /) -> T: return self.query_types(t.arg_types + [t.ret_type]) def visit_tuple_type(self, t: TupleType, /) -> T: - return self.query_types(t.items) + return self.query_types([t.partial_fallback] + t.items) def visit_typeddict_type(self, t: TypedDictType, /) -> T: return self.query_types(t.items.values()) @@ -550,7 +550,7 @@ def visit_callable_type(self, t: CallableType, /) -> bool: return args and ret def visit_tuple_type(self, t: TupleType, /) -> bool: - return self.query_types(t.items) + return self.query_types([t.partial_fallback] + t.items) def visit_typeddict_type(self, t: TypedDictType, /) -> bool: return self.query_types(list(t.items.values())) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 2cc072eb16e7..6b888c0047c3 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -6829,3 +6829,22 @@ reveal_type(a.f) tmp/b.py:4: note: Revealed type is "builtins.int" tmp/b.py:5: error: Incompatible types in assignment (expression has type "int", variable has type "str") tmp/b.py:6: note: Revealed type is "builtins.int" + +[case testSerializeDeferredGenericNamedTuple] +import pkg +[file pkg/__init__.py] +from .lib import NT +[file pkg/lib.py] +from typing import Generic, NamedTuple, TypeVar +from pkg import does_not_exist # type: ignore +from pkg.missing import also_missing # type: ignore + +T = TypeVar("T", bound=does_not_exist) +class NT(NamedTuple, Generic[T]): + values: also_missing[T] +[file pkg/__init__.py.2] +# touch +from .lib import NT +[builtins fixtures/tuple.pyi] +[out] +[out2] diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 0da1c092efe8..bdd0ac305904 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -3886,3 +3886,11 @@ def a4(x: List[str], y: List[Never]) -> None: reveal_type(z2) # N: Revealed type is "builtins.list[builtins.object]" z1[1].append("asdf") # E: "object" has no attribute "append" [builtins fixtures/dict.pyi] + +[case testTupleJoinFallbackInference] +foo = [ + (1, ("a", "b")), + (2, []), +] +reveal_type(foo) # N: Revealed type is "builtins.list[Tuple[builtins.int, typing.Sequence[builtins.str]]]" +[builtins fixtures/tuple.pyi]