10
10
from mypy .expandtype import expand_type
11
11
from mypy .graph_utils import prepare_sccs , strongly_connected_components , topsort
12
12
from mypy .join import join_types
13
- from mypy .meet import meet_types
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_type_vars
16
16
from mypy .types import (
17
17
AnyType ,
18
+ Instance ,
19
+ NoneType ,
18
20
ProperType ,
19
21
Type ,
20
22
TypeOfAny ,
@@ -108,15 +110,15 @@ def solve_constraints(
108
110
else :
109
111
candidate = AnyType (TypeOfAny .special_form )
110
112
res .append (candidate )
111
- return res , [ originals [ tv ] for tv in free_vars ]
113
+ return res , free_vars
112
114
113
115
114
116
def solve_with_dependent (
115
117
vars : list [TypeVarId ],
116
118
constraints : list [Constraint ],
117
119
original_vars : list [TypeVarId ],
118
120
originals : dict [TypeVarId , TypeVarLikeType ],
119
- ) -> tuple [Solutions , list [TypeVarId ]]:
121
+ ) -> tuple [Solutions , list [TypeVarLikeType ]]:
120
122
"""Solve set of constraints that may depend on each other, like T <: List[S].
121
123
122
124
The whole algorithm consists of five steps:
@@ -135,23 +137,24 @@ def solve_with_dependent(
135
137
raw_batches = list (topsort (prepare_sccs (sccs , dmap )))
136
138
137
139
free_vars = []
140
+ free_solutions = {}
138
141
for scc in raw_batches [0 ]:
139
142
# If there are no bounds on this SCC, then the only meaningful solution we can
140
143
# express, is that each variable is equal to a new free variable. For example,
141
144
# if we have T <: S, S <: U, we deduce: T = S = U = <free>.
142
145
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
147
150
148
151
# Update lowers/uppers with free vars, so these can now be used
149
152
# as valid solutions.
150
- for l , u in graph . copy () :
153
+ for l , u in graph :
151
154
if l in free_vars :
152
- lowers [u ].add (originals [l ])
155
+ lowers [u ].add (free_solutions [l ])
153
156
if u in free_vars :
154
- uppers [l ].add (originals [u ])
157
+ uppers [l ].add (free_solutions [u ])
155
158
156
159
# Flatten the SCCs that are independent, we can solve them together,
157
160
# since we don't need to update any targets in between.
@@ -166,7 +169,7 @@ def solve_with_dependent(
166
169
for flat_batch in batches :
167
170
res = solve_iteratively (flat_batch , graph , lowers , uppers )
168
171
solutions .update (res )
169
- return solutions , free_vars
172
+ return solutions , [ free_solutions [ tv ] for tv in free_vars ]
170
173
171
174
172
175
def solve_iteratively (
@@ -276,6 +279,61 @@ def solve_one(lowers: Iterable[Type], uppers: Iterable[Type]) -> Type | None:
276
279
return candidate
277
280
278
281
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
+
279
337
def normalize_constraints (
280
338
constraints : list [Constraint ], vars : list [TypeVarId ]
281
339
) -> list [Constraint ]:
0 commit comments