1010from mypy .expandtype import expand_type
1111from mypy .graph_utils import prepare_sccs , strongly_connected_components , topsort
1212from mypy .join import join_types
13- from mypy .meet import meet_types
13+ from mypy .meet import meet_type_list , meet_types
1414from mypy .subtypes import is_subtype
1515from mypy .typeops import get_type_vars
1616from mypy .types import (
1717 AnyType ,
18+ Instance ,
19+ NoneType ,
1820 ProperType ,
1921 Type ,
2022 TypeOfAny ,
@@ -108,15 +110,15 @@ def solve_constraints(
108110 else :
109111 candidate = AnyType (TypeOfAny .special_form )
110112 res .append (candidate )
111- return res , [ originals [ tv ] for tv in free_vars ]
113+ return res , free_vars
112114
113115
114116def solve_with_dependent (
115117 vars : list [TypeVarId ],
116118 constraints : list [Constraint ],
117119 original_vars : list [TypeVarId ],
118120 originals : dict [TypeVarId , TypeVarLikeType ],
119- ) -> tuple [Solutions , list [TypeVarId ]]:
121+ ) -> tuple [Solutions , list [TypeVarLikeType ]]:
120122 """Solve set of constraints that may depend on each other, like T <: List[S].
121123
122124 The whole algorithm consists of five steps:
@@ -135,23 +137,24 @@ def solve_with_dependent(
135137 raw_batches = list (topsort (prepare_sccs (sccs , dmap )))
136138
137139 free_vars = []
140+ free_solutions = {}
138141 for scc in raw_batches [0 ]:
139142 # If there are no bounds on this SCC, then the only meaningful solution we can
140143 # express, is that each variable is equal to a new free variable. For example,
141144 # if we have T <: S, S <: U, we deduce: T = S = U = <free>.
142145 if all (not lowers [tv ] and not uppers [tv ] for tv in scc ):
143- # For convenience with current type application machinery, we use a stable
144- # choice that prefers the original type variables (not polymorphic ones) in SCC.
145- # TODO: be careful about upper bounds (or values) when introducing free vars.
146- free_vars . append ( sorted ( scc , key = lambda x : ( x not in original_vars , x . raw_id ))[ 0 ])
146+ best_free = choose_free ([ originals [ tv ] for tv in scc ], original_vars )
147+ if best_free :
148+ free_vars . append ( best_free . id )
149+ free_solutions [ best_free . id ] = best_free
147150
148151 # Update lowers/uppers with free vars, so these can now be used
149152 # as valid solutions.
150- for l , u in graph . copy () :
153+ for l , u in graph :
151154 if l in free_vars :
152- lowers [u ].add (originals [l ])
155+ lowers [u ].add (free_solutions [l ])
153156 if u in free_vars :
154- uppers [l ].add (originals [u ])
157+ uppers [l ].add (free_solutions [u ])
155158
156159 # Flatten the SCCs that are independent, we can solve them together,
157160 # since we don't need to update any targets in between.
@@ -166,7 +169,7 @@ def solve_with_dependent(
166169 for flat_batch in batches :
167170 res = solve_iteratively (flat_batch , graph , lowers , uppers )
168171 solutions .update (res )
169- return solutions , free_vars
172+ return solutions , [ free_solutions [ tv ] for tv in free_vars ]
170173
171174
172175def solve_iteratively (
@@ -276,6 +279,61 @@ def solve_one(lowers: Iterable[Type], uppers: Iterable[Type]) -> Type | None:
276279 return candidate
277280
278281
282+ def choose_free (
283+ scc : list [TypeVarLikeType ], original_vars : list [TypeVarId ]
284+ ) -> TypeVarLikeType | None :
285+ """Choose the best solution for an SCC containing only type variables.
286+
287+ This is needed to preserve e.g. the upper bound in a situation like this:
288+ def dec(f: Callable[[T], S]) -> Callable[[T], S]: ...
289+
290+ @dec
291+ def test(x: U) -> U: ...
292+
293+ where U <: A.
294+ """
295+
296+ if len (scc ) == 1 :
297+ # Fast path, choice is trivial.
298+ return scc [0 ]
299+
300+ common_upper_bound = meet_type_list ([t .upper_bound for t in scc ])
301+ common_upper_bound_p = get_proper_type (common_upper_bound )
302+ # We include None for when strict-optional is disabled.
303+ if isinstance (common_upper_bound_p , (UninhabitedType , NoneType )):
304+ # This will cause to infer <nothing>, which is better than a free TypeVar
305+ # that has an upper bound <nothing>.
306+ return None
307+
308+ values : list [Type ] = []
309+ for tv in scc :
310+ if isinstance (tv , TypeVarType ) and tv .values :
311+ if values :
312+ # It is too tricky to support multiple TypeVars with values
313+ # within the same SCC.
314+ return None
315+ values = tv .values .copy ()
316+
317+ if values and not is_trivial_bound (common_upper_bound_p ):
318+ # If there are both values and upper bound present, we give up,
319+ # since type variables having both are not supported.
320+ return None
321+
322+ # For convenience with current type application machinery, we use a stable
323+ # choice that prefers the original type variables (not polymorphic ones) in SCC.
324+ best = sorted (scc , key = lambda x : (x .id not in original_vars , x .id .raw_id ))[0 ]
325+ if isinstance (best , TypeVarType ):
326+ return best .copy_modified (values = values , upper_bound = common_upper_bound )
327+ if is_trivial_bound (common_upper_bound_p ):
328+ # TODO: support more cases for ParamSpecs/TypeVarTuples
329+ return best
330+ return None
331+
332+
333+ def is_trivial_bound (tp : ProperType ) -> bool :
334+ return isinstance (tp , Instance ) and tp .type .fullname == "builtins.object"
335+
336+
279337def normalize_constraints (
280338 constraints : list [Constraint ], vars : list [TypeVarId ]
281339) -> list [Constraint ]:
0 commit comments