Skip to content

feat(deps): SemVer merge — Level 2 of multi-version resolution#18

Merged
Sunrisepeak merged 1 commit intomainfrom
feat/semver-merge
May 9, 2026
Merged

feat(deps): SemVer merge — Level 2 of multi-version resolution#18
Sunrisepeak merged 1 commit intomainfrom
feat/semver-merge

Conversation

@Sunrisepeak
Copy link
Copy Markdown
Member

Summary

Layer 2 of the 0.0.3 dep-resolution work (Level 1, multi-version mangling, follows in a separate PR).

When the transitive walker hits the same package twice with different pinned versions, AND-combine the two original constraints, re-query the index, and pick the single concrete version that satisfies both. Bare exacts like 0.0.1 are promoted to =0.0.1 so they cleanly participate in the AND. If the merged pin differs from what was previously recorded, the dep is re-fetched and its slot in dep_manifests / packages is replaced in-place — the old [build].include_dirs entries are evicted from the root manifest, the new ones appended, and the new manifest's children re-walked.

Three outcomes:

  • Same pin → just record the second consumer
  • Different pin, but a satisfying version exists → re-fetch + replace
  • No overlap (e.g. =0.0.1=0.0.2) → hard error, with a hint that cross-major / non-overlapping cases land in the upcoming Level-1 mangling fallback PR

Test plan

  • new tests/e2e/32_semver_merge.sh — compatible-merge happy path + irreconcilable hard-error
  • existing tests/e2e/31_transitive_deps.sh still green (path-dep semantics unchanged)
  • CI green on linux x86_64 self-host

When the transitive walker encounters the same package twice with different
pinned versions, AND-combine the two original constraints and re-query the
index for a single satisfying version. Bare exact pins like `0.0.1` are
treated as `=0.0.1` so they participate cleanly in the AND.

If the merged pin differs from the previously-recorded one, the dep is
re-fetched at the merged version: the slot in `dep_manifests`/`packages`
is replaced in-place, the old `[build].include_dirs` entries are evicted
from the main manifest, the new ones are appended, and the new manifest's
children are pushed onto the worklist. Same pin → just record the new
consumer; no overlap → hard error with a Level-1 mangling hint.

Code shape:
- `mcpp.pm.resolver::try_merge_semver` is the new public helper.
- `cli.cppm`'s resolve loop tracks `originalConstraint` per WorkItem and
  `constraint` / `depIndex` / `includeDirsAdded` per ResolvedRecord.
- The version-source manifest acquisition (install + xpkg-lua field
  dispatch) is factored into `loadVersionDep` so the merger can re-use it.

Tests: new `32_semver_merge.sh` covers the compatible-merge happy path
(`=0.0.1` ⨯ `>=0.0.1, <1` → 0.0.1, with the previously-pinned 0.0.2 slot
overwritten) and the irreconcilable case (`=0.0.1` ⨯ `=0.0.2` still
errors). Existing 31_transitive_deps stays green.

CHANGELOG: opens 0.0.3 entry covering both PR #17 (transitive walker)
and this one (SemVer merge); the Level-1 mangling fallback follows in a
separate PR before tagging 0.0.3.
@Sunrisepeak Sunrisepeak merged commit 32d6847 into main May 9, 2026
1 of 2 checks passed
Sunrisepeak added a commit that referenced this pull request May 9, 2026
- mcpp.toml + MCPP_VERSION → 0.0.3
- CHANGELOG: lock [Unreleased] → [0.0.3] — 2026-05-10

Three-tier dependency resolution lands in this release: transitive
walker (#17), SemVer merge / Level 2 (#18), multi-version mangling /
Level 1 (#19). See the 0.0.3 entry for the full breakdown.
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.

1 participant