Skip to content

AI updates #3: revise macros and documentation#250

Merged
soareschen merged 18 commits into
mainfrom
ai-updates-3
Jul 4, 2026
Merged

AI updates #3: revise macros and documentation#250
soareschen merged 18 commits into
mainfrom
ai-updates-3

Conversation

@soareschen

Copy link
Copy Markdown
Collaborator

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-core crate 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 — HasField and CgpRecord, FromVariant and CgpVariant, 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 a trybuild failure 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 with match *self {} rather than match 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 'a lifetime onto the reserved '__a__ so they can never collide with an enum that names its own lifetime 'a, and a namespace for … in … loop's optional where clause — 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 internal parse_internal! macro. This is not cosmetic. parse_internal! fails with an error that names the target syn type 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/reference explains each macro to a user — its syntax and its expansion — and it received many small revisions. The implementation reference under docs/implementation explains 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 under docs/skills/cgp teaches 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 new keyword of delegate_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 plain delegate_components! and never with delegate_and_check_components!, whose CanUseComponent assertion 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 same delegate_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-core files — the parse_internal! swap, the empty-enum branches, the lifetime rename, and explanatory comments at every insert(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#type tagged by its logical name Symbol!("type")), lifetime-carrying records and variants, the empty enum, a self reference in a nested item, generic-key checking through the fused macro, and the for … in … where loop. A new set of parser_rejections suites asserts that the cgp_impl, cgp_namespace, cgp_provider, derive_cgp_data, and derive_from_variant parsers 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 the problematic/extract_field/empty_enum compile-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.md was heavily rewritten, two new sub-skills were added — modern-idioms.md, which maps every legacy explicit form to the modern idiom to prefer, and macro-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.md is new.

One unintended artifact is included: a compiled libempty_match.rlib binary. It is a 6,936-byte ar archive 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.

  • Empty enums are now derivable. #[derive(CgpData)], and the extractor and HasFields derives 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.
  • Better diagnostics on malformed macro input. The 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.
  • A latent namespace bug is fixed. The where clause on a for … 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.
  • Reduced risk of lifetime-name collisions. Moving the extractor's borrowed impls onto the reserved '__a__ removes a collision hazard for any enum whose own lifetime parameter is named 'a.
  • Wider regression coverage. New behavioral tests, snapshot tests, and negative parser tests lock in the reviewed behavior, so future macro edits that regress these corners will fail visibly.
  • Regenerated snapshots. Reviewers will see updated insta/trybuild fixtures that are a direct consequence of the codegen changes, not independent behavior changes.
  • A clearer, three-audience documentation surface. Users get a revised construct reference, maintainers and agents get the cross-cutting implementation notes and the formalized aggregate-provider concept, and agents get sharper skill guidance through the two new sub-skills and the modernized SKILL.md.
  • Guidance against a real misuse. The aggregate-provider document and the reference clarifications steer users away from applying delegate_and_check_components! to a bundle, which would produce spurious check failures.
  • A stray binary to remove before merge. libempty_match.rlib should be deleted from the branch (and ideally added to .gitignore), since committing a build artifact bloats history and serves no purpose in the tree.

@soareschen soareschen added the AI label Jul 4, 2026
@soareschen soareschen merged commit 67ba4e3 into main Jul 4, 2026
3 checks passed
@soareschen soareschen deleted the ai-updates-3 branch July 4, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant