AI updates #3: revise macros and documentation#250
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AI Overview
This PR is a review-and-hardening pass over CGP's procedural-macro internals, paired with a large documentation build-out — it is not a feature release and changes no public API. Across 17 commits it touches 126 files for roughly 2,400 insertions, of which the great majority is documentation and tests; the compiled-code changes are confined to the
cgp-macro-corecrate and are small, targeted fixes rather than new capability. A reader reviewing this branch should expect three things: a handful of real codegen corrections, a much wider test net around the derive macros, and a documentation surface that now spans users, macro maintainers, and AI agents.High-level concepts
The core of the work is an iterative, per-macro review of the codegen, hardening corner cases as it goes. Each commit takes one construct —
HasFieldandCgpRecord,FromVariantandCgpVariant,CgpData, the core component macros, the namespace impls,check_components!— reads its expansion end to end, and fixes what it finds. The pattern is deliberate and matches the ongoing "macro review campaign" the repository already tracks, so this branch reads as one more slice of that campaign rather than an isolated bug fix.The most consequential behavioral change is that
#[derive(CgpData)]now accepts a variantless enum instead of rejecting it. Previously an empty enum failed to compile, and that rejection was pinned by atrybuildfailure fixture; this PR deletes that fixture and replaces it with a passing snapshot test. The fix is subtle for a good reason: an empty enum borrows nothing, so the generated borrowed partial enum must drop the'__a__lifetime and__R__selector it would otherwise carry (they would be unused parameters,E0392), and every borrowed accessor must match the dereferenced place withmatch *self {}rather thanmatch self {}over a reference, which is non-exhaustive because a reference is always inhabited (E0004). Two smaller hardening changes ride alongside it: the extractor's borrowed impls move off a bare'alifetime onto the reserved'__a__so they can never collide with an enum that names its own lifetime'a, and a namespacefor … in …loop's optionalwhereclause — which was parsed and then silently dropped — is now merged into every impl the loop generates.A broad, mechanical refactor replaces every
parse2(quote!{…})?in the data-derive codegen with the internalparse_internal!macro. This is not cosmetic.parse_internal!fails with an error that names the targetsyntype and the offending tokens, so when a generated fragment is malformed the macro reports something diagnosable instead of a bare parse error or a panic that aborts the compiler. The same change threads consistent error handling through the builder and extractor derivations.The documentation now addresses three distinct audiences through three tiers, and this PR advances all three. The construct reference under
docs/referenceexplains each macro to a user — its syntax and its expansion — and it received many small revisions. The implementation reference underdocs/implementationexplains to a maintainer or agent how each macro produces that behavior, and it is the sole home for pointers into the test suite; its README gained a "Cross-cutting implementation notes" section that captures the recurring, easy-to-misread mechanics one must hold in mind for every macro — leading-generic insertion and why it survives lifetimes, keeping the generic kinds and roles distinct, span handling, parsing discipline, and identifier hygiene. The CGP agent skill underdocs/skills/cgpteaches an AI agent to read and write CGP, and it was overhauled.One new concept is formalized: the aggregate provider. A new concept document explains a zero-sized provider whose body is a delegation table rather than a method, defined with the
newkeyword ofdelegate_components!, so a group of component wirings can be bundled once and adopted by many contexts as a single unit. The document's substantive contribution is the checking rule it pins down: an aggregate provider is a provider and never its own context, so it must be wired with plaindelegate_components!and never withdelegate_and_check_components!, whoseCanUseComponentassertion would describe a situation that never occurs at runtime and report spurious failures. It is verified indirectly through a real context, or directly with the#[check_providers(...)]form. The commit series also clarifies that samedelegate_and_check_components!-versus-delegate_components!distinction in the reference docs.Overall structural changes
No source files move and no public interface changes; the structural growth is concentrated in tests and documentation. In the code, the changes are edits within existing
cgp-macro-corefiles — theparse_internal!swap, the empty-enum branches, the lifetime rename, and explanatory comments at everyinsert(0, …)site that cross-reference the implementation README. Nothing is renamed or relocated.The test tree grows substantially, adding behavioral tests, parser-rejection tests, and macro-expansion snapshots. New passing tests cover raw-identifier fields (
r#typetagged by its logical nameSymbol!("type")), lifetime-carrying records and variants, the empty enum, aselfreference in a nested item, generic-key checking through the fused macro, and thefor … in … whereloop. A new set ofparser_rejectionssuites asserts that thecgp_impl,cgp_namespace,cgp_provider,derive_cgp_data, andderive_from_variantparsers reject malformed input cleanly, and a new compile-fail fixture rejects a duplicate namespace path key. Several existing snapshots were regenerated to reflect the codegen changes, and theproblematic/extract_field/empty_enumcompile-fail fixture was removed because that input now compiles.The documentation gains two new skill sub-references and one new concept page, while most existing pages were revised in place. The CGP skill's
SKILL.mdwas heavily rewritten, two new sub-skills were added —modern-idioms.md, which maps every legacy explicit form to the modern idiom to prefer, andmacro-grammar.md, which gives the formal grammar of each macro plus an error decoder — and Greek-alphabet naming was removed from the skill text. On the concepts side,aggregate-providers.mdis new.One unintended artifact is included: a compiled
libempty_match.rlibbinary. It is a 6,936-byteararchive committed in the empty-enum-fix commit, it is referenced by nothing in the tree, and it is not covered by.gitignore. It appears to be an accidental build artifact.Impacts
The changes above land as the following concrete impacts, ordered roughly from most to least user-visible.
#[derive(CgpData)], and the extractor andHasFieldsderives beneath it, compile on a variantless enum where they previously errored, so generic code can treat an empty enum as a degenerate case without a special guard.parse_internal!refactor and the new parser-rejection suites mean that when a macro fragment is malformed, the error names the target type and offending tokens instead of surfacing a bare parse error or aborting the compiler with a panic.whereclause on afor … in …loop is now honored on every generated impl rather than being silently discarded, so code that relied on that bound will now type-check as intended.'__a__removes a collision hazard for any enum whose own lifetime parameter is named'a.insta/trybuildfixtures that are a direct consequence of the codegen changes, not independent behavior changes.SKILL.md.delegate_and_check_components!to a bundle, which would produce spurious check failures.libempty_match.rlibshould be deleted from the branch (and ideally added to.gitignore), since committing a build artifact bloats history and serves no purpose in the tree.