type_leak/
lib.rs

1#![doc = include_str!("./README.md")]
2
3use gotgraph::graph::{Graph as GotGraph, GraphUpdate};
4use gotgraph::prelude::VecGraph;
5use proc_macro2::Span;
6use std::cell::RefCell;
7use std::collections::{HashMap, HashSet};
8use std::rc::Rc;
9use syn::parse::Parse;
10use syn::punctuated::Punctuated;
11use syn::spanned::Spanned;
12use syn::visit::Visit;
13use syn::visit_mut::VisitMut;
14use syn::*;
15use template_quote::{quote, ToTokens};
16
17pub use syn;
18
19/// The entry point of this crate.
20pub struct Leaker {
21    generics: Generics,
22    graph: VecGraph<Type, ()>,
23    pub self_ty_can_be_interned: bool,
24    reachable_types: HashSet<Type>,
25    pending_operations: Option<Vec<GraphOperation>>,
26}
27
28/// Error represents that the type is not internable.
29#[derive(Debug, Clone)]
30pub struct NotInternableError(pub Span);
31
32impl std::fmt::Display for NotInternableError {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.write_str("Not internable")
35    }
36}
37
38impl std::error::Error for NotInternableError {}
39
40/// Encode [`GenericArgument`]s to a type.
41pub fn encode_generics_args_to_ty<'a>(iter: impl IntoIterator<Item = &'a GenericArgument>) -> Type {
42    Type::Tuple(TypeTuple {
43        paren_token: Default::default(),
44        elems: iter
45            .into_iter()
46            .map(|param| -> Type {
47                match param {
48                    GenericArgument::Lifetime(lifetime) => {
49                        parse_quote!(& #lifetime ())
50                    }
51                    GenericArgument::Const(expr) => {
52                        parse_quote!([(); #expr as usize])
53                    }
54                    GenericArgument::Type(ty) => ty.clone(),
55                    _ => panic!(),
56                }
57            })
58            .collect(),
59    })
60}
61
62/// Encode [`GenericParam`]s to a type.
63pub fn encode_generics_params_to_ty<'a>(iter: impl IntoIterator<Item = &'a GenericParam>) -> Type {
64    Type::Tuple(TypeTuple {
65        paren_token: Default::default(),
66        elems: iter
67            .into_iter()
68            .map(|param| -> Type {
69                match param {
70                    GenericParam::Lifetime(LifetimeParam { lifetime, .. }) => {
71                        parse_quote!(& #lifetime ())
72                    }
73                    GenericParam::Const(ConstParam { ident, .. }) => {
74                        parse_quote!([(); #ident as usize])
75                    }
76                    GenericParam::Type(TypeParam { ident, .. }) => parse_quote!(#ident),
77                }
78            })
79            .collect(),
80    })
81}
82
83/// Represents result of [`Leaker::check()`], holding the cause in its tuple item.
84#[derive(Clone, Debug)]
85pub enum CheckResult {
86    /// The type must be interned because it directly depends on the type context.
87    MustIntern(Span),
88    /// The type must be interned because one of the types which it constituted with must be
89    /// interned.
90    MustInternOrInherit(Span),
91    /// The type must not be interned, because `type_leak` cannot intern this. (e.g. `impl Trait`s,
92    /// `_`, trait bounds with relative trait path, ...)
93    MustNotIntern(Span),
94    /// Other.
95    Neutral,
96}
97
98#[derive(Debug, Clone)]
99struct GraphOperation {
100    node_type: Type,
101    parent: Option<Type>,
102    is_root: bool,
103    is_must_intern: bool,
104}
105
106struct AnalyzeVisitor<'a> {
107    leaker: &'a mut Leaker,
108    generics: Generics,
109    parent: Option<Type>,
110    error: Option<Span>,
111    operations: Vec<GraphOperation>,
112}
113
114impl<'a, 'ast> Visit<'ast> for AnalyzeVisitor<'a> {
115    fn visit_trait_item_fn(&mut self, i: &TraitItemFn) {
116        let mut visitor = AnalyzeVisitor {
117            leaker: &mut self.leaker,
118            generics: self.generics.clone(),
119            parent: self.parent.clone(),
120            error: self.error.clone(),
121            operations: Vec::new(),
122        };
123        for g in &i.sig.generics.params {
124            visitor.generics.params.push(g.clone());
125        }
126        let mut i = i.clone();
127        i.default = None;
128        i.semi_token = Some(Default::default());
129        syn::visit::visit_trait_item_fn(&mut visitor, &mut i);
130        self.error = visitor.error;
131        self.operations.extend(visitor.operations);
132    }
133
134    fn visit_receiver(&mut self, i: &Receiver) {
135        for attr in &i.attrs {
136            self.visit_attribute(attr);
137        }
138        if let Some((_, Some(lt))) = &i.reference {
139            self.visit_lifetime(lt);
140        }
141        if i.colon_token.is_some() {
142            self.visit_type(&i.ty);
143        }
144    }
145
146    fn visit_trait_item_type(&mut self, i: &TraitItemType) {
147        let mut visitor = AnalyzeVisitor {
148            leaker: &mut self.leaker,
149            generics: self.generics.clone(),
150            parent: self.parent.clone(),
151            error: self.error.clone(),
152            operations: Vec::new(),
153        };
154        for g in &i.generics.params {
155            visitor.generics.params.push(g.clone());
156        }
157        syn::visit::visit_trait_item_type(&mut visitor, i);
158        self.error = visitor.error;
159        self.operations.extend(visitor.operations);
160    }
161
162    fn visit_type(&mut self, i: &Type) {
163        match self.leaker.check(i) {
164            Err((_, s)) => {
165                // Emit error and terminate searching
166                self.error = Some(s);
167            }
168            Ok(CheckResult::MustNotIntern(_)) => (),
169            o => {
170                // Collect the operation instead of directly modifying the graph
171                let is_must_intern = matches!(o, Ok(CheckResult::MustIntern(_)));
172                let is_root = self.parent.is_none();
173
174                self.operations.push(GraphOperation {
175                    node_type: i.clone(),
176                    parent: self.parent.clone(),
177                    is_root,
178                    is_must_intern,
179                });
180
181                if !is_must_intern {
182                    // Perform recursive call
183                    let parent = self.parent.clone();
184                    self.parent = Some(i.clone());
185                    syn::visit::visit_type(self, i);
186                    self.parent = parent;
187                }
188            }
189        }
190    }
191
192    fn visit_trait_bound(&mut self, i: &TraitBound) {
193        if i.path.leading_colon.is_none() {
194            // Trait bounds with relative oath
195            self.error = Some(i.span());
196        } else {
197            syn::visit::visit_trait_bound(self, i)
198        }
199    }
200
201    fn visit_expr_path(&mut self, i: &ExprPath) {
202        if i.path.leading_colon.is_none() {
203            // Value or trait bounds with relative oath
204            self.error = Some(i.span());
205        } else {
206            syn::visit::visit_expr_path(self, i)
207        }
208    }
209}
210
211impl Default for Leaker {
212    fn default() -> Self {
213        Self::with_generics(Generics::default())
214    }
215}
216
217impl Leaker {
218    /// Initialize with [`ItemStruct`]
219    ///
220    /// ```
221    /// # use type_leak::*;
222    /// # use syn::*;
223    /// let test_struct: ItemStruct = parse_quote!(
224    ///     pub struct MyStruct<'a, T1, T2: ::path::to::MyType1<MyType4>> {
225    ///         field1: MyType1,
226    ///         field2: (MyType2, MyType3<MyType1>, MyType4, MyType5),
227    ///         field3: &'a (T1, T2),
228    ///     }
229    /// );
230    /// let leaker = Leaker::from_struct(&test_struct).unwrap();
231    /// ```
232    pub fn from_struct(input: &ItemStruct) -> std::result::Result<Self, NotInternableError> {
233        let mut leaker = Self::with_generics(input.generics.clone());
234        leaker.intern_with(|visitor| {
235            visitor.visit_item_struct(input);
236        })?;
237        Ok(leaker)
238    }
239
240    /// Initialize with [`ItemEnum`]
241    pub fn from_enum(input: &ItemEnum) -> std::result::Result<Self, NotInternableError> {
242        let mut leaker = Self::with_generics(input.generics.clone());
243        leaker.intern_with(|visitor| {
244            visitor.visit_item_enum(input);
245        })?;
246        Ok(leaker)
247    }
248
249    /// Build an [`Leaker`] with given trait.
250    ///
251    /// Unlike enum nor struct, it requires ~alternative path~, an absolute path of a struct
252    /// which is declared the same crate with the leaker trait and also visible from
253    /// [`Referrer`]s' context. That struct is used as an `impl` target of `Repeater`
254    /// instead of the Leaker's path.
255    ///
256    /// ```
257    /// # use syn::*;
258    /// # use type_leak::Leaker;
259    /// let s: ItemTrait = parse_quote!{
260    ///     pub trait MyTrait<T, U> {
261    ///         fn func(self, t: T) -> U;
262    ///     }
263    /// };
264    /// let alternate: ItemStruct = parse_quote!{
265    ///     pub struct MyAlternate;
266    /// };
267    /// let _ = Leaker::from_trait(&s);
268    /// ```
269    pub fn from_trait(input: &ItemTrait) -> std::result::Result<Self, NotInternableError> {
270        let mut leaker = Self::with_generics(input.generics.clone());
271        leaker.intern_with(|visitor| {
272            visitor.visit_item_trait(input);
273        })?;
274        Ok(leaker)
275    }
276
277    /// Initialize empty [`Leaker`] with no generics.
278    pub fn new() -> Self {
279        Self::default()
280    }
281
282    /// Initialize empty [`Leaker`] with given generics.
283    ///
284    /// Types, consts, lifetimes defined in the [`Generics`] is treated as "no needs to be interned" although
285    /// they looks like relative path names.
286    pub fn with_generics(generics: Generics) -> Self {
287        Self {
288            generics,
289            graph: VecGraph::default(),
290            self_ty_can_be_interned: true,
291            reachable_types: HashSet::new(),
292            pending_operations: None,
293        }
294    }
295
296    /// Apply collected graph operations using scope_mut()
297    fn apply_operations(&mut self, operations: Vec<GraphOperation>) {
298        if operations.is_empty() {
299            return;
300        }
301
302        // Store operations for proper graph reduction in reduce_roots()
303        self.pending_operations = Some(operations);
304    }
305
306    /// Intern ast elements with visitor
307    pub fn intern_with<'ast, F>(
308        &mut self,
309        f: F,
310    ) -> std::result::Result<&mut Self, NotInternableError>
311    where
312        F: FnOnce(&mut dyn syn::visit::Visit<'ast>),
313    {
314        let generics = self.generics.clone();
315        let mut visitor = AnalyzeVisitor {
316            leaker: self,
317            parent: None,
318            error: None,
319            generics,
320            operations: Vec::new(),
321        };
322        f(&mut visitor);
323        if let Some(e) = visitor.error {
324            Err(NotInternableError(e))
325        } else {
326            let operations = visitor.operations;
327            self.apply_operations(operations);
328            Ok(self)
329        }
330    }
331
332    /// Check that the internableness of give `ty`. It returns `Err` in contradiction (the type
333    /// must and must not be interned).
334    ///
335    ///
336    /// See [`CheckResult`].
337    pub fn check(&self, ty: &Type) -> std::result::Result<CheckResult, (Span, Span)> {
338        use syn::visit::Visit;
339        #[derive(Clone)]
340        struct Visitor {
341            generic_lifetimes_base: Vec<Lifetime>,
342            generic_idents_base: Vec<Ident>,
343            generic_lifetimes: Vec<Lifetime>,
344            generic_idents: Vec<Ident>,
345            impossible: Option<Span>,
346            must: Option<(isize, Span)>,
347            self_ty_can_be_interned: bool,
348        }
349
350        const _: () = {
351            use syn::visit::Visit;
352            impl<'a> Visit<'a> for Visitor {
353                fn visit_type(&mut self, i: &Type) {
354                    match i {
355                        Type::BareFn(TypeBareFn {
356                            lifetimes,
357                            inputs,
358                            output,
359                            ..
360                        }) => {
361                            let mut visitor = self.clone();
362                            visitor.must = None;
363                            visitor.generic_lifetimes.extend(
364                                lifetimes
365                                    .as_ref()
366                                    .map(|ls| {
367                                        ls.lifetimes.iter().map(|gp| {
368                                            if let GenericParam::Lifetime(lt) = gp {
369                                                lt.lifetime.clone()
370                                            } else {
371                                                panic!()
372                                            }
373                                        })
374                                    })
375                                    .into_iter()
376                                    .flatten(),
377                            );
378                            for input in inputs {
379                                visitor.visit_type(&input.ty);
380                            }
381                            if let ReturnType::Type(_, output) = output {
382                                visitor.visit_type(output.as_ref());
383                            }
384                            if self.impossible.is_none() {
385                                self.impossible = visitor.impossible;
386                            }
387                            match (self.must.clone(), visitor.must.clone()) {
388                                (Some((s_l, _)), Some((v_l, v_m))) if v_l + 1 < s_l => {
389                                    self.must = Some((v_l + 1, v_m))
390                                }
391                                (None, Some((v_l, v_m))) => self.must = Some((v_l + 1, v_m)),
392                                _ => (),
393                            }
394                            return;
395                        }
396                        Type::TraitObject(TypeTraitObject { bounds, .. }) => {
397                            for bound in bounds {
398                                match bound {
399                                    TypeParamBound::Trait(TraitBound {
400                                        lifetimes, path, ..
401                                    }) => {
402                                        let mut visitor = self.clone();
403                                        visitor.must = None;
404                                        visitor.generic_lifetimes.extend(
405                                            lifetimes
406                                                .as_ref()
407                                                .map(|ls| {
408                                                    ls.lifetimes.iter().map(|gp| {
409                                                        if let GenericParam::Lifetime(lt) = gp {
410                                                            lt.lifetime.clone()
411                                                        } else {
412                                                            panic!()
413                                                        }
414                                                    })
415                                                })
416                                                .into_iter()
417                                                .flatten(),
418                                        );
419                                        visitor.visit_path(path);
420                                        if self.impossible.is_none() {
421                                            self.impossible = visitor.impossible;
422                                        }
423                                        match (self.must.clone(), visitor.must.clone()) {
424                                            (Some((s_l, _)), Some((v_l, v_m))) if v_l + 1 < s_l => {
425                                                self.must = Some((v_l + 1, v_m))
426                                            }
427                                            (None, Some((v_l, v_m))) => {
428                                                self.must = Some((v_l + 1, v_m))
429                                            }
430                                            _ => (),
431                                        }
432                                        return;
433                                    }
434                                    TypeParamBound::Verbatim(_) => {
435                                        self.impossible = Some(bound.span());
436                                        return;
437                                    }
438                                    _ => (),
439                                }
440                            }
441                        }
442                        Type::ImplTrait(_) | Type::Macro(_) | Type::Verbatim(_) => {
443                            self.impossible = Some(i.span());
444                        }
445                        Type::Reference(TypeReference { lifetime, .. }) => {
446                            if lifetime.is_none() {
447                                self.impossible = Some(i.span());
448                            }
449                        }
450                        _ => (),
451                    }
452                    let mut visitor = self.clone();
453                    visitor.must = None;
454                    syn::visit::visit_type(&mut visitor, i);
455                    if visitor.impossible.is_some() {
456                        self.impossible = visitor.impossible;
457                    }
458                    match (self.must.clone(), visitor.must.clone()) {
459                        (Some((s_l, _)), Some((v_l, v_m))) if v_l + 1 < s_l => {
460                            self.must = Some((v_l + 1, v_m))
461                        }
462                        (None, Some((v_l, v_m))) => self.must = Some((v_l + 1, v_m)),
463                        _ => (),
464                    }
465                }
466                fn visit_qself(&mut self, i: &QSelf) {
467                    if i.as_token.is_none() {
468                        self.impossible = Some(i.span());
469                    }
470                    syn::visit::visit_qself(self, i)
471                }
472                fn visit_lifetime(&mut self, i: &Lifetime) {
473                    match i.to_string().as_str() {
474                        "'static" => (),
475                        "'_" => self.impossible = Some(i.span()),
476                        _ if self.generic_lifetimes_base.iter().any(|lt| lt == i) => {}
477                        _ if self.generic_lifetimes.iter().any(|lt| lt == i) => {
478                            self.impossible = Some(i.span());
479                        }
480                        _ => {
481                            self.must = Some((-1, i.span()));
482                        }
483                    }
484                    syn::visit::visit_lifetime(self, i)
485                }
486                fn visit_expr(&mut self, i: &Expr) {
487                    match i {
488                        Expr::Closure(_) | Expr::Assign(_) | Expr::Verbatim(_) | Expr::Macro(_) => {
489                            self.impossible = Some(i.span());
490                        }
491                        _ => (),
492                    }
493                    syn::visit::visit_expr(self, i)
494                }
495                fn visit_path(&mut self, i: &Path) {
496                    if matches!(i.segments.iter().next(), Some(PathSegment { ident, arguments }) if ident == "Self" && arguments.is_none())
497                        && i.leading_colon.is_none()
498                    {
499                        if !self.self_ty_can_be_interned {
500                            self.impossible = Some(i.span());
501                        }
502                    } else {
503                        match (i.leading_colon, i.get_ident()) {
504                            // i is a generic parameter
505                            (None, Some(ident)) if self.generic_idents_base.contains(&ident) => {}
506                            (None, Some(ident)) if self.generic_idents.contains(&ident) => {
507                                self.impossible = Some(i.span());
508                            }
509                            // relative path, not a generic parameter
510                            (None, _) => {
511                                self.must = Some((-1, i.span()));
512                            }
513                            // absolute path
514                            (Some(_), _) => (),
515                        }
516                    }
517                    syn::visit::visit_path(self, i)
518                }
519            }
520        };
521        let mut visitor = Visitor {
522            generic_lifetimes_base: self
523                .generics
524                .params
525                .iter()
526                .filter_map(|gp| {
527                    if let GenericParam::Lifetime(lt) = gp {
528                        Some(lt.lifetime.clone())
529                    } else {
530                        None
531                    }
532                })
533                .collect(),
534            generic_idents_base: self
535                .generics
536                .params
537                .iter()
538                .filter_map(|gp| match gp {
539                    GenericParam::Type(TypeParam { ident, .. })
540                    | GenericParam::Const(ConstParam { ident, .. }) => Some(ident.clone()),
541                    _ => None,
542                })
543                .collect(),
544            generic_lifetimes: self
545                .generics
546                .params
547                .iter()
548                .filter_map(|gp| {
549                    if let GenericParam::Lifetime(lt) = gp {
550                        Some(lt.lifetime.clone())
551                    } else {
552                        None
553                    }
554                })
555                .collect(),
556            generic_idents: self
557                .generics
558                .params
559                .iter()
560                .filter_map(|gp| match gp {
561                    GenericParam::Type(TypeParam { ident, .. })
562                    | GenericParam::Const(ConstParam { ident, .. }) => Some(ident.clone()),
563                    _ => None,
564                })
565                .collect(),
566            impossible: None,
567            must: None,
568            self_ty_can_be_interned: self.self_ty_can_be_interned,
569        };
570        visitor.visit_type(ty);
571        match (visitor.must, visitor.impossible) {
572            (None, None) => Ok(CheckResult::Neutral),
573            (Some((0, span)), None) => Ok(CheckResult::MustIntern(span)),
574            (Some((_, span)), None) => Ok(CheckResult::MustInternOrInherit(span)),
575            (None, Some(span)) => Ok(CheckResult::MustNotIntern(span)),
576            (Some((_, span0)), Some(span1)) => Err((span0, span1)),
577        }
578    }
579
580    pub fn generics(&self) -> &Generics {
581        &self.generics
582    }
583
584    /// Finish building the [`Leaker`] and convert it into [`Referrer`].
585    pub fn finish(self) -> Referrer {
586        // Use the reachable types computed by apply_operations
587        let leak_types: Vec<_> = self.reachable_types.into_iter().collect();
588        let map = leak_types
589            .iter()
590            .enumerate()
591            .map(|(n, ty)| (ty.clone(), n))
592            .collect();
593        Referrer { leak_types, map }
594    }
595
596    #[cfg_attr(doc, aquamarine::aquamarine)]
597    /// Reduce nodes to decrease cost of {`Leaker`}'s implementation.
598    ///
599    /// # Algorithm
600    ///
601    /// To consult the algorithm, see the following [`Leaker`]'s input:
602    ///
603    /// ```ignore
604    /// pub struct MyStruct<'a, T1, T2: ::path::to::MyType1<MyType4>> {
605    ///     field1: MyType1,
606    ///     field2: (MyType2, MyType3<MyType1>, MyType4, MyType5),
607    ///     field3: &'a (T1, T2),
608    /// }
609    /// ```
610    ///
611    /// [`Leaker`], when initialized with [`Leaker::from_struct()`], analyze the AST and
612    /// construct a DAG which represents all (internable) types and the dependency relations like
613    /// this:
614    ///
615    /// ```mermaid
616    /// graph TD
617    ///   1["★MyType1
618    ///   (Node 1)"]
619    ///   2["★(MyType2, MyType3#lt;MyType1#gt;, MyType4, MyType5)
620    ///   (Node 2)"] -->3["MyType2
621    ///   (Node 3)"]
622    ///   2 -->4["MyType3#lt;MyType1#gt;
623    ///   (Node 4)"]
624    ///   2 -->0["★MyType4
625    ///   (Node 0)"]
626    ///   2 -->5["MyType5
627    ///   (Node 5)"]
628    ///   6["★&a (T1, T2)
629    ///   (Node 6)"] -->7["(T1, T2)
630    ///   (Node 7)"]
631    ///   7 -->8["T1
632    ///   (Node 8)"]
633    ///   7 -->9["T2
634    ///   (Node 9)"]
635    ///   classDef redNode stroke:#ff0000;
636    ///   class 0,1,3,4,5 redNode;
637    /// ```
638    ///
639    /// The **red** node is flagged as [`CheckResult::MustIntern`] by [`Leaker::check()`] (which means
640    /// the type literature depends on the type context, so it must be interned).
641    ///
642    /// This algorithm reduce the nodes, remaining that all root type (annotated with ★) can be
643    /// expressed with existing **red** nodes.
644    ///
645    /// Here, there are some choice in its freedom:
646    ///
647    /// - Intern all **red** nodes and ignore others (because other nodes are not needed to be
648    /// intern, or constructable with red nodes)
649    /// - Not directly intern **red** nodes; intern common ancessors instead if it is affordable.
650    ///
651    /// So finally, it results like:
652    ///
653    /// ```mermaid
654    /// graph TD
655    ///   0["MyType4
656    ///   (Node 0)"]
657    ///   1["MyType1
658    ///   (Node 1)"]
659    ///   2["(MyType2, MyType3 #lt; MyType1 #gt;, MyType4, MyType5)
660    ///   (Node 2)"]
661    ///   classDef redNode stroke:#ff0000;
662    ///   class 0,1,2 redNode;
663    /// ```
664    ///
665    pub fn reduce_roots(&mut self) {
666        if let Some(operations) = self.pending_operations.take() {
667            self.build_graph_and_reduce(operations);
668        }
669        self.reduce_unreachable_nodes();
670        self.reduce_obvious_nodes();
671    }
672
673    fn build_graph_and_reduce(&mut self, operations: Vec<GraphOperation>) {
674        // Build parent-child relationships from operations
675        let mut children: HashMap<Type, Vec<Type>> = HashMap::new();
676        let mut parents: HashMap<Type, Vec<Type>> = HashMap::new();
677        let mut root_types = HashSet::new();
678        let mut must_intern_types = HashSet::new();
679
680        for operation in &operations {
681            if operation.is_root {
682                root_types.insert(operation.node_type.clone());
683            }
684            if operation.is_must_intern {
685                must_intern_types.insert(operation.node_type.clone());
686            }
687
688            if let Some(parent_type) = &operation.parent {
689                children
690                    .entry(parent_type.clone())
691                    .or_default()
692                    .push(operation.node_type.clone());
693                parents
694                    .entry(operation.node_type.clone())
695                    .or_default()
696                    .push(parent_type.clone());
697            }
698        }
699
700        // Implement proper reduction algorithm:
701        // 1. Keep all must-intern root types
702        // 2. Keep root types that transitively contain must-intern types
703        // 3. Do NOT keep non-root must-intern types that are only components of kept root types
704
705        let mut kept_types = HashSet::new();
706
707        // Step 1: Keep must-intern types that are also roots
708        for root_type in &root_types {
709            if must_intern_types.contains(root_type) {
710                kept_types.insert(root_type.clone());
711            }
712        }
713
714        // Step 2: Keep root types that contain must-intern descendants
715        for root_type in &root_types {
716            if !kept_types.contains(root_type) {
717                if self.contains_must_intern_descendant(root_type, &children, &must_intern_types) {
718                    kept_types.insert(root_type.clone());
719                }
720            }
721        }
722
723        // Step 3: Only add must-intern types that are NOT components of any kept type
724        for must_intern_type in &must_intern_types {
725            if !self.is_component_of_any_kept_type(must_intern_type, &kept_types, &children) {
726                kept_types.insert(must_intern_type.clone());
727            }
728        }
729
730        self.reachable_types = kept_types;
731    }
732
733    fn contains_must_intern_descendant(
734        &self,
735        root: &Type,
736        children: &HashMap<Type, Vec<Type>>,
737        must_intern_types: &HashSet<Type>,
738    ) -> bool {
739        let mut visited = HashSet::new();
740        let mut stack = vec![root.clone()];
741
742        while let Some(current) = stack.pop() {
743            if !visited.insert(current.clone()) {
744                continue;
745            }
746
747            if must_intern_types.contains(&current) {
748                return true;
749            }
750
751            if let Some(child_list) = children.get(&current) {
752                for child in child_list {
753                    if !visited.contains(child) {
754                        stack.push(child.clone());
755                    }
756                }
757            }
758        }
759
760        false
761    }
762
763    fn is_component_of_any_kept_type(
764        &self,
765        target_type: &Type,
766        kept_types: &HashSet<Type>,
767        children: &HashMap<Type, Vec<Type>>,
768    ) -> bool {
769        for kept_type in kept_types {
770            if self.is_descendant_of(target_type, kept_type, children) {
771                return true;
772            }
773        }
774        false
775    }
776
777    fn is_descendant_of(
778        &self,
779        target: &Type,
780        ancestor: &Type,
781        children: &HashMap<Type, Vec<Type>>,
782    ) -> bool {
783        if target == ancestor {
784            return false; // Not a descendant of itself
785        }
786
787        let mut visited = HashSet::new();
788        let mut stack = vec![ancestor.clone()];
789
790        while let Some(current) = stack.pop() {
791            if !visited.insert(current.clone()) {
792                continue;
793            }
794
795            if let Some(child_list) = children.get(&current) {
796                for child in child_list {
797                    if child == target {
798                        return true;
799                    }
800                    if !visited.contains(child) {
801                        stack.push(child.clone());
802                    }
803                }
804            }
805        }
806
807        false
808    }
809
810    fn reduce_obvious_nodes(&mut self) {
811        // Remove intermediate nodes that have exactly one parent and one child
812        // This step eliminates unnecessary intermediate types
813    }
814
815    fn reduce_unreachable_nodes(&mut self) {
816        if let Some(operations) = self.pending_operations.take() {
817            self.apply_vecgraph_reduction(operations);
818        }
819    }
820
821    fn apply_vecgraph_reduction(&mut self, operations: Vec<GraphOperation>) {
822        let mut root_types = HashSet::new();
823        let mut must_intern_types = HashSet::new();
824
825        // Collect graph operations
826        for operation in &operations {
827            if operation.is_root {
828                root_types.insert(operation.node_type.clone());
829            }
830            if operation.is_must_intern {
831                must_intern_types.insert(operation.node_type.clone());
832            }
833        }
834
835        // Build the graph using scope_mut
836        self.graph.scope_mut(|mut ctx| {
837            let mut type_to_node = HashMap::new();
838
839            // Add all nodes first
840            for operation in &operations {
841                if !type_to_node.contains_key(&operation.node_type) {
842                    let node_tag = ctx.add_node(operation.node_type.clone());
843                    type_to_node.insert(operation.node_type.clone(), node_tag);
844                }
845
846                if let Some(parent_type) = &operation.parent {
847                    if !type_to_node.contains_key(parent_type) {
848                        let parent_node_tag = ctx.add_node(parent_type.clone());
849                        type_to_node.insert(parent_type.clone(), parent_node_tag);
850                    }
851                }
852            }
853
854            // Add edges between nodes
855            for operation in &operations {
856                if let Some(parent_type) = &operation.parent {
857                    let parent_node = type_to_node[parent_type];
858                    let child_node = type_to_node[&operation.node_type];
859                    ctx.add_edge((), parent_node, child_node);
860                }
861            }
862        });
863
864        // Perform analysis using the same logic as build_graph_and_reduce
865        self.reachable_types =
866            self.analyze_reachable_types(&root_types, &must_intern_types, &operations);
867    }
868
869    fn analyze_reachable_types(
870        &self,
871        root_types: &HashSet<Type>,
872        must_intern_types: &HashSet<Type>,
873        operations: &[GraphOperation],
874    ) -> HashSet<Type> {
875        // Implement the same logic as build_graph_and_reduce
876        let mut final_types = HashSet::new();
877
878        // Keep must-intern root types
879        for root_type in root_types {
880            if must_intern_types.contains(root_type) {
881                final_types.insert(root_type.clone());
882            }
883        }
884
885        // Keep root types that contain must-intern descendants
886        for root_type in root_types {
887            if !final_types.contains(root_type) {
888                if self.contains_must_intern_in_tree(root_type, operations, must_intern_types) {
889                    final_types.insert(root_type.clone());
890                }
891            }
892        }
893
894        // Only keep must-intern types that aren't subcomponents of kept root types
895        for must_intern_type in must_intern_types {
896            if !self.is_subcomponent_of_kept_root(must_intern_type, &final_types, operations) {
897                final_types.insert(must_intern_type.clone());
898            }
899        }
900
901        final_types
902    }
903
904    fn contains_must_intern_in_tree(
905        &self,
906        root: &Type,
907        operations: &[GraphOperation],
908        must_intern_types: &HashSet<Type>,
909    ) -> bool {
910        let mut stack = vec![root.clone()];
911        let mut visited = HashSet::new();
912
913        while let Some(current) = stack.pop() {
914            if !visited.insert(current.clone()) {
915                continue;
916            }
917
918            if must_intern_types.contains(&current) {
919                return true;
920            }
921
922            for operation in operations {
923                if let Some(parent_type) = &operation.parent {
924                    if parent_type == &current && !visited.contains(&operation.node_type) {
925                        stack.push(operation.node_type.clone());
926                    }
927                }
928            }
929        }
930
931        false
932    }
933
934    fn is_subcomponent_of_kept_root(
935        &self,
936        target: &Type,
937        kept_roots: &HashSet<Type>,
938        operations: &[GraphOperation],
939    ) -> bool {
940        for root in kept_roots {
941            if self.contains_must_intern_in_tree(root, operations, &HashSet::from([target.clone()]))
942                && root != target
943            {
944                return true;
945            }
946        }
947        false
948    }
949
950    // TODO: Reimplement reduce_unreachable_nodes with VecGraph APIs
951}
952
953/// Holds the list of types that need to be encoded, produced by [`Leaker::finish()`].
954///
955/// The `Referrer` provides methods to iterate over leak types and to expand/transform
956/// types using a custom mapping function.
957#[derive(Clone, PartialEq, Eq, Debug)]
958pub struct Referrer {
959    leak_types: Vec<Type>,
960    map: HashMap<Type, usize>,
961}
962
963impl Referrer {
964    /// Returns `true` if there are no types to be encoded.
965    pub fn is_empty(&self) -> bool {
966        self.leak_types.is_empty()
967    }
968
969    /// Returns an iterator over the types that need to be encoded.
970    ///
971    /// ```ignore
972    /// let args = encode_generics_params_to_ty(&generics.params);
973    /// referrer.iter().enumerate().map(|(ix, ty)| quote!{
974    ///     impl #crate::TypeRef<#ix, #args> for #marker_ty {
975    ///         type Type = #ty;
976    ///     }
977    /// }).collect::<TokenStream>();
978    /// ```
979    pub fn iter(&self) -> impl Iterator<Item = &Type> {
980        self.leak_types.iter()
981    }
982
983    /// Converts this `Referrer` into a [`Visitor`] that can be used to transform AST nodes.
984    ///
985    /// The `type_fn` callback is called for each type that needs to be converted,
986    /// receiving the original type and its index, and returning the replacement type.
987    /// See [`Referrer::expand()`] for details.
988    pub fn into_visitor<F: FnMut(Type, usize) -> Type>(self, type_fn: F) -> Visitor<F> {
989        Visitor(self, Rc::new(RefCell::new(type_fn)))
990    }
991
992    /// Expands a type by replacing any interned types using the provided mapping function.
993    ///
994    /// The `type_fn` callback is called for each subtype that needs to be converted,
995    /// receiving the original type and its index, and returning the replacement type.
996    ///
997    /// ```ignore
998    /// let args = encode_generics_params_to_ty(&generics.params);
999    /// referrer.expand(ty, |_, ix| {
1000    ///     parse_quote!(<#marker_ty as #crate::TypeRef<#ix, #args>>::Type)
1001    /// })
1002    /// ```
1003    pub fn expand(&self, ty: Type, type_fn: impl FnMut(Type, usize) -> Type) -> Type {
1004        use syn::fold::Fold;
1005        struct Folder<'a, F>(&'a Referrer, F);
1006        impl<'a, F: FnMut(Type, usize) -> Type> Fold for Folder<'a, F> {
1007            fn fold_type(&mut self, ty: Type) -> Type {
1008                if let Some(idx) = self.0.map.get(&ty) {
1009                    self.1(ty, *idx)
1010                } else {
1011                    syn::fold::fold_type(self, ty)
1012                }
1013            }
1014        }
1015        let mut folder = Folder(self, type_fn);
1016        folder.fold_type(ty)
1017    }
1018}
1019
1020#[derive(Debug)]
1021pub struct Visitor<F>(Referrer, Rc<RefCell<F>>);
1022
1023impl<F> Clone for Visitor<F> {
1024    fn clone(&self) -> Self {
1025        Self(self.0.clone(), self.1.clone())
1026    }
1027}
1028
1029impl<F: FnMut(Type, usize) -> Type> Visitor<F> {
1030    fn with_generics(&mut self, generics: &mut Generics) -> Self {
1031        let mut visitor = self.clone();
1032        for gp in generics.params.iter_mut() {
1033            if let GenericParam::Type(TypeParam { ident, .. }) = gp {
1034                visitor.0.map.remove(&parse_quote!(#ident));
1035            }
1036            visitor.visit_generic_param_mut(gp);
1037        }
1038        visitor
1039    }
1040
1041    fn with_signature(&mut self, sig: &mut Signature) -> Self {
1042        let mut visitor = self.with_generics(&mut sig.generics);
1043        for input in sig.inputs.iter_mut() {
1044            visitor.visit_fn_arg_mut(input);
1045        }
1046        visitor.visit_return_type_mut(&mut sig.output);
1047        visitor
1048    }
1049}
1050
1051impl<F: FnMut(Type, usize) -> Type> VisitMut for Visitor<F> {
1052    fn visit_type_mut(&mut self, i: &mut Type) {
1053        *i = self.0.expand(i.clone(), &mut *self.1.borrow_mut());
1054    }
1055    fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) {
1056        for attr in i.attrs.iter_mut() {
1057            self.visit_attribute_mut(attr);
1058        }
1059        let mut visitor = self.with_generics(&mut i.generics);
1060        visitor.visit_fields_mut(&mut i.fields);
1061    }
1062    fn visit_item_enum_mut(&mut self, i: &mut ItemEnum) {
1063        for attr in i.attrs.iter_mut() {
1064            self.visit_attribute_mut(attr);
1065        }
1066        let mut visitor = self.with_generics(&mut i.generics);
1067        for variant in i.variants.iter_mut() {
1068            visitor.visit_variant_mut(variant);
1069        }
1070    }
1071    fn visit_item_trait_mut(&mut self, i: &mut ItemTrait) {
1072        for attr in i.attrs.iter_mut() {
1073            self.visit_attribute_mut(attr);
1074        }
1075        let mut visitor = self.with_generics(&mut i.generics);
1076        for supertrait in i.supertraits.iter_mut() {
1077            visitor.visit_type_param_bound_mut(supertrait);
1078        }
1079        for item in i.items.iter_mut() {
1080            visitor.visit_trait_item_mut(item);
1081        }
1082    }
1083    fn visit_item_union_mut(&mut self, i: &mut ItemUnion) {
1084        for attr in i.attrs.iter_mut() {
1085            self.visit_attribute_mut(attr);
1086        }
1087        let mut visitor = self.with_generics(&mut i.generics);
1088        visitor.visit_fields_named_mut(&mut i.fields);
1089    }
1090    fn visit_item_type_mut(&mut self, i: &mut ItemType) {
1091        for attr in i.attrs.iter_mut() {
1092            self.visit_attribute_mut(attr);
1093        }
1094        let mut visitor = self.with_generics(&mut i.generics);
1095        visitor.visit_type_mut(&mut i.ty);
1096    }
1097    fn visit_item_fn_mut(&mut self, i: &mut ItemFn) {
1098        for attr in i.attrs.iter_mut() {
1099            self.visit_attribute_mut(attr);
1100        }
1101        let mut visitor = self.with_signature(&mut i.sig);
1102        visitor.visit_block_mut(i.block.as_mut());
1103    }
1104    fn visit_trait_item_fn_mut(&mut self, i: &mut TraitItemFn) {
1105        for attr in i.attrs.iter_mut() {
1106            self.visit_attribute_mut(attr);
1107        }
1108        let mut visitor = self.with_signature(&mut i.sig);
1109        if let Some(block) = &mut i.default {
1110            visitor.visit_block_mut(block);
1111        }
1112    }
1113    fn visit_trait_item_type_mut(&mut self, i: &mut TraitItemType) {
1114        for attr in i.attrs.iter_mut() {
1115            self.visit_attribute_mut(attr);
1116        }
1117        let mut visitor = self.with_generics(&mut i.generics);
1118        for bound in i.bounds.iter_mut() {
1119            visitor.visit_type_param_bound_mut(bound);
1120        }
1121        if let Some((_, ty)) = &mut i.default {
1122            visitor.visit_type_mut(ty);
1123        }
1124    }
1125    fn visit_trait_item_const_mut(&mut self, i: &mut TraitItemConst) {
1126        for attr in i.attrs.iter_mut() {
1127            self.visit_attribute_mut(attr);
1128        }
1129        let mut visitor = self.with_generics(&mut i.generics);
1130        visitor.visit_type_mut(&mut i.ty);
1131        if let Some((_, expr)) = &mut i.default {
1132            visitor.visit_expr_mut(expr);
1133        }
1134    }
1135    fn visit_block_mut(&mut self, i: &mut Block) {
1136        let mut visitor = self.clone();
1137        for stmt in &i.stmts {
1138            match stmt {
1139                Stmt::Item(Item::Struct(ItemStruct { ident, .. }))
1140                | Stmt::Item(Item::Enum(ItemEnum { ident, .. }))
1141                | Stmt::Item(Item::Union(ItemUnion { ident, .. }))
1142                | Stmt::Item(Item::Trait(ItemTrait { ident, .. }))
1143                | Stmt::Item(Item::Type(ItemType { ident, .. })) => {
1144                    visitor.0.map.remove(&parse_quote!(#ident));
1145                }
1146                _ => (),
1147            }
1148        }
1149        for stmt in i.stmts.iter_mut() {
1150            visitor.visit_stmt_mut(stmt);
1151        }
1152    }
1153}
1154
1155impl Parse for Referrer {
1156    fn parse(input: parse::ParseStream) -> Result<Self> {
1157        let content: syn::parse::ParseBuffer<'_>;
1158        parenthesized!(content in input);
1159        let leak_types: Vec<Type> = Punctuated::<Type, Token![,]>::parse_terminated(&content)?
1160            .into_iter()
1161            .collect();
1162        let map = leak_types
1163            .iter()
1164            .enumerate()
1165            .map(|(n, ty)| (ty.clone(), n))
1166            .collect();
1167        Ok(Self { map, leak_types })
1168    }
1169}
1170
1171impl ToTokens for Referrer {
1172    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1173        tokens.extend(quote! {
1174            (
1175                #(for item in &self.leak_types), {
1176                    #item
1177                }
1178            )
1179        })
1180    }
1181}