@@ -209,37 +209,36 @@ impl<DP: DependencyProvider> State<DP> {
209
209
Ok ( satisfier_causes)
210
210
}
211
211
212
- /// Return the root cause or the terminal incompatibility.
213
- /// CF <https://github.com/dart-lang/pub/blob/master/doc/solver.md#unit-propagation>
212
+ /// Return the root cause or the terminal incompatibility. CF
213
+ /// <https://github.com/dart-lang/pub/blob/master/doc/solver.md#unit-propagation>
214
214
///
215
- /// Usually by the time we have a conflict `unit_propagation` has done a lot of work.
216
- /// So the actual conflict we find is important, but not particularly actionable.
217
- /// It says something like "the dependency on package X and the dependency on package Y are incompatible".
218
- /// To make it actionable we want to track it back to decisions that made the dependency required.
219
- /// "The decision on B is incompatible with the decision on C,
220
- /// because unit propagation from just those decisions will lead to the conflict about X and Y"
221
- /// is much more actionable, backtrack until one of those decisions can be revisited.
222
- /// To make a practical, we really only need one of the terms to be a decision.
223
- /// We may as well leave the other terms general. Something like
224
- /// "the dependency on the package X is incompatible with the decision on C" tends to work out pretty well.
225
- /// Then if A turns out to also have a dependency on X the resulting root cause is still useful.
226
- /// Of course, this is more heuristics than science. If the output is too general, then `unit_propagation` will
227
- /// handle the confusion by calling us again with the next most specific conflict it comes across.
228
- /// If the output is to specific, then the outer `solver` loop will eventually end up calling us again
229
- /// until all possibilities are enumerated.
215
+ /// When we found a conflict, we want to learn as much as possible from it, to avoid making (or
216
+ /// keeping) decisions that will be rejected. Say we found that the dependency requirements on X and the
217
+ /// dependency requirements on Y are incompatible. We may find that the decisions on earlier packages B and C
218
+ /// require us to make incompatible requirements on X and Y, so we backtrack until either B or C
219
+ /// can be revisited. To make it practical, we really only need one of the terms to be a
220
+ /// decision. We may as well leave the other terms general. Something like "the dependency on
221
+ /// the package X is incompatible with the decision on C" tends to work out pretty well. Then if
222
+ /// A turns out to also have a dependency on X the resulting root cause is still useful.
223
+ /// (`unit_propagation` will ensure we don't try that version of C.)
224
+ /// Of course, this is more heuristics than science. If the output is too general, then
225
+ /// `unit_propagation` will handle the confusion by calling us again with the next most specific
226
+ /// conflict it comes across. If the output is too specific, then the outer `solver` loop will
227
+ /// eventually end up calling us again until all possibilities are enumerated.
230
228
///
231
- /// This function combines incompatibilities with things that make the problem inevitable to end up with a
232
- /// more useful incompatibility. For the correctness of the PubGrub algorithm only the final output is required.
233
- /// By banning the final output, unit propagation will prevent the intermediate steps from occurring again,
234
- /// at least prevent the exact same way. However, the statistics collected for `prioritize`may want
235
- /// to analyze those intermediate steps. For example we might start with "there is no version 1 of Z",
236
- /// and `conflict_resolution` may be able to determine that "that was inevitable when we picked version 1 of X"
237
- /// which was inevitable when picked W and ... and version 1 of B, which was depended on by version 1 of A.
238
- /// Therefore the root cause may simplify all the way down to "we cannot pick version 1 of A".
239
- /// This will prevent us going down this path again. However when we start looking at version 2 of A,
240
- /// and discover that it depends on version 2 of B, we will want to prioritize the chain of intermediate steps
241
- /// to confirm if it has a problem with the same shape.
242
- /// The `satisfier_causes` argument keeps track of these intermediate steps so that the caller can use.
229
+ /// To end up with a more useful incompatibility, this function combines incompatibilities into
230
+ /// derivations. Fulfilling this derivation implies the later conflict. By banning it, we
231
+ /// prevent the intermediate steps from occurring again, at least in the exact same way.
232
+ /// However, the statistics collected for `prioritize` may want to analyze those intermediate
233
+ /// steps. For example we might start with "there is no version 1 of Z", and
234
+ /// `conflict_resolution` may be able to determine that "that was inevitable when we picked
235
+ /// version 1 of X" which was inevitable when we picked W and so on, until version 1 of B, which
236
+ /// was depended on by version 1 of A. Therefore the root cause may simplify all the way down to
237
+ /// "we cannot pick version 1 of A". This will prevent us going down this path again. However
238
+ /// when we start looking at version 2 of A, and discover that it depends on version 2 of B, we
239
+ /// will want to prioritize the chain of intermediate steps to check if it has a problem with
240
+ /// the same shape. The `satisfier_causes` argument keeps track of these intermediate steps so
241
+ /// that the caller can use them for prioritization.
243
242
#[ allow( clippy:: type_complexity) ]
244
243
#[ cold]
245
244
fn conflict_resolution (
0 commit comments