|
1 | 1 | use proc_macro2::TokenStream; |
2 | | -use quote::{quote, ToTokens}; |
| 2 | +use quote::{format_ident, quote, ToTokens}; |
| 3 | +use std::collections::HashMap; |
3 | 4 | use syn::{ |
4 | 5 | parse::{Parse, ParseStream}, |
5 | 6 | punctuated::Punctuated, |
@@ -133,9 +134,12 @@ impl Parse for HasFnsItem { |
133 | 134 | _ = input.parse::<Token![pub]>(); |
134 | 135 | let lookahead = input.lookahead1(); |
135 | 136 | if lookahead.peek(Token![trait]) { |
136 | | - input.parse().map(HasFnsItem::Trait) |
| 137 | + let t = input.parse()?; |
| 138 | + Ok(HasFnsItem::Trait(t)) |
137 | 139 | } else if lookahead.peek(Token![impl]) { |
138 | | - input.parse().map(HasFnsItem::Impl) |
| 140 | + let mut imp = input.parse()?; |
| 141 | + flatten_associated_items_in_impl_fns(&mut imp); |
| 142 | + Ok(HasFnsItem::Impl(imp)) |
139 | 143 | } else { |
140 | 144 | Err(lookahead.error()) |
141 | 145 | } |
@@ -209,3 +213,45 @@ fn unpack_result(typ: &Type) -> Option<(Type, Type)> { |
209 | 213 | _ => None, |
210 | 214 | } |
211 | 215 | } |
| 216 | + |
| 217 | +fn flatten_associated_items_in_impl_fns(imp: &mut ItemImpl) { |
| 218 | + // TODO: Flatten associated consts used in functions. |
| 219 | + // Flatten associated types used in functions. |
| 220 | + let associated_types = imp |
| 221 | + .items |
| 222 | + .iter() |
| 223 | + .filter_map(|item| match item { |
| 224 | + ImplItem::Type(i) => Some((i.ident.clone(), i.ty.clone())), |
| 225 | + _ => None, |
| 226 | + }) |
| 227 | + .collect::<HashMap<_, _>>(); |
| 228 | + let fn_input_types = imp |
| 229 | + .items |
| 230 | + .iter_mut() |
| 231 | + .filter_map(|item| match item { |
| 232 | + ImplItem::Fn(f) => Some(f.sig.inputs.iter_mut().filter_map(|input| match input { |
| 233 | + FnArg::Typed(t) => Some(&mut t.ty), |
| 234 | + _ => None, |
| 235 | + })), |
| 236 | + _ => None, |
| 237 | + }) |
| 238 | + .flatten(); |
| 239 | + for t in fn_input_types { |
| 240 | + if let Type::Path(TypePath { qself: None, path }) = t.as_mut() { |
| 241 | + let segments = &path.segments; |
| 242 | + if segments.len() == 2 |
| 243 | + && segments.first() == Some(&PathSegment::from(format_ident!("Self"))) |
| 244 | + { |
| 245 | + if let Some(PathSegment { |
| 246 | + arguments: PathArguments::None, |
| 247 | + ident, |
| 248 | + }) = segments.get(1) |
| 249 | + { |
| 250 | + if let Some(resolved_ty) = associated_types.get(ident) { |
| 251 | + *t.as_mut() = resolved_ty.clone(); |
| 252 | + } |
| 253 | + } |
| 254 | + } |
| 255 | + } |
| 256 | + } |
| 257 | +} |
0 commit comments