Skip to content

Commit ebc2cb8

Browse files
sterliakovhauntsaninja
authored andcommitted
Prevent crash on generic NamedTuple with unresolved typevar bound (#18585)
Fixes #18582. Fixes #17396. Supersedes #18351. --------- Co-authored-by: hauntsaninja <[email protected]>
1 parent 63c251e commit ebc2cb8

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

mypy/checker.py

+5
Original file line numberDiff line numberDiff line change
@@ -8347,6 +8347,11 @@ def visit_type_var(self, t: TypeVarType) -> bool:
83478347
# multi-step type inference.
83488348
return t.id.is_meta_var()
83498349

8350+
def visit_tuple_type(self, t: TupleType, /) -> bool:
8351+
# Exclude fallback to avoid bogus "need type annotation" errors
8352+
# TODO: Maybe erase plain tuples used as fallback in TupleType constructor?
8353+
return self.query_types(t.items)
8354+
83508355

83518356
class SetNothingToAny(TypeTranslator):
83528357
"""Replace all ambiguous Uninhabited types with Any (to avoid spurious extra errors)."""

mypy/type_visitor.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ def visit_callable_type(self, t: CallableType, /) -> T:
410410
return self.query_types(t.arg_types + [t.ret_type])
411411

412412
def visit_tuple_type(self, t: TupleType, /) -> T:
413-
return self.query_types(t.items)
413+
return self.query_types([t.partial_fallback] + t.items)
414414

415415
def visit_typeddict_type(self, t: TypedDictType, /) -> T:
416416
return self.query_types(t.items.values())
@@ -550,7 +550,7 @@ def visit_callable_type(self, t: CallableType, /) -> bool:
550550
return args and ret
551551

552552
def visit_tuple_type(self, t: TupleType, /) -> bool:
553-
return self.query_types(t.items)
553+
return self.query_types([t.partial_fallback] + t.items)
554554

555555
def visit_typeddict_type(self, t: TypedDictType, /) -> bool:
556556
return self.query_types(list(t.items.values()))

test-data/unit/check-incremental.test

+19
Original file line numberDiff line numberDiff line change
@@ -6745,3 +6745,22 @@ from typing_extensions import TypeAlias
67456745
IntOrStr: TypeAlias = int | str
67466746
assert isinstance(1, IntOrStr)
67476747
[builtins fixtures/type.pyi]
6748+
6749+
[case testSerializeDeferredGenericNamedTuple]
6750+
import pkg
6751+
[file pkg/__init__.py]
6752+
from .lib import NT
6753+
[file pkg/lib.py]
6754+
from typing import Generic, NamedTuple, TypeVar
6755+
from pkg import does_not_exist # type: ignore
6756+
from pkg.missing import also_missing # type: ignore
6757+
6758+
T = TypeVar("T", bound=does_not_exist)
6759+
class NT(NamedTuple, Generic[T]):
6760+
values: also_missing[T]
6761+
[file pkg/__init__.py.2]
6762+
# touch
6763+
from .lib import NT
6764+
[builtins fixtures/tuple.pyi]
6765+
[out]
6766+
[out2]

test-data/unit/check-inference.test

+8
Original file line numberDiff line numberDiff line change
@@ -3886,3 +3886,11 @@ def a4(x: List[str], y: List[Never]) -> None:
38863886
reveal_type(z2) # N: Revealed type is "builtins.list[builtins.object]"
38873887
z1[1].append("asdf") # E: "object" has no attribute "append"
38883888
[builtins fixtures/dict.pyi]
3889+
3890+
[case testTupleJoinFallbackInference]
3891+
foo = [
3892+
(1, ("a", "b")),
3893+
(2, []),
3894+
]
3895+
reveal_type(foo) # N: Revealed type is "builtins.list[Tuple[builtins.int, typing.Sequence[builtins.str]]]"
3896+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)