MCPcopy Index your code
hub / github.com/python/mypy / solve_with_dependent

Function solve_with_dependent

mypy/solve.py:130–188  ·  view source on GitHub ↗

Solve set of constraints that may depend on each other, like T <: List[S]. The whole algorithm consists of five steps: * Propagate via linear constraints and use secondary constraints to get transitive closure * Find dependencies between type variables, group them in SCCs, and sort

(
    vars: list[TypeVarId],
    constraints: list[Constraint],
    original_vars: list[TypeVarId],
    originals: dict[TypeVarId, TypeVarLikeType],
)

Source from the content-addressed store, hash-verified

128
129
130def solve_with_dependent(
131 vars: list[TypeVarId],
132 constraints: list[Constraint],
133 original_vars: list[TypeVarId],
134 originals: dict[TypeVarId, TypeVarLikeType],
135) -> tuple[Solutions, list[TypeVarLikeType]]:
136 """Solve set of constraints that may depend on each other, like T <: List[S].
137
138 The whole algorithm consists of five steps:
139 * Propagate via linear constraints and use secondary constraints to get transitive closure
140 * Find dependencies between type variables, group them in SCCs, and sort topologically
141 * Check that all SCC are intrinsically linear, we can&#x27;t solve (express) T <: List[T]
142 * Variables in leaf SCCs that don&#x27;t have constant bounds are free (choose one per SCC)
143 * Solve constraints iteratively starting from leaves, updating bounds after each step.
144 """
145 graph, lowers, uppers = transitive_closure(vars, constraints)
146
147 dmap = compute_dependencies(vars, graph, lowers, uppers)
148 sccs = list(strongly_connected_components(set(vars), dmap))
149 if not all(check_linear(scc, lowers, uppers) for scc in sccs):
150 return {}, []
151 raw_batches = list(topsort(prepare_sccs(sccs, dmap)))
152
153 free_vars = []
154 free_solutions = {}
155 for scc in raw_batches[0]:
156 # If there are no bounds on this SCC, then the only meaningful solution we can
157 # express, is that each variable is equal to a new free variable. For example,
158 # if we have T <: S, S <: U, we deduce: T = S = U = <free>.
159 if all(not lowers[tv] and not uppers[tv] for tv in scc):
160 best_free = choose_free([originals[tv] for tv in scc], original_vars)
161 if best_free:
162 # TODO: failing to choose may cause leaking type variables,
163 # we need to fail gracefully instead.
164 free_vars.append(best_free.id)
165 free_solutions[best_free.id] = best_free
166
167 # Update lowers/uppers with free vars, so these can now be used
168 # as valid solutions.
169 for l, u in graph:
170 if l in free_vars:
171 lowers[u].add(free_solutions[l])
172 if u in free_vars:
173 uppers[l].add(free_solutions[u])
174
175 # Flatten the SCCs that are independent, we can solve them together,
176 # since we don't need to update any targets in between.
177 batches = []
178 for batch in raw_batches:
179 next_bc = []
180 for scc in batch:
181 next_bc.extend(list(scc))
182 batches.append(next_bc)
183
184 solutions: dict[TypeVarId, Type | None] = {}
185 for flat_batch in batches:
186 res = solve_iteratively(flat_batch, graph, lowers, uppers)
187 solutions.update(res)

Callers 1

solve_constraintsFunction · 0.85

Calls 15

topsortClass · 0.90
prepare_sccsFunction · 0.90
transitive_closureFunction · 0.85
compute_dependenciesFunction · 0.85
listClass · 0.85
setClass · 0.85
allFunction · 0.85
check_linearFunction · 0.85
choose_freeFunction · 0.85
solve_iterativelyFunction · 0.85
appendMethod · 0.80

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…