Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4a48ec0
filter == version constraints
philderbeast Jan 30, 2026
f2e190c
Show flag setting in FailReason
philderbeast Feb 2, 2026
50ff059
Add changelog
philderbeast Feb 2, 2026
619d09a
Add tests using projects
philderbeast Feb 6, 2026
ffb08da
SkipIfOSX
philderbeast Feb 6, 2026
7de5921
Update expectation in solver unit test
philderbeast Feb 7, 2026
94d71bf
Add constrained solving tests
philderbeast Feb 9, 2026
292786e
Add mkConstraint
philderbeast Feb 9, 2026
5ba7c48
Use normalise not normaliseVersionRange
philderbeast Feb 10, 2026
6e90de1
Add >= version constraint check
philderbeast Feb 10, 2026
4c36dc5
Finer grained test groups; pass and rejects
philderbeast Feb 10, 2026
d1100f0
Add <= tests
philderbeast Feb 10, 2026
1c76221
Combine >= with <= tests
philderbeast Feb 10, 2026
2019049
Test >0 && ==1 and also ==1 && >0
philderbeast Feb 10, 2026
07758e8
Test B <=1 && >=1, C <=1 && >=1
philderbeast Feb 10, 2026
f999d0c
Reuse solutions
philderbeast Feb 10, 2026
d1b1ed3
Test >0 && ==1 && <2
philderbeast Feb 10, 2026
5658156
Lines between commented bindings
philderbeast Feb 10, 2026
b9046cf
Add test for B ==1 || >0, C >0 || ==1
philderbeast Feb 10, 2026
cf73447
Add eqFailure
philderbeast Feb 10, 2026
575f141
Add test for ^>=1 constraint
philderbeast Feb 11, 2026
836a928
Change s/all goals/goal all/
philderbeast Feb 11, 2026
4101ecd
Add test for ==1 || ==2
philderbeast Feb 11, 2026
49a73ac
Add test for ==1 || >1 and ==1 || <1
philderbeast Feb 11, 2026
36a8555
Add VersionEqualitiesInPackages test
philderbeast Feb 11, 2026
f387810
Follow hlint suggestion: redundant $
philderbeast Mar 20, 2026
f3c69ab
Satisfy fourmolu
philderbeast Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import Distribution.Types.UnqualComponentName
( unUnqualComponentName )

import Text.PrettyPrint ( nest, render )
import Distribution.Solver.Types.Settings (OnlyConstrained(..))

-- A data type to hold log information from the modular solver.
data Message =
Expand Down Expand Up @@ -311,7 +312,7 @@ showFR _ (PackageRequiresMissingComponent qpn comp) = " (requires " ++ showExpos
showFR _ (PackageRequiresPrivateComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component is private)"
showFR _ (PackageRequiresUnbuildableComponent qpn comp) = " (requires " ++ showExposedComponent comp ++ " from " ++ showQPN qpn ++ ", but the component is not buildable in the current environment)"
showFR _ CannotReinstall = " (avoiding to reinstall a package with same version but new dependencies)"
showFR _ NotExplicit = " (not a user-provided goal nor mentioned as a constraint, but reject-unconstrained-dependencies was set)"
showFR _ (NotExplicit oc) = showNotExplicit oc
showFR _ Shadowed = " (shadowed by another installed package with same version)"
showFR _ (Broken u) = " (package is broken, missing dependency " ++ prettyShow u ++ ")"
showFR _ UnknownPackage = " (unknown package)"
Expand All @@ -334,6 +335,11 @@ showFR _ (MalformedFlagChoice qfn) = " (INTERNAL ERROR: MALFORMED FLAG CH
showFR _ (MalformedStanzaChoice qsn) = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ showQSN qsn ++ ")"
showFR _ EmptyGoalChoice = " (INTERNAL ERROR: EMPTY GOAL CHOICE)"

showNotExplicit :: OnlyConstrained -> String
showNotExplicit oc = if oc == OnlyConstrainedNone
then " (INTERNAL ERROR: NOT EXPLICIT when reject-unconstrained-dependencies=" ++ prettyShow oc ++ " was set)"
else " (not a user-provided goal nor mentioned as a constraint, but reject-unconstrained-dependencies=" ++ prettyShow oc ++ " was set)"

showExposedComponent :: ExposedComponent -> String
showExposedComponent (ExposedLib LMainLibName) = "library"
showExposedComponent (ExposedLib (LSubLibName name)) = "library '" ++ unUnqualComponentName name ++ "'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import Distribution.Solver.Modular.Tree
import Distribution.Solver.Modular.Version
import qualified Distribution.Solver.Modular.ConflictSet as CS
import qualified Distribution.Solver.Modular.WeightedPSQ as W
import Distribution.Solver.Types.Settings (OnlyConstrained(..))

-- | Update the weights of children under 'PChoice' nodes. 'addWeights' takes a
-- list of weight-calculating functions in order to avoid sorting the package
Expand Down Expand Up @@ -351,13 +352,13 @@ avoidReinstalls p = go
go x = x

-- | Require all packages to be mentioned in a constraint or as a goal.
onlyConstrained :: (PN -> Bool) -> EndoTreeTrav d QGoalReason
onlyConstrained p = go
onlyConstrained :: OnlyConstrained -> (PN -> Bool) -> EndoTreeTrav d QGoalReason
onlyConstrained oc p = go
where
go (PChoiceF v@(Q _ pn) _ gr _) | not (p pn)
= FailF
(varToConflictSet (P v) `CS.union` goalReasonToConflictSetWithConflict v gr)
NotExplicit
(NotExplicit oc)
go x
= x

Expand Down
26 changes: 18 additions & 8 deletions cabal-install-solver/src/Distribution/Solver/Modular/Solver.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
#ifdef DEBUG_TRACETREE
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
Expand All @@ -11,6 +12,7 @@ module Distribution.Solver.Modular.Solver

import Distribution.Solver.Compat.Prelude
import Prelude ()
import Data.Function ((&))

import qualified Data.Map as M
import qualified Data.List as L
Expand All @@ -19,10 +21,12 @@ import Distribution.Verbosity

import Distribution.Compiler (CompilerInfo)

import Distribution.Version
import Distribution.Solver.Types.PackagePath
import Distribution.Solver.Types.PackagePreferences
import Distribution.Solver.Types.PkgConfigDb (PkgConfigDb)
import Distribution.Solver.Types.LabeledPackageConstraint
import Distribution.Solver.Types.PackageConstraint (PackageConstraint(..), PackageProperty(..))
import Distribution.Solver.Types.Settings
import Distribution.Solver.Types.Variable

Expand Down Expand Up @@ -139,18 +143,15 @@ solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =
validateLinking idx .
validateTree cinfo idx pkgConfigDB
prunePhase = (if asBool (avoidReinstalls sc) then P.avoidReinstalls (const True) else id) .
(case onlyConstrained sc of
OnlyConstrainedAll ->
P.onlyConstrained pkgIsExplicit
OnlyConstrainedNone ->
id)
(let oc = onlyConstrained sc in oc & \case
OnlyConstrainedEq -> P.onlyConstrained oc (`S.member` allExplicitEq)
OnlyConstrainedAll -> P.onlyConstrained oc (`S.member` allExplicit)
OnlyConstrainedNone -> id)
buildPhase = buildTree idx (independentGoals sc) (S.toList userGoals)

allExplicitEq = M.keysSet (filterThisVersion userConstraints) `S.union` userGoals
allExplicit = M.keysSet userConstraints `S.union` userGoals

pkgIsExplicit :: PN -> Bool
pkgIsExplicit pn = S.member pn allExplicit

-- When --reorder-goals is set, we use preferReallyEasyGoalChoices, which
-- prefers (keeps) goals only if the have 0 or 1 enabled choice.
--
Expand All @@ -167,6 +168,15 @@ solve sc cinfo idx pkgConfigDB userPrefs userConstraints userGoals =
| asBool (reorderGoals sc) = P.preferReallyEasyGoalChoices
| otherwise = id {- P.firstGoal -}

-- | Keep version ranges that normalise to equality version constraints (== v).
filterThisVersion :: M.Map PN [LabeledPackageConstraint] -> M.Map PN [LabeledPackageConstraint]
filterThisVersion = M.filter (not . null) . M.map (filter isThisVersion) where
normalise = fromVersionIntervals . toVersionIntervals
isThisVersion lpc
| LabeledPackageConstraint (PackageConstraint _ (PackagePropertyVersion vr)) _ <- lpc
, ThisVersionF _ <- projectVersionRange $ normalise vr = True
| otherwise = False

-- | Dump solver tree to a file (in debugging mode)
--
-- This only does something if the @debug-tracetree@ configure argument was
Expand Down
3 changes: 2 additions & 1 deletion cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Distribution.Solver.Types.PackagePath
import Distribution.Types.PkgconfigVersionRange
import Distribution.Types.UnitId (UnitId)
import Language.Haskell.Extension (Extension, Language)
import Distribution.Solver.Types.Settings (OnlyConstrained(..))

type Weight = Double

Expand Down Expand Up @@ -112,7 +113,7 @@ data FailReason = UnsupportedExtension Extension
| PackageRequiresPrivateComponent QPN ExposedComponent
| PackageRequiresUnbuildableComponent QPN ExposedComponent
| CannotReinstall
| NotExplicit
| NotExplicit OnlyConstrained
| Shadowed
| Broken UnitId
| UnknownPackage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ newtype AllowBootLibInstalls = AllowBootLibInstalls Bool
data OnlyConstrained
= OnlyConstrainedNone
| OnlyConstrainedAll
| OnlyConstrainedEq
deriving (Eq, Generic, Show)

newtype EnableBackjumping = EnableBackjumping Bool
Expand Down Expand Up @@ -108,12 +109,14 @@ instance NFData AllowBootLibInstalls
instance NFData OnlyConstrained

instance Pretty OnlyConstrained where
pretty OnlyConstrainedEq = PP.text "eq"
pretty OnlyConstrainedAll = PP.text "all"
pretty OnlyConstrainedNone = PP.text "none"

instance Parsec OnlyConstrained where
parsec = P.choice
[ P.string "all" >> return OnlyConstrainedAll
[ P.string "eq" >> return OnlyConstrainedEq
, P.string "all" >> return OnlyConstrainedAll
, P.string "none" >> return OnlyConstrainedNone
]

Expand Down
4 changes: 2 additions & 2 deletions cabal-install/src/Distribution/Client/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3736,9 +3736,9 @@ optionSolverFlags
getoc
setoc
( reqArg
"none|all"
"none|all|eq"
( parsecToReadE
(const "reject-unconstrained-dependencies must be 'none' or 'all'")
(const "reject-unconstrained-dependencies must be 'none', 'all', or 'eq'")
(toFlag `fmap` parsec)
)
(flagToList . fmap prettyShow)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

-- | Utilities for creating HUnit test cases with the solver DSL.
module UnitTests.Distribution.Solver.Modular.DSL.TestCaseUtils
( SolverTest
( SolverTest (..)
, SolverResult (..)
, maxBackjumps
, disableFineGrainedConflicts
Expand Down Expand Up @@ -80,9 +80,9 @@ allowBootLibInstalls :: SolverTest -> SolverTest
allowBootLibInstalls test =
test{testAllowBootLibInstalls = AllowBootLibInstalls True}

onlyConstrained :: SolverTest -> SolverTest
onlyConstrained test =
test{testOnlyConstrained = OnlyConstrainedAll}
onlyConstrained :: OnlyConstrained -> SolverTest -> SolverTest
onlyConstrained oc test =
test{testOnlyConstrained = oc}

disableBackjumping :: SolverTest -> SolverTest
disableBackjumping test =
Expand Down
Loading
Loading