Fix can no longer derive Union for union types with lifetimes. #311

This commit is contained in:
Sunli 2020-10-15 06:27:31 +08:00 committed by Sunli
parent bc5cf2f2a2
commit b054f1bf9f
10 changed files with 74 additions and 22 deletions

View File

@ -56,9 +56,7 @@ This crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in
## Examples
If you are just getting started, we recommend checking out our examples at: https://github.com/async-graphql/examples
To see how you would create a Relay-compliant server using async-graphql, warp, diesel & postgresql, you can also check out a real-world example at: https://github.com/phated/twentyfive-stars
https://github.com/async-graphql/examples
## Benchmark

View File

@ -6,7 +6,8 @@ use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use std::collections::HashSet;
use syn::{Error, Type};
use syn::visit_mut::VisitMut;
use syn::{visit_mut, Error, Lifetime, Type};
pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream> {
let crate_name = get_crate_name(interface_args.internal);
@ -71,7 +72,20 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
);
}
struct RemoveLifetime;
impl VisitMut for RemoveLifetime {
fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
i.ident = Ident::new("_", Span::call_site());
visit_mut::visit_lifetime_mut(self, i);
}
}
let mut assert_ty = p.clone();
RemoveLifetime.visit_type_path_mut(&mut assert_ty);
type_into_impls.push(quote! {
#crate_name::static_assertions::assert_impl_one!(#assert_ty: #crate_name::ObjectType);
#[allow(clippy::all, clippy::pedantic)]
impl #generics ::std::convert::From<#p> for #ident #generics {
fn from(obj: #p) -> Self {
@ -322,7 +336,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
Ok(None)
}
fn collect_all_fields<'a>(&'a self, ctx: &#crate_name::ContextSelectionSet<'a>, fields: &mut #crate_name::resolver_utils::Fields<'a>) -> #crate_name::ServerResult<()> {
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}

View File

@ -77,10 +77,10 @@ pub fn generate(object_args: &args::MergedSubscription) -> GeneratorResult<Token
#[allow(clippy::all, clippy::pedantic)]
impl #crate_name::SubscriptionType for #ident {
fn create_field_stream<'a>(
&'a self,
ctx: &'a #crate_name::Context<'a>
) -> Option<::std::pin::Pin<::std::boxed::Box<dyn #crate_name::futures::Stream<Item = #crate_name::ServerResult<#crate_name::Value>> + ::std::marker::Send + 'a>>> {
fn create_field_stream<'__life>(
&'__life self,
ctx: &'__life #crate_name::Context<'__life>
) -> Option<::std::pin::Pin<::std::boxed::Box<dyn #crate_name::futures::Stream<Item = #crate_name::ServerResult<#crate_name::Value>> + ::std::marker::Send + '__life>>> {
None #create_field_stream
}
}

View File

@ -141,7 +141,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
let expanded = quote! {
#[allow(clippy::all, clippy::pedantic)]
impl #generics #ident #where_clause {
impl #generics #ident #generics #where_clause {
#(#getters)*
}

View File

@ -388,10 +388,10 @@ pub fn generate(
#[allow(clippy::all, clippy::pedantic)]
#[allow(unused_braces, unused_variables)]
impl #crate_name::SubscriptionType for #self_ty #where_clause {
fn create_field_stream<'a>(
&'a self,
ctx: &'a #crate_name::Context<'a>,
) -> ::std::option::Option<::std::pin::Pin<::std::boxed::Box<dyn #crate_name::futures::Stream<Item = #crate_name::ServerResult<#crate_name::Value>> + Send + 'a>>> {
fn create_field_stream<'__life>(
&'__life self,
ctx: &'__life #crate_name::Context<'__life>,
) -> ::std::option::Option<::std::pin::Pin<::std::boxed::Box<dyn #crate_name::futures::Stream<Item = #crate_name::ServerResult<#crate_name::Value>> + Send + '__life>>> {
#(#create_stream)*
None
}

View File

@ -2,9 +2,11 @@ use crate::args::{self, RenameTarget};
use crate::utils::{get_crate_name, get_rustdoc, GeneratorResult};
use darling::ast::{Data, Style};
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use std::collections::HashSet;
use syn::{Error, Type};
use syn::visit_mut::VisitMut;
use syn::{visit_mut, Error, Lifetime, Type};
pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
let crate_name = get_crate_name(union_args.internal);
@ -68,9 +70,20 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
enum_names.push(enum_name);
struct RemoveLifetime;
impl VisitMut for RemoveLifetime {
fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
i.ident = Ident::new("_", Span::call_site());
visit_mut::visit_lifetime_mut(self, i);
}
}
let mut assert_ty = p.clone();
RemoveLifetime.visit_type_path_mut(&mut assert_ty);
if !variant.flatten {
type_into_impls.push(quote! {
#crate_name::static_assertions::assert_impl_one!(#p: #crate_name::ObjectType);
#crate_name::static_assertions::assert_impl_one!(#assert_ty: #crate_name::ObjectType);
#[allow(clippy::all, clippy::pedantic)]
impl #generics ::std::convert::From<#p> for #ident #generics {
@ -81,7 +94,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
});
} else {
type_into_impls.push(quote! {
#crate_name::static_assertions::assert_impl_one!(#p: #crate_name::UnionType);
#crate_name::static_assertions::assert_impl_one!(#assert_ty: #crate_name::UnionType);
#[allow(clippy::all, clippy::pedantic)]
impl #generics ::std::convert::From<#p> for #ident #generics {
@ -167,7 +180,7 @@ pub fn generate(union_args: &args::Union) -> GeneratorResult<TokenStream> {
Ok(None)
}
fn collect_all_fields<'a>(&'a self, ctx: &#crate_name::ContextSelectionSet<'a>, fields: &mut #crate_name::resolver_utils::Fields<'a>) -> #crate_name::ServerResult<()> {
fn collect_all_fields<'__life>(&'__life self, ctx: &#crate_name::ContextSelectionSet<'__life>, fields: &mut #crate_name::resolver_utils::Fields<'__life>) -> #crate_name::ServerResult<()> {
match self {
#(#collect_all_fields),*
}

View File

@ -49,6 +49,8 @@ let schema = Schema::new(
);
```
> ⚠️ **MergedObject cannot be used in Interface。**
# Merging Subscriptions
Along with `MergedObject`, you can derive `MergedSubscription` or use `#[MergedSubscription]` to merge separate `#[Subscription]` blocks.

View File

@ -49,6 +49,8 @@ let schema = Schema::new(
);
```
> ⚠️ **合并的对象无法在Interface中使用。**
# 合并订阅
和`MergedObject`一样,你可以派生`MergedSubscription`来合并单独的`[Subscription]`块。

View File

@ -92,12 +92,8 @@
//!
//! ## Examples
//!
//! If you are just getting started, we recommend checking out our examples at:
//! [https://github.com/async-graphql/examples](https://github.com/async-graphql/examples)
//!
//! To see how you would create a Relay-compliant server using async-graphql, warp, diesel & postgresql, you can also check out a real-world example at:
//! [https://github.com/phated/twentyfive-stars](https://github.com/phated/twentyfive-stars)
//!
//! ## Benchmarks
//!
//! Ensure that there is no CPU-heavy process in background!

27
tests/lifetime.rs Normal file
View File

@ -0,0 +1,27 @@
use async_graphql::*;
use static_assertions::_core::marker::PhantomData;
#[derive(SimpleObject)]
struct ObjA<'a> {
value: &'a i32,
}
struct ObjB<'a>(PhantomData<&'a i32>);
#[Object]
impl<'a> ObjB<'a> {
async fn value(&self) -> &'a i32 {
todo!()
}
}
#[derive(Union)]
enum MyUnion1<'a> {
ObjA(ObjA<'a>),
}
#[derive(Interface)]
#[graphql(field(name = "value", type = "&&'a i32"))]
enum MyInterface<'a> {
ObjA(ObjA<'a>),
}