Skip to content

Commit

Permalink
Prevent crash on generic NamedTuple with unresolved typevar bound (#1…
Browse files Browse the repository at this point in the history
…8585)

Fixes #18582. Fixes #17396. Supersedes #18351.

---------

Co-authored-by: hauntsaninja <hauntsaninja@gmail.com>
  • Loading branch information
2 people authored and wesleywright committed Feb 4, 2025
1 parent 63c251e commit ebc2cb8
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 2 deletions.
5 changes: 5 additions & 0 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8347,6 +8347,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)."""
Expand Down
4 changes: 2 additions & 2 deletions mypy/type_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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()))
Expand Down
19 changes: 19 additions & 0 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -6745,3 +6745,22 @@ from typing_extensions import TypeAlias
IntOrStr: TypeAlias = int | str
assert isinstance(1, IntOrStr)
[builtins fixtures/type.pyi]

[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]
8 changes: 8 additions & 0 deletions test-data/unit/check-inference.test
Original file line number Diff line number Diff line change
Expand Up @@ -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]

0 comments on commit ebc2cb8

Please sign in to comment.