Skip to content

Collect catalog rows where the catalog object compiles - #213

Merged
russwyte merged 1 commit into
mainfrom
catalog/definition-site
Oct 5, 2026
Merged

russwyte merged 1 commit into
mainfrom
catalog/definition-site

Conversation

@russwyte

@russwyte russwyte commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

A catalog's rows are collected where the catalog object compiles, so no caller can hold a stale row list.

Why

MyVersions.settings was inline, so its row list expanded into build.sbt, or into any project/*.scala caller, at that caller's compile. Neither recompiles when the catalog gains or loses a val:

  • zinc tracks the names the old expansion used, not the object's member set;
  • sbt's Eval keys each compiled build.sbt statement on its text, imports, and SNAPSHOT jars only, never the meta-build's class directory. clean and cleanFull never clear project/target/config-classes.

So an added row was silently ignored, and a removed one failed with NoSuchMethodError. heddle hit the first: a new catalog row was not forced until its config-classes was deleted by hand.

What changes

  • trait Catalog(using CatalogContents). The CatalogContents given resolves in the catalog object's own constructor. Its macro finds that object through Symbol.spliceOwner and walks its vals with the walk coordsOf already uses: parent traits, then the object, in source order, by AsCoords, AsPins, AsActions, and AsShips. The rows are read lazily, after the object's vals are set.
  • Plain methods. coords, pins, actions, ships, and ZipxVersions.settings are ordinary methods, so a caller only references them.
  • No catalog changes for users. object MyVersions extends ZipxVersions, a company trait between them (trait SpliceVersions extends ZipxVersions), and local objects all work as before. A scala-cli miniature proved each shape first.

Tests

  • catalog-wins drops its workaround, which kept an expansion inside every swapped catalog file. Its build.sbt now calls MyVersions.settings and MyVersions.deps(...) directly, and the scenarios that remove oldClient and add shared pass.
  • sbt "scalafmtAll; cleanFull; testFull": 122 suites passed (core 980 tests).
  • zipxWorkflowCheck: every generated file up to date.
  • plugin/scripted: all 24 fixtures passed.
  • zipx's own meta-build catalog and every docs catalog compile through the new given.

Follow-up

Write up the sbt Eval cache-key bug for sbt itself, later.

MyVersions.settings was inline, so its row list expanded into build.sbt (or
any caller) at that caller's compile. Neither zinc nor sbt's build.sbt cache
recompiles a caller when the catalog it expanded gains or loses a val, so an
added row was silently ignored and a removed one failed with
NoSuchMethodError. No sbt command clears the cached build.sbt statement.

Catalog now takes a CatalogContents given, resolved in the catalog object's
own constructor. Its macro walks that object's vals with the same walk
coordsOf uses, and the rows are read lazily once the vals are set. coords,
pins, actions, ships, and settings are plain methods, so a caller only
references them and cannot hold a stale list.
@russwyte
russwyte merged commit 82a69d6 into main Oct 5, 2026
13 checks passed
@russwyte
russwyte deleted the catalog/definition-site branch October 5, 2026 13:46
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