Skip to content

Refactor and move check_components! implementation to cgp-macro-core#239

Merged
soareschen merged 8 commits into
mainfrom
refactor-check-components
Jun 21, 2026
Merged

Refactor and move check_components! implementation to cgp-macro-core#239
soareschen merged 8 commits into
mainfrom
refactor-check-components

Conversation

@soareschen

@soareschen soareschen commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

AI Summary

This PR is an internal refactor of the macro logic behind the check_components!
and delegate_and_check_components! macros. It moves the parsing and code
generation for CGP's compile-time wiring checks out of the thin cgp-macro-lib
crate and into the shared cgp-macro-core crate, reorganizing one large file
into a focused set of small, single-responsibility modules.

There are no changes to the public macro surface — the syntax accepted by
check_components! and delegate_and_check_components! (array syntax,
#[check_trait], #[check_providers], #[check_params], #[skip_check],
generic parameters) and the code they generate are preserved. This is a
"move and reshape" change, not a feature change.

High-level concepts

The check macros generate the compile-time check traits described in the CGP
fundamentals: a dummy alias trait (__Check{Context} / __CanUse{Context})
with CanUseComponent (or IsProviderFor for provider checks) as its supertrait,
plus one impl block per component/parameter pair being verified. This forces the
compiler to surface the real missing dependency rather than a vague
"provider trait not implemented" error.

Previously, the type definitions, parser, and the derive_check_components /
derive_check_provider code generator for these traits all lived inside
cgp-macro-lib. This PR turns that logic into a set of first-class types
in cgp-macro-core
that own both their parsing and their evaluation:

  • A CheckComponentsTable (formerly CheckComponents) now exposes eval()
    and to_items() methods directly, rather than being fed to a free function
    derive_check_components. Generation is now a method on the data, not a
    separate procedure.
  • The flat CheckEntry (which previously baked the resolved span and a single
    optional param into one struct at parse time) is replaced by a layered model:
    • CheckKeySingle(Type) or Multi([..]), modeling the component-key
      array syntax explicitly.
    • CheckValueSingle or Multi([..]), modeling the parameter array
      syntax explicitly.
    • CheckEntry — a key/value pair as written in source.
    • EvaluatedCheckEntry — the expanded form (one key, one optional value,
      one resolved span) produced by CheckEntry::eval().
  • TypeWithGenerics (a type plus its ImplGenerics) is promoted to its own
    module and reused throughout, including inside EvaluatedCheckEntry.

The key structural shift is the separation of parsing (source syntax →
CheckEntry with CheckKey/CheckValue) from evaluation (the cartesian
expansion of keys × params into EvaluatedCheckEntry, with span-resolution
heuristics). Previously these two concerns were fused into a single
ParseCheckEntries::parse implementation that did expansion inline during
parsing.

Structural changes

Added — cgp-macro-core/src/types/check_components/

A new module split into one concept per file:

Removed — cgp-macro-lib

  • src/check_components/ (whole directory): derive.rs
    (derive_check_components / derive_check_provider), override_span.rs, mod.rs
  • src/parse/check_components.rs (the old CheckComponents, CheckEntries,
    CheckEntry, ParseCheckEntries, TypeWithGenerics)
  • The corresponding mod/pub use lines in
    lib.rs and
    parse/mod.rs

Rewired — cgp-macro-lib entrypoints

  • entrypoints/check_components.rs
    now parses straight into CheckComponentsTables and emits tables.to_items(),
    replacing the manual loop over derive_check_components.
  • entrypoints/delegate_and_check_components.rs
    now builds CheckEntry { key, value } values (using CheckKey::Single /
    CheckValue::Single) and lets CheckComponentsTable::eval() resolve spans,
    instead of constructing pre-evaluated entries with manually computed spans.

Net diff: ~512 insertions / ~403 deletions across 18 files; the deletions are
almost entirely the old cgp-macro-lib implementation being relocated.

Impacts

  • Crate boundary moved. The check-trait generation logic now lives in
    cgp-macro-core alongside the other CGP code generators (cgp_component,
    cgp_impl, delegate_component, etc.). cgp-macro-lib keeps only the
    proc-macro entrypoints and delegates into the core types — consistent with how
    the other macros are already structured. This makes the check logic reusable
    by anything depending on cgp-macro-core, not just the cgp-macro-lib entrypoints.

  • Parse/eval separation. Source syntax is now preserved faithfully in
    CheckKey/CheckValue and only expanded later in eval(). This is a cleaner
    pipeline and makes the array/cartesian expansion easier to reason about and test
    in isolation.

  • Span-resolution behavior unchanged, but relocated. The heuristic that aims
    the error span at the component type when
    component_types_count >= component_params_count (and otherwise at the
    parameter type) is moved verbatim from parse-time into CheckEntry::eval().
    The override_span helper (which retargets the context type's tokens so
    unsatisfied-constraint errors point at the component) now lives privately in
    table.rs. Error-message quality for failed wiring checks should be unchanged.

  • delegate_and_check_components! span handling simplified. The entrypoint no
    longer pre-computes spans; it hands raw key/value pairs to eval(). The
    #[skip_check] path (an empty parameter list) naturally emits zero check impls
    because the per-param loop has nothing to iterate — this is now documented inline.

  • Provider checks (#[check_providers]) now share one code path. Previously
    derive_check_provider was a separate function that used impl_generics as-is
    and dropped any generics attached to the check value (.. pattern). The unified
    eval() now merges the check value's generics with the impl generics for the
    provider case too. In practice the existing macro inputs produce equivalent
    output, but provider checks are now consistent with context checks and would
    correctly carry generics on the checked parameter if present.

  • No public API / no syntax change. check_components!,
    delegate_and_check_components!, and all their attributes behave the same for
    end users. No downstream crate needs changes.

@soareschen soareschen marked this pull request as draft June 21, 2026 21:03
@soareschen soareschen marked this pull request as ready for review June 21, 2026 21:46
@soareschen soareschen merged commit 2f83303 into main Jun 21, 2026
5 checks passed
@soareschen soareschen deleted the refactor-check-components branch June 21, 2026 21:47
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