[derive] Make generated-scope syntax validation an explicit capability
- Dominant language
- Rust
- Stars
- 2.6k
- Forks
- 179
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 29
Description
## Motivation
The fixes for #3619 and #3633 validate caller syntax before replaying it in
generated scopes. In the #3633 fix, correctness currently depends on each
derive path remembering independently:
- which field types, generic parameters, predicates, or expressions are
copied;
- which exact helper names or prefixes exist in the destination scope;
- whether contextual names such as `Self` change meaning there;
- whether unresolved syntax (especially macros or `Verbatim`) can expand
differently; and
- whether syntax is evaluated more than once and therefore needs a stronger
specialized grammar.
This is easy to omit at a new replay site, and generated identifiers and
literal reserved-name lists can drift apart. The immediate fixes should land
independently; this issue tracks reducing that residual proof surface.
## Proposal
Represent “this syntax has been checked for this generated destination”
explicitly, rather than passing raw `syn::Type`/`syn::Expr` values from
validation into generation by convention. One possible shape is:
```rust
struct GeneratedScope {
exact_names: &'static [&'static str],
reserved_prefixes: &'static [&'static str],
rebinds_self: bool,
evaluation: Evaluation,
}
struct ValidatedCopiedType<'a> { /* private */ }
struct StableCopiedDiscriminant<'a> { /* private */ }
```
Constructors would perform the checks appropriate to that destination:
unresolved macro/`Verbatim` rejection, unqualified-name capture checks,
contextual-`Self` checks, and repeated-evaluation restrictions. Generators
which replay caller syntax should accept an opaque validated wrapper instead
of a raw AST node where practical.
Define generated names and their corresponding reservations from one registry
or scope descriptor, including prefix-generated names, so adding or renaming a
helper cannot silently leave validation stale.
Keep validation path-sensitive rather than introducing one global syntax
allowlist:
- syntax emitted unchanged in its original scope may need no restriction;
- copied field types need lexical-capture and contextual-name checks;
- expressions evaluated repeatedly need stability constraints; and
- enum discriminants need the stronger grammar introduced for #3619, not
merely #3633’s lexical checks.
## Suggested rollout
1. Inventory every place `zerocopy-derive` copies caller types, generics,
predicates, expressions, attributes, or patterns into a new generated
scope.
2. Define destination-scope descriptors for the sites fixed by #3633 first.
3. Make those emitters consume validated wrappers.
4. Migrate other replay sites incrementally, preserving diagnostics where
reasonable.
5. Add tests which fail if a helper is added or renamed without updating the
scope validation, plus regressions for generated-name capture, contextual
`Self`, unresolved macros, raw identifiers, qualified paths, and nested
scopes binding their own `Self`.
## Non-goals
- Hashed/randomized helper names are not a soundness boundary; callers can
still choose names and deterministic validation is reviewable.
- Do not collapse distinct grammars into one global rejection rule.
- Do not require original-scope syntax to pass copied-syntax checks.
- This refactor does not by itself prove all proc-macro output sound; it makes
a validation obligation explicit and harder to omit.
## Acceptance criteria
- Generated helper names/prefixes and capture validation have one authoritative
definition per destination scope.
- A migrated generator cannot replay raw caller syntax without first obtaining
the matching validation capability.
- The #3619 and #3633 regression families remain covered, including
`on_error = "skip"` and supertrait-chain behavior where applicable.
- Specialized restrictions remain separately documented and tested.
Related: #11, #1684, #1725, #388, #3619, #3633.
*Authored by an AI agent acting on Josh Liebow-Feeser's behalf.*
Contributor guide
Research direction
Start by inventorying every caller-syntax replay site in zerocopy-derive, then read the regression work from #3619 and #3633. Define destination-scope descriptors and validated wrappers for the migrated emitters, and preserve their regression coverage, including on_error = "skip" and relevant supertrait-chain cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100