Skip to main content

prebindgen_flat/flat/
ty.rs

1//! Types: the accepted syntax, paired with the tokens it was read from.
2//!
3//! [`TypeKind`] is the subset of [`syn::Type`] a `#[prebindgen]` crate may
4//! write — one variant per accepted **form**, nothing folded together, nothing
5//! interpreted. What `&str` and `String` have in common is a *destination*
6//! language's business, and the adapters are where that decision belongs.
7//!
8//! [`TypeRef`] pairs that kind with the tokens the source wrote. The pairing
9//! survives the pivot because the two answer different questions — the kind is
10//! the grammar an adapter may rely on, the syntax is what generated Rust must
11//! spell — but the syntax is no longer *load-bearing*: nothing is recoverable
12//! only from it. [`TypeKind::to_syn`] is what checks that, and
13//! `syntax_is_recoverable_from_kind` is what runs it over the whole acceptance
14//! corpus.
15//!
16//! [`TypeKind`] is total over the accepted grammar: a form with no variant here
17//! is a form the language does not accept, so acceptance is mostly a
18//! consequence of lowering rather than a second list that can drift from it.
19//! Mostly: [`Uninit`](TypeKind::Uninit) is accepted in one **position** only,
20//! which no variant set can express — see
21//! [`OwnedUninit`](UnsupportedTypeReason::OwnedUninit). Same contract otherwise,
22//! and for the same reason, as [`lower_array_len`].
23
24use std::{fmt, rc::Rc};
25
26use prebindgen::SourceLocation;
27use quote::ToTokens;
28
29use super::{
30    array_len::{lower_array_len, ArrayExtent, ConstIndex, UnsupportedArrayLen},
31    key::TypeKey,
32    origin::Origin,
33};
34
35/// A type as the language accepted it, plus the exact syntax it came from.
36///
37/// The retained slice is what generated Rust spells, through
38/// [`spell`](Self::spell). It is **not**
39/// where facts go to survive a lossy classification any more — `kind` keeps the
40/// lifetime, the wrapper and the argument it used to drop, and rebuilding the
41/// syntax from it proves so. Keeping the slice anyway is cheap, exact
42/// (nothing has to reconstruct token for token what the source already wrote),
43/// and it is what makes the proof possible at all.
44///
45/// # The invariant
46///
47/// > **Every `TypeRef` was classified by the model.** [`Flat`](super::Flat)
48/// > classified it from source syntax, or the registry pipeline composed it by
49/// > layering over something already classified.
50///
51/// **Historically enforced by visibility, now by convention.** Before the
52/// registry pipeline moved to the separate `prebindgen-registry` crate, the
53/// boundary was `api::core` and was drawn by visibility at four places, each
54/// checked by the compiler on every build:
55///
56/// | | |
57/// |---|---|
58/// | the `kind` and `origin` fields | `pub(super)` — a public field **is** a constructor, so restricting only the composers would block nothing |
59/// | `borrowed` / `optional` / `scalar` | `pub(crate)` |
60/// | `named` | `pub(super)` — `flat` alone |
61/// | `Flat::classify` | `pub(crate)` |
62///
63/// A module-path seal can no longer express "the registry pipeline, and
64/// nothing else" once that pipeline is a different crate — there is no path
65/// inside this crate to name it — so `borrowed` / `optional` / `scalar` and
66/// `Flat::classify` are now plain `pub`, and the fields stay `pub(super)`
67/// (nothing outside `flat` ever needed them). The intent is unchanged and
68/// documented here, but no longer compiler-enforced against a destination
69/// adapter (`prebindgen-c`, `prebindgen-jni`): restoring that would need a real
70/// API, e.g. a sealed capability token minted only by `prebindgen-registry`.
71/// Where one needs a type the model already declares, the **declaration**
72/// answers: see [`Variant::type_ref`](super::Variant::type_ref), which is what
73/// the `SumTag` selector uses instead of composing a reading from an ident.
74///
75/// The invariant is unconditional — no phase, no lifetime, no direction — so it
76/// holds for a **stored** value. That is the point: a `TypeRef` lives in
77/// `UnfoldLeaf::out_ty` and `FoldLeaf::ty`, inside plans the registry itself
78/// stores, so a borrow-carrying token would make the registry self-referential.
79///
80/// It deliberately does **not** claim the type's converters exist. That is
81/// false by design for stored readings — `unrequire_output` leaves a cell whose
82/// converter genuinely cannot resolve, and a `SumTag` leaf never has one — so
83/// converter existence stays a lookup that answers `Option`.
84///
85/// It does **not** claim a registry cell either, and the two are separate
86/// questions. Holding a `TypeRef` means the model classified the type; whether
87/// it is in a type table is the registry's business, and the registry states it
88/// in three parts — a **cell** (the type entered the pipeline), a **root** (the
89/// binding asked for it directly), an **entry** (a converter resolved). A
90/// `SumTag` leaf's type makes the first and not the second, deliberately
91/// (#282); see `Registry::reference_output` in the registry layer above.
92#[derive(Clone, Debug)]
93pub struct TypeRef {
94    /// The accepted syntax this type is — the closed grammar, not an
95    /// interpretation of it.
96    pub(super) kind: TypeKind,
97    /// The type as generated Rust must spell it — the source's own tokens,
98    /// normalized to the flat namespace the generated crate can name (see
99    /// [`Flat::parse`](super::Flat::parse)) — plus the source they came
100    /// from.
101    ///
102    /// It says exactly what `kind` says — that is the invariant
103    /// [`TypeKind::to_syn`] checks — and it says it in the source's own tokens,
104    /// which is why generated Rust re-emits this rather than a reconstruction.
105    pub(super) origin: Origin<syn::Type>,
106}
107
108impl fmt::Display for TypeRef {
109    /// The type as the source wrote it, **for a message**.
110    ///
111    /// Diagnostics are not emission: a panic naming an unsupported type is
112    /// decision code reporting why it decided, and it must not need the
113    /// [`Emit`](crate::flat::emit::Emit) capability to say so. So this is
114    /// ungated where [`spell`](Self::spell) is not.
115    ///
116    /// **The identity, not the spelling** — `TypeKey`, which is
117    /// `canonical_type` rendered. Delegating to `spell()` would have handed the
118    /// captured spelling back out through `format!("{ty}")`, so
119    /// `syn::parse_str(&ty.to_string())` reconstructed it exactly and the
120    /// capability was a suggestion. Rendering the canonical form keeps
121    /// diagnostics readable while making the round trip land on a *normalized*
122    /// type rather than the source's own tokens.
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        write!(f, "{}", self.key().as_str())
125    }
126}
127
128impl TypeRef {
129    /// What the type means. **Classify off this**, never off the spelling.
130    ///
131    /// The seal, as a compiled assertion. An out-of-crate consumer cannot
132    /// assemble a reading, because the fields it would have to name are private
133    /// (`E0451`):
134    ///
135    /// ```compile_fail
136    /// # use prebindgen_flat::flat::{TypeKind, TypeRef};
137    /// let forged = TypeRef { kind: TypeKind::Unit, origin: todo!() };
138    /// ```
139    ///
140    /// …nor, historically, through a composer (`E0624`) — **no longer true**:
141    /// `borrowed` / `optional` / `scalar` are `pub` now that the registry
142    /// pipeline that composes with them is the separate `prebindgen-registry`
143    /// crate rather than code inside this one:
144    ///
145    /// ```
146    /// # use prebindgen_flat::flat::{ScalarKind, TypeRef};
147    /// let composed = TypeRef::scalar(ScalarKind::Bool);
148    /// ```
149    ///
150    /// The struct-literal case above still proves the **crate** boundary. The
151    /// stronger claim this crate used to enforce by visibility — that nothing
152    /// above `api::core` can mint one either — no longer has a module path to
153    /// be checked against once the registry pipeline is the separate
154    /// `prebindgen-registry` crate; see the type-level doc's "The invariant"
155    /// section for what replaced it.
156    pub fn kind(&self) -> &TypeKind {
157        &self.kind
158    }
159
160    /// The tokens generated Rust must spell. **Spell off this**, never off
161    /// `kind` — re-deriving a spelling from the classification is how
162    /// `Box<Option<T>>` becomes an `E0308`.
163    ///
164    /// Tokens, not a `syn::Type`: a spelling is for spelling. What the type
165    /// *is* has an answer in [`kind`](Self::kind) and in the readings beside
166    /// it; the node itself never leaves the model.
167    pub fn spell(&self) -> proc_macro2::TokenStream {
168        self.origin.spell()
169    }
170
171    /// The type as `syn` — **the escape**. See [`Origin::as_syn`].
172    // Test-only as of C7: `Emit` hands out a spelling, never the node, so the
173    // round-trip checks (`syntax_is_recoverable_from_kind`) are the last
174    // callers. That is the correct end state — the check that a kind can
175    // reproduce its own syntax needs both halves.
176    #[allow(dead_code)]
177    pub(crate) fn as_syn(&self) -> &syn::Type {
178        self.origin.as_syn()
179    }
180
181    /// Where the type was written, for diagnostics. A composed type is
182    /// **placeless** — [`SourceLocation::has_position`] gates what is printed.
183    pub fn location(&self) -> &SourceLocation {
184        &self.origin.location
185    }
186
187    /// An [`Origin`] for a node that exists **because of** this type, sharing
188    /// its location — a synthesized getter built from a return type, say.
189    ///
190    /// Deliberately narrower than handing out the origin: it lends provenance
191    /// without lending the field, so a `TypeRef`'s own `Origin` still cannot be
192    /// obtained from outside the model.
193    pub(crate) fn origin_with<S>(&self, syntax: S) -> Origin<S> {
194        self.origin.with(syntax)
195    }
196}
197
198impl TypeRef {
199    /// The **arity layers** over this type, and what they wrap.
200    ///
201    /// `Option<Vec<T>>` is `Optional(Iterable(Base))` over `T`. The stack is the
202    /// same [`Shape`](crate::shape::Shape) the expansion and decomposition plans are built from — so a
203    /// consumer that needs a plan shape has it, rather than rebuilding one from
204    /// flags that were derived from this type moments earlier.
205    ///
206    /// **A borrow is not a layer.** `Optional` and `Iterable` change arity — none
207    /// or one, none or many — while `&T` is the same single value held
208    /// differently. That is ownership, and it stays on the returned core, where
209    /// [`borrow_target`](Self::borrow_target) reads it.
210    ///
211    /// A layer out of position is not a layer: `Vec<Option<T>>` is
212    /// `Iterable(Base)` over `Option<T>`, because the optional is inside the run.
213    /// The stack is what wraps the payload, in order, and nothing is reordered to
214    /// make it fit a shape a caller hoped for.
215    ///
216    /// Returning the stack rather than a set of flags is what lets a caller
217    /// **decline**: a consumer that can only build `Base` and `Optional(Base)`
218    /// matches those and falls through on anything else, instead of silently
219    /// consuming a layer it cannot honour.
220    pub fn layer_stack(&self) -> (crate::shape::Shape, &TypeRef) {
221        use crate::shape::Shape;
222        // Bounded on purpose, and not a recursion: the accepted crossing is
223        // `Option<Vec<T>>` — at most one optional, then at most one run, in that
224        // order. Recursing would accept `Vec<Option<T>>` as `Iterable(Optional)`,
225        // which reads the inner optional as a boundary layer when it is part of
226        // the element, and `Option<Option<T>>` as two nullable layers when the
227        // boundary has one way to say absent.
228        // Through the transparent wrappers, never past the node: a layer is read
229        // off `unwrapped`, while the type this returns is the one the source
230        // spelled — `Box<Foo>` is a `Base` whose core still spells the `Box`.
231        let mut core = self;
232        let optional = matches!(core.unwrapped().kind, TypeKind::Optional(_));
233        if let TypeKind::Optional(inner) = &core.unwrapped().kind {
234            core = inner;
235        }
236        let iterable = matches!(core.unwrapped().kind, TypeKind::Vec(_) | TypeKind::Slice(_));
237        if let TypeKind::Vec(inner) | TypeKind::Slice(inner) = &core.unwrapped().kind {
238            core = inner;
239        }
240
241        let mut shape = Shape::Base;
242        if iterable {
243            shape = Shape::iterable(shape);
244        }
245        if optional {
246            shape = Shape::optional((), shape);
247        }
248        (shape, core)
249    }
250
251    /// Every type on the way down through the arity layers, outermost first and
252    /// ending at the core [`layer_stack`](Self::layer_stack) returns.
253    ///
254    /// What a **registration** walks, which is a different question from what
255    /// crosses: a value delivered layer-by-layer needs each of these un-required,
256    /// and none of them has a converter of its own.
257    pub fn layer_types(&self) -> Vec<&TypeRef> {
258        // Stops exactly where `layer_stack` stops, or the registration view would
259        // un-require types the shape says are part of the element.
260        let mut out = vec![self];
261        let mut cur = self;
262        if let TypeKind::Optional(inner) = &cur.unwrapped().kind {
263            out.push(inner);
264            cur = inner;
265        }
266        if let TypeKind::Vec(inner) | TypeKind::Slice(inner) = &cur.unwrapped().kind {
267            out.push(inner);
268        }
269        out
270    }
271
272    /// This type with every [transparent wrapper](TRANSPARENT_WRAPPERS) peeled
273    /// off — `Box<Cow<'_, [T]>>` → the `[T]` node, an unwrapped type → itself.
274    ///
275    /// **The fold, made explicit.** [`kind`](Self::kind) is the syntax the source
276    /// wrote, wrappers and all; a consumer that does not care which of them stand
277    /// over a type says so here, at its own call site, and the ones that must put
278    /// them back in generated Rust ask [`erased_wrappers`](Self::erased_wrappers)
279    /// instead. That split is why the wrapper is no longer erased during
280    /// lowering: the model reports, the consumer decides.
281    ///
282    /// Per layer, and only this one: a wrapper under a borrow or inside an
283    /// `Option` belongs to that inner node, which answers for itself.
284    pub fn unwrapped(&self) -> &TypeRef {
285        match &self.kind {
286            TypeKind::Boxed(inner) | TypeKind::Cow { inner, .. } => inner.unwrapped(),
287            _ => self,
288        }
289    }
290
291    /// What an `Option<T>` wraps, else `None`.
292    ///
293    /// One layer, named. [`layer_stack`](Self::layer_stack) reads the whole
294    /// arity stack; these three read exactly the layer a caller asks for, which
295    /// is what a consumer wants when it can only *represent* some of them.
296    ///
297    /// Read through [`unwrapped`](Self::unwrapped), like every layer accessor
298    /// here: `Box<Option<T>>` is an optional to a destination language, and the
299    /// `Box` is still on the node for whoever has to spell it.
300    pub fn optional_inner(&self) -> Option<&TypeRef> {
301        match &self.unwrapped().kind {
302            TypeKind::Optional(inner) => Some(inner),
303            _ => None,
304        }
305    }
306
307    /// The element of a run of values (`Vec<T>`, `[T]`), else `None`.
308    pub fn sequence_elem(&self) -> Option<&TypeRef> {
309        match &self.unwrapped().kind {
310            TypeKind::Vec(elem) | TypeKind::Slice(elem) => Some(elem),
311            _ => None,
312        }
313    }
314
315    /// What a borrow points at, else `None`.
316    ///
317    /// Through an out-parameter's [`Uninit`](TypeKind::Uninit): `&mut
318    /// MaybeUninit<T>` points at a `T`'s storage, and the slot is not a type
319    /// anything converts, registers or crosses with. A consumer that needs to
320    /// tell the two borrows apart reads the [`kind`](Self::kind), where the
321    /// `MaybeUninit` the source wrote is still standing.
322    pub fn borrow_target(&self) -> Option<&TypeRef> {
323        let inner = match &self.unwrapped().kind {
324            TypeKind::Ref { inner, .. } => inner,
325            _ => return None,
326        };
327        Some(match &inner.kind {
328            TypeKind::Uninit(slot) => slot,
329            _ => inner,
330        })
331    }
332
333    // ── Composition ───────────────────────────────────────────────
334    //
335    // Building a type the SOURCE did not write, as opposed to reading one it
336    // did. The decomposition plans need this: a leaf may be the borrow of a
337    // value, a presence flag, or a selector — none of which any source spelled,
338    // and all of which have to carry a reading like everything else.
339    //
340    // Here rather than at the callers, and not via
341    // [`Flat::classify`](super::Flat::classify), because the two acts are
342    // different. `classify` lowers *source syntax* — it is the frontend reading
343    // what a crate wrote, and `classify_has_no_caller_outside_the_registry`
344    // keeps it that way. These compose a type from parts already understood,
345    // which needs no lowering at all: each builds `kind` **and** the matching
346    // `spell()` in one place, so the classification and the spelling
347    // cannot disagree — the invariant every consumer of a `TypeRef` relies on.
348
349    /// A borrow of this type — `&T` from `T`.
350    ///
351    /// Keeps this type's location: the borrow exists *because of* this value,
352    /// so a diagnostic about it should point where the value came from.
353    pub fn borrowed(&self) -> TypeRef {
354        let inner = self.origin.spell();
355        TypeRef {
356            kind: TypeKind::Ref {
357                lifetime: None,
358                mutable: false,
359                inner: Box::new(self.clone()),
360            },
361            origin: self.origin.with(syn::parse_quote!(&#inner)),
362        }
363    }
364
365    /// An optional of this type — `Option<T>` from `T`. Location as
366    /// [`Self::borrowed`].
367    pub fn optional(&self) -> TypeRef {
368        let inner = self.origin.spell();
369        TypeRef {
370            kind: TypeKind::Optional(Box::new(self.clone())),
371            origin: self.origin.with(syn::parse_quote!(Option<#inner>)),
372        }
373    }
374
375    /// A scalar the binding invented — a presence flag, a selector.
376    ///
377    /// **Placeless**, and deliberately: no file wrote it, so claiming a location
378    /// would make a fabricated one indistinguishable from a real one.
379    /// [`Flat::classify`](super::Flat::classify) does exactly this for a
380    /// composed spelling, and `ensure_entry` gives adapter-authored cells the
381    /// same treatment — `has_position` already gates what a diagnostic prints.
382    pub fn scalar(kind: ScalarKind) -> TypeRef {
383        // The spelling comes from the kind, so the two cannot drift.
384        let ident = syn::Ident::new(kind.as_str(), proc_macro2::Span::call_site());
385        TypeRef {
386            kind: TypeKind::Scalar(kind),
387            origin: Origin::new(
388                syn::parse_quote!(#ident),
389                std::rc::Rc::new(prebindgen::SourceLocation::default()),
390            ),
391        }
392    }
393
394    /// A nominal reference to a declared type, by name. Placeless for the same
395    /// reason as [`Self::scalar`] — this is the binding naming a type, not a
396    /// source mentioning one.
397    pub(super) fn named(ident: &syn::Ident) -> TypeRef {
398        TypeRef {
399            kind: TypeKind::Named {
400                id: TypeId {
401                    name: ident.to_string(),
402                },
403                args: Vec::new(),
404            },
405            origin: Origin::new(
406                syn::parse_quote!(#ident),
407                std::rc::Rc::new(prebindgen::SourceLocation::default()),
408            ),
409        }
410    }
411
412    /// This type's identity as a table key.
413    ///
414    /// The canonical spelling is what a key *is* (#113), and reading it is
415    /// legitimate — but it should be the model's answer rather than every caller
416    /// reaching for the spelling itself, since a caller that reaches
417    /// into `origin` to *reason* is the thing this model exists to stop.
418    pub fn key(&self) -> TypeKey {
419        TypeKey::from_type(self.origin.as_syn())
420    }
421
422    /// The [transparent wrapper](TRANSPARENT_WRAPPERS) this type's **spelling**
423    /// adds over its classification, if any — `Box<Option<T>>` → `Some("Box")`,
424    /// `Option<T>` → `None`.
425    ///
426    /// This exists because [`kind`](Self::kind) and [`spell`](Self::spell)
427    /// answer different questions, and only one of them is about the
428    /// destination:
429    ///
430    /// * `kind` decides what the **destination** sees — the surface type and the
431    ///   wire. `Box<Option<String>>` and `Option<String>` are one optional
432    ///   string to every destination language, which is why the wrapper is
433    ///   erased.
434    /// * `syntax` decides how the value is **converted** — and Rust does tell
435    ///   them apart. A converter that rebuilds a value must produce the type
436    ///   the source actually spelled.
437    ///
438    /// So a consumer that *classifies* should never consult this; a consumer
439    /// that **reconstructs a Rust value** must, because rebuilding from the
440    /// classification alone yields the stripped type and handing that to a
441    /// parameter spelled `Box<..>` is an `E0308` in the generated crate.
442    ///
443    /// Only the outermost wrapper is named. That is enough to decide *whether*
444    /// a spelling was erased — which is the question a **refusal** asks — but a
445    /// consumer that rebuilds a nested `Box<Cow<'_, T>>` needs every layer, and
446    /// asks [`erased_wrappers`](Self::erased_wrappers) for the whole list, and
447    /// [`stripped_key`](Self::stripped_key) for what sits under them.
448    ///
449    /// Erased says nothing about **rebuildable**: `Box` reconstructs as
450    /// `Box::new(v)`, while `Cow`'s `Owned`/`Borrowed` choice is not determined
451    /// by any fact the model holds. Which wrappers an emitter can rebuild is
452    /// that emitter's policy; this only stops the wrapper from being invisible.
453    pub fn erased_wrapper(&self) -> Option<&'static str> {
454        self.erased_wrappers().into_iter().next()
455    }
456
457    /// Every [transparent wrapper](TRANSPARENT_WRAPPERS) this type's **spelling**
458    /// adds over its classification, outermost first — `Box<Box<T>>` →
459    /// `["Box", "Box"]`, `Box<Cow<'_, T>>` → `["Box", "Cow"]`, an unwrapped
460    /// spelling → `[]`.
461    ///
462    /// The list [`erased_wrapper`](Self::erased_wrapper) names the head of. A
463    /// consumer deciding *whether* to refuse needs only that head; one that
464    /// **rebuilds** needs all of them, because it has to apply an operation per
465    /// layer — and `Box<Cow<'_, T>>` is two different operations, not one
466    /// repeated.
467    ///
468    /// # This answers for one layer's spelling
469    ///
470    /// **An erasure sits outside the layer it wraps**, so this is a question
471    /// that has to be asked on the way *down*, at every layer, and never once at
472    /// the top:
473    ///
474    /// | Spelling | here | on [`borrow_target`](Self::borrow_target) |
475    /// |---|---|---|
476    /// | `Box<&Vec<T>>` | `["Box"]` | `[]` — `kind` is `Ref`, and peeling it first drops the `Box` |
477    /// | `&Box<Vec<T>>` | `[]` — a `syn::Type::Reference` cannot be peeled | `["Box"]` |
478    ///
479    /// A rebuild therefore collects wrappers **as it descends**: by the time it
480    /// reaches the leaf they are gone from `kind`, which is precisely the thing
481    /// they are missing from.
482    pub fn erased_wrappers(&self) -> Vec<&'static str> {
483        let mut names = Vec::new();
484        let mut ty = self;
485        loop {
486            let name = match &ty.kind {
487                TypeKind::Boxed(inner) => {
488                    ty = inner;
489                    "Box"
490                }
491                TypeKind::Cow { inner, .. } => {
492                    ty = inner;
493                    "Cow"
494                }
495                _ => return names,
496            };
497            names.push(name);
498        }
499    }
500
501    /// This type's identity as a table key with every transparent wrapper
502    /// removed.
503    ///
504    /// What [`key`](Self::key) answers for a **spelling**, this answers for the
505    /// **type**. The two are different questions and both are legitimate:
506    ///
507    /// * a *conversion* is keyed by `key`, because `Box<Option<T>>` and
508    ///   `Option<T>` genuinely need different converter bodies — one has to put
509    ///   a `Box` back and the other must not;
510    /// * a **declaration** is keyed by this, because a declaration says what a
511    ///   type *is* to the destination language, and a wrapper the model erases
512    ///   cannot change that. A `Box<Payload>` parameter is a `Payload` to
513    ///   Kotlin, so it must find `Payload`'s data-class declaration — keying it
514    ///   by spelling finds nothing and silently costs the parameter its
515    ///   lowering.
516    ///
517    /// Use this wherever the lookup is against declarations the binding author
518    /// wrote, and `key` wherever it is against something derived per spelling.
519    pub fn stripped_key(&self) -> TypeKey {
520        TypeKey::from_type(&self.stripped_syntax())
521    }
522
523    /// This type's spelling with every [transparent
524    /// wrapper](TRANSPARENT_WRAPPERS) removed — `Box<Box<Option<T>>>` →
525    /// `Option<T>`, an unwrapped spelling → itself.
526    ///
527    /// The spelling a reconstruction builds *before* it puts the wrappers back:
528    /// rebuilding from [`kind`](Self::kind) alone yields this, so an emitter
529    /// that hands it to a parameter spelled `Box<..>` writes an `E0308`. Paired
530    /// with [`erased_wrappers`](Self::erased_wrappers), which says exactly what
531    /// has to go back on.
532    ///
533    /// **The invariant, which is what defines this rather than the loop that
534    /// computes it**: it is the spelling whose own lowering yields exactly this
535    /// type's `kind`. So the peel runs to a **fixed point** — `Box<Box<T>>`
536    /// classifies as `T`, and stripping one layer leaves a `Box<T>` that does
537    /// not match.
538    ///
539    /// Per-layer, for the reason [`erased_wrappers`](Self::erased_wrappers)
540    /// tabulates: this strips what stands over *this* node's classification, and
541    /// a wrapper under a borrow or inside an `Option` belongs to that inner
542    /// node's own spelling.
543    pub(crate) fn stripped_syntax(&self) -> syn::Type {
544        self.unwrapped().origin.as_syn().clone()
545    }
546
547    /// True when this is `&mut T` over a **value** — not `&mut MaybeUninit<T>`.
548    ///
549    /// The one distinction an out-parameter's form makes to a converter: an
550    /// exclusive borrow may be read before it is written and an out-parameter
551    /// may not, so the two cannot share a conversion. Everything else about the
552    /// slot — that it points at a `T`, that the `T` is what crosses — is
553    /// [`borrow_target`](Self::borrow_target)'s answer.
554    pub fn is_exclusive_borrow(&self) -> bool {
555        matches!(
556            &self.unwrapped().kind,
557            TypeKind::Ref { mutable: true, inner, .. } if !matches!(inner.kind, TypeKind::Uninit(_))
558        )
559    }
560
561    /// The `Ok` and `Err` sides when this is a `Result`, else `None`.
562    pub fn fallible_parts(&self) -> Option<(&TypeRef, &TypeRef)> {
563        match &self.unwrapped().kind {
564            TypeKind::Fallible { ok, err } => Some((ok, err)),
565            _ => None,
566        }
567    }
568
569    /// The argument types when this is a callback, else `None` — the reading
570    /// counterpart of
571    /// [`extract_fn_trait_args`](super::extract_fn_trait_args).
572    ///
573    /// The two are the same question asked of different things, and that is the
574    /// whole difference. `extract_fn_trait_args` takes an
575    /// `impl Fn(..) + Send + Sync + 'static` **apart**: it walks the bounds,
576    /// checks the three markers, and refuses a written return type — it is a
577    /// classifier, and the one the model itself runs to build
578    /// [`TypeKind::Callback`]. This reads the result of that classification,
579    /// already made. A consumer holding a reading has no reason to redo the
580    /// walk, and every reason not to: a `Vec<syn::Type>` of *arguments* has lost
581    /// which of them the model accepted and how, while each `TypeRef` here
582    /// carries its own classification and its own spelling.
583    ///
584    /// Consequently this answers `None` for a type that merely *looks* like a
585    /// callback but was refused (a missing `Send`, an `impl Fn() -> u8`): the
586    /// acceptance already happened, and asking again is how the two drift.
587    pub fn callback_args(&self) -> Option<&[TypeRef]> {
588        match &self.unwrapped().kind {
589            TypeKind::Callback { args } => Some(args),
590            _ => None,
591        }
592    }
593
594    /// The extent of this type when it is an array, else `None`.
595    pub fn array_extent(&self) -> Option<&ArrayExtent> {
596        match &self.unwrapped().kind {
597            TypeKind::Array { extent, .. } => Some(extent),
598            _ => None,
599        }
600    }
601
602    /// Every extent reachable from this type, outermost first — so a nested
603    /// `[[u8; A]; B]` yields `B` then `A`.
604    ///
605    /// Used to find which consts an emitted C type may name, and therefore which
606    /// must reach the header as a `#define`.
607    pub fn extents(&self) -> Vec<&ArrayExtent> {
608        let mut out = Vec::new();
609        self.collect_extents(&mut out);
610        out
611    }
612
613    /// The first nominal type reachable from here that `declared` does not hold.
614    ///
615    /// Recurses the same structure [`Self::collect_extents`] walks: what is
616    /// reachable is what a destination language will have to convert, so every
617    /// layer's inner reference counts.
618    pub(super) fn first_unresolved(
619        &self,
620        declared: &std::collections::HashSet<String>,
621    ) -> Option<String> {
622        match &self.kind {
623            // The name resolves; the arguments do not. No declaration takes type
624            // parameters, so `Foo<Bar>` is one reference to `Foo` — requiring
625            // `Bar` to be declared as well would refuse a reference the source
626            // crate compiles.
627            TypeKind::Named { id, .. } => (!declared.contains(&id.name)).then(|| id.name.clone()),
628            TypeKind::Optional(t)
629            | TypeKind::Vec(t)
630            | TypeKind::Slice(t)
631            | TypeKind::Boxed(t)
632            | TypeKind::Uninit(t)
633            | TypeKind::Cow { inner: t, .. }
634            | TypeKind::Ref { inner: t, .. } => t.first_unresolved(declared),
635            TypeKind::Array { elem, .. } => elem.first_unresolved(declared),
636            TypeKind::Fallible { ok, err } => ok
637                .first_unresolved(declared)
638                .or_else(|| err.first_unresolved(declared)),
639            TypeKind::Callback { args } => args.iter().find_map(|a| a.first_unresolved(declared)),
640            TypeKind::Scalar(_) | TypeKind::Str | TypeKind::String | TypeKind::Unit => None,
641        }
642    }
643
644    /// This type and every type reachable inside it, outermost first.
645    ///
646    /// The nested positions are real [`TypeRef`]s carrying their own spelling and
647    /// origin, so a consumer that indexes types finds `Foo` from `Vec<Foo>` with
648    /// the classification already made rather than a sub-path to re-read.
649    ///
650    /// A [`Named`](TypeKind::Named)'s generic arguments are **not** among them:
651    /// [`TypeId`] keeps a name and nothing else, so `MyBox<Foo>` reaches no `Foo`
652    /// here. The full spelling is [`Self::spell`]'s answer for whoever needs it.
653    pub fn walk(&self) -> Vec<&TypeRef> {
654        let mut out = Vec::new();
655        self.collect_refs(&mut out);
656        out
657    }
658
659    // Both walks descend through [`unwrapped`](Self::unwrapped): a transparent
660    // wrapper is not a type of its own to a consumer that indexes or converts,
661    // so `Box<Vec<Foo>>` reaches `Foo` and yields no node in between.
662    fn collect_refs<'a>(&'a self, out: &mut Vec<&'a TypeRef>) {
663        out.push(self);
664        match &self.unwrapped().kind {
665            // Through [`borrow_target`](Self::borrow_target), so an
666            // out-parameter reaches the value and not its slot.
667            TypeKind::Ref { .. } => {
668                if let Some(t) = self.borrow_target() {
669                    t.collect_refs(out)
670                }
671            }
672            TypeKind::Optional(t) | TypeKind::Vec(t) | TypeKind::Slice(t) | TypeKind::Uninit(t) => {
673                t.collect_refs(out)
674            }
675            TypeKind::Array { elem, .. } => elem.collect_refs(out),
676            TypeKind::Fallible { ok, err } => {
677                ok.collect_refs(out);
678                err.collect_refs(out);
679            }
680            TypeKind::Callback { args } => args.iter().for_each(|t| t.collect_refs(out)),
681            TypeKind::Named { .. }
682            | TypeKind::Scalar(_)
683            | TypeKind::Str
684            | TypeKind::String
685            | TypeKind::Unit => {}
686            // `unwrapped` peeled these off, so reaching one is impossible.
687            TypeKind::Boxed(_) | TypeKind::Cow { .. } => unreachable!(),
688        }
689    }
690
691    fn collect_extents<'a>(&'a self, out: &mut Vec<&'a ArrayExtent>) {
692        match &self.unwrapped().kind {
693            TypeKind::Array { elem, extent } => {
694                out.push(extent);
695                elem.collect_extents(out);
696            }
697            TypeKind::Optional(t)
698            | TypeKind::Vec(t)
699            | TypeKind::Slice(t)
700            | TypeKind::Uninit(t)
701            | TypeKind::Ref { inner: t, .. } => t.collect_extents(out),
702            TypeKind::Fallible { ok, err } => {
703                ok.collect_extents(out);
704                err.collect_extents(out);
705            }
706            TypeKind::Callback { args } => args.iter().for_each(|t| t.collect_extents(out)),
707            TypeKind::Named { .. }
708            | TypeKind::Scalar(_)
709            | TypeKind::Str
710            | TypeKind::String
711            | TypeKind::Unit => {}
712            TypeKind::Boxed(_) | TypeKind::Cow { .. } => unreachable!(),
713        }
714    }
715}
716
717/// The **accepted syntax** of a [`TypeRef`]: the subset of [`syn::Type`] a
718/// `#[prebindgen]` crate may write, and nothing more.
719///
720/// One variant per accepted Rust **form**, not per destination concept. `str`
721/// and `String` are two forms and get two variants; `Box<T>` is a form of its
722/// own and does not disappear into `T`. Nothing here folds two spellings
723/// together, which is what makes [`TypeRef::spell`] recoverable from this —
724/// rebuilding the syntax from a kind is the round-trip that checks it.
725///
726/// # Why it is only syntax
727///
728/// It was a *destination-neutral classification* once, and that leaked: `&T`
729/// earned a layer while `Box<T>` was declared transparent, on no principle
730/// either adapter shared, and `Cbindgen` went on picking its C type from the
731/// Rust spelling anyway. Deciding that `&str` and `String` are both "a string"
732/// is a **destination** decision, so it belongs to the destination — the model
733/// hands over what the source wrote and stays out of it.
734///
735/// Where two adapters want the same fold, it is a *reading*, not a variant:
736/// [`TypeRef::unwrapped`] peels `Box`/`Cow` for the consumers that want them
737/// gone, and the ones that must rebuild the Rust value ask
738/// [`TypeRef::erased_wrappers`] instead. One helper, visible at the call site,
739/// rather than a fold baked into every classification.
740#[derive(Clone, Debug)]
741pub enum TypeKind {
742    /// A primitive with a fixed C/JVM counterpart — `u8`, `bool`, `f64`.
743    ///
744    /// A closed set of bare idents, so recognising one is reading the syntax
745    /// rather than interpreting it — and it keeps every adapter off a name
746    /// table of its own.
747    Scalar(ScalarKind),
748    /// `str` — unsized, so it is only ever reached through a
749    /// [`Ref`](TypeKind::Ref) or a wrapper.
750    Str,
751    /// `String`.
752    String,
753    /// `Option<T>`.
754    Optional(Box<TypeRef>),
755    /// `Vec<T>`.
756    Vec(Box<TypeRef>),
757    /// `[T]` — the unsized run, reached through a [`Ref`](TypeKind::Ref) or a
758    /// wrapper. Not the same form as [`Vec`](TypeKind::Vec), so not the same
759    /// variant.
760    Slice(Box<TypeRef>),
761    /// `Result<T, E>`.
762    Fallible { ok: Box<TypeRef>, err: Box<TypeRef> },
763    /// Any other named type: a `#[prebindgen]` struct or enum, or a foreign
764    /// path.
765    ///
766    /// `id` is the type's **identity** — a name, not a `syn::Path`, so nothing
767    /// downstream has to take a path apart to learn what a type is. `args` is
768    /// the last segment's generic arguments, in the order they were written and
769    /// including lifetimes, because dropping either would make the spelling
770    /// unrecoverable.
771    Named { id: TypeId, args: Vec<GenericArg> },
772    /// `[T; N]` — a run of `T` whose length is known at compile time.
773    Array {
774        elem: Box<TypeRef>,
775        /// Boxed: an extent carries an [`Origin`] over the length expression, which
776        /// makes it the size outlier among the kinds, and an array is the rare one.
777        /// The same trade-off [`Unsupported::error`](super::Unsupported) makes.
778        extent: Box<ArrayExtent>,
779    },
780    /// A borrow — `&T` or `&mut T`, with the lifetime the source wrote.
781    ///
782    /// An out-parameter is `&mut` over [`Uninit`](TypeKind::Uninit), which is
783    /// what the source spells. What that *means* at a boundary — the caller
784    /// supplies the slot, the callee fills it — is the adapter's reading of the
785    /// form, not a third value of a mode enum.
786    Ref {
787        lifetime: Option<syn::Lifetime>,
788        mutable: bool,
789        inner: Box<TypeRef>,
790    },
791    /// `Box<T>`.
792    ///
793    /// A form of its own. It was erased once, on the grounds that no
794    /// destination language can tell `Box<T>` from `T` — true, and still the
795    /// adapter's call to make: [`TypeRef::unwrapped`] makes it, on demand.
796    Boxed(Box<TypeRef>),
797    /// `Cow<'a, T>`.
798    ///
799    /// The lifetime is **not** optional: `Cow` has one in its own signature, so
800    /// a `Cow<T>` is not Rust and no source crate can compile it. Lowering
801    /// refuses the shape ([`WrongGenericArguments`](UnsupportedTypeReason::WrongGenericArguments))
802    /// rather than modelling an absence that would then have to be spelled back
803    /// as something the source did not write.
804    Cow {
805        lifetime: syn::Lifetime,
806        inner: Box<TypeRef>,
807    },
808    /// `MaybeUninit<T>`.
809    ///
810    /// Accepted **only** directly under a `&mut` — see
811    /// [`UnsupportedTypeReason::OwnedUninit`]. It has a variant because the
812    /// source writes it; that it is refused elsewhere is an acceptance rule,
813    /// which is a separate question from how the form is represented.
814    Uninit(Box<TypeRef>),
815    /// `impl Fn(A, B, …) + Send + Sync + 'static` — the callback form.
816    Callback { args: Vec<TypeRef> },
817    /// `()`.
818    Unit,
819}
820
821/// One generic argument of a [`Named`](TypeKind::Named) type, as written.
822///
823/// A lifetime is kept rather than dropped: no destination language acts on it,
824/// but `Foo<'a>` is not `Foo`, and a model that cannot say which one the source
825/// wrote cannot claim to have lost nothing.
826#[derive(Clone, Debug)]
827pub enum GenericArg {
828    Lifetime(syn::Lifetime),
829    /// Boxed so a lifetime argument — the common one, and a fraction of the
830    /// size — does not pay for a type it is not. The same trade-off
831    /// [`Array`](TypeKind::Array)'s extent makes.
832    Type(Box<TypeRef>),
833}
834
835impl TypeKind {
836    /// This kind spelled back as Rust — the inverse of the lowering.
837    ///
838    /// # What it is for
839    ///
840    /// **Not** for generating code: generated Rust spells
841    /// [`TypeRef::syntax`], the source's own tokens, and always will. This
842    /// exists so that claim can be *checked* — a kind that cannot reproduce the
843    /// syntax it was lowered from has dropped something, and the round-trip test
844    /// is what says so before a consumer has to discover it.
845    ///
846    /// Two forms reconstruct up to their own freedom rather than token for
847    /// token, because the model keeps what was written and not how it was
848    /// written:
849    ///
850    /// * a `Group` or `Paren` around a type, which the lowering sees through;
851    /// * a [`Callback`](TypeKind::Callback)'s bound *order* — `Send + Sync` and
852    ///   `Sync + Send` are one accepted form, and nothing reads the order.
853    // Its whole job is the round-trip check (`syntax_is_recoverable_from_kind`),
854    // and with the spelling sealed nothing in a built crate calls it — which is
855    // the correct end state, not dead code: a kind that cannot reproduce its
856    // own syntax has lost something, and this is what says so.
857    #[allow(dead_code)]
858    pub(crate) fn to_syn(&self) -> syn::Type {
859        let opt_lifetime =
860            |l: &Option<syn::Lifetime>| l.as_ref().map(|l| quote::quote!(#l)).unwrap_or_default();
861        match self {
862            Self::Scalar(k) => {
863                let ident = syn::Ident::new(k.as_str(), proc_macro2::Span::call_site());
864                syn::parse_quote!(#ident)
865            }
866            Self::Str => syn::parse_quote!(str),
867            Self::String => syn::parse_quote!(String),
868            Self::Optional(t) => {
869                let inner = t.kind.to_syn();
870                syn::parse_quote!(Option<#inner>)
871            }
872            Self::Vec(t) => {
873                let inner = t.kind.to_syn();
874                syn::parse_quote!(Vec<#inner>)
875            }
876            Self::Slice(t) => {
877                let inner = t.kind.to_syn();
878                syn::parse_quote!([#inner])
879            }
880            Self::Boxed(t) => {
881                let inner = t.kind.to_syn();
882                syn::parse_quote!(Box<#inner>)
883            }
884            Self::Uninit(t) => {
885                let inner = t.kind.to_syn();
886                syn::parse_quote!(MaybeUninit<#inner>)
887            }
888            Self::Cow { lifetime, inner } => {
889                let inner = inner.kind.to_syn();
890                syn::parse_quote!(Cow<#lifetime, #inner>)
891            }
892            Self::Fallible { ok, err } => {
893                let (ok, err) = (ok.kind.to_syn(), err.kind.to_syn());
894                syn::parse_quote!(Result<#ok, #err>)
895            }
896            Self::Ref {
897                lifetime,
898                mutable,
899                inner,
900            } => {
901                let lt = opt_lifetime(lifetime);
902                let mutability = mutable.then(|| quote::quote!(mut)).unwrap_or_default();
903                let inner = inner.kind.to_syn();
904                syn::parse_quote!(& #lt #mutability #inner)
905            }
906            Self::Array { elem, extent } => {
907                let elem = elem.kind.to_syn();
908                let len = extent.origin.spell();
909                syn::parse_quote!([#elem; #len])
910            }
911            Self::Named { id, args } => {
912                // The name is a spelling, so it parses back as one — including
913                // the leading `::` and any path segments before the last.
914                let mut path: syn::Path =
915                    syn::parse_str(&id.name).expect("a name this model built from a path");
916                if !args.is_empty() {
917                    let args = args.iter().map(|a| match a {
918                        GenericArg::Lifetime(l) => quote::quote!(#l),
919                        GenericArg::Type(t) => {
920                            let t = t.kind.to_syn();
921                            quote::quote!(#t)
922                        }
923                    });
924                    let last = path.segments.last_mut().expect("a non-empty path");
925                    last.arguments =
926                        syn::PathArguments::AngleBracketed(syn::parse_quote!(<#(#args),*>));
927                }
928                syn::parse_quote!(#path)
929            }
930            Self::Callback { args } => {
931                let args = args.iter().map(|a| a.kind.to_syn());
932                syn::parse_quote!(impl Fn(#(#args),*) + Send + Sync + 'static)
933            }
934            Self::Unit => syn::parse_quote!(()),
935        }
936    }
937}
938
939/// A nominal type's identity: a name, and nothing else.
940///
941/// `#[prebindgen]` names live in one flat namespace — a duplicate is a
942/// [`ParseError`](super::ParseError) — so the name is the whole address. It
943/// deliberately carries **no crate**: a reference carries a name, and the
944/// declaring crate belongs to the declaration, reachable by looking the name up
945/// among the elements. Putting the use site's crate here would make the same
946/// type compare unequal to itself across two source crates.
947///
948/// A name rather than a `syn::Path` on purpose: an identity kept as syntax
949/// makes every consumer take a path apart to learn what a type is, which is the
950/// re-classification issue #211 exists to stop.
951#[derive(Clone, Debug, PartialEq, Eq)]
952pub struct TypeId {
953    /// The path as written, minus any generic arguments — `Foo`,
954    /// `foreign::Option`. Normalized, so a reducible std or source-module path
955    /// has already collapsed to its final segment.
956    ///
957    /// A `String`, so a **raw** identifier is stored the way `Ident` prints
958    /// it — `r#type`, hashes and all. Recover it with [`Self::ident`] rather
959    /// than `Ident::new`, which rejects that spelling.
960    pub name: String,
961}
962
963impl TypeId {
964    /// This name as an identifier, **raw forms included**.
965    ///
966    /// `Ident::new("r#type", …)` *panics* — it takes a bare name, not a
967    /// spelling — so a consumer rebuilding an ident from [`Self::name`] has to
968    /// parse rather than construct. Here so that recovery is written once: the
969    /// caller that gets it wrong does not fail until a source happens to use a
970    /// keyword, which is exactly the kind of bug that ships.
971    ///
972    /// `None` for a name that is not a single identifier at all (a
973    /// path-qualified `foreign::Option`), which is the same answer
974    /// `bare_path_ident` gave for one.
975    pub fn ident(&self) -> Option<syn::Ident> {
976        syn::parse_str::<syn::Ident>(&self.name).ok()
977    }
978}
979
980/// The primitives the source language accepts. Mirrors the set every adapter
981/// already treats as directly representable.
982#[derive(Clone, Copy, Debug, PartialEq, Eq)]
983pub enum ScalarKind {
984    Bool,
985    I8,
986    I16,
987    I32,
988    I64,
989    Isize,
990    U8,
991    U16,
992    U32,
993    U64,
994    Usize,
995    F32,
996    F64,
997}
998
999impl ScalarKind {
1000    fn from_name(name: &str) -> Option<Self> {
1001        Some(match name {
1002            "bool" => Self::Bool,
1003            "i8" => Self::I8,
1004            "i16" => Self::I16,
1005            "i32" => Self::I32,
1006            "i64" => Self::I64,
1007            "isize" => Self::Isize,
1008            "u8" => Self::U8,
1009            "u16" => Self::U16,
1010            "u32" => Self::U32,
1011            "u64" => Self::U64,
1012            "usize" => Self::Usize,
1013            "f32" => Self::F32,
1014            "f64" => Self::F64,
1015            _ => return None,
1016        })
1017    }
1018
1019    /// The Rust spelling — the identity this was lowered from.
1020    pub fn as_str(self) -> &'static str {
1021        match self {
1022            Self::Bool => "bool",
1023            Self::I8 => "i8",
1024            Self::I16 => "i16",
1025            Self::I32 => "i32",
1026            Self::I64 => "i64",
1027            Self::Isize => "isize",
1028            Self::U8 => "u8",
1029            Self::U16 => "u16",
1030            Self::U32 => "u32",
1031            Self::U64 => "u64",
1032            Self::Usize => "usize",
1033            Self::F32 => "f32",
1034            Self::F64 => "f64",
1035        }
1036    }
1037}
1038
1039/// A type the prebindgen source language does not accept.
1040#[derive(Clone, Debug, PartialEq, Eq)]
1041pub struct UnsupportedType {
1042    /// The offending type as written.
1043    pub offending: String,
1044    pub reason: UnsupportedTypeReason,
1045}
1046
1047/// Why a type was refused.
1048#[derive(Clone, Debug, PartialEq, Eq)]
1049pub enum UnsupportedTypeReason {
1050    /// A syntactic form with no place in the language: a raw pointer, a bare
1051    /// trait object, a closure type, a macro, `Self`, a never type, an inferred
1052    /// type.
1053    ///
1054    /// A `#[prebindgen]` crate is idiomatic Rust — the adapter owns the lowering
1055    /// to pointers — so `*const T` / `*mut T` are refused here rather than
1056    /// modelled. No adapter has a selection arm for one, so accepting them would
1057    /// only defer the failure to a late "unresolved type".
1058    UnsupportedForm,
1059    /// `impl Trait` that is not the accepted callback form — anything but
1060    /// `impl Fn(..) + Send + Sync + 'static` returning `()`.
1061    DisallowedImplTrait,
1062    /// A generic that takes a fixed arity and did not get it — `Option` with no
1063    /// argument, `Result` with one.
1064    ///
1065    /// Counts **type** arguments, which is the whole question for every builtin
1066    /// but one: a lifetime on `Option`, `Vec`, `Box` or `Result` is not a shape
1067    /// this language has, and such a spelling is a nominal type nobody declared
1068    /// rather than a builtin with a bad argument. `Cow` is the exception and has
1069    /// its own reason, [`WrongGenericArguments`](Self::WrongGenericArguments).
1070    WrongGenericArity { expected: usize },
1071    /// A builtin whose whole argument list is not the shape it takes —
1072    /// `Cow<u8>` (no lifetime), `Cow<u8, 'a>` (wrong order), `Cow<'a, 'b, u8>`
1073    /// (two lifetimes).
1074    ///
1075    /// Separate from [`WrongGenericArity`](Self::WrongGenericArity) because it
1076    /// is about the list and not its type-argument count: each of those three
1077    /// has exactly one type argument, and refusing them is what keeps every
1078    /// accepted form rebuildable from its kind.
1079    WrongGenericArguments { expected: &'static str },
1080    /// A non-empty tuple. Only `()` is in the language: no adapter has ever
1081    /// lowered a tuple, so accepting one would defer the failure to a late
1082    /// "unresolved type" instead of naming it here.
1083    UnsupportedTuple,
1084    /// `MaybeUninit<T>` somewhere other than directly under a `&mut`.
1085    ///
1086    /// The one acceptance rule about a **position** rather than a form:
1087    /// [`Uninit`](TypeKind::Uninit) exists, and only an out-parameter can hold
1088    /// one. Owned, returned or stored in a field it promises nothing a
1089    /// destination language can use, and reading it would be undefined.
1090    OwnedUninit,
1091    /// `&MaybeUninit<T>` — a shared borrow of uninitialized storage.
1092    ///
1093    /// A shared borrow promises a readable `T`, and this supplies storage that may
1094    /// not be one. Only `&mut MaybeUninit<T>` means anything — see
1095    /// [`Uninit`](TypeKind::Uninit).
1096    SharedUninit,
1097    /// A path with a qualified self — `<T as Trait>::Assoc`.
1098    ///
1099    /// The frontend never captures `impl` blocks, so it cannot know what an
1100    /// associated type resolves to; carrying the spelling would only move the
1101    /// failure downstream.
1102    AssociatedType,
1103    /// A generic argument that is neither a type nor a lifetime — a const
1104    /// generic, an associated-type binding.
1105    UnsupportedGenericArgument,
1106    /// The array's extent — see [`ArrayLenReason`](super::ArrayLenReason).
1107    BadArrayExtent(Box<UnsupportedArrayLen>),
1108}
1109
1110impl fmt::Display for UnsupportedType {
1111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1112        match &self.reason {
1113            UnsupportedTypeReason::BadArrayExtent(e) => return write!(f, "{e}"),
1114            UnsupportedTypeReason::UnsupportedForm => write!(
1115                f,
1116                "type `{}` is a form the prebindgen source language does not accept",
1117                self.offending
1118            ),
1119            UnsupportedTypeReason::DisallowedImplTrait => write!(
1120                f,
1121                "type `{}` is not an accepted callback — the only `impl Trait` in the language is \
1122                 `impl Fn(..) + Send + Sync + 'static` returning `()`",
1123                self.offending
1124            ),
1125            UnsupportedTypeReason::WrongGenericArity { expected } => write!(
1126                f,
1127                "type `{}` needs exactly {expected} type argument(s)",
1128                self.offending
1129            ),
1130            UnsupportedTypeReason::WrongGenericArguments { expected } => write!(
1131                f,
1132                "type `{}` is not the shape `{expected}` \u{2014} its arguments are the ones \
1133                 that type takes, in the order it takes them",
1134                self.offending
1135            ),
1136            UnsupportedTypeReason::UnsupportedTuple => write!(
1137                f,
1138                "type `{}` is a tuple; only the unit `()` is supported — return the \
1139                 components separately, or wrap them in a `#[prebindgen]` struct",
1140                self.offending
1141            ),
1142            UnsupportedTypeReason::OwnedUninit => write!(
1143                f,
1144                "type `{}` is uninitialized storage outside an out-parameter. Only `&mut \
1145                 MaybeUninit<T>` means anything at a boundary \u{2014} it says the caller supplies \
1146                 the slot and the callee fills it; owned or in a field it promises nothing, and \
1147                 reading it would be undefined",
1148                self.offending
1149            ),
1150            UnsupportedTypeReason::SharedUninit => write!(
1151                f,
1152                "type `{}` is a shared borrow of uninitialized storage: `&T` promises a readable \
1153                 `T`, which this may not be. Use `&mut MaybeUninit<T>` for an out-parameter",
1154                self.offending
1155            ),
1156            UnsupportedTypeReason::AssociatedType => write!(
1157                f,
1158                "type `{}` is an associated type; `#[prebindgen]` never captures `impl` \
1159                 blocks, so its resolution is unknowable here — name the concrete type",
1160                self.offending
1161            ),
1162            UnsupportedTypeReason::UnsupportedGenericArgument => write!(
1163                f,
1164                "type `{}` has a generic argument that is neither a type nor a lifetime",
1165                self.offending
1166            ),
1167        }?;
1168        write!(f, " — see docs/source-language.md for the accepted grammar")
1169    }
1170}
1171
1172impl std::error::Error for UnsupportedType {}
1173
1174/// Lower one captured type.
1175///
1176/// **Total over the accepted grammar**: `Ok` means every part of the type was
1177/// understood, so a form this function does not lower is a form the language
1178/// does not accept.
1179///
1180/// `at` is the origin of the item this type was written in — the location every
1181/// node lowered from that item shares, and the crate an array extent's const
1182/// must come from.
1183/// The wrappers a destination language **cannot see**: `W<T>` crosses as
1184/// whatever `T` crosses as, because nothing outside Rust can tell them apart.
1185///
1186/// The single source of truth for that set. [`TypeRef::unwrapped`] peels exactly
1187/// these, and an adapter that has to *put one back* in generated Rust reads the
1188/// same list — so the question "which wrappers are transparent?" has one answer
1189/// instead of a copy per consumer that can drift out of step.
1190///
1191/// It is a **reading**, not a classification: [`TypeKind`] keeps every wrapper
1192/// the source wrote, and a consumer says here, at its own call site, that it
1193/// does not care. What that means for a given destination is still that
1194/// adapter's business — erasing a wrapper says nothing about whether Rust can
1195/// move a value out of it, which is why `Cow` is on this list and is still
1196/// refused where a converter would have to move its payload.
1197pub const TRANSPARENT_WRAPPERS: &[&str] = &["Box", "Cow"];
1198
1199/// Strip one [transparent wrapper](TRANSPARENT_WRAPPERS) from a **spelling**,
1200/// naming the one removed — `Box<Option<T>>` → `("Box", Option<T>)`.
1201///
1202/// Spelling in, spelling out — the syntax-side peer of
1203/// [`TypeRef::unwrapped`], for an adapter comparing a spelling it composed
1204/// against one it has a converter for. Here rather than in the adapter because
1205/// taking a `syn::Type` apart is this module's job, and doing it next door would
1206/// put a classifier back outside the model.
1207pub fn peel_transparent(ty: &syn::Type) -> Option<(&'static str, syn::Type)> {
1208    let syn::Type::Path(tp) = ty else { return None };
1209    let seg = tp.path.segments.last()?;
1210    let name = TRANSPARENT_WRAPPERS.iter().find(|w| seg.ident == **w)?;
1211    let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
1212        return None;
1213    };
1214    ab.args.iter().find_map(|a| match a {
1215        syn::GenericArgument::Type(inner) => Some((*name, inner.clone())),
1216        _ => None,
1217    })
1218}
1219
1220pub(crate) fn lower_type(
1221    ty: &syn::Type,
1222    consts: &ConstIndex,
1223    at: &Rc<SourceLocation>,
1224) -> Result<TypeRef, UnsupportedType> {
1225    let fail = |reason| UnsupportedType {
1226        offending: ty.to_token_stream().to_string(),
1227        reason,
1228    };
1229    // Every arm builds `kind` only; the origin is attached once, here, so no arm
1230    // can forget it or attach a rebuilt approximation.
1231    let kind = match ty {
1232        // A group or paren wraps the same type. Its inner node keeps the inner
1233        // spelling, which is the one a consumer wants to emit.
1234        syn::Type::Group(g) => return lower_type(&g.elem, consts, at),
1235        syn::Type::Paren(p) => return lower_type(&p.elem, consts, at),
1236        // The borrow and its target are read together for one reason only: a
1237        // `MaybeUninit` is accepted **here** and refused everywhere else, so the
1238        // position is what decides, and only this arm knows it.
1239        syn::Type::Reference(r) => {
1240            let inner = match maybe_uninit_inner(&r.elem) {
1241                Some(uninit) if r.mutability.is_some() => TypeRef {
1242                    kind: TypeKind::Uninit(Box::new(lower_type(&uninit, consts, at)?)),
1243                    origin: Origin::new((*r.elem).clone(), Rc::clone(at)),
1244                },
1245                // `&MaybeUninit<T>` promises a readable `T` and supplies storage
1246                // that may not be one. Nothing at a boundary can use it.
1247                Some(_) => return Err(fail(UnsupportedTypeReason::SharedUninit)),
1248                None => lower_type(&r.elem, consts, at)?,
1249            };
1250            TypeKind::Ref {
1251                lifetime: r.lifetime.clone(),
1252                mutable: r.mutability.is_some(),
1253                inner: Box::new(inner),
1254            }
1255        }
1256        syn::Type::Slice(s) => TypeKind::Slice(Box::new(lower_type(&s.elem, consts, at)?)),
1257        _ if is_unit_type(ty) => TypeKind::Unit,
1258        // Only the unit is in the language. Refusing here names the type;
1259        // accepting would defer the failure to an "unresolved type" much later.
1260        syn::Type::Tuple(_) => return Err(fail(UnsupportedTypeReason::UnsupportedTuple)),
1261        syn::Type::Array(a) => {
1262            let rendered = a.to_token_stream().to_string();
1263            let extent = lower_array_len(&a.len, &rendered, at, consts)
1264                .map_err(|e| fail(UnsupportedTypeReason::BadArrayExtent(Box::new(e))))?;
1265            TypeKind::Array {
1266                elem: Box::new(lower_type(&a.elem, consts, at)?),
1267                extent: Box::new(extent),
1268            }
1269        }
1270        // The callback shape is decided by `extract_fn_trait_args`, this
1271        // module's own — and the pipeline's only — authority for the form.
1272        syn::Type::ImplTrait(_) => match super::extract_fn_trait_args(ty) {
1273            Some(args) => TypeKind::Callback {
1274                args: args
1275                    .iter()
1276                    .map(|a| lower_type(a, consts, at))
1277                    .collect::<Result<_, _>>()?,
1278            },
1279            None => return Err(fail(UnsupportedTypeReason::DisallowedImplTrait)),
1280        },
1281        syn::Type::Path(tp) => lower_path(ty, tp, consts, at)?,
1282        _ => return Err(fail(UnsupportedTypeReason::UnsupportedForm)),
1283    };
1284    Ok(TypeRef {
1285        kind,
1286        origin: Origin::new(ty.clone(), Rc::clone(at)),
1287    })
1288}
1289
1290fn lower_path(
1291    ty: &syn::Type,
1292    tp: &syn::TypePath,
1293    consts: &ConstIndex,
1294    at: &Rc<SourceLocation>,
1295) -> Result<TypeKind, UnsupportedType> {
1296    let fail = |reason| UnsupportedType {
1297        offending: ty.to_token_stream().to_string(),
1298        reason,
1299    };
1300    // An associated type is refused rather than carried: the frontend never
1301    // captures `impl` blocks, so what `<T as Trait>::Assoc` resolves to is
1302    // unknowable here, and keeping the spelling would only move the failure
1303    // downstream.
1304    if tp.qself.is_some() {
1305        return Err(fail(UnsupportedTypeReason::AssociatedType));
1306    }
1307    let Some(last) = tp.path.segments.last() else {
1308        return Err(fail(UnsupportedTypeReason::UnsupportedForm));
1309    };
1310    let name = last.ident.to_string();
1311
1312    // Every argument is kept, in the order it was written — a lifetime among
1313    // them. `Foo<'a>` is not `Foo`, and a model that drops the difference cannot
1314    // spell the type back.
1315    let mut has_lifetime_arg = false;
1316    let args: Vec<GenericArg> = match &last.arguments {
1317        syn::PathArguments::None => Vec::new(),
1318        syn::PathArguments::AngleBracketed(ab) => {
1319            let mut out = Vec::new();
1320            for a in &ab.args {
1321                match a {
1322                    syn::GenericArgument::Type(t) => {
1323                        out.push(GenericArg::Type(Box::new(lower_type(t, consts, at)?)));
1324                    }
1325                    syn::GenericArgument::Lifetime(l) => {
1326                        has_lifetime_arg = true;
1327                        out.push(GenericArg::Lifetime(l.clone()));
1328                    }
1329                    _ => return Err(fail(UnsupportedTypeReason::UnsupportedGenericArgument)),
1330                }
1331            }
1332            out
1333        }
1334        syn::PathArguments::Parenthesized(_) => {
1335            return Err(fail(UnsupportedTypeReason::UnsupportedForm))
1336        }
1337    };
1338    // `Named` holds the last segment's arguments, so a generic anywhere else is
1339    // a spelling this model cannot give back. Refused rather than dropped: no
1340    // flat API writes `a::B<T>::C`.
1341    if tp
1342        .path
1343        .segments
1344        .iter()
1345        .rev()
1346        .skip(1)
1347        .any(|s| !matches!(s.arguments, syn::PathArguments::None))
1348    {
1349        return Err(fail(UnsupportedTypeReason::UnsupportedForm));
1350    }
1351
1352    // A builtin must be spelled BARE. `normalize_type` has already reduced the
1353    // real std paths (`std::option::Option` → `Option`) at ingest and
1354    // deliberately leaves unknown crate paths alone, so anything still carrying
1355    // a prefix is a foreign type that merely shares a name — `foreign::Option`
1356    // is not `Option`, and collapsing it would silently retype the field.
1357    let is_bare = tp.path.leading_colon.is_none() && tp.path.segments.len() == 1;
1358    if is_bare {
1359        if args.is_empty() {
1360            if let Some(kind) = ScalarKind::from_name(&name) {
1361                return Ok(TypeKind::Scalar(kind));
1362            }
1363            match name.as_str() {
1364                "String" => return Ok(TypeKind::String),
1365                "str" => return Ok(TypeKind::Str),
1366                _ => {}
1367            }
1368        }
1369        // A builtin generic takes TYPE arguments only — a lifetime on one is not a
1370        // shape this language has — with one exception: `Cow`'s own signature HAS a
1371        // lifetime, so it is the one builtin where a lifetime argument is expected
1372        // rather than refused.
1373        if !has_lifetime_arg || name == "Cow" {
1374            let mut types: Vec<TypeRef> = args
1375                .iter()
1376                .filter_map(|a| match a {
1377                    GenericArg::Type(t) => Some((**t).clone()),
1378                    GenericArg::Lifetime(_) => None,
1379                })
1380                .collect();
1381            let arity = |n: usize| {
1382                if types.len() == n {
1383                    Ok(())
1384                } else {
1385                    Err(fail(UnsupportedTypeReason::WrongGenericArity {
1386                        expected: n,
1387                    }))
1388                }
1389            };
1390            match name.as_str() {
1391                "Option" => {
1392                    arity(1)?;
1393                    return Ok(TypeKind::Optional(Box::new(types.remove(0))));
1394                }
1395                "Vec" => {
1396                    arity(1)?;
1397                    return Ok(TypeKind::Vec(Box::new(types.remove(0))));
1398                }
1399                "Box" => {
1400                    arity(1)?;
1401                    return Ok(TypeKind::Boxed(Box::new(types.remove(0))));
1402                }
1403                // The one builtin whose signature has a lifetime, so it is the
1404                // one whose WHOLE argument list has to be checked: counting type
1405                // arguments alone accepts `Cow<u8, 'a>` and `Cow<'a, 'b, u8>`,
1406                // which are not `Cow`s at all, and a model that then kept only
1407                // the first lifetime could not spell either one back.
1408                "Cow" => {
1409                    let [GenericArg::Lifetime(lifetime), GenericArg::Type(inner)] = &args[..]
1410                    else {
1411                        return Err(fail(UnsupportedTypeReason::WrongGenericArguments {
1412                            expected: "Cow<'a, T>",
1413                        }));
1414                    };
1415                    return Ok(TypeKind::Cow {
1416                        lifetime: lifetime.clone(),
1417                        inner: inner.clone(),
1418                    });
1419                }
1420                // Reached here it is not directly under a `&mut`, and that is the
1421                // one position where uninitialized storage means anything —
1422                // `TypeKind::Uninit` is built by the reference arm alone.
1423                "MaybeUninit" => return Err(fail(UnsupportedTypeReason::OwnedUninit)),
1424                "Result" => {
1425                    arity(2)?;
1426                    let err = Box::new(types.remove(1));
1427                    let ok = Box::new(types.remove(0));
1428                    return Ok(TypeKind::Fallible { ok, err });
1429                }
1430                _ => return Ok(named(tp, args)),
1431            }
1432        }
1433    }
1434    Ok(named(tp, args))
1435}
1436
1437/// If `ty` is a bare `MaybeUninit<T>`, the `T` it holds storage for.
1438///
1439/// Bare, for the reason every builtin generic is: `normalize_type` has already
1440/// reduced the real std paths at ingest, so anything still carrying a prefix is a
1441/// foreign type that merely shares the name.
1442fn maybe_uninit_inner(ty: &syn::Type) -> Option<syn::Type> {
1443    let syn::Type::Path(tp) = ty else { return None };
1444    if tp.qself.is_some() || tp.path.leading_colon.is_some() || tp.path.segments.len() != 1 {
1445        return None;
1446    }
1447    let seg = &tp.path.segments[0];
1448    if seg.ident != "MaybeUninit" {
1449        return None;
1450    }
1451    let syn::PathArguments::AngleBracketed(ab) = &seg.arguments else {
1452        return None;
1453    };
1454    match ab.args.first() {
1455        Some(syn::GenericArgument::Type(t)) if ab.args.len() == 1 => Some(t.clone()),
1456        _ => None,
1457    }
1458}
1459
1460/// True when `ty` is the unit type `()`.
1461///
1462/// The language's one answer to that question: [`lower_type`] classifies it as
1463/// [`TypeKind::Unit`], and the callback grammar uses it to insist a callback
1464/// returns nothing.
1465pub(crate) fn is_unit_type(ty: &syn::Type) -> bool {
1466    match ty {
1467        syn::Type::Tuple(t) => t.elems.is_empty(),
1468        // A parenthesized or grouped `()` is still `()`.
1469        syn::Type::Paren(p) => is_unit_type(&p.elem),
1470        syn::Type::Group(g) => is_unit_type(&g.elem),
1471        _ => false,
1472    }
1473}
1474
1475/// `Named` with the identity read off the path: every segment joined, minus the
1476/// generic arguments, which are already in `args`.
1477///
1478/// The leading `::` rides along in the name when the source wrote one. It is
1479/// nothing a destination language acts on — but the name is what
1480/// [`TypeKind::to_syn`] spells the path back from, and `::a::B` is not `a::B`.
1481fn named(tp: &syn::TypePath, args: Vec<GenericArg>) -> TypeKind {
1482    let mut name = String::new();
1483    if tp.path.leading_colon.is_some() {
1484        name.push_str("::");
1485    }
1486    name.push_str(
1487        &tp.path
1488            .segments
1489            .iter()
1490            .map(|s| s.ident.to_string())
1491            .collect::<Vec<_>>()
1492            .join("::"),
1493    );
1494    TypeKind::Named {
1495        id: TypeId { name },
1496        args,
1497    }
1498}