@@ -109,6 +109,13 @@ def solve_constraints(
109109 else :
110110 candidate = AnyType (TypeOfAny .special_form )
111111 res .append (candidate )
112+
113+ if not free_vars :
114+ # Most of the validation for solutions is done in applytype.py, but here we can
115+ # quickly test solutions w.r.t. to upper bounds, and use the latter (if possible),
116+ # if solutions are actually not valid (due to poor inference context).
117+ res = pre_validate_solutions (res , original_vars , constraints )
118+
112119 return res , free_vars
113120
114121
@@ -487,3 +494,31 @@ def check_linear(scc: set[TypeVarId], lowers: Bounds, uppers: Bounds) -> bool:
487494def get_vars (target : Type , vars : list [TypeVarId ]) -> set [TypeVarId ]:
488495 """Find type variables for which we are solving in a target type."""
489496 return {tv .id for tv in get_all_type_vars (target )} & set (vars )
497+
498+
499+ def pre_validate_solutions (
500+ solutions : list [Type | None ],
501+ original_vars : Sequence [TypeVarLikeType ],
502+ constraints : list [Constraint ],
503+ ) -> list [Type | None ]:
504+ """Check is each solution satisfies the upper bound of the corresponding type variable.
505+
506+ If it doesn't satisfy the bound, check if bound itself satisfies all constraints, and
507+ if yes, use it instead as a fallback solution.
508+ """
509+ new_solutions : list [Type | None ] = []
510+ for t , s in zip (original_vars , solutions ):
511+ if s is not None and not is_subtype (s , t .upper_bound ):
512+ bound_satisfies_all = True
513+ for c in constraints :
514+ if c .op == SUBTYPE_OF and not is_subtype (t .upper_bound , c .target ):
515+ bound_satisfies_all = False
516+ break
517+ if c .op == SUPERTYPE_OF and not is_subtype (c .target , t .upper_bound ):
518+ bound_satisfies_all = False
519+ break
520+ if bound_satisfies_all :
521+ new_solutions .append (t .upper_bound )
522+ continue
523+ new_solutions .append (s )
524+ return new_solutions
0 commit comments