99from mypy .constraints import SUBTYPE_OF , SUPERTYPE_OF , Constraint , infer_constraints , neg_op
1010from mypy .expandtype import expand_type
1111from mypy .graph_utils import prepare_sccs , strongly_connected_components , topsort
12- from mypy .join import join_types
12+ from mypy .join import join_type_list
1313from mypy .meet import meet_type_list , meet_types
1414from mypy .subtypes import is_subtype
1515from mypy .typeops import get_all_type_vars
@@ -247,10 +247,16 @@ def solve_iteratively(
247247 return solutions
248248
249249
250+ def _join_sorted_key (t : Type ) -> int :
251+ t = get_proper_type (t )
252+ if isinstance (t , UnionType ):
253+ return - 1
254+ return 0
255+
256+
250257def solve_one (lowers : Iterable [Type ], uppers : Iterable [Type ]) -> Type | None :
251258 """Solve constraints by finding by using meets of upper bounds, and joins of lower bounds."""
252- bottom : Type | None = None
253- top : Type | None = None
259+
254260 candidate : Type | None = None
255261
256262 # Filter out previous results of failed inference, they will only spoil the current pass...
@@ -267,19 +273,26 @@ def solve_one(lowers: Iterable[Type], uppers: Iterable[Type]) -> Type | None:
267273 candidate .ambiguous = True
268274 return candidate
269275
276+ bottom : Type | None = None
277+ top : Type | None = None
278+
270279 # Process each bound separately, and calculate the lower and upper
271280 # bounds based on constraints. Note that we assume that the constraint
272281 # targets do not have constraint references.
273- for target in lowers :
274- if bottom is None :
275- bottom = target
276- else :
277- if type_state .infer_unions :
278- # This deviates from the general mypy semantics because
279- # recursive types are union-heavy in 95% of cases.
280- bottom = UnionType .make_union ([bottom , target ])
281- else :
282- bottom = join_types (bottom , target )
282+ if type_state .infer_unions :
283+ # This deviates from the general mypy semantics because
284+ # recursive types are union-heavy in 95% of cases.
285+ bottom = UnionType .make_union (list (lowers ))
286+ else :
287+ # The order of lowers is non-deterministic.
288+ # We attempt to sort lowers because joins are non-associative. For instance:
289+ # join(join(int, str), int | str) == join(object, int | str) == object
290+ # join(int, join(str, int | str)) == join(int, int | str) == int | str
291+ # Note that joins in theory should be commutative, but in practice some bugs mean this is
292+ # also a source of non-deterministic type checking results.
293+ sorted_lowers = sorted (lowers , key = _join_sorted_key )
294+ if sorted_lowers :
295+ bottom = join_type_list (sorted_lowers )
283296
284297 for target in uppers :
285298 if top is None :
0 commit comments