AI-review CGP macro implementations, use. instead of :: as separator in #[use_type]#248
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 Summary
This PR is a systematic hardening pass over the CGP procedural macros, reviewing one construct at a time until each macro's implementation, tests, and documentation are correct, complete, and mutually consistent. It is not a feature branch — it is a quality campaign. Across nine commits it works through
product!,#[cgp_component],delegate_components!, theopenstatement,#[cgp_impl],check_components!,#[cgp_fn], and#[use_type], fixing latent miscompilations and confusing diagnostics, closing test gaps, and bringing the four documentation views (reference, implementation, snapshots, and the bundled/cgpskill) back in sync with the code. The change touches 127 files, but the bulk of the line count is documentation propagation and new tests; the behavioral surface changes in a focused set of macro-core files.High-level concepts
The campaign follows a standing workflow that this PR itself codifies. The single largest documentation addition is a new "Macro review workflow" section in cgp/CLAUDE.md that defines the review as a repeatable process: reload the CGP mental model and the prose convention, read the macro's documentation and implementation, harden the implementation and its tests, scrutinize the codegen against every way its input can be parsed and its output expanded, and keep all four documentation views in sync before verifying green. The section reads as the operating manual for the very changes in this PR, so future iterations of the same campaign can proceed identically.
The most consequential change to users is a breaking syntax change to
#[use_type]. The separator between a trait and the associated type it imports moves from::to., so#[use_type(HasErrorType::Error)]becomes#[use_type(HasErrorType.Error)]. The motivation is disambiguation: a.unambiguously marks where the associated type begins, which lets the trait itself be a full path such asfoo::bar::HasScalarTypewithout a greedy path parser silently swallowing the trailing::Error. The rewrite also drops the older<Trait>angle-bracket form and the pre-.braced form, standardizing on a single path-based grammar (the braced multi-import list after the.,HasFooType.{A, B}, is retained). Every call site inside the CGP crates — the error, handler, runner, and runtime traits — is migrated, and the duplicate-alias guard now also fires within a single braced list rather than only across separate attributes.The remaining behavioral changes are corner-case corrections in the macro codegen. Each fixes a case where a macro either emitted invalid Rust, panicked the compiler, or silently dropped input, and each now ships with a behavioral test that pins the corrected behavior. The corrections are individually small but collectively remove a class of latent bugs that only surfaced on unusual-but-valid input.
Behavioral and syntax changes
The following changes alter what the macros accept or emit, and are the substance of the PR.
The
#[use_type]trait/associated-type separator changes from::to., and the attribute now accepts a path-qualified trait, as described above (cgp/crates/macros/cgp-macro-core/src/types/attributes/use_type/attribute.rs). This is the one breaking change for downstream code.The
#[cgp_fn]implicit-argument access mode now follows each argument's own type rather than the receiver's mutability (cgp/crates/macros/cgp-macro-core/src/functions/implicits/parse.rs). Previously a&mut selfreceiver forced a mutable field read for every implicit and capped the count at one; now immutable implicits under a&mut selfreceiver read through the sharedHasField/get_fieldpath and any number of them may coexist, while the "must be the only implicit" restriction correctly applies only to a genuine&mutimplicit whose exclusive borrow of the context would otherwise conflict.The
mut selfowned receiver is now rewritten correctly by#[cgp_impl](cgp/crates/macros/cgp-macro-core/src/visitors/replace_self/replace_self_receiver.rs). Themutkeyword now binds the generated parameter (mut __context__: Context) instead of being emitted as the invalid type__context__: mut Context, so all four receiver shapes —&self,&mut self,self, andmut self— now round-trip.A
self::module path inside a#[cgp_impl]body is now preserved rather than being rewritten to the context (cgp/crates/macros/cgp-macro-core/src/visitors/replace_self/replace_self_value.rs). Because token-level rewriting inside a macro invocation cannot see through the macro, the visitor now peeks for a trailing::to tell a valueself(rewritten) from aself::module path (left intact).Const generic parameters on a CGP component trait are now rejected with a clear spanned error instead of panicking the compiler (cgp/crates/macros/cgp-macro-core/src/functions/is_provider_params.rs). The
IsProviderForparams tuple holds types and cannot key on a const value, so the previousunimplemented!()is replaced by a diagnostic that names the unsupported parameter.The
openstatement now accepts a braceless single component,open A;, while the braced listopen { A, B };remains required for multiple components (cgp/crates/macros/cgp-macro-core/src/types/delegate_component/statement/open.rs).The
check_components!macro now accepts a path-qualified context type such asinner::Context, deriving the check-trait name from the final path segment (cgp/crates/macros/cgp-macro-core/src/types/check_components/table.rs). This mirrorsdelegate_components!, which already uses the context type verbatim, so a context defined in another module can now be both wired and checked by its path. The same file also hardens#[check_providers(...)], which now errors on an empty list and on more than one occurrence rather than silently accumulating.The
delegate_components!attribute validation now recurses into nested inner tables (cgp/crates/macros/cgp-macro-core/src/types/delegate_component/validate_attributes.rs). Attributes placed on keys inside a Normal or Direct mapping's inner table, or inside a for-loop statement's mappings, were previously dropped without warning; they are now validated so an unsupported attribute fails with a spanned error instead of vanishing.The value-level
product!macro now parses its items as expressions rather than types (cgp/crates/macros/cgp-macro-core/src/types/product/product_expr.rs), so it can build a runtime product from value expressions and not only type names.Finally, a small diagnostic improvement renames the missing-argument error on
#[cgp_component]from "provider_identkey must be given" to the user-facing "theproviderkey must be given" (cgp/crates/macros/cgp-macro-core/src/types/cgp_component/args/component_args.rs).Structural changes
The test suite grows from three jobs to four with a new crate. cgp/crates/tests/cgp-compile-fail-tests/ is a new library crate holding
compile_faildoctests — the tool for input a macro accepts but whose expansion then fails to compile, such as twodelegate_components!blocks that delegate the same key, which the macro cannot reject without a whole-program view. It is a library crate on purpose, because doctests are collected only from a library target; it currently ships as a documented scaffold with no cases enumerated yet, ready for the first case a future iteration captures. The crate is registered in the workspace cgp/Cargo.toml and cgp/Cargo.lock.The macro-internals suite gains a new parser-rejection layer. New files under cgp/crates/tests/cgp-macro-tests/tests/parser_rejections/ drive the macro entrypoints directly with an
assert_macro_rejectshelper to pin the rejections forcgp_fn,check_components,delegate_components, anduse_type, and extend the existingcgp_componentrejections. These verify that malformed input fails at the macro's own parse stage with a clear message.The behavioral suite gains one test per corrected corner case. New files in cgp/crates/tests/cgp-tests/tests/ cover the owned/
mut selfreceiver, theself::-in-macro distinction, the path-qualifiedcheck_components!context, a type-parameter-only generic component,&mut selfwith all-immutable implicits, and the path-qualified#[use_type]trait. Several are snapshot tests that also pin the exact macro expansion in the owning target.Inline documentation is filled in across the macro-core AST modules. Many public structs, traits, and functions in the
cgp_impl,cgp_component,delegate_component,check_components, anduse_typemodule trees gain a///doc comment, and the two test-suite guides — cgp/crates/tests/CLAUDE.md alongside the workflow section in cgp/CLAUDE.md — are rewritten to document the four-target structure and when to reach for each kind of failure test.The published documentation and the bundled skill are swept for consistency. The
::→.change and the other corrections propagate across cgp/docs/reference/, cgp/docs/implementation/, cgp/docs/concepts/, cgp/docs/examples/, and the vendored copy of the CGP skill under cgp/docs/skills/cgp/, keeping every view aligned with the code.Impacts
The impacts below follow from the changes above, ordered from the most disruptive to the most local.
Downstream code using
#[use_type]must migrate from::to.. Any existing#[use_type(SomeTrait::Assoc)]will no longer parse and must become#[use_type(SomeTrait.Assoc)]. The removed<Trait>angle-bracket and pre-.braced forms must be rewritten to the path form as well. Everything inside the CGP crates is already migrated, so only external callers are affected.CI must run doctests separately. The new
cgp-compile-fail-testscrate is not exercised bycargo nextest, which does not run doctests; verifying it requirescargo test --doc -p cgp-compile-fail-tests, and this is now documented in the test guide.Several previously-broken or panicking inputs now compile or fail cleanly. Providers with a
mut selfreceiver,#[cgp_impl]bodies referencingself::module paths,#[cgp_fn]with a&mut selfreceiver plus immutable implicits, path-qualified contexts incheck_components!, path-qualified traits in#[use_type], and the bracelessopen A;all work now. A const generic parameter on a component trait now produces a readable error instead of aborting the compiler.Diagnostics improve in several macros. Empty or duplicated
#[check_providers], unsupported attributes on nesteddelegate_components!keys, duplicate#[use_type]aliases within one braced list, and the missingproviderkey on#[cgp_component]now surface as clear spanned errors rather than being silently accepted, dropped, or reported with an internal identifier.product!can now take value expressions, broadening what the value-level macro accepts beyond bare type names.No public runtime API of the CGP crates changes. The library-crate edits in
cgp-error,cgp-handler,cgp-run, andcgp-runtimeare all the#[use_type]separator migration on trait definitions; the generated traits and their semantics are unchanged, so the impact is confined to the macro grammar, diagnostics, tests, and documentation.