Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 28 additions & 29 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -8394,43 +8394,42 @@ def conditional_types(

if isinstance(proper_type, AnyType):
return proposed_type, current_type
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, would it be technically more correct to return AnyType(TypeOfAny.from_another_any, source_any=proper_type) for the else branch, rather than proper_type itself?

elif isinstance(proposed_type, AnyType):
if isinstance(proposed_type, AnyType):
# We don't really know much about the proposed type, so we shouldn't
# attempt to narrow anything. Instead, we broaden the expr to Any to
# avoid false positives
return proposed_type, default
elif not any(type_range.is_upper_bound for type_range in proposed_type_ranges) and (
# concrete subtypes
is_proper_subtype(current_type, proposed_type, ignore_promotions=True)
if not any(type_range.is_upper_bound for type_range in proposed_type_ranges):
# concrete subtype
if is_proper_subtype(current_type, proposed_type, ignore_promotions=True):
return default, UninhabitedType()

# structural subtypes
or (
(
isinstance(proposed_type, CallableType)
or (isinstance(proposed_type, Instance) and proposed_type.type.is_protocol)
if (
isinstance(proposed_type, CallableType)
or (isinstance(proposed_type, Instance) and proposed_type.type.is_protocol)
) and is_subtype(current_type, proposed_type, ignore_promotions=True):
# Note: It's possible that current_type=`Any | Proto` while proposed_type=`Proto`
# so we cannot return `Never` for the else branch
remainder = restrict_subtype_away(
current_type,
default if default is not None else proposed_type,
consider_runtime_isinstance=consider_runtime_isinstance,
)
and is_subtype(current_type, proposed_type, ignore_promotions=True)
)
):
# Expression is always of one of the types in proposed_type_ranges
return default, UninhabitedType()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return was problematic in the structural case when current_type=Any | Proto, restricting Proto away should leave us with Any and not Never.

elif not is_overlapping_types(current_type, proposed_type, ignore_promotions=True):
return default, remainder
if not is_overlapping_types(current_type, proposed_type, ignore_promotions=True):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted the elif to if because the if not any(type_range.is_upper_bound for type_range in proposed_type_ranges): is not guaranteed to return anymore.

# Expression is never of any type in proposed_type_ranges
return UninhabitedType(), default
else:
# we can only restrict when the type is precise, not bounded
proposed_precise_type = UnionType.make_union(
[
type_range.item
for type_range in proposed_type_ranges
if not type_range.is_upper_bound
]
)
remaining_type = restrict_subtype_away(
current_type,
proposed_precise_type,
consider_runtime_isinstance=consider_runtime_isinstance,
)
return proposed_type, remaining_type
# we can only restrict when the type is precise, not bounded
proposed_precise_type = UnionType.make_union(
[type_range.item for type_range in proposed_type_ranges if not type_range.is_upper_bound]
)
remaining_type = restrict_subtype_away(
current_type,
proposed_precise_type,
consider_runtime_isinstance=consider_runtime_isinstance,
)
return proposed_type, remaining_type


def conditional_types_to_typemaps(
Expand Down
14 changes: 14 additions & 0 deletions test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,20 @@ class Foo:
return 2
[builtins fixtures/list.pyi]

[case testRedundantExpressionsUnionWithAny]
# flags: --enable-error-code redundant-expr
from typing import Any, Awaitable, Union
ok_list: list[Union[Any, Awaitable]]
for y in ok_list:
z = 1 if isinstance(y, Awaitable) else 2

bad_list: list[Awaitable]
for y in bad_list:
z = 1 if isinstance(y, Awaitable) else 2 # E: If condition is always true [redundant-expr]
[builtins fixtures/isinstancelist.pyi]
[typing fixtures/typing-full.pyi]


[case testNamedTupleNameMismatch]
from typing import NamedTuple

Expand Down