Skip to content

Commit afbb9e8

Browse files
committed
Only combine after removing trivially unsatisfiable constraints
1 parent aff5fc7 commit afbb9e8

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

mypy/constraints.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,8 @@ def any_constraints(options: list[list[Constraint] | None], *, eager: bool) -> l
532532
# Multiple sets of constraints that are all the same. Just pick any one of them.
533533
return valid_options[0]
534534

535-
if all(is_similar_constraints(valid_options[0], c) for c in valid_options[1:]):
535+
all_similar = all(is_similar_constraints(valid_options[0], c) for c in valid_options[1:])
536+
if all_similar:
536537
# All options have same structure. In this case we can merge-in trivial
537538
# options (i.e. those that only have Any) and try again.
538539
trivial_options = select_trivial(valid_options)
@@ -543,10 +544,6 @@ def any_constraints(options: list[list[Constraint] | None], *, eager: bool) -> l
543544
continue
544545
merged_options.append([merge_with_any(c) for c in option])
545546
return any_constraints(list(merged_options), eager=eager)
546-
# Solver will apply meets and joins as necessary, return everything we know.
547-
# Just deduplicate to reduce the amount of work.
548-
all_combined = sum(valid_options, [])
549-
return list(dict.fromkeys(all_combined))
550547

551548
# If normal logic didn't work, try excluding trivially unsatisfiable constraint (due to
552549
# upper bounds) from each option, and comparing them again.
@@ -562,6 +559,13 @@ def any_constraints(options: list[list[Constraint] | None], *, eager: bool) -> l
562559
if filtered_options != options:
563560
return any_constraints(filtered_options, eager=eager)
564561

562+
if all_similar:
563+
# Now we know all constraints might be satisfiable and have similar structure.
564+
# Solver will apply meets and joins as necessary, return everything we know.
565+
# Just deduplicate to reduce the amount of work.
566+
all_combined = sum(valid_options, [])
567+
return list(dict.fromkeys(all_combined))
568+
565569
# Otherwise, there are either no valid options or multiple, inconsistent valid
566570
# options. Give up and deduce nothing.
567571
return []

test-data/unit/check-inference-context.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,3 +1542,21 @@ def f(x: P) -> None:
15421542
def g(x: Union[dict[str, Any], None], s: Union[str, None]) -> None:
15431543
f(x or {'x': s})
15441544
[builtins fixtures/dict.pyi]
1545+
1546+
[case testInferConstrainedTypeVarInUnion]
1547+
from typing import Generic, TypeVar, Union
1548+
1549+
_S_co = TypeVar("_S_co", str, int, covariant=True)
1550+
_S = TypeVar("_S", str, int)
1551+
1552+
class HasFoo(Generic[_S_co]):
1553+
def foo(self) -> _S_co: ...
1554+
1555+
def walk(path: Union[_S, HasFoo[_S]]) -> None:
1556+
...
1557+
1558+
class Path(HasFoo[str]):
1559+
def foo(self) -> str: ...
1560+
1561+
walk(Path())
1562+
[builtins fixtures/tuple.pyi]

0 commit comments

Comments
 (0)