From bf219867b6b55f8ac07188d9ffa891a3d48ba8d5 Mon Sep 17 00:00:00 2001 From: tyranron Date: Mon, 12 Sep 2022 17:54:57 +0300 Subject: [PATCH] Impl fields resolving, vol.4 [skip ci] --- juniper_codegen/src/common/parse/mod.rs | 49 ++++++++++++++++++++--- juniper_codegen/src/graphql_object/mod.rs | 2 +- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/juniper_codegen/src/common/parse/mod.rs b/juniper_codegen/src/common/parse/mod.rs index 53781675..40eae7bd 100644 --- a/juniper_codegen/src/common/parse/mod.rs +++ b/juniper_codegen/src/common/parse/mod.rs @@ -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(&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)>(&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(&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::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(&mut self, func: &mut F) { + fn lifetimes_iter_mut)>(&mut self, func: &mut F) { use syn::{GenericArgument as GA, Type as T}; fn iter_path(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::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), diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs index df3f195e..496294b3 100644 --- a/juniper_codegen/src/graphql_object/mod.rs +++ b/juniper_codegen/src/graphql_object/mod.rs @@ -323,7 +323,7 @@ impl Definition { // 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());