Skip to content

Avoid re-validating when decoding from Binary or Read - #12169

Open
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:andrea/wip/prep/decode-no-revalidate
Open

Avoid re-validating when decoding from Binary or Read#12169
andreabedini wants to merge 1 commit into
haskell:masterfrom
andreabedini:andrea/wip/prep/decode-no-revalidate

Conversation

@andreabedini

Copy link
Copy Markdown
Collaborator

The Binary and Read instances rebuilt the graph with fromDistinctList, which re-checks key uniqueness and calls 'error' (stringifying the key with 'show') on a duplicate. That check is pointless on data we serialised ourselves from an already-valid graph, yet it forced a Show (Key a) constraint onto both instances purely to format that panic. Decode now reconstructs directly or via a non-validating helper, dropping the Show (Key a) constraint.

Binary (GenericInstallPlan …) had the same shape one layer up: its get routed
through mkInstallPlan, re-running the plan-validity check (which errors rather
than failing the decode) on cached data. It now reconstructs the plan directly.

This is an interface change to Cabal-syntax — the Binary/Read (Graph a)
instances require fewer constraints — but a backwards-compatible widening: no
existing caller breaks.

  • Patches conform to the coding conventions. (fourmolu + hlint clean.)
  • Changes recorded in the changelog (changelog.d/decode-no-revalidate.md).
    • Not significant — backwards-compatible, no user-visible behaviour change.
  • Documentation updated, if necessary. (N/A — internal.)
  • QA notes: cache serialisation round-trips are unaffected; Distribution.Compat.Graph (4 props) and InstallPlan (5 props) unit suites pass.
  • Tests: covered by the existing Graph/InstallPlan round-trip & consistency suites; no new test added since this is a constraint relaxation exercised by existing coverage.

Copilot AI review requested due to automatic review settings July 28, 2026 05:14
The Binary and Read instances rebuilt the graph with fromDistinctList,
which re-checks key uniqueness and calls 'error' (stringifying the
key with 'show') on a duplicate. That check is pointless on data we
serialised ourselves from an already-valid graph, yet it forced a Show
(Key a) constraint onto both instances purely to format that panic.
Decode now reconstructs directly or via a non-validating helper,
dropping the Show (Key a) constraint.

While this is API changing, it is a backwards-compatible as it is a
widening of the Binary/Read instances.
@andreabedini
andreabedini force-pushed the andrea/wip/prep/decode-no-revalidate branch from 7ec10cc to 178fdcf Compare July 28, 2026 05:16

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 streamlines decoding of serialized graphs and install plans by removing redundant invariant checks during Binary/Read decoding, thereby relaxing instance constraints (notably dropping Show (Key a) requirements) while keeping encoding/decoding behavior equivalent for valid, self-produced serialized data.

Changes:

  • Relax Read (Graph a) / Binary (Graph a) constraints by decoding via a non-validating reconstruction helper.
  • Decode GenericInstallPlan directly instead of routing through mkInstallPlan (avoids re-running plan validity checks on decode).
  • Add a changelog entry documenting the decode behavior and constraint widening.

Reviewed changes

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

File Description
changelog.d/decode-no-revalidate.md Records the change in decode behavior and instance constraint widening.
Cabal-syntax/src/Distribution/Compat/Graph.hs Drops Show (Key a) from Read/Binary instances by decoding via a trusted reconstruction helper.
cabal-install/src/Distribution/Client/InstallPlan.hs Adjusts Binary decoding to reconstruct GenericInstallPlan directly rather than validating via mkInstallPlan.

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

Comment on lines +395 to +402
-- | Like 'fromDistinctList', but for reconstructing a graph whose keys are
-- already known to be distinct — in particular a graph produced by 'toList'
-- and round-tripped through the 'Binary'/'Read' instances. It performs no
-- duplicate-key check, and so (unlike 'fromDistinctList') does not require
-- @Show (Key a)@.
fromDistinctListTrusted :: IsNode a => [a] -> Graph a
fromDistinctListTrusted =
fromMap . Map.fromList . map (\n -> n `seq` (nodeKey n, n))
Comment on lines +317 to +324
-- Reconstruct the plan directly rather than routing through 'mkInstallPlan':
-- the bytes were serialised from a valid plan, so re-running the invariant
-- check on decode is redundant (and would 'error' rather than fail the
-- decode). This keeps 'get' the inverse of 'put'.
get = do
graph <- get
indepGoals <- get
return $! mkInstallPlan "(instance Binary)" graph indepGoals
pure $! GenericInstallPlan graph indepGoals
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants