Working with a syn::Path of nested types (eg Option<Box<Foo>>)

Before I try to solve this myself, it feels like a problem which probably already has a good solution in a crate somewhere.... Does anyone know of a crate that helps with the following?:

I want to manipulate nested types in a Path, as part of a proc_macro

E.g. if I have parsed Option<Box<Foo>> as a syn::Path I would like to:

  • iterate into it getting: Option<Box<Foo>>, Box<Foo>, Foo
  • update the innermost type to give Option<Box<Bar>>

This could get arbitrarily complicated when associated types (nice to have) and types with multiple generics (need) come into play.

neither of these two statements is very comprehensible to me.

please explain clearly and precisely what you really want to do with the syn::Path.

Ah ... I typed the original on my phone and didn't spot the messed up formatting. I've fixed the original.

And here's the improved explanation of what I want to do in pseudo-code:

let bar: Path = parse_quote!(Bar);
let mut nested: Path = parse_quote!(Option<Box<Foo>>);
*nested.innermost() = bar; // change the innermost path
let drill_down: Vec<Path> = nested
    .iter_nesting() // drill into nesting one level at a time
    .cloned()    
    .collect();
assert_eq!(drill_down, vec![
    parse_quote!(Option<Box<Bar>>),
    parse_quote!(Box<Bar>),
    parse_quote!(Bar)
]);

you need to define what "inner most" mean. when multiple generic arguments are present, "inner" became ambiguous. e.g. what do you consider is the "innermost" in this example:

std::result::Result<
  std::boxed::Box<MyWrapper<T1, T2, T3>>,
  std::boxed::Box<dyn std::error::Error + MyTrait<U1, U2, U3>>
>

again, this only makes sense for simple case where every "level" has at most a single generic argument, and each argument itself is recursively a simple Path.

this becomes intractable in a general case, for example, the following monstrosity can be parsed successfully as a Path, but how do you "drill" into it?

let nested: Path = parse_quote!(
    std::Option<Box<foo::MyType>>::MyGat<
      <Option<Box<dyn MyTrait<T>>>
        as MyTrait<T>
      >::MyAssociatedType
    >
);

as you can see, the parsed result can be really messy due to the complexity of rust syntax. you must be very specific to the problem at hand, instead of seeking a solution for a "general" problem.

you can craft a custom solution for the specific case relatively easily, you can walk down the Path segments, and recurse into the PathArguments of the last segment when it is a simple Path, and return errors otherwise.

but I don't think there exists a readily made solution.

the general mechanism to traverse nested ast is to use the visitor pattern, but I don't think it suits your problem very well, because it's too generic, and the visitor trait is very large (188 methods in current version), thanks to rust's complex syntax.