Skip to content

Commit 6e99af4

Browse files
committed
Fix self-check
1 parent b435a03 commit 6e99af4

File tree

2 files changed

+45
-19
lines changed

2 files changed

+45
-19
lines changed

mypy/binder.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -237,25 +237,34 @@ def update_from_options(self, frames: list[Frame]) -> bool:
237237
):
238238
type = AnyType(TypeOfAny.from_another_any, source_any=declaration_type)
239239
else:
240-
type = make_simplified_union([t.type for t in resulting_values])
241-
# Try simplifying resulting type for unions involving variadic tuples.
242-
# Technically, everything is still valid without this step, but if we do
243-
# not do this, this may create long unions after exiting an if check like:
244-
# x: tuple[int, ...]
245-
# if len(x) < 10:
246-
# ...
247-
# We want the type of x to be tuple[int, ...] after this block (if it is
248-
# still equivalent to such type).
249-
if isinstance(type, UnionType):
250-
type = collapse_variadic_union(type)
251-
if isinstance(type, ProperType) and isinstance(type, UnionType):
252-
# Simplify away any extra Any's that were added to the declared
253-
# type when popping a frame.
254-
simplified = UnionType.make_union(
255-
[t for t in type.items if not isinstance(get_proper_type(t), AnyType)]
256-
)
257-
if simplified == self.declarations[key]:
258-
type = simplified
240+
possible_types = []
241+
for t in resulting_values:
242+
assert t is not None
243+
possible_types.append(t.type)
244+
if len(possible_types) == 1:
245+
# This is to avoid calling get_proper_type() unless needed, as this may
246+
# interfere with our (hacky) TypeGuard support.
247+
type = possible_types[0]
248+
else:
249+
type = make_simplified_union(possible_types)
250+
# Try simplifying resulting type for unions involving variadic tuples.
251+
# Technically, everything is still valid without this step, but if we do
252+
# not do this, this may create long unions after exiting an if check like:
253+
# x: tuple[int, ...]
254+
# if len(x) < 10:
255+
# ...
256+
# We want the type of x to be tuple[int, ...] after this block (if it is
257+
# still equivalent to such type).
258+
if isinstance(type, UnionType):
259+
type = collapse_variadic_union(type)
260+
if isinstance(type, ProperType) and isinstance(type, UnionType):
261+
# Simplify away any extra Any's that were added to the declared
262+
# type when popping a frame.
263+
simplified = UnionType.make_union(
264+
[t for t in type.items if not isinstance(get_proper_type(t), AnyType)]
265+
)
266+
if simplified == self.declarations[key]:
267+
type = simplified
259268
if current_value is None or not is_same_type(type, current_value[0]):
260269
self._put(key, type, from_assignment=True)
261270
changed = True

test-data/unit/check-typeguard.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,20 @@ def func2(val: Union[int, str]):
786786
else:
787787
reveal_type(val) # N: Revealed type is "Union[builtins.int, builtins.str]"
788788
[builtins fixtures/tuple.pyi]
789+
790+
[case testTypeGuardRestrictAwaySingleInvariant]
791+
from typing import List
792+
from typing_extensions import TypeGuard
793+
794+
class B: ...
795+
class C(B): ...
796+
797+
def is_c_list(x: list[B]) -> TypeGuard[list[C]]: ...
798+
799+
def test() -> None:
800+
x: List[B]
801+
if not is_c_list(x):
802+
reveal_type(x) # N: Revealed type is "builtins.list[__main__.B]"
803+
return
804+
reveal_type(x) # N: Revealed type is "builtins.list[__main__.C]"
805+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)