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.
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:
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.