From b484a6104d70a2c861d5e39f82068f9375481729 Mon Sep 17 00:00:00 2001 From: Sunli Date: Wed, 5 Jan 2022 11:52:02 +0800 Subject: [PATCH] Fix the generic `SimpleObject` can't define the lifetimes. #774 --- derive/src/simple_object.rs | 38 ++++++++++++++++++--- tests/generic_types.rs | 68 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/derive/src/simple_object.rs b/derive/src/simple_object.rs index 15f80f85..5534149a 100644 --- a/derive/src/simple_object.rs +++ b/derive/src/simple_object.rs @@ -3,7 +3,8 @@ use proc_macro::TokenStream; use quote::quote; use std::str::FromStr; use syn::ext::IdentExt; -use syn::{Error, Ident, Path, Type}; +use syn::visit::Visit; +use syn::{Error, Ident, LifetimeDef, Path, Type}; use crate::args::{self, RenameRuleExt, RenameTarget, SimpleObjectField}; use crate::utils::{ @@ -320,6 +321,33 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult { + lifetimes: Vec<&'a LifetimeDef>, + } + + impl<'a> Visit<'a> for GetLifetimes<'a> { + fn visit_lifetime_def(&mut self, i: &'a LifetimeDef) { + self.lifetimes.push(i); + } + } + + let mut visitor = GetLifetimes::default(); + visitor.visit_generics(&object_args.generics); + let lifetimes = visitor.lifetimes; + + let def_lifetimes = if !lifetimes.is_empty() { + Some(quote!(<#(#lifetimes),*>)) + } else { + None + }; + + let type_lifetimes = if !lifetimes.is_empty() { + Some(quote!(#(#lifetimes,)*)) + } else { + None + }; + code.push(quote! { impl #impl_generics #ident #ty_generics #where_clause { #(#getters)* @@ -357,12 +385,12 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult }; + let concrete_type = quote! { #ident<#type_lifetimes #(#params),*> }; let expanded = quote! { #[allow(clippy::all, clippy::pedantic)] #[#crate_name::async_trait::async_trait] - impl #crate_name::resolver_utils::ContainerType for #concrete_type { + impl #def_lifetimes #crate_name::resolver_utils::ContainerType for #concrete_type { async fn resolve_field(&self, ctx: &#crate_name::Context<'_>) -> #crate_name::ServerResult<::std::option::Option<#crate_name::Value>> { #complex_resolver self.__internal_resolve_field(ctx).await @@ -371,7 +399,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult ::std::borrow::Cow<'static, ::std::primitive::str> { ::std::borrow::Cow::Borrowed(#gql_typename) } @@ -387,7 +415,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult + where + T: Sync + OutputType + 'a, + { + data: &'a T, + } + + struct Query { + value1: i32, + value2: i64, + } + + #[Object] + impl Query { + async fn a(&self) -> Foo<'_, i32> { + Foo { data: &self.value1 } + } + + async fn b(&self) -> Foo<'_, i64> { + Foo { data: &self.value2 } + } + + async fn static_a(&self) -> Foo<'static, i32> { + Foo { data: &100 } + } + + async fn static_b(&self) -> Foo<'static, i32> { + Foo { data: &200 } + } + } + + let schema = Schema::new( + Query { + value1: 88, + value2: 99, + }, + EmptyMutation, + EmptySubscription, + ); + + assert_eq!( + schema + .execute( + r#"{ + a { data } + b { data } + staticA { data } + staticB { data } + }"# + ) + .await + .into_result() + .unwrap() + .data, + value!({ + "a": { "data": 88 }, + "b": { "data": 99 }, + "staticA": { "data": 100 }, + "staticB": { "data": 200 }, + }) + ); +}