9
9
from mypy .constraints import SUBTYPE_OF , SUPERTYPE_OF , Constraint , infer_constraints , neg_op
10
10
from mypy .expandtype import expand_type
11
11
from 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
13
13
from mypy .meet import meet_type_list , meet_types
14
14
from mypy .subtypes import is_subtype
15
15
from mypy .typeops import get_all_type_vars
@@ -247,10 +247,16 @@ def solve_iteratively(
247
247
return solutions
248
248
249
249
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
+
250
257
def solve_one (lowers : Iterable [Type ], uppers : Iterable [Type ]) -> Type | None :
251
258
"""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
+
254
260
candidate : Type | None = None
255
261
256
262
# 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:
267
273
candidate .ambiguous = True
268
274
return candidate
269
275
276
+ bottom : Type | None = None
277
+ top : Type | None = None
278
+
270
279
# Process each bound separately, and calculate the lower and upper
271
280
# bounds based on constraints. Note that we assume that the constraint
272
281
# 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 )
283
296
284
297
for target in uppers :
285
298
if top is None :
0 commit comments