Namespace macro refactoring#241
Merged
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 reworks how CGP's namespace and path machinery is configured and expanded, and pulls
derive_delegateout of the#[cgp_component]argument block into a standalone attribute. The headline change is grouped paths — a syntax that lets one delegation entry expand into the cartesian product of several path elements. Alongside it are a cluster of supporting refactors: thederive_delegateconfiguration moves to its own attribute, namespace-struct generation is decoupled from parent-namespace inheritance, and several macro-internal references are now resolved through the crate's export table rather than bare identifiers. The user-facing surface is small; most of the work is in the proc-macro core.High-level concepts
The central new idea is that a single path key can name a set of components and a set of parameters at once. Where you previously wrote one delegation line per component, you can now write
@app.[FooComponent, BarComponent].[u64, String]: DummyImpland have the macro expand it into all four combinations (Foo×u64,Foo×String,Bar×u64,Bar×String). This is purely an expansion-time convenience — each combination still produces an independentDelegateComponentandIsProviderForimpl, exactly as if you had written them out by hand. The grouping composes, so two bracketed groups chained with.multiply together.The second concept is that
derive_delegateis now an ordinary attribute rather than a key inside the#[cgp_component { ... }]brace block. Instead of#[cgp_component { provider: ErrorRaiser, derive_delegate: UseDelegate<SourceError> }], you now write two lines:#[cgp_component(ErrorRaiser)]followed by#[derive_delegate(UseDelegate<SourceError>)]. Multiple delegates that used to be a bracketed list become repeated attributes, one per line. This makes#[cgp_component]read like the other attribute-driven CGP macros, and it lets the same delegate-deriving logic be shared more uniformly across#[cgp_type]and#[cgp_getter].The third concept is a cleaner separation inside namespace tables between defining a namespace and inheriting from a parent. Creating the backing
__XComponentsstruct is now the job of one function keyed on thenewkeyword, while wiring a namespace to its parent is the job of another keyed on the presence of a parent clause. The two concerns no longer share a code path.Structural changes
The path parser gains a dedicated type and a richer enum. A new
PathElementWithGenericstype pairs a path element with its optional generic binder, and thePathHeadenum is reshaped so that grouping is explicit: the old grouping variant is renamedNested, and a newGroup(elements, tail)variant carries a bracketed list plus the rest of the path. Both expansion routines —into_pathsin the macro core andpath_head_to_prefixin the macro lib — learn to walk theGroupvariant and emit the cartesian product. A newPath!proc-macro is exposed that parses a single path expression into its type form.The
derive_delegateplumbing is relocated, not just renamed. The parsing logic now lives inCgpComponentAttributes, which collects each#[derive_delegate(...)]occurrence into a vector; the old bracketed-listParseimpl and thederive_delegatekey (with its duplicate-key guard) are deleted from the component-args types. The evaluation step reads the delegates from the parsed attributes instead of from the component args. Documentation, the test utilities README, and the affected component definitions acrosscgp-error,cgp-type,cgp-handler, andcgp-runare all migrated to the new form, and the handler components additionally gain explicit#[prefix(@cgp.extra.handler in DefaultNamespace)]annotations.The namespace table is split along the seam described above.
build_namespace_structnow emits the__XComponentsstruct whenevernewis present, independent of any parent, andbuild_parent_namespace_implreturns only the inheritance impl. TheDelegateComponenttrait's parameter is renamedName → Keyto match the type-level-table framing, and macro-internal references toLife,CanUseComponent, and friends are now resolved through theexport_constructs!table so generated code points at the canonical paths.The test suite tracks these changes. A new
group.rssnapshot test exercises grouped-path expansion end to end, themulti_paramtests are simplified away from heavy snapshot wrapping toward direct macro use, and the namespace snapshots are updated to reflect thatnewnamespaces now always emit their backing struct.Impacts
The user-facing migration is the most direct impact: any code using the brace-form
derive_delegatemust move to the standalone#[derive_delegate(...)]attribute. The brace key is now rejected withunknown key derive_delegate, so the change is a hard break for that syntax rather than a deprecation. All in-tree call sites are migrated, but downstream crates that used the old form will need the same edit.Grouped paths reduce delegation boilerplate wherever the same provider serves many component-and-parameter combinations. The expansion is mechanical and equivalent to the longhand, so it introduces no new runtime behavior — the benefit is entirely in how much wiring a developer has to write and read.
The namespace refactor changes generated output in one visible way: a
newnamespace now always emits its__XComponentsstruct, even without a parent clause, which is why several snapshots grew apub struct __…Components;line. This is consistent and intended, but it is a codegen difference worth noting for anyone comparing expanded output across versions.A few sharp edges accompany the new flexibility, and they are worth keeping in mind. Specifying a parent namespace without
newis no longer caught by a dedicated error; it now falls through to generated code that references an undefined struct, so the failure shows up as a confusing "cannot find type" message instead of a clear diagnostic. Grouped paths that reuse the same generic binder name across levels, or that contain an empty[]group, are not validated either — the former yields a duplicate-generic compile error and the latter silently expands to nothing. The newPath!macro currently parses only the single-path form and has no group support or tests. None of these block the feature, but they are the places where a user is most likely to hit an unhelpful error.