Skip to content
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

Allow the solver to toggle manual flags to match constraints that have any qualifier. #4342

Merged
merged 3 commits into from Feb 20, 2017

Conversation

grayjay
Copy link
Collaborator

@grayjay grayjay commented Feb 19, 2017

Three commits:

Allow the solver to toggle manual flags to match constraints that have any qualifier.

This fixes #4299. The change gives the dependency solver the flexibility to link
dependencies when the user has only set a manual flag on one of them.
Previously, the solver would force the constrained dependency to have the
flag value from the constraint and force the unconstrained dependency to have
the default flag value. In cases where the single instance restriction required
the dependencies to be linked, the solver couldn't find a solution.

Qualified constraints can still be used to force different dependencies on a
package to use different flag values. For example,
--constraint 'pkg +flag' --constraint 'pkg2:setup.pkg -flag' turns the flag on
for the top-level dependency and off for the setup dependency.

I also stored flag default values in the search tree to simplify the code.

Add manual flags to the solver DSL.

Tests can now declare flags before using them, in order to specify non-default
values for the fields in D.Types.GenericPackageDescription.Flag.

Add tests for manual flags.


@23Skidoo Do you think we could add this to the release branch? I wanted to fix #4299 because it's a regression.

@ezyang What do you think of this solution?

/cc @kosmikus

…e any qualifier.

This fixes haskell#4299. The change gives the dependency solver the flexibility to link
dependencies when the user has only set a manual flag on one of them.
Previously, the solver would force the constrained dependency to have the
flag value from the constraint and force the unconstrained dependency to have
the default flag value. In cases where the single instance restriction required
the dependencies to be linked, the solver couldn't find a solution.

Qualified constraints can still be used to force different dependencies on a
package to use different flag values. For example,
"--constraint 'pkg +flag' --constraint 'pkg2:setup.pkg -flag'" turns the flag on
for the top-level dependency and off for the setup dependency.

I also stored flag default values in the search tree to simplify the code.
Tests can now declare flags before using them, in order to specify non-default
values for the fields in 'D.Types.GenericPackageDescription.Flag'.
@mention-bot
Copy link

@grayjay, thanks for your PR! By analyzing the history of the files in this pull request, we identified @edsko, @ezyang and @kosmikus to be potential reviewers.

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read through the key diff until it made sense. I will admit the approach taken is a little indirect; for example, if I have three instances of a flag, and one is explicitly set to True (via a constraint) and the other is explicitly set to False (ditto), then the third instance will be toggled by the solver however it wants (since there is "a constraint" for true and "a constraint" for false). In fact, IIUC, it can toggle the flag even if we don't end up linking?

OTOH, I don't really know you would directly say, "If you link, toggle the manual flag this way", so this might be OK for now.

checkChild qpn x@(GoalChoice rdm _) = failIfCycle qpn rdm x
checkChild _ x@(Fail _ _) = x
checkChild qpn x@(Done rdm _) = failIfCycle qpn rdm x
checkChild qpn x@(PChoice _ rdm _ _) = failIfCycle qpn rdm x
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something you have to do, but I wonder if we shouldn't have selectors here :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What type of selector? A function that returns a Maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

--
-- This function does not enforce any of the constraints, since that is done by
-- 'enforcePackageConstraints'.
enforceManualFlags :: M.Map PN [LabeledPackageConstraint] -> Tree d c -> Tree d c
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key change!

@23Skidoo
Copy link
Member

Sure, I can cherry-pick this into 2.0.

Copy link
Member

@23Skidoo 23Skidoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed this PR thoroughly, but the idea makes sense to me, so I'm merging this.

@@ -166,16 +169,23 @@ data ExampleDependency =
| ExPkg (ExamplePkgName, ExamplePkgVersion)
deriving Show

data ExFlag = ExFlag {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Haddock comment here would be nice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a PR: #4345

@23Skidoo 23Skidoo merged commit 330857a into haskell:master Feb 20, 2017
@23Skidoo
Copy link
Member

Also cherry-picked into 2.0.

@grayjay
Copy link
Collaborator Author

grayjay commented Feb 20, 2017

@23Skidoo @ezyang Thanks!

I read through the key diff until it made sense. I will admit the approach taken is a little indirect; for example, if I have three instances of a flag, and one is explicitly set to True (via a constraint) and the other is explicitly set to False (ditto), then the third instance will be toggled by the solver however it wants (since there is "a constraint" for true and "a constraint" for false). In fact, IIUC, it can toggle the flag even if we don't end up linking?

Yes, the third instance can take either value, even if it isn't linked. I thought that would be more consistent with how the solver behaves in other situations. It usually treats linking as just an optimization: any choices that are allowed when packages are linked are also allowed when the packages aren't linked. (The one exception is the single instance restriction, but I think we can remove that now.)

I also wanted to avoid adding a dependency between manual flag choices and linking. In general, dependencies between different choices made by the solver lead to larger conflict sets and longer run times. If we need to control manual flag values more precisely, we could add it later.

@grayjay grayjay deleted the issue-4299 branch February 20, 2017 20:04
@ezyang
Copy link
Contributor

ezyang commented Feb 20, 2017

Aha! I guess I misunderstood how linking works; I thought it was semantically meaningful, probably due to its use for handling the single instance restriction. So then, would it be accurate to say that if we got rid of the single instance restriction, this patch wouldn't be necessary either?

@grayjay
Copy link
Collaborator Author

grayjay commented Feb 21, 2017

Yes, that was one of my suggestions in #4299. Maybe we can remove the single instance restriction on master and then revert this behavior change. I'm not sure how hard that would be. A few sections of code assume that there is only one instance of each package, and we might need to change how the solver decides when to build the inplace copies of packages.

@ezyang
Copy link
Contributor

ezyang commented Feb 21, 2017

Oops, I missed that! Maybe it is worth a comment saying that this change can be reverted if single instance is dropped. If the semantics here cause us trouble in the future, we'll know what to change!

@grayjay
Copy link
Collaborator Author

grayjay commented Feb 22, 2017

Good idea. I made a PR: #4354

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot find solution with +parsec on Cabal, with cabal-install HEAD
4 participants