Skip to content

[AI] Refactor constructs for parsing ident/path with type parameters#237

Merged
soareschen merged 15 commits into
mainfrom
ident-with-params
Jun 20, 2026
Merged

[AI] Refactor constructs for parsing ident/path with type parameters#237
soareschen merged 15 commits into
mainfrom
ident-with-params

Conversation

@soareschen

@soareschen soareschen commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

AI Summary

CGP's procedural macros (#[cgp_component], #[cgp_impl], #[cgp_provider],
delegate_components!, the #[uses]/#[use_type]/#[use_provider]
attributes, etc.) need to parse the angle-bracketed generic lists that appear
in their inputs. Two different positions exist:

  • Use-site arguments — the <A, B> in Foo<A, B> (what you pass).
  • Definition-site parameters — the <'a, C> in Bar<'a, C> (what you
    declare).

Previously these were modelled with permissive syn wrappers
(GenericArguments around syn::AngleBracketedGenericArguments, and
syn::Generics/TypeGenerics). Those wrappers silently accepted many forms
that are invalid in CGP positions — associated bindings (Foo<A, B = C>),
associated bounds (Foo<A: Clone>), turbofish (Foo::<A>), parameter defaults
(A = B), parenthesized args (Fn(A) -> B) — and the failures only surfaced
later as confusing downstream errors.

This PR replaces that machinery with a set of purpose-built, strict parser
types
that reject invalid forms at parse time with clear messages, and at the
same time generalizes identifier heads to full paths so attributes can
accept path::to::Trait<A> rather than only a bare identifier.

High-level concepts

New strict parsing types (in cgp/crates/macros/cgp-macro-core/src/types/ident/)

Type Position Accepts Rejects
TypeArg / TypeArgs (type_arg.rs) use-site args lifetimes, types, literal/{ } const args associated bindings, associated bounds
TypeGenericParam / TypeGenericParams (type_generic_param.rs) definition-site params bare lifetime, bare type ident, const N: T trait/lifetime bounds, defaults, composites
PathWithTypeArgs (path_with_type_args.rs) path head + use-site args path::to::Foo<A, B>, lifts final-segment args into TypeArgs turbofish, intermediate-segment generics, parenthesized args

Shared parse_angle_bracketed / to_tokens_angle_bracketed helpers
(angle_bracketed.rs)
back both list types; an absent <...> and an explicit empty <> both render
as nothing (stable round-trip).

Reworked existing types

  • IdentWithTypeArgs.type_args: GenericArgumentsTypeArgs.
  • IdentWithTypeGenerics.type_generics: TypeGenericsTypeGenericParams.
  • TypeGenerics is kept (still used to adapt an already-parsed
    syn::Generics off an item, via split_for_impl) and is now documented as
    the deliberate complement to TypeGenericParams — the two are intentionally
    not merged because TypeGenerics's normalization (collapsing const N: T to
    a bare N) is load-bearing for some callers.

Structural changes

  • Deleted generics/arguments.rs
    (the GenericArguments wrapper and its make_args() get-or-insert helper);
    removed from generics/mod.rs.
  • Option removed from the list payloads (TypeArgs::args,
    TypeGenericParams::params) — an empty Punctuated now represents "no
    brackets", eliminating Option handling and make_args() mutation.
  • Broad call-site migration across cgp-macro-core: the attribute parsers
    (function, prefix, uses, use_type, use_provider, default_impl,
    cgp_impl_attributes), cgp_provider, cgp_impl, delegate_component
    (incl. eval/for_loop/table), namespace (inherit/table), and
    provider_impl were moved from IdentWithTypeArgsPathWithTypeArgs and
    from GenericArguments/make_argsTypeArgs. Fields such as namespace,
    trait_path, provider_trait_path, provider_trait_bounds, uses,
    imports, and parent_namespace are now path-aware.
  • Code relocation: cgp-macro-lib's
    parse/component_spec.rs
    (the CgpComponentArgs parser) was removed; the equivalent logic now lives in
    cgp-macro-core (cgp_component/args/component_args.rs), consolidating
    component-spec parsing in the core crate.
  • New test crate cgp-macro-tests added to the workspace
    (Cargo.toml), with parse/reject/idempotency tests for
    IdentWithTypeArgs, IdentWithTypeGenerics, and PathWithTypeArgs, plus a
    side-by-side comparison documenting where their behaviors diverge.
  • Dev-dependencies (cgp-macro-core, syn, quote, proc-macro2) added to
    both cgp-macro-tests and the existing cgp-tests crate to allow direct
    unit-testing of the macro-core parsers.

Impacts

  1. Stricter validation / better errors. Invalid generic forms (associated
    bindings, associated bounds, turbofish, defaults, parenthesized args,
    generics on non-final path segments) are now rejected at parse time with
    explicit messages, instead of being silently accepted or producing opaque
    downstream compile errors.
  2. New capability: path-headed inputs. Attributes that take a trait,
    provider, or namespace now accept fully-qualified paths
    (path::to::Trait<A>), not just bare identifiers — a genuine feature
    addition, not only a refactor.
  3. Const-generic support at definition sites. TypeGenericParams can now
    represent const N: usize parameters; normalization differences vs.
    TypeGenerics are explicitly documented.
  4. Simpler internal API. Dropping Option and make_args() removes a class
    of get-or-insert mutation; empty-list semantics are uniform across both list
    types.
  5. Crate boundary shift. Component-spec parsing moves from cgp-macro-lib
    to cgp-macro-core; anything that imported CgpComponentArgs from the lib
    crate path is affected.
  6. CI / build surface grows. A new workspace member plus new dev-deps add to
    compile and test time.
  7. Behavior preserved for valid inputs. Round-trip idempotency is covered by
    the new tests; the regression-risk surface is specifically any code that
    relied on the old permissive parsing of now-rejected forms.

@soareschen soareschen merged commit 5cda4a9 into main Jun 20, 2026
5 checks passed
@soareschen soareschen deleted the ident-with-params branch June 20, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant