Skip to content

Commit b5777d6

Browse files
committed
refactor(Cabal-syntax): Improve Graph.broken
If a node has dangling edges, then the list of missing neighbours cannot be empty.
1 parent c196779 commit b5777d6

File tree

7 files changed

+39
-31
lines changed

7 files changed

+39
-31
lines changed

Cabal-syntax/src/Distribution/Compat/Graph.hs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ import qualified Data.Graph as G
103103
import qualified Data.Map.Strict as Map
104104
import qualified Data.Set as Set
105105
import qualified Data.Tree as Tree
106-
import qualified Distribution.Compat.Prelude as Prelude
107106
import GHC.Stack (HasCallStack)
107+
import qualified Data.List.NonEmpty as NE
108108

109109
-- | A graph of nodes @a@. The nodes are expected to have instance
110110
-- of class 'IsNode'.
@@ -115,7 +115,7 @@ data Graph a = Graph
115115
, graphAdjoint :: G.Graph
116116
, graphVertexToNode :: G.Vertex -> a
117117
, graphKeyToVertex :: Key a -> Maybe G.Vertex
118-
, graphBroken :: [(a, [Key a])]
118+
, graphBroken :: [(a, NonEmpty (Key a))]
119119
}
120120

121121
-- NB: Not a Functor! (or Traversable), because you need
@@ -285,7 +285,7 @@ cycles g = [vs | CyclicSCC vs <- stronglyConnComp g]
285285
-- | /O(1)/. Return a list of nodes paired with their broken
286286
-- neighbors (i.e., neighbor keys which are not in the graph).
287287
-- Requires amortized construction of graph.
288-
broken :: Graph a -> [(a, [Key a])]
288+
broken :: Graph a -> [(a, NonEmpty (Key a))]
289289
broken g = graphBroken g
290290

291291
-- | Lookup the immediate neighbors from a key in the graph.
@@ -344,7 +344,7 @@ revTopSort g = map (graphVertexToNode g) $ G.topSort (graphAdjoint g)
344344
-- if you can't fulfill this invariant use @'fromList' ('Data.Map.elems' m)@
345345
-- instead. The values of the map are assumed to already
346346
-- be in WHNF.
347-
fromMap :: IsNode a => Map (Key a) a -> Graph a
347+
fromMap :: forall a. (IsNode a, Eq (Key a)) => Map (Key a) a -> Graph a
348348
fromMap m =
349349
Graph
350350
{ graphMap = m
@@ -353,18 +353,27 @@ fromMap m =
353353
, graphAdjoint = G.transposeG g
354354
, graphVertexToNode = vertex_to_node
355355
, graphKeyToVertex = key_to_vertex
356-
, graphBroken = broke
356+
, graphBroken =
357+
map (\ns'' -> (fst (NE.head ns''), NE.map snd ns''))
358+
$ NE.groupWith (nodeKey . fst)
359+
$ brokenEdges'
357360
}
358361
where
359-
try_key_to_vertex k = maybe (Left k) Right (key_to_vertex k)
360-
362+
brokenEdges' :: [(a, Key a)]
363+
brokenEdges' = concat brokenEdges
364+
365+
brokenEdges :: [[(a, Key a)]]
361366
(brokenEdges, edges) =
362-
unzip $
363-
[ partitionEithers (map try_key_to_vertex (nodeNeighbors n))
364-
| n <- ns
365-
]
366-
broke = filter (not . Prelude.null . snd) (zip ns brokenEdges)
367-
367+
unzip
368+
[ partitionEithers
369+
[ case key_to_vertex n' of
370+
Just v -> Right v
371+
Nothing -> Left (n, n')
372+
| n' <- nodeNeighbors n
373+
]
374+
| n <- ns
375+
]
376+
368377
g = Array.listArray bounds edges
369378

370379
ns = Map.elems m -- sorted ascending

Cabal/src/Distribution/Backpack/Configure.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,14 @@ toComponentLocalBuildInfos
283283
[ "installed package "
284284
++ prettyShow (packageId pkg)
285285
++ " is broken due to missing package "
286-
++ intercalate ", " (map prettyShow deps)
286+
++ intercalate ", " (map prettyShow $ toList deps)
287287
| (Left pkg, deps) <- broken
288288
]
289289
++ unlines
290290
[ "planned package "
291291
++ prettyShow (packageId pkg)
292292
++ " is broken due to missing package "
293-
++ intercalate ", " (map prettyShow deps)
293+
++ intercalate ", " (map prettyShow $ toList deps)
294294
| (Right pkg, deps) <- broken
295295
]
296296

cabal-install/src/Distribution/Client/CmdErrorMessages.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ renderCannotPruneDependencies (CannotPruneDependencies brokenPackages) =
501501
where
502502
-- throw away the details and just list the deps that are needed
503503
pkgids :: [PackageId]
504-
pkgids = nub . map packageId . concatMap snd $ brokenPackages
504+
pkgids = nub . map packageId . concatMap (NE.toList . snd) $ brokenPackages
505505

506506
{-
507507
++ "Syntax:\n"

cabal-install/src/Distribution/Client/Install.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ pruneInstallPlan pkgSpecifiers =
715715
nub
716716
[ depid
717717
| SolverInstallPlan.PackageMissingDeps _ depids <- problems
718-
, depid <- depids
718+
, depid <- toList depids
719719
, packageName depid `elem` targetnames
720720
]
721721

cabal-install/src/Distribution/Client/InstallPlan.hs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,7 @@ data PlanProblem ipkg srcpkg
10401040
= PackageMissingDeps
10411041
(GenericPlanPackage ipkg srcpkg)
10421042
-- ^ The package that is missing dependencies
1043-
[GraphKey ipkg srcpkg]
1043+
(NonEmpty (GraphKey ipkg srcpkg))
10441044
-- ^ The missing dependencies
10451045
| PackageCycle
10461046
[GenericPlanPackage ipkg srcpkg]
@@ -1070,7 +1070,7 @@ renderPlanProblem (PackageMissingDeps pkg missingDeps) =
10701070
fsep [ text "Package"
10711071
, pretty (nodeKey pkg)
10721072
, text "depends on the following packages which are missing from the plan:"
1073-
, fsep (punctuate comma (map pretty missingDeps))
1073+
, fsep (punctuate comma (map pretty $ NE.toList missingDeps))
10741074
]
10751075
renderPlanProblem (PackageCycle cycleGroup) =
10761076
fsep [ text "The following packages are involved in a dependency cycle:"
@@ -1111,10 +1111,7 @@ checkForMissingDeps
11111111
checkForMissingDeps graph =
11121112
[ PackageMissingDeps
11131113
pkg
1114-
( mapMaybe
1115-
(fmap nodeKey . flip Graph.lookup graph)
1116-
missingDeps
1117-
)
1114+
missingDeps
11181115
| (pkg, missingDeps) <- Graph.broken graph
11191116
]
11201117

cabal-install/src/Distribution/Client/ProjectPlanning.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3897,7 +3897,7 @@ pruneInstallPlanToDependencies pkgTargets installPlan =
38973897
CannotPruneDependencies
38983898
[ (pkg, missingDeps)
38993899
| (pkg, missingDepIds) <- brokenPackages
3900-
, let missingDeps = mapMaybe lookupDep missingDepIds
3900+
, let missingDeps = NE.map (fromMaybe (error "should not happen") . lookupDep) missingDepIds
39013901
]
39023902
where
39033903
-- lookup in the original unpruned graph
@@ -3912,7 +3912,7 @@ pruneInstallPlanToDependencies pkgTargets installPlan =
39123912
newtype CannotPruneDependencies
39133913
= CannotPruneDependencies
39143914
[ ( ElaboratedPlanPackage
3915-
, [ElaboratedPlanPackage]
3915+
, NonEmpty ElaboratedPlanPackage
39163916
)
39173917
]
39183918
deriving (Show)

cabal-install/src/Distribution/Client/SolverInstallPlan.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import qualified Data.Map as Map
7777
import Distribution.Compat.Graph (Graph, IsNode (..))
7878
import qualified Distribution.Compat.Graph as Graph
7979
import GHC.Stack (HasCallStack)
80+
import qualified Data.List.NonEmpty as NE
8081

8182
type SolverPlanPackage = ResolverPackage UnresolvedPkgLoc
8283

@@ -171,7 +172,7 @@ valid = null . problems
171172
data SolverPlanProblem
172173
= PackageMissingDeps
173174
SolverPlanPackage
174-
[PackageIdentifier]
175+
(NE.NonEmpty PackageIdentifier)
175176
| PackageCycle [SolverPlanPackage]
176177
| PackageInconsistency QPN [(SolverId, SolverId)]
177178
| PackageStateInvalid SolverPlanPackage SolverPlanPackage
@@ -181,7 +182,7 @@ showPlanProblem (PackageMissingDeps pkg missingDeps) =
181182
"Package "
182183
++ prettyShow (packageId pkg)
183184
++ " depends on the following packages which are missing from the plan: "
184-
++ intercalate ", " (map prettyShow missingDeps)
185+
++ intercalate ", " (map prettyShow (NE.toList missingDeps))
185186
showPlanProblem (PackageCycle cycleGroup) =
186187
"The following packages are involved in a dependency cycle "
187188
++ intercalate ", " (map (prettyShow . packageId) cycleGroup)
@@ -220,10 +221,11 @@ problems
220221
problems index =
221222
[ PackageMissingDeps
222223
pkg
223-
( mapMaybe
224-
(fmap packageId . flip Graph.lookup index)
225-
missingDeps
226-
)
224+
-- ( mapMaybe
225+
-- (fmap packageId . flip Graph.lookup index)
226+
-- missingDeps
227+
-- )
228+
(NE.map (packageId . fromMaybe (error "should not happen") . flip Graph.lookup index) missingDeps)
227229
| (pkg, missingDeps) <- Graph.broken index
228230
]
229231
++ [ PackageCycle cycleGroup

0 commit comments

Comments
 (0)