Impl fields resolving, vol.4 [skip ci]

This commit is contained in:
tyranron 2022-09-12 17:54:57 +03:00
parent 129ff559d1
commit bf219867b6
No known key found for this signature in database
GPG key ID: 762E144FB230A4F0
2 changed files with 44 additions and 7 deletions

View file

@ -7,7 +7,7 @@ pub(crate) mod downcaster;
use std::{any::TypeId, iter, mem};
use proc_macro2::Span;
use quote::quote;
use quote::{quote, format_ident};
use syn::{
ext::IdentExt as _,
parse::{Parse, ParseBuffer},
@ -105,15 +105,29 @@ pub(crate) trait TypeExt {
#[must_use]
fn unreferenced(&self) -> &Self;
/// Iterates mutably over all the lifetime parameters of this [`syn::Type`]
/// with the given `func`tion.
fn lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F);
/// Iterates mutably over all the lifetime parameters (even implicit) of
/// this [`syn::Type`] with the given `func`tion.
fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F);
/// Iterates mutably over all the named lifetime parameters (explicit only)
/// of this [`syn::Type`] with the given `func`tion.
fn named_lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F) {
self.lifetimes_iter_mut(&mut |lt| {
if let Some(lt) = lt {
func(lt);
}
})
}
/// Anonymizes all the lifetime parameters of this [`syn::Type`] (except
/// the `'static` ones), making it suitable for using in contexts with
/// inferring.
fn lifetimes_anonymized(&mut self);
/// Lifts all the lifetimes of this [`syn::Type`] (except `'static`) to a
/// `for<>` quantifier, preserving the type speciality as much as possible.
fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type);
/// Returns the topmost [`syn::Ident`] of this [`syn::TypePath`], if any.
#[must_use]
fn topmost_ident(&self) -> Option<&syn::Ident>;
@ -135,7 +149,7 @@ impl TypeExt for syn::Type {
}
}
fn lifetimes_iter_mut<F: FnMut(&mut syn::Lifetime)>(&mut self, func: &mut F) {
fn lifetimes_iter_mut<F: FnMut(&mut Option<syn::Lifetime>)>(&mut self, func: &mut F) {
use syn::{GenericArgument as GA, Type as T};
fn iter_path<F: FnMut(&mut syn::Lifetime)>(path: &mut syn::Path, func: &mut F) {
@ -213,13 +227,36 @@ impl TypeExt for syn::Type {
}
fn lifetimes_anonymized(&mut self) {
self.lifetimes_iter_mut(&mut |lt| {
self.named_lifetimes_iter_mut(&mut |lt| {
if lt.ident != "_" && lt.ident != "static" {
lt.ident = syn::Ident::new("_", Span::call_site());
}
});
}
fn to_hrtb_lifetimes(&self) -> (Option<syn::BoundLifetimes>, syn::Type) {
let mut ty = self.clone();
let mut lts = vec![];
let anon_ident = &syn::Ident::new("_", Span::call_site());
ty.lifetimes_iter_mut(&mut |lt| {
let ident = lt.map(|l| l.ident).unwrap_or(anon_ident);
if ident != "static" {
let ident = format_ident!("__fa_f_{ident}");
if !lts.contains(&ident) {
lts.push(ident);
}
*lt = Some(parse_quote! { '#ident })
}
});
let for_ = (!lts.is_empty()).then(|| parse_quote! {
for< #( #lts ),* >}
);
(for_, ty)
}
fn topmost_ident(&self) -> Option<&syn::Ident> {
match self.unparenthesized() {
syn::Type::Path(p) => Some(&p.path),

View file

@ -323,7 +323,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
// Modify lifetime names to omit "lifetime name `'a` shadows a
// lifetime name that is already in scope" error.
let mut ty = self.ty.clone();
ty.lifetimes_iter_mut(&mut |lt| {
ty.named_lifetimes_iter_mut(&mut |lt| {
let ident = lt.ident.unraw();
lt.ident = format_ident!("__fa__{ident}");
lifetimes.push(lt.clone());