Revise #[use_type] and expand the error catalog#255
Merged
Conversation
…FooType.Foo` to `HasFooType.Foo in Context`
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 the
#[use_type]attribute — CGP's tool for importing an abstract associated type under a bare alias — and builds out the documentation around post-codegen errors and the attribute internals. The code changes are concentrated in one macro (cgp-macro-core), and the bulk of the diff is tests and docs that make the new behavior correct, covered, and explained. In numbers, the change touches 100 files with roughly 1,500 lines added undercrates/(almost all of it tests) and 1,200 underdocs/, against a much smaller net change to the macro logic itself. This tree is the pre-release of v0.8.0, so the syntax change lands before any stable release depends on it.What changed, in concept
The headline change is a new syntax for importing an abstract type from a foreign context. Previously a
#[use_type]spec named a non-Selfrewrite target with a leading@prefix —#[use_type(@Types.HasScalarType.Scalar)]meant "rewriteScalarto<Types as HasScalarType>::Scalar." The prefix now moves to a trailingin Contextclause, so the same import reads#[use_type(HasScalarType.Scalar in Types)]. The motivation is readability and consistency:inis a reserved Rust keyword, so it can never be mistaken for a trait, type, or associated-type name and needs no sigil to disambiguate, and it matches theinalready used elsewhere in CGP wiring such as#[prefix(@path in Namespace)]. The clause scopes over the whole spec, so a braced group like#[use_type(HasFooType.{Foo, Bar} in Ctx)]projects every imported type in the group againstCtx.Alongside the syntax, the foreign-import semantics became more ergonomic. A foreign
in Contextimport now adds the requiredContext: Traitbound to the generated trait's ownwhereclause, not only to the impl. Before this change, a component that imported a type from one of its own generic parameters had to declare that parameter's bound by hand —pub trait CanCalculateArea<Types: HasScalarType>— because the macro rewrote the signatures to name<Types as HasScalarType>::Scalarwithout ensuringTypes: HasScalarTypeheld. The macro now supplies that bound itself, so writing the plain, unboundedpub trait CanCalculateArea<Types>is enough. This closes a real soundness gap as much as a convenience one: the old behavior silently dropped the constraint, leaving a signature that compiled only when the bound happened to be supplied elsewhere. The type-equality (= T) pin remains impl-side and is deliberately never added to the trait.The revision also adds a genuinely new capability: nested foreign imports that chain through one another. One import's
in Contextmay now name another import's alias, as in#[use_type(HasTypes.Types, HasScalarType.Scalar in Types)], whereTypesis itself imported rather than a real generic parameter. The macro resolves these to a fixpoint, so the order in which the imports are written does not matter —#[use_type(HasC.C in B, HasB.B in A, HasA.A)]grounds identically to its front-to-back rewrite. The one arrangement with no valid order is a cycle, and the macro stops rather than looping on one, letting the compiler report an ordinary "cannot find type" error at the offending alias instead of hanging.Structural changes
The macro internals were refactored to support the above rather than merely patched.
#[use_type]transformation grew from a two-phase pass (substitute, then add bounds) into a three-step one: a new grounding step resolves every spec's context against all the other specs and iterates to a fixpoint, then a single substitution pass rewrites the bare aliases, then the bounds are appended. The substitution visitor was generalized to match: the per-specSubstituteAbstractTypebecameSubstituteAbstractTypes, which holds every grounded spec at once and rewrites all imports in one traversal, carrying anis_changedflag the grounding fixpoint reads to know when a further pass would be a no-op. This let the old cross-spec alias resolver (find_type_aliasintype_predicates.rs) be removed entirely, since grounding now does that work up front and the predicate derivation reads the already-grounded context directly.The implementation docs were reorganized to match the code's structure. The single monolithic
asts/attributes.mdwas split into anasts/attributes/directory with one page per modifier —#[uses],#[use_type],#[use_provider],#[extend],#[extend_where],#[derive_delegate], and#[default_impl]— plus a README that covers what the modifiers share, namely how a host macro collects them and which host accepts which. Links from the reference and implementation READMEs were repointed to the new layout.The errors catalog saw the largest documentation expansion. It grew from three class subdirectories to five, and gained a supporting reference. A new
lowering/class directory covers failures that arise in what a macro lowered the input into rather than in wiring — an ill-formed generated (unsized) type, and an unresolved imported abstract type from a misspelled#[use_type]. A newerror_codes/directory is a forward reference of the ninerustccodes the catalog surfaces (E0117,E0119,E0207,E0210,E0275,E0277,E0428,E0576,E0599), each stating what the code means in plain Rust and the rule behind it, so the class documents can cite one verified entry instead of restating the language rule. The wiring section gained two namespace-specific coherence documents (overlapping forwarding, and override conflict) that had previously been folded into the generic conflict doc, and the checks section gained a document for an unsatisfied ordinary trait bound. The debugging guide gained a new section on grep-based error triage — classifying a failure from its^errorheadlines and confirming the cause with one class-specific pattern before reading the whole cascade.Test coverage was extended broadly. The
cgp-testssuite gained behavioral tests for the new and revised#[use_type]forms — foreign imports, nested and reverse-order imports, imports feeding a getter, and imports combined with a supertrait — and thecgp-macro-testssuite gainedtrybuildcompile-fail fixtures (with pinned.stderr) for the new failure classes: cyclic and unresolved foreign imports, unsatisfied ordinary bounds surfaced through a check, foreign-component#[default_impl]orphan violations, and namespace override and forwarding conflicts.Impacts
The changes ripple out in a handful of distinct ways, listed here because each affects a different reader or workflow.
#[use_type(@Context.Trait.Type)]must be rewritten to#[use_type(Trait.Type in Context)]; the@-prefix form no longer parses. Because the old foreign-import form existed only in this pre-release tree and not in the stable v0.7.0 line, the migration is confined to this repository's own sources, which are updated in the PR.in Contextnow emits an extraContext: Traitpredicate on the generated trait'swhereclause. This is why the hand-written parameter bound can be dropped, but it also means anyone relying on the previous (unsound) expansion — a signature that compiled without the bound — will now see the bound enforced.SubstituteAbstractType→SubstituteAbstractTypes, the newgrounded_specsstep, and the removal offind_type_aliaschange the internal API surface that the implementation docs describe; anyone reading or extending theuse_typetransform meets a different, single-pass shape.asts/attributes.mdintoasts/attributes/moves several stable anchor targets, so external links into the old single page will break and were repointed within the tree./cgpskill references were updated to the new syntax and behavior, so an agent following the skill now writesin Contextimports and unbounded component parameters rather than the retired forms.#[use_type]imports sees no difference.