Skip to content
Merged
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
8 changes: 1 addition & 7 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -9322,13 +9322,7 @@ def is_overlapping_types_for_overload(left: Type, right: Type) -> bool:
# def foo(x: None) -> None: ..
# @overload
# def foo(x: T) -> Foo[T]: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this example in the comment still work (is there an existing test case for this)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, see testOverloadDetectsPossibleMatchesWithGenerics and #15846

return is_overlapping_types(
left,
right,
ignore_promotions=True,
prohibit_none_typevar_overlap=True,
overlap_for_overloads=True,
)
return is_overlapping_types(left, right, ignore_promotions=True, overlap_for_overloads=True)


def is_private(node_name: str) -> bool:
Expand Down
4 changes: 1 addition & 3 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6399,9 +6399,7 @@ def narrow_type_from_binder(
isinstance(get_proper_type(known_type), AnyType) and self.chk.current_node_deferred
):
# Note: this call should match the one in narrow_declared_type().
if skip_non_overlapping and not is_overlapping_types(
known_type, restriction, prohibit_none_typevar_overlap=True
):
if skip_non_overlapping and not is_overlapping_types(known_type, restriction):
return None
narrowed = narrow_declared_type(known_type, restriction)
if isinstance(get_proper_type(narrowed), UninhabitedType):
Expand Down
19 changes: 2 additions & 17 deletions mypy/meet.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
return declared.copy_modified(
upper_bound=narrow_declared_type(declared.upper_bound, original_narrowed)
)
elif not is_overlapping_types(declared, narrowed, prohibit_none_typevar_overlap=True):
elif not is_overlapping_types(declared, narrowed):
if state.strict_optional:
return UninhabitedType()
else:
Expand Down Expand Up @@ -308,10 +308,6 @@ def is_object(t: ProperType) -> bool:
return isinstance(t, Instance) and t.type.fullname == "builtins.object"


def is_none_typevarlike_overlap(t1: ProperType, t2: ProperType) -> bool:
return isinstance(t1, NoneType) and isinstance(t2, TypeVarLikeType)


def is_none_object_overlap(t1: ProperType, t2: ProperType) -> bool:
return (
isinstance(t1, NoneType)
Expand All @@ -337,15 +333,12 @@ def is_overlapping_types(
left: Type,
right: Type,
ignore_promotions: bool = False,
prohibit_none_typevar_overlap: bool = False,
overlap_for_overloads: bool = False,
seen_types: set[tuple[Type, Type]] | None = None,
) -> bool:
"""Can a value of type 'left' also be of type 'right' or vice-versa?
If 'ignore_promotions' is True, we ignore promotions while checking for overlaps.
If 'prohibit_none_typevar_overlap' is True, we disallow None from overlapping with
TypeVars (in both strict-optional and non-strict-optional mode).
If 'overlap_for_overloads' is True, we check for overlaps more strictly (to avoid false
positives), for example: None only overlaps with explicitly optional types, Any
doesn't overlap with anything except object, we don't ignore positional argument names.
Expand Down Expand Up @@ -433,10 +426,6 @@ def is_overlapping_types(
# If both types are singleton variants (and are not TypeVarLikes), we've hit the base case:
# we skip these checks to avoid infinitely recursing.

if prohibit_none_typevar_overlap:
if is_none_typevarlike_overlap(left, right) or is_none_typevarlike_overlap(right, left):
return False

def _is_overlapping_types(left: Type, right: Type) -> bool:
"""Encode the kind of overlapping check to perform.
Expand All @@ -446,7 +435,6 @@ def _is_overlapping_types(left: Type, right: Type) -> bool:
left,
right,
ignore_promotions=ignore_promotions,
prohibit_none_typevar_overlap=prohibit_none_typevar_overlap,
overlap_for_overloads=overlap_for_overloads,
seen_types=seen_types.copy(),
)
Expand Down Expand Up @@ -662,10 +650,7 @@ def is_overlapping_erased_types(
) -> bool:
"""The same as 'is_overlapping_erased_types', except the types are erased first."""
return is_overlapping_types(
erase_type(left),
erase_type(right),
ignore_promotions=ignore_promotions,
prohibit_none_typevar_overlap=True,
erase_type(left), erase_type(right), ignore_promotions=ignore_promotions
)


Expand Down