Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Solver: Improve error message by finding a minimal conflict set (issue …
…haskell#5647). This commit improves the error message in the case where the solver finds no solution after an exhaustive search. Previously, cabal generated the error message by rerunning the solver and having it prefer goals from the final conflict set, so that the error message only mentioned conflicts between packages from the final conflict set. Conflicts relating to the final conflict set are more likely to be relevant, because the conflict set contains all variables that are involved in one conflict that makes the dependencies unsatisfiable. However, the conflict set can also include variables that led to some conflicts but aren't relevant to the main conflict. This commit improves the error message further by first trying to reduce the size of the conflict set. The current algorithm for reducing the conflict set simply reruns the solver with different goal orders, so it has some downsides: - Reducing the conflict set can be slow. It is also possible for the solver to reach the backjump limit on a rerun, even though the first run completed. In that case, it uses the original conflict set. - The function can fail to remove some unnecessary variables from the conflict set. In the worst case, it returns the original conflict set. I tested the feature on the example in https://www.reddit.com/r/haskell/comments/9rmh9s/how_to_read_cabal_solver_failure_output/ and haskell#5647. Both runs used the command "cabal install --only-dependencies --enable-tests --force-reinstalls --index-state=2018-10-26T20:30:16Z". Before: Resolving dependencies... cabal: Could not resolve dependencies: [__0] trying: opaleye-0.6.7003.0 (user goal) [__1] rejecting: opaleye:!test (constraint from config file, command line flag, or user target requires opposite flag selection) [__1] trying: opaleye:*test [__2] trying: dotenv-0.6.0.3 (dependency of opaleye *test) [__3] trying: transformers-0.5.5.0/installed-0.5... (dependency of opaleye) [__4] next goal: contravariant (dependency of opaleye) [__4] rejecting: contravariant-1.5 (conflict: opaleye => contravariant>=1.2 && <1.5) [__4] rejecting: contravariant-1.4.1, contravariant-1.4 (conflict: transformers => base==4.12.0.0/installed-4.1..., contravariant => base<4.12) [__4] rejecting: contravariant-1.3.3, contravariant-1.3.2, contravariant-1.3.1.1, contravariant-1.3.1, contravariant-1.3, contravariant-1.2.2.1, contravariant-1.2.2, contravariant-1.2.1, contravariant-1.2.0.1, contravariant-1.2 (conflict: transformers==0.5.5.0/installed-0.5..., contravariant => transformers>=0.2 && <0.5) [__4] rejecting: contravariant-1.1, contravariant-1.0, contravariant-0.6.1.1, contravariant-0.6.1, contravariant-0.6, contravariant-0.5.2, contravariant-0.5.1, contravariant-0.5, contravariant-0.4.4, contravariant-0.4.3, contravariant-0.4.1, contravariant-0.4, contravariant-0.3, contravariant-0.2.0.2, contravariant-0.2.0.1, contravariant-0.2, contravariant-0.1.3, contravariant-0.1.2.1, contravariant-0.1.2, contravariant-0.1.1, contravariant-0.1.0.1, contravariant-0.1.0 (conflict: opaleye => contravariant>=1.2 && <1.5) [__4] fail (backjumping, conflict set: contravariant, opaleye, transformers) After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: transformers, contravariant, opaleye, base, dotenv, opaleye:test After: Resolving dependencies... cabal: Could not resolve dependencies: [__0] trying: opaleye-0.6.7003.0 (user goal) [__1] trying: transformers-0.5.5.0/installed-0.5... (dependency of opaleye) [__2] next goal: contravariant (dependency of opaleye) [__2] rejecting: contravariant-1.5 (conflict: opaleye => contravariant>=1.2 && <1.5) [__2] rejecting: contravariant-1.4.1, contravariant-1.4 (conflict: transformers => base==4.12.0.0/installed-4.1..., contravariant => base<4.12) [__2] rejecting: contravariant-1.3.3, contravariant-1.3.2, contravariant-1.3.1.1, contravariant-1.3.1, contravariant-1.3, contravariant-1.2.2.1, contravariant-1.2.2, contravariant-1.2.1, contravariant-1.2.0.1, contravariant-1.2 (conflict: transformers==0.5.5.0/installed-0.5..., contravariant => transformers>=0.2 && <0.5) [__2] rejecting: contravariant-1.1, contravariant-1.0, contravariant-0.6.1.1, contravariant-0.6.1, contravariant-0.6, contravariant-0.5.2, contravariant-0.5.1, contravariant-0.5, contravariant-0.4.4, contravariant-0.4.3, contravariant-0.4.1, contravariant-0.4, contravariant-0.3, contravariant-0.2.0.2, contravariant-0.2.0.1, contravariant-0.2, contravariant-0.1.3, contravariant-0.1.2.1, contravariant-0.1.2, contravariant-0.1.1, contravariant-0.1.0.1, contravariant-0.1.0 (conflict: opaleye => contravariant>=1.2 && <1.5) [__2] fail (backjumping, conflict set: contravariant, opaleye, transformers) After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: base, opaleye, contravariant, transformers In this case, the feature found a minimal conflict set, {base, opaleye, contravariant, transformers}, by removing dotenv and opaleye:test from the original conflict set.
- Loading branch information