Solve constraints by finding by using meets of upper bounds, and joins of lower bounds.
(lowers: Iterable[Type], uppers: Iterable[Type])
| 261 | |
| 262 | |
| 263 | def solve_one(lowers: Iterable[Type], uppers: Iterable[Type]) -> Type | None: |
| 264 | """Solve constraints by finding by using meets of upper bounds, and joins of lower bounds.""" |
| 265 | |
| 266 | candidate: Type | None = None |
| 267 | |
| 268 | # Filter out previous results of failed inference, they will only spoil the current pass... |
| 269 | new_uppers = [] |
| 270 | for u in uppers: |
| 271 | pu = get_proper_type(u) |
| 272 | if not isinstance(pu, UninhabitedType) or not pu.ambiguous: |
| 273 | new_uppers.append(u) |
| 274 | uppers = new_uppers |
| 275 | |
| 276 | # ...unless this is the only information we have, then we just pass it on. |
| 277 | lowers = list(lowers) |
| 278 | if not uppers and not lowers: |
| 279 | candidate = UninhabitedType() |
| 280 | candidate.ambiguous = True |
| 281 | return candidate |
| 282 | |
| 283 | bottom: Type | None = None |
| 284 | top: Type | None = None |
| 285 | |
| 286 | # Process each bound separately, and calculate the lower and upper |
| 287 | # bounds based on constraints. Note that we assume that the constraint |
| 288 | # targets do not have constraint references. |
| 289 | if type_state.infer_unions and lowers: |
| 290 | # This deviates from the general mypy semantics because |
| 291 | # recursive types are union-heavy in 95% of cases. |
| 292 | # Retain `None` when no bottoms were provided to avoid bogus `Never` inference. |
| 293 | bottom = UnionType.make_union(lowers) |
| 294 | else: |
| 295 | # The order of lowers is non-deterministic. |
| 296 | # We attempt to sort lowers because joins are non-associative. For instance: |
| 297 | # join(join(int, str), int | str) == join(object, int | str) == object |
| 298 | # join(int, join(str, int | str)) == join(int, int | str) == int | str |
| 299 | # Note that joins in theory should be commutative, but in practice some bugs mean this is |
| 300 | # also a source of non-deterministic type checking results. |
| 301 | sorted_lowers = sorted(lowers, key=_join_sorted_key) |
| 302 | if sorted_lowers: |
| 303 | bottom = join_type_list(sorted_lowers) |
| 304 | |
| 305 | for target in uppers: |
| 306 | if top is None: |
| 307 | top = target |
| 308 | else: |
| 309 | top = meet_types(top, target) |
| 310 | |
| 311 | p_top = get_proper_type(top) |
| 312 | p_bottom = get_proper_type(bottom) |
| 313 | if isinstance(p_top, AnyType) or isinstance(p_bottom, AnyType): |
| 314 | source_any = top if isinstance(p_top, AnyType) else bottom |
| 315 | assert isinstance(source_any, ProperType) and isinstance(source_any, AnyType) |
| 316 | return AnyType(TypeOfAny.from_another_any, source_any=source_any) |
| 317 | elif bottom is None: |
| 318 | if top: |
| 319 | candidate = top |
| 320 | else: |
no test coverage detected
searching dependent graphs…