-
Notifications
You must be signed in to change notification settings - Fork 712
Fix construction of conflict sets once and for all (WIP) #3357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
1a1f1f9
Make ConflictSet abstract
edsko 2cee0fe
Add test case for backjumping after enforcing SIR
grayjay 3bc157a
Fix construction of conflict sets during SIR
edsko 503593c
Fix construction of conflict sets in cycle check
edsko 8ddf587
Explain test in more detail
edsko 91e2be1
Add failing test case
grayjay 6a4aa92
Explain test case in a bit more detail
edsko 98c7fef
Add test case for inconsistent dependency bug
grayjay 8c22df4
Use tasty-expected-failure for failing unit test
grayjay 81b1f1a
Document test case
edsko 2f4c440
Test that setup dependencies of linked packages are linked correctly
grayjay 0fe6258
Add failing test case for conflict set bug
grayjay 6835115
Sort solver unit tests
grayjay 2cfe4e3
Add issue numbers to solver unit tests
grayjay 6617ca6
Fix link deps
edsko bafcd96
Expect test to pass
grayjay 9bf8e81
Merge pull request #3359 from grayjay/solver-test-cases
edsko 6949def
Merge pull request #3360 from grayjay/rebase-FixLinkDeps
edsko ed0f002
Add test case for backjumping when dependencies are not linked
grayjay d4b08e9
Merge pull request #3363 from grayjay/test-3327
edsko 7995ea2
Remove goal reason chains.
kosmikus 9a3e339
Fix incorrect comment
edsko 5a4149f
Use empty POption for unknown packages
edsko 34bfdf8
Fix bug in link validation
edsko 440033d
Declare indepGoals3 as passing.
edsko 7f48059
Use larger conflict set when solver chooses wrong version for package…
grayjay fc2739e
Remove reference to tasty-expected-failure (#3367)
grayjay 26252b4
Replace toConflictSet by goalVar/varToConflictSet
edsko 0a2e772
Document unqualifyDeps
edsko 188e4f4
Fix (very) minor mistake during merging
edsko 04bc698
Use zipWithM in linkDeps
edsko 49b422b
Remove redundant calls to simplifyVar
edsko 119f3e6
Rename args to linkDeps
edsko 4ff4e2b
Document that qualification is flag independent
edsko 162d258
Add two more solver test cases.
kosmikus 018e936
Add the current goal to the initial conflict set while backjumping.
kosmikus 16cae8a
Replace Goal with Var where possible; remove Unknown goal reason.
kosmikus 268edad
Allow to test error messages in the solver tests.
kosmikus ef050ee
Remove a redundant import.
kosmikus 2fc1c14
Remove redundant constraints.
kosmikus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
cabal-install/Distribution/Client/Dependency/Modular/ConflictSet.hs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
{-# LANGUAGE CPP #-} | ||
-- | Conflict sets | ||
-- | ||
-- Intended for double import | ||
-- | ||
-- > import Distribution.Client.Dependency.Modular.ConflictSet (ConflictSet) | ||
-- > import qualified Distribution.Client.Dependency.Modular.ConflictSet as CS | ||
module Distribution.Client.Dependency.Modular.ConflictSet ( | ||
ConflictSet -- opaque | ||
, showCS | ||
-- Set-like operations | ||
, toList | ||
, union | ||
, unions | ||
, insert | ||
, empty | ||
, singleton | ||
, member | ||
, filter | ||
, fromList | ||
) where | ||
|
||
import Prelude hiding (filter) | ||
import Data.List (intercalate) | ||
import Data.Set (Set) | ||
import qualified Data.Set as S | ||
|
||
import Distribution.Client.Dependency.Modular.Package | ||
import Distribution.Client.Dependency.Modular.Var | ||
|
||
-- | The set of variables involved in a solver conflict | ||
-- | ||
-- Since these variables should be preprocessed in some way, this type is | ||
-- kept abstract. | ||
newtype ConflictSet qpn = CS { fromConflictSet :: Set (Var qpn) } | ||
deriving (Eq, Ord, Show) | ||
|
||
showCS :: ConflictSet QPN -> String | ||
showCS = intercalate ", " . map showVar . toList | ||
|
||
{------------------------------------------------------------------------------- | ||
Set-like operations | ||
-------------------------------------------------------------------------------} | ||
|
||
toList :: ConflictSet qpn -> [Var qpn] | ||
toList = S.toList . fromConflictSet | ||
|
||
union :: Ord qpn => ConflictSet qpn -> ConflictSet qpn -> ConflictSet qpn | ||
union (CS a) (CS b) = CS (a `S.union` b) | ||
|
||
unions :: Ord qpn => [ConflictSet qpn] -> ConflictSet qpn | ||
unions = CS . S.unions . map fromConflictSet | ||
|
||
insert :: Ord qpn => Var qpn -> ConflictSet qpn -> ConflictSet qpn | ||
insert var (CS set) = CS (S.insert (simplifyVar var) set) | ||
|
||
empty :: ConflictSet qpn | ||
empty = CS S.empty | ||
|
||
singleton :: Var qpn -> ConflictSet qpn | ||
singleton = CS . S.singleton . simplifyVar | ||
|
||
member :: Ord qpn => Var qpn -> ConflictSet qpn -> Bool | ||
member var (CS set) = S.member (simplifyVar var) set | ||
|
||
#if MIN_VERSION_containers(0,5,0) | ||
filter :: (Var qpn -> Bool) -> ConflictSet qpn -> ConflictSet qpn | ||
#else | ||
filter :: Ord qpn => (Var qpn -> Bool) -> ConflictSet qpn -> ConflictSet qpn | ||
#endif | ||
filter p (CS set) = CS $ S.filter p set | ||
|
||
fromList :: Ord qpn => [Var qpn] -> ConflictSet qpn | ||
fromList = CS . S.fromList . map simplifyVar |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm leaning towards reverting this, and simply adapting the conflict set for the
FailF
, which is easy enough. The log manipulation seems fragile to me, and having to adapt the initial conflict set in backjumping instead is also not really nicer.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I thought that including the current variable in the initial conflict set was more correct. If we were using an explicit
_|_
node, and it wasn't last in the list of children, its conflict set would need to contain the current variable in order for the solver to try the other siblings.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grayjay I'm certainly still undecided on this, but I don't think I understand your argument: the original code creates an explicit Failure node here in place of a package choice node, so it'll be a child of a goal choice node. I don't understand what you mean about it being last in a list of children in this context ...
Or are you talking about something different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kosmikus Maybe I misunderstood, but I thought part of the change to use an empty
PChoice
involved adding the current variable to the initial conflict set that is given to the backjump function. Theninitial
would contain the current variable and the goal reason variable. I meant to say that I thought using both variables was more correct than using just the goal reason, regardless of how we deal with unknown packages.I think it makes sense to revert the rest of the empty
POption
change, because it complicates the log processing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grayjay But why do you think it's "more correct"? Except in the case where we have no available choices at all (the one we're talking about here), the only way we could be asked to
Fail
here is because we discovered conflicts lower in the tree. But then we're backjumping already, and we wouldn't even consider the current node if their conflict didn't include our package name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This I disagree with. Log processing is just that -- log processing. Having the conflict sets created in the same way everywhere seems a worthwhile goal to have to me. Having one place in the tree construction where the conflict set is created in a different way to everywhere else seems very unfortunate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that
initial
represents the_|_
node, and_|_
should have a conflict set containing the current variable. Say we used an explicit_|_
node, and it happened to be first in the list of children. If_|_
didn't contain the current variable, the solver would backjump after reaching the failure and would skip the siblings, even though those siblings might lead to solutions.Since we're not using an explicit failure node, adding the current variable to
initial
wouldn't actually affect the behavior. I just thought it might be more consistent with representing the_|_
node.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grayjay Oh ok, I understand your argument now, and I agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edsko I just meant that I was okay with reverting the change; I don't have a strong opinion. Now that we show the unknown package in the summarized log, I'm happy with the empty
PChoice
approach. I like how it simplifies conflict sets.