feat(generator): emit the derived module identity methods - #141
Conversation
Run logos-lidl's injectIdentityMethods() on every ModuleDecl this generator
emits code from, and give the cdylib dispatch a body for the two methods it
adds.
Injection happens at EMISSION points, never at artifact points:
* generateInterfaceWrappers -- one load point covering both --dep and
--interface, so a consumer sees name()/version() on every dependency and
bound interface;
* --from-header --backend cdylib and --lidl --backend cdylib, so the provider
answers them;
* NOT --header-to-lidl, which writes the published contract.
The distinction is belt-and-braces rather than load-bearing: the injected
methods are `derived` and lidlSerialize omits those, so the .lidl a
--from-header build writes stays byte-identical to what --header-to-lidl writes
for the same header.
The dispatch emits a literal for a derived identity method instead of the usual
lidlImpl().<name>(...) -- the author's impl class has no such member, so
delegating would not compile. The literal is the module's own name and version,
so it cannot drift from the metadata the module was built with. A module that
declares name() itself is not derived and still reaches its impl.
290/290 tests pass, 4 new: that the emitted literal is the module's OWN version
(a test at 1.0.0 could not tell a correct generator from one that fell back),
that identity is listed for introspection as well as dispatched, that an
author's own name() still reaches the impl, and that a versionless declaration
falls back rather than emitting "" -- which would read as a failed call.
Requires logos-lidl#10; flake.lock pins that branch until it merges.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
📊 cpp-sdk doc-test reportThe real accounts module, run through a logoscore daemon with the whole stack built against this commit of the C++ SDK — rendered alongside the commands actually run and their output (updated each run, commit Pages can take a minute to update after the run finishes. |
On the red doc-testsTwo causes, both ordering rather than defects in this PR — recording the analysis so it isn't re-derived. 1.
logos-cpp-sdk.inputs.logos-lidl.follows = "logos-lidl";so this repo compiles against the consumer's logos-lidl, not its own lock. qt-sdk master still pins the old one. I initially read this as the vendored Clears when logos-co/logos-lidl#10 merges and qt-sdk master's lidl pin advances — i.e. after logos-co/logos-qt-sdk#35, which re-points it. 2. The doc-test resolves an old logos-capability-module against module-builder master, which now rejects interface-less core modules. Already fixed upstream by the 2026-08-20 migration ( What is green
|
…anded logos-co/logos-lidl#10 merged as ae3ffe0. The lock pointed at the PR branch while it was open; this re-points it at master. The narHash is unchanged across the move (sha256-WHmisUvYA8DQ2ZxSF2mM2...), so the merged tree is byte-identical to the branch this was built and tested against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Runs logos-lidl's
injectIdentityMethods()on everyModuleDeclthis generator emits code from, and gives the cdylib dispatch a body for the two methods it adds.Depends on logos-co/logos-lidl#10.
flake.lockpins that branch until it merges.Where injection goes
At emission points, never at artifact points:
generateInterfaceWrappers— one load point covering both--depand--interface, so a consumer seesname()/version()on every dependency and bound interface--from-header --backend cdyliband--lidl --backend cdylib, so the provider answers them--header-to-lidl, which writes the published contractThat distinction is belt-and-braces rather than load-bearing: the injected methods are
derivedandlidlSerializeomits those, so the.lidla--from-headerbuild writes stays byte-identical to what--header-to-lidlwrites for the same header.The dispatch body
A derived identity method emits a literal instead of the usual
lidlImpl().<name>(...)— the author's impl class has no such member, so delegating would not compile. The literal is the module's own name and version, so it cannot drift from the metadata the module was built with.A module that declares
name()itself is notderivedand still reaches its impl, unchanged.Verification
290/290 tests pass, 4 new. Worth noting what they pin:
1.0.0could not tell a correct generator from one silently falling back to the defaultlmand untyped callers see what is callablename()still reaches the impl (the logos-delivery-module case)"", which would read as a failed call rather than as "unversioned"End to end:
test_basic_module_cpp— a universal module with zero source changes — answersname→test_basic_module_cppandversion→1.0.0through logoscore, andlm methodslists both with descriptions.🤖 Generated with Claude Code