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}