Skip to content

refactor(cabal-install): generalise GenericInstallPlan to arbitrary node keys#12092

Open
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:andrea/wip/prep/p06-installplan-nodekey
Open

refactor(cabal-install): generalise GenericInstallPlan to arbitrary node keys#12092
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:andrea/wip/prep/p06-installplan-nodekey

Conversation

@andreabedini

Copy link
Copy Markdown
Collaborator

Summary

Distribution.Client.InstallPlan was already polymorphic in its two node types
(GenericPlanPackage ipkg srcpkg), yet it hardcoded the key of those nodes to
UnitId throughout: the IsUnit synonym pinned Key a ~ UnitId, Processing
held Set UnitId, and BuildOutcomes was a Map UnitId.

This replaces the UnitId-specific IsUnit constraint with

type IsGraph ipkg srcpkg = (IsNode ipkg, IsNode srcpkg, Key ipkg ~ Key srcpkg)

and threads the shared key type (Key ipkg) through the operations that
previously mentioned UnitId directly, so Processing and BuildOutcomes
become parameterised over the key. Functions that print or report on keys gain
Pretty/Show (Key ipkg) constraints accordingly, and helpers become more
honest about what they need — e.g. depends :: IsNode a => a -> [Key a] instead
of depends :: IsUnit a => a -> [UnitId].

Why

Nothing in the plan logic actually depends on the key being a UnitId; it only
needs the two node types to share a common IsNode key. Removing that
over-specialisation is a small tightening of the abstraction on its own.

The concrete motivation is cross-compilation (#11179), where install plans are
keyed by a stage-qualified key rather than a bare UnitId. This is a
preparatory refactor extracted from that PR — landing it separately shrinks
the eventual core change and keeps it reviewable.

Behaviour

Behaviour-preserving. The sole instantiation on master
type PlanPackage = GenericPlanPackage InstalledPackageInfo (ConfiguredPackage UnresolvedPkgLoc)
— remains UnitId-keyed, so there is no functional change. No changelog entry
(internal refactor, not user-facing).

QA notes

  • cabal build all is green.
  • cabal-install /InstallPlan/ unit tests pass.
  • -Werror validate build (cabal.validate.project) is clean; hlint reports no hints.

Copilot AI review requested due to automatic review settings July 6, 2026 05:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors cabal-install’s install-plan graph abstractions to stop hardcoding UnitId as the node key, instead threading a shared Key type through GenericInstallPlan operations via a new IsGraph constraint. This is a behaviour-preserving abstraction tightening that keeps the current UnitId-keyed instantiation working while enabling future work (e.g. stage-qualified keys for cross compilation).

Changes:

  • Replace the IsUnit synonym with IsGraph and generalise key-dependent APIs (depends, Processing, BuildOutcomes, lookup, closures, execution).
  • Update ProjectBuilding code to use nodeKey/generic keys instead of installedUnitId/UnitId-specific types.
  • Adjust unit tests to use IsGraph and add key-type constraints where required for pretty-printing/debug output.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
cabal-install/src/Distribution/Client/InstallPlan.hs Introduces IsGraph and generalises plan operations/state from UnitId to an arbitrary shared node key.
cabal-install/src/Distribution/Client/ProjectBuilding.hs Updates dependency-fold and build-status lookup to use generic node keys (nodeKey) and key-parameterised maps.
cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs Updates generators/tests to work with IsGraph and key pretty-printing/show constraints.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cabal-install/src/Distribution/Client/ProjectBuilding.hs Outdated
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs Outdated
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs
Comment thread cabal-install/src/Distribution/Client/InstallPlan.hs
…ode keys

The install-plan machinery in Distribution.Client.InstallPlan was written to
be polymorphic in its two node types (`GenericPlanPackage ipkg srcpkg`), yet
it hardcoded the *key* of those nodes to `UnitId` everywhere: the `IsUnit`
synonym pinned `Key a ~ UnitId`, `Processing` held `Set UnitId`, and
`BuildOutcomes` was a `Map UnitId`. That is an over-specialisation — nothing
in the plan logic actually depends on the key being a `UnitId`; it only needs
the two node types to share a common key that is an `IsNode` key.

This replaces the `UnitId`-specific `IsUnit` constraint with

    type IsGraph ipkg srcpkg = (IsNode ipkg, IsNode srcpkg, Key ipkg ~ Key srcpkg)

and threads the shared key type (`Key ipkg`) through the operations that
previously mentioned `UnitId` directly, so `Processing` and `BuildOutcomes`
become parameterised over the key. The few functions that print or report on
keys gain `Pretty`/`Show (Key ipkg)` constraints accordingly. Helpers become
more honest about what they need — e.g. `depends :: IsNode a => a -> [Key a]`
rather than `depends :: IsUnit a => a -> [UnitId]`.

This is a behaviour-preserving refactor. The sole instantiation on master,
`type PlanPackage = GenericPlanPackage InstalledPackageInfo (ConfiguredPackage
UnresolvedPkgLoc)`, remains `UnitId`-keyed, so there is no functional change.
The motivation is cross-compilation (haskell#11179), where install plans are keyed by
a stage-qualified key rather than a bare `UnitId`; extracting this
generalisation on its own removes the `UnitId` assumption ahead of that work
and keeps the eventual core change smaller.
@andreabedini andreabedini force-pushed the andrea/wip/prep/p06-installplan-nodekey branch from 31a8412 to 07c2b95 Compare July 6, 2026 07:00
@andreabedini andreabedini requested review from Mikolaj and fgaz July 6, 2026 09:15
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.

2 participants