Implement range intersection conflict resolution
This commit introduces a range intersection conflict resolution strategy. To deal with this, an additional flag has been added to
selectors. The flag will tell if a selector is allowed to return multiple candidates. In this case, it is expected to be called
multiple times for different matching versions. The first version checked will always be the latest.
Before this change, if 2 dependencies disagree on a range, there could be a chance that a version was selected out of the intersection.
For example, if one depends on range `[3,6]` and another depends on range `[4,8]`, then the first range selects the latest revision in
range, which is `6`, and the second version selects `8`, which is the highest version within its range. Then conflict resolution kicks
in and sees `6` and `8`. It decides to upgrade to version `8`.
This commit, on the other hand, makes sure that if a selector can have multiple valid candidates, then we remember the other candidates
as well. When we see that `6` and `8` are in conflict, we then check if those selected versions come from a selector which had multiple
possible answers. If yes, then we compute the intersection of the ranges. In our example, the intersection of `[3,6]` and `[4,8]` is
`[4,6]`. The intersection is not empty, so it means that there's actually no conflict between the two ranges, because both ranges
agree that there are possible answers.
We then select the highest version within range, which is `6`, and choose the candidate which has this as its selected component version.
This is range `[3,6]`.
08 Sep 17 590c7582429719088ef07d912090e0d4d7b476af
This commit merges `RepositoryResolveState` with `ComponentSelectionContext`. This makes the code easier to read, by avoiding
incomprehensible back references. Unit tests are also clearer since they now clearly show which versions were tested, rejected
and not found.
06 Sep 17 25ee6c68e80355ee1a64ae0dcad9efac6051652d