juniper_codegen/graphql_interface/
mod.rs

1//! Code generation for [GraphQL interface][1].
2//!
3//! [1]: https://spec.graphql.org/October2021#sec-Interfaces
4
5pub mod attr;
6pub mod derive;
7
8use std::collections::HashSet;
9
10use proc_macro2::TokenStream;
11use quote::{format_ident, quote, quote_spanned, ToTokens};
12use syn::{
13    ext::IdentExt as _,
14    parse::{Parse, ParseStream},
15    parse_quote,
16    punctuated::Punctuated,
17    spanned::Spanned,
18    token,
19    visit::Visit,
20};
21
22use crate::common::{
23    field, filter_attrs, gen,
24    parse::{
25        attr::{err, OptionExt as _},
26        GenericsExt as _, ParseBufferExt as _,
27    },
28    rename, scalar, AttrNames, Description, SpanContainer,
29};
30
31/// Returns [`syn::Ident`]s for a generic enum deriving [`Clone`] and [`Copy`]
32/// on it and enum alias which generic arguments are filled with
33/// [GraphQL interface][1] implementers.
34///
35/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
36fn enum_idents(
37    trait_ident: &syn::Ident,
38    alias_ident: Option<&syn::Ident>,
39) -> (syn::Ident, syn::Ident) {
40    let enum_alias_ident = alias_ident
41        .cloned()
42        .unwrap_or_else(|| format_ident!("{trait_ident}Value"));
43    let enum_ident = alias_ident.map_or_else(
44        || format_ident!("{trait_ident}ValueEnum"),
45        |c| format_ident!("{c}Enum"),
46    );
47    (enum_ident, enum_alias_ident)
48}
49
50/// Available arguments behind `#[graphql_interface]` attribute placed on a
51/// trait or struct definition, when generating code for [GraphQL interface][1]
52/// type.
53///
54/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
55#[derive(Debug, Default)]
56struct Attr {
57    /// Explicitly specified name of [GraphQL interface][1] type.
58    ///
59    /// If [`None`], then Rust trait name is used by default.
60    ///
61    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
62    name: Option<SpanContainer<String>>,
63
64    /// Explicitly specified [description][2] of [GraphQL interface][1] type.
65    ///
66    /// If [`None`], then Rust doc comment will be used as the [description][2],
67    /// if any.
68    ///
69    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
70    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
71    description: Option<SpanContainer<Description>>,
72
73    /// Explicitly specified identifier of the type alias of Rust enum type
74    /// behind the trait or struct, being an actual implementation of a
75    /// [GraphQL interface][1] type.
76    ///
77    /// If [`None`], then `{trait_name}Value` identifier will be used.
78    ///
79    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
80    r#enum: Option<SpanContainer<syn::Ident>>,
81
82    /// Explicitly specified Rust types of [GraphQL objects][2] or
83    /// [interfaces][1] implementing this [GraphQL interface][1] type.
84    ///
85    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
86    /// [2]: https://spec.graphql.org/October2021#sec-Objects
87    implemented_for: HashSet<SpanContainer<syn::TypePath>>,
88
89    /// Explicitly specified [GraphQL interfaces, implemented][1] by this
90    /// [GraphQL interface][0].
91    ///
92    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
93    /// [1]: https://spec.graphql.org/October2021#sel-GAHbhBDABAB_E-0b
94    implements: HashSet<SpanContainer<syn::TypePath>>,
95
96    /// Explicitly specified type of [`Context`] to use for resolving this
97    /// [GraphQL interface][1] type with.
98    ///
99    /// If [`None`], then unit type `()` is assumed as a type of [`Context`].
100    ///
101    /// [`Context`]: juniper::Context
102    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
103    context: Option<SpanContainer<syn::Type>>,
104
105    /// Explicitly specified type (or type parameter with its bounds) of
106    /// [`ScalarValue`] to resolve this [GraphQL interface][1] type with.
107    ///
108    /// If [`None`], then generated code will be generic over any
109    /// [`ScalarValue`] type, which, in turn, requires all [interface][1]
110    /// implementers to be generic over any [`ScalarValue`] type too. That's why
111    /// this type should be specified only if one of the implementers implements
112    /// [`GraphQLType`] in a non-generic way over [`ScalarValue`] type.
113    ///
114    /// [`GraphQLType`]: juniper::GraphQLType
115    /// [`ScalarValue`]: juniper::ScalarValue
116    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
117    scalar: Option<SpanContainer<scalar::AttrValue>>,
118
119    /// Explicitly specified marker indicating that the Rust trait should be
120    /// transformed into [`async_trait`].
121    ///
122    /// If [`None`], then trait will be transformed into [`async_trait`] only if
123    /// it contains async methods.
124    asyncness: Option<SpanContainer<syn::Ident>>,
125
126    /// Explicitly specified [`rename::Policy`] for all fields of this
127    /// [GraphQL interface][1] type.
128    ///
129    /// If [`None`], then the [`rename::Policy::CamelCase`] will be applied by
130    /// default.
131    ///
132    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
133    rename_fields: Option<SpanContainer<rename::Policy>>,
134
135    /// Indicator whether the generated code is intended to be used only inside
136    /// the [`juniper`] library.
137    is_internal: bool,
138}
139
140impl Parse for Attr {
141    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
142        let mut out = Self::default();
143        while !input.is_empty() {
144            let ident = input.parse_any_ident()?;
145            match ident.to_string().as_str() {
146                "name" => {
147                    input.parse::<token::Eq>()?;
148                    let name = input.parse::<syn::LitStr>()?;
149                    out.name
150                        .replace(SpanContainer::new(
151                            ident.span(),
152                            Some(name.span()),
153                            name.value(),
154                        ))
155                        .none_or_else(|_| err::dup_arg(&ident))?
156                }
157                "desc" | "description" => {
158                    input.parse::<token::Eq>()?;
159                    let desc = input.parse::<Description>()?;
160                    out.description
161                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
162                        .none_or_else(|_| err::dup_arg(&ident))?
163                }
164                "ctx" | "context" | "Context" => {
165                    input.parse::<token::Eq>()?;
166                    let ctx = input.parse::<syn::Type>()?;
167                    out.context
168                        .replace(SpanContainer::new(ident.span(), Some(ctx.span()), ctx))
169                        .none_or_else(|_| err::dup_arg(&ident))?
170                }
171                "scalar" | "Scalar" | "ScalarValue" => {
172                    input.parse::<token::Eq>()?;
173                    let scl = input.parse::<scalar::AttrValue>()?;
174                    out.scalar
175                        .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
176                        .none_or_else(|_| err::dup_arg(&ident))?
177                }
178                "for" | "implementers" => {
179                    input.parse::<token::Eq>()?;
180                    for impler in input.parse_maybe_wrapped_and_punctuated::<
181                        syn::TypePath, token::Bracket, token::Comma,
182                    >()? {
183                        let impler_span = impler.span();
184                        out
185                            .implemented_for
186                            .replace(SpanContainer::new(ident.span(), Some(impler_span), impler))
187                            .none_or_else(|_| err::dup_arg(impler_span))?;
188                    }
189                }
190                "impl" | "implements" => {
191                    input.parse::<token::Eq>()?;
192                    for iface in input.parse_maybe_wrapped_and_punctuated::<
193                        syn::TypePath, token::Bracket, token::Comma,
194                    >()? {
195                        let iface_span = iface.span();
196                        out
197                            .implements
198                            .replace(SpanContainer::new(ident.span(), Some(iface_span), iface))
199                            .none_or_else(|_| err::dup_arg(iface_span))?;
200                    }
201                }
202                "enum" => {
203                    input.parse::<token::Eq>()?;
204                    let alias = input.parse::<syn::Ident>()?;
205                    out.r#enum
206                        .replace(SpanContainer::new(ident.span(), Some(alias.span()), alias))
207                        .none_or_else(|_| err::dup_arg(&ident))?
208                }
209                "async" => {
210                    let span = ident.span();
211                    out.asyncness
212                        .replace(SpanContainer::new(span, Some(span), ident))
213                        .none_or_else(|_| err::dup_arg(span))?;
214                }
215                "rename_all" => {
216                    input.parse::<token::Eq>()?;
217                    let val = input.parse::<syn::LitStr>()?;
218                    out.rename_fields
219                        .replace(SpanContainer::new(
220                            ident.span(),
221                            Some(val.span()),
222                            val.try_into()?,
223                        ))
224                        .none_or_else(|_| err::dup_arg(&ident))?;
225                }
226                "internal" => {
227                    out.is_internal = true;
228                }
229                name => {
230                    return Err(err::unknown_arg(&ident, name));
231                }
232            }
233            input.try_parse::<token::Comma>()?;
234        }
235        Ok(out)
236    }
237}
238
239impl Attr {
240    /// Tries to merge two [`TraitAttr`]s into a single one, reporting about
241    /// duplicates, if any.
242    fn try_merge(self, mut another: Self) -> syn::Result<Self> {
243        Ok(Self {
244            name: try_merge_opt!(name: self, another),
245            description: try_merge_opt!(description: self, another),
246            context: try_merge_opt!(context: self, another),
247            scalar: try_merge_opt!(scalar: self, another),
248            implemented_for: try_merge_hashset!(implemented_for: self, another => span_joined),
249            implements: try_merge_hashset!(implements: self, another => span_joined),
250            r#enum: try_merge_opt!(r#enum: self, another),
251            asyncness: try_merge_opt!(asyncness: self, another),
252            rename_fields: try_merge_opt!(rename_fields: self, another),
253            is_internal: self.is_internal || another.is_internal,
254        })
255    }
256
257    /// Parses a [`TraitAttr`] from the provided multiple [`syn::Attribute`]s with
258    /// the specified `names`, placed on a trait or struct definition.
259    fn from_attrs(names: impl AttrNames, attrs: &[syn::Attribute]) -> syn::Result<Self> {
260        let mut attr = filter_attrs(names, attrs)
261            .map(|attr| attr.parse_args())
262            .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
263
264        if attr.description.is_none() {
265            attr.description = Description::parse_from_doc_attrs(attrs)?;
266        }
267
268        Ok(attr)
269    }
270}
271
272/// Definition of [GraphQL interface][1] for code generation.
273///
274/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
275struct Definition {
276    /// [`syn::Generics`] of the trait or struct describing the
277    /// [GraphQL interface][1].
278    ///
279    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
280    generics: syn::Generics,
281
282    /// [`syn::Visibility`] of the trait or struct describing the
283    /// [GraphQL interface][1].
284    ///
285    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
286    vis: syn::Visibility,
287
288    /// Name of the generic enum describing all [`implementers`]. It's generic
289    /// to derive [`Clone`], [`Copy`] and [`Debug`] on it.
290    ///
291    /// [`implementers`]: Self::implementers
292    /// [`Debug`]: std::fmt::Debug
293    enum_ident: syn::Ident,
294
295    /// Name of the type alias for [`enum_ident`] with [`implementers`].
296    ///
297    /// [`enum_ident`]: Self::enum_ident
298    /// [`implementers`]: Self::implementers
299    enum_alias_ident: syn::Ident,
300
301    /// Name of this [GraphQL interface][0] in GraphQL schema.
302    ///
303    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
304    name: Box<str>,
305
306    /// Description of this [GraphQL interface][0] to put into GraphQL schema.
307    ///
308    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
309    description: Option<Description>,
310
311    /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
312    /// for this [GraphQL interface][1].
313    ///
314    /// [`GraphQLType`]: juniper::GraphQLType
315    /// [`Context`]: juniper::Context
316    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
317    context: syn::Type,
318
319    /// [`ScalarValue`] parametrization to generate [`GraphQLType`]
320    /// implementation with for this [GraphQL interface][1].
321    ///
322    /// [`GraphQLType`]: juniper::GraphQLType
323    /// [`ScalarValue`]: juniper::ScalarValue
324    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
325    scalar: scalar::Type,
326
327    /// Defined [GraphQL fields][2] of this [GraphQL interface][1].
328    ///
329    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
330    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
331    fields: Vec<field::Definition>,
332
333    /// Defined [`Implementer`]s of this [GraphQL interface][1].
334    ///
335    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
336    implemented_for: Vec<syn::TypePath>,
337
338    /// [GraphQL interfaces implemented][1] by this [GraphQL interface][0].
339    ///
340    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
341    /// [1]: https://spec.graphql.org/October2021#sel-GAHbhBDABAB_E-0b
342    implements: Vec<syn::TypePath>,
343
344    /// Unlike `#[graphql_interface]` maro, `#[derive(GraphQLInterface)]` can't
345    /// append `#[allow(dead_code)]` to the unused struct, representing
346    /// [GraphQL interface][1]. We generate hacky `const` which doesn't actually
347    /// use it, but suppresses this warning.
348    ///
349    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
350    suppress_dead_code: Option<(syn::Ident, syn::Fields)>,
351
352    /// Intra-doc link to the [`syn::Item`] defining this
353    /// [GraphQL interface][0].
354    ///
355    /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
356    src_intra_doc_link: Box<str>,
357}
358
359impl ToTokens for Definition {
360    fn to_tokens(&self, into: &mut TokenStream) {
361        self.generate_enum_tokens().to_tokens(into);
362        self.impl_graphql_interface_tokens().to_tokens(into);
363        self.impl_output_type_tokens().to_tokens(into);
364        self.impl_graphql_type_tokens().to_tokens(into);
365        self.impl_graphql_value_tokens().to_tokens(into);
366        self.impl_graphql_value_async_tokens().to_tokens(into);
367        self.impl_reflection_traits_tokens().to_tokens(into);
368        self.impl_field_meta_tokens().to_tokens(into);
369        self.impl_field_tokens().to_tokens(into);
370        self.impl_async_field_tokens().to_tokens(into);
371    }
372}
373
374impl Definition {
375    /// Generates enum describing all the [`implementers`].
376    ///
377    /// [`implementers`]: Self::implementers
378    #[must_use]
379    fn generate_enum_tokens(&self) -> TokenStream {
380        let vis = &self.vis;
381        let enum_ident = &self.enum_ident;
382        let alias_ident = &self.enum_alias_ident;
383
384        let variant_gens_pars = (0..self.implemented_for.len()).map::<syn::GenericParam, _>(|id| {
385            let par = format_ident!("__I{id}");
386            parse_quote! { #par }
387        });
388        let variants_idents = self
389            .implemented_for
390            .iter()
391            .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident));
392
393        let interface_gens = &self.generics;
394        let (interface_impl_gens, interface_ty_gens, interface_where_clause) =
395            self.generics.split_for_impl();
396        let (interface_gens_lifetimes, interface_gens_tys) = interface_gens
397            .params
398            .clone()
399            .into_iter()
400            .partition::<Punctuated<_, _>, _>(|par| matches!(par, syn::GenericParam::Lifetime(_)));
401
402        let enum_gens = {
403            let mut enum_gens = interface_gens.clone();
404            enum_gens.params = interface_gens_lifetimes.clone();
405            enum_gens.params.extend(variant_gens_pars.clone());
406            enum_gens.params.extend(interface_gens_tys.clone());
407            enum_gens
408        };
409        let enum_alias_gens = {
410            let mut enum_alias_gens = interface_gens.clone();
411            enum_alias_gens.move_bounds_to_where_clause();
412            enum_alias_gens
413        };
414        let enum_to_alias_gens = {
415            interface_gens_lifetimes
416                .into_iter()
417                .map(|par| match par {
418                    syn::GenericParam::Lifetime(def) => {
419                        let lifetime = &def.lifetime;
420                        quote! { #lifetime }
421                    }
422                    rest => quote! { #rest },
423                })
424                .chain(self.implemented_for.iter().map(ToTokens::to_token_stream))
425                .chain(interface_gens_tys.into_iter().map(|par| match par {
426                    syn::GenericParam::Type(ty) => {
427                        let par_ident = &ty.ident;
428                        quote! { #par_ident }
429                    }
430                    rest => quote! { #rest },
431                }))
432        };
433        let enum_doc = format!(
434            "Enum building an opaque value represented by [`{}`]({}) \
435             [GraphQL interface][0].\
436             \n\n\
437             [0]: https://spec.graphql.org/October2021#sec-Interfaces",
438            self.name, self.src_intra_doc_link,
439        );
440        let enum_alias_doc = format!(
441            "Opaque value represented by [`{}`]({}) [GraphQL interface][0].\
442             \n\n\
443             [0]: https://spec.graphql.org/October2021#sec-Interfaces",
444            self.name, self.src_intra_doc_link,
445        );
446
447        let phantom_variant = self
448            .has_phantom_variant()
449            .then(|| {
450                let phantom_params = interface_gens.params.iter().filter_map(|p| {
451                    let ty = match p {
452                        syn::GenericParam::Type(ty) => {
453                            let ident = &ty.ident;
454                            quote! { #ident }
455                        }
456                        syn::GenericParam::Lifetime(lt) => {
457                            let lifetime = &lt.lifetime;
458                            quote! { &#lifetime () }
459                        }
460                        syn::GenericParam::Const(_) => return None,
461                    };
462                    Some(quote! {
463                        ::core::marker::PhantomData<
464                            ::core::sync::atomic::AtomicPtr<std::boxed::Box<#ty>>
465                        >
466                    })
467                });
468                quote! { __Phantom(#(#phantom_params),*) }
469            })
470            .into_iter();
471
472        let from_impls = self
473            .implemented_for
474            .iter()
475            .zip(variants_idents.clone())
476            .map(|(ty, ident)| {
477                quote! {
478                    #[automatically_derived]
479                    impl #interface_impl_gens ::core::convert::From<#ty>
480                        for #alias_ident #interface_ty_gens
481                        #interface_where_clause
482                    {
483                        fn from(v: #ty) -> Self {
484                            Self::#ident(v)
485                        }
486                    }
487                }
488            });
489
490        quote! {
491            #[automatically_derived]
492            #[derive(::core::clone::Clone, ::core::marker::Copy, ::core::fmt::Debug)]
493            #[doc = #enum_doc]
494            #vis enum #enum_ident #enum_gens {
495                #( #[doc(hidden)] #variants_idents(#variant_gens_pars), )*
496                #( #[doc(hidden)] #phantom_variant, )*
497            }
498
499            #[automatically_derived]
500            #[doc = #enum_alias_doc]
501            #vis type #alias_ident #enum_alias_gens =
502                #enum_ident<#( #enum_to_alias_gens ),*>;
503
504            #( #from_impls )*
505        }
506    }
507
508    /// Returns generated code implementing [`GraphQLInterface`] trait for this
509    /// [GraphQL interface][1].
510    ///
511    /// [`GraphQLInterface`]: juniper::GraphQLInterface
512    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
513    #[must_use]
514    fn impl_graphql_interface_tokens(&self) -> TokenStream {
515        let ty = &self.enum_alias_ident;
516        let scalar = &self.scalar;
517
518        let gens = self.impl_generics(false);
519        let (impl_generics, _, where_clause) = gens.split_for_impl();
520        let (_, ty_generics, _) = self.generics.split_for_impl();
521
522        let suppress_dead_code = self.suppress_dead_code.as_ref().map(|(ident, fields)| {
523            let const_gens = self.const_trait_generics();
524            let fields = fields.iter().map(|f| &f.ident);
525
526            quote! {{
527                const SUPPRESS_DEAD_CODE: () = {
528                    let none = ::core::option::Option::<#ident #const_gens>::None;
529                    match none {
530                        ::core::option::Option::Some(unreachable) => {
531                            #( let _ = unreachable.#fields; )*
532                        }
533                        ::core::option::Option::None => {}
534                    }
535                };
536                let _ = SUPPRESS_DEAD_CODE;
537            }}
538        });
539
540        let implemented_for = &self.implemented_for;
541        let all_impled_for_unique = (implemented_for.len() > 1).then(|| {
542            quote! { ::juniper::sa::assert_type_ne_all!(#( #implemented_for ),*); }
543        });
544
545        let mark_object_or_interface = self.implemented_for.iter().map(|impl_for| {
546            quote_spanned! { impl_for.span() =>
547                trait GraphQLObjectOrInterface<S: ::juniper::ScalarValue, T> {
548                    fn mark();
549                }
550
551                {
552                    struct Object;
553
554                    impl<S, T> GraphQLObjectOrInterface<S, Object> for T
555                    where
556                        S: ::juniper::ScalarValue,
557                        T: ::juniper::marker::GraphQLObject<S>,
558                    {
559                        fn mark() {
560                            <T as ::juniper::marker::GraphQLObject<S>>::mark()
561                        }
562                    }
563                }
564
565                {
566                    struct Interface;
567
568                    impl<S, T> GraphQLObjectOrInterface<S, Interface> for T
569                    where
570                        S: ::juniper::ScalarValue,
571                        T: ::juniper::marker::GraphQLInterface<S>,
572                    {
573                        fn mark() {
574                            <T as ::juniper::marker::GraphQLInterface<S>>::mark()
575                        }
576                    }
577                }
578
579                <#impl_for as GraphQLObjectOrInterface<#scalar, _>>::mark();
580            }
581        });
582
583        quote! {
584            #[automatically_derived]
585            impl #impl_generics ::juniper::marker::GraphQLInterface<#scalar>
586                for #ty #ty_generics
587                #where_clause
588            {
589                fn mark() {
590                    #suppress_dead_code
591                    #all_impled_for_unique
592                    #( { #mark_object_or_interface } )*
593                }
594            }
595        }
596    }
597
598    /// Returns generated code implementing [`marker::IsOutputType`] trait for
599    /// this [GraphQL interface][1].
600    ///
601    /// [`marker::IsOutputType`]: juniper::marker::IsOutputType
602    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
603    #[must_use]
604    fn impl_output_type_tokens(&self) -> TokenStream {
605        let ty = &self.enum_alias_ident;
606        let scalar = &self.scalar;
607        let const_scalar = &self.scalar.default_ty();
608
609        let generics = self.impl_generics(false);
610        let (impl_generics, _, where_clause) = generics.split_for_impl();
611        let (_, ty_generics, _) = self.generics.split_for_impl();
612        let ty_const_generics = self.const_trait_generics();
613
614        let fields_marks = self
615            .fields
616            .iter()
617            .map(|f| f.method_mark_tokens(false, scalar));
618
619        let is_output = self.implemented_for.iter().map(|impler| {
620            quote_spanned! { impler.span() =>
621               <#impler as ::juniper::marker::IsOutputType<#scalar>>::mark();
622            }
623        });
624
625        let const_impl_for = self.implemented_for.iter().cloned().map(|mut ty| {
626            generics.replace_type_path_with_defaults(&mut ty);
627            ty
628        });
629        let const_implements = self
630            .implements
631            .iter()
632            .cloned()
633            .map(|mut ty| {
634                generics.replace_type_path_with_defaults(&mut ty);
635                ty
636            })
637            .collect::<Vec<_>>();
638        let transitive_checks = const_impl_for.clone().map(|const_impl_for| {
639            quote_spanned! { const_impl_for.span() =>
640                ::juniper::assert_transitive_impls!(
641                    #const_scalar,
642                    #ty #ty_const_generics,
643                    #const_impl_for,
644                    #( #const_implements ),*
645                );
646            }
647        });
648
649        quote! {
650            #[automatically_derived]
651            impl #impl_generics ::juniper::marker::IsOutputType<#scalar>
652                for #ty #ty_generics
653                #where_clause
654            {
655                fn mark() {
656                    #( #fields_marks )*
657                    #( #is_output )*
658                    ::juniper::assert_interfaces_impls!(
659                        #const_scalar,
660                        #ty #ty_const_generics,
661                        #( #const_impl_for ),*
662                    );
663                    ::juniper::assert_implemented_for!(
664                        #const_scalar,
665                        #ty #ty_const_generics,
666                        #( #const_implements ),*
667                    );
668                    #( #transitive_checks )*
669                }
670            }
671        }
672    }
673
674    /// Returns generated code implementing [`GraphQLType`] trait for this
675    /// [GraphQL interface][1].
676    ///
677    /// [`GraphQLType`]: juniper::GraphQLType
678    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
679    #[must_use]
680    fn impl_graphql_type_tokens(&self) -> TokenStream {
681        let ty = &self.enum_alias_ident;
682        let scalar = &self.scalar;
683
684        let generics = self.impl_generics(false);
685        let (impl_generics, _, where_clause) = generics.split_for_impl();
686        let (_, ty_generics, _) = self.generics.split_for_impl();
687
688        let name = &self.name;
689        let description = &self.description;
690
691        // Sorting is required to preserve/guarantee the order of implementers registered in schema.
692        let mut implemented_for = self.implemented_for.clone();
693        implemented_for.sort_unstable_by(|a, b| {
694            let (a, b) = (quote!(#a).to_string(), quote!(#b).to_string());
695            a.cmp(&b)
696        });
697
698        // Sorting is required to preserve/guarantee the order of interfaces registered in schema.
699        let mut implements = self.implements.clone();
700        implements.sort_unstable_by(|a, b| {
701            let (a, b) = (quote!(#a).to_string(), quote!(#b).to_string());
702            a.cmp(&b)
703        });
704        let impl_interfaces = (!implements.is_empty()).then(|| {
705            quote! {
706                .interfaces(&[
707                    #( registry.get_type::<#implements>(info), )*
708                ])
709            }
710        });
711
712        let fields_meta = self.fields.iter().map(|f| f.method_meta_tokens(None));
713
714        quote! {
715            #[automatically_derived]
716            impl #impl_generics ::juniper::GraphQLType<#scalar>
717                for #ty #ty_generics
718                #where_clause
719            {
720                fn name(
721                    _ : &Self::TypeInfo,
722                ) -> ::core::option::Option<&'static ::core::primitive::str> {
723                    ::core::option::Option::Some(#name)
724                }
725
726                fn meta<'r>(
727                    info: &Self::TypeInfo,
728                    registry: &mut ::juniper::Registry<'r, #scalar>
729                ) -> ::juniper::meta::MetaType<'r, #scalar>
730                where #scalar: 'r,
731                {
732                    // Ensure all implementer types are registered.
733                    #( let _ = registry.get_type::<#implemented_for>(info); )*
734
735                    let fields = [
736                        #( #fields_meta, )*
737                    ];
738                    registry.build_interface_type::<#ty #ty_generics>(info, &fields)
739                        #description
740                        #impl_interfaces
741                        .into_meta()
742                }
743            }
744        }
745    }
746
747    /// Returns generated code implementing [`GraphQLValue`] trait for this
748    /// [GraphQL interface][1].
749    ///
750    /// [`GraphQLValue`]: juniper::GraphQLValue
751    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
752    #[must_use]
753    fn impl_graphql_value_tokens(&self) -> TokenStream {
754        let ty = &self.enum_alias_ident;
755        let trait_name = &self.name;
756        let scalar = &self.scalar;
757        let context = &self.context;
758
759        let generics = self.impl_generics(false);
760        let (impl_generics, _, where_clause) = generics.split_for_impl();
761        let (_, ty_generics, _) = self.generics.split_for_impl();
762
763        let fields_resolvers = self.fields.iter().map(|f| {
764            let name = &f.name;
765            Some(quote! {
766                #name => {
767                    ::juniper::macros::reflect::Field::<
768                        #scalar,
769                        { ::juniper::macros::reflect::fnv1a128(#name) }
770                    >::call(self, info, args, executor)
771                }
772            })
773        });
774
775        let no_field_err =
776            field::Definition::method_resolve_field_err_no_field_tokens(scalar, trait_name);
777
778        let downcast_check = self.method_concrete_type_name_tokens();
779
780        let downcast = self.method_resolve_into_type_tokens();
781
782        quote! {
783            #[allow(deprecated)]
784            #[automatically_derived]
785            impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty #ty_generics
786                #where_clause
787            {
788                type Context = #context;
789                type TypeInfo = ();
790
791                fn type_name<'__i>(
792                    &self,
793                    info: &'__i Self::TypeInfo,
794                ) -> ::core::option::Option<&'__i ::core::primitive::str> {
795                    <Self as ::juniper::GraphQLType<#scalar>>::name(info)
796                }
797
798                fn resolve_field(
799                    &self,
800                    info: &Self::TypeInfo,
801                    field: &::core::primitive::str,
802                    args: &::juniper::Arguments<'_, #scalar>,
803                    executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
804                ) -> ::juniper::ExecutionResult<#scalar> {
805                    match field {
806                        #( #fields_resolvers )*
807                        _ => #no_field_err,
808                    }
809                }
810
811                fn concrete_type_name(
812                    &self,
813                    context: &Self::Context,
814                    info: &Self::TypeInfo,
815                ) -> ::std::string::String {
816                    #downcast_check
817                }
818
819                fn resolve_into_type(
820                    &self,
821                    info: &Self::TypeInfo,
822                    type_name: &::core::primitive::str,
823                    _: ::core::option::Option<&[::juniper::Selection<'_, #scalar>]>,
824                    executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
825                ) -> ::juniper::ExecutionResult<#scalar> {
826                    #downcast
827                }
828            }
829        }
830    }
831
832    /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
833    /// [GraphQL interface][1].
834    ///
835    /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync
836    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
837    #[must_use]
838    fn impl_graphql_value_async_tokens(&self) -> TokenStream {
839        let ty = &self.enum_alias_ident;
840        let trait_name = &self.name;
841        let scalar = &self.scalar;
842
843        let generics = self.impl_generics(true);
844        let (impl_generics, _, where_clause) = generics.split_for_impl();
845        let (_, ty_generics, _) = self.generics.split_for_impl();
846
847        let fields_resolvers = self.fields.iter().map(|f| {
848            let name = &f.name;
849            quote! {
850                #name => {
851                    ::juniper::macros::reflect::AsyncField::<
852                        #scalar,
853                        { ::juniper::macros::reflect::fnv1a128(#name) }
854                    >::call(self, info, args, executor)
855                }
856            }
857        });
858        let no_field_err =
859            field::Definition::method_resolve_field_err_no_field_tokens(scalar, trait_name);
860
861        let downcast = self.method_resolve_into_type_async_tokens();
862
863        quote! {
864            #[allow(deprecated, non_snake_case)]
865            #[automatically_derived]
866            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #ty_generics
867                #where_clause
868            {
869                fn resolve_field_async<'b>(
870                    &'b self,
871                    info: &'b Self::TypeInfo,
872                    field: &'b ::core::primitive::str,
873                    args: &'b ::juniper::Arguments<'_, #scalar>,
874                    executor: &'b ::juniper::Executor<'_, '_, Self::Context, #scalar>,
875                ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
876                    match field {
877                        #( #fields_resolvers )*
878                        _ => ::std::boxed::Box::pin(async move { #no_field_err }),
879                    }
880                }
881
882                fn resolve_into_type_async<'b>(
883                    &'b self,
884                    info: &'b Self::TypeInfo,
885                    type_name: &::core::primitive::str,
886                    _: ::core::option::Option<&'b [::juniper::Selection<'b, #scalar>]>,
887                    executor: &'b ::juniper::Executor<'b, 'b, Self::Context, #scalar>
888                ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
889                    #downcast
890                }
891            }
892        }
893    }
894
895    /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`],
896    /// [`WrappedType`] and [`Fields`] traits for this [GraphQL interface][1].
897    ///
898    /// [`BaseSubTypes`]: juniper::macros::reflect::BaseSubTypes
899    /// [`BaseType`]: juniper::macros::reflect::BaseType
900    /// [`Fields`]: juniper::macros::reflect::Fields
901    /// [`WrappedType`]: juniper::macros::reflect::WrappedType
902    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
903    #[must_use]
904    fn impl_reflection_traits_tokens(&self) -> TokenStream {
905        let ty = &self.enum_alias_ident;
906        let implemented_for = &self.implemented_for;
907        let implements = &self.implements;
908        let scalar = &self.scalar;
909        let name = &self.name;
910        let fields = self.fields.iter().map(|f| &f.name);
911
912        let generics = self.impl_generics(false);
913        let (impl_generics, _, where_clause) = generics.split_for_impl();
914        let (_, ty_generics, _) = self.generics.split_for_impl();
915
916        quote! {
917            #[automatically_derived]
918            impl #impl_generics ::juniper::macros::reflect::BaseType<#scalar>
919                for #ty #ty_generics
920                #where_clause
921            {
922                const NAME: ::juniper::macros::reflect::Type = #name;
923            }
924
925            #[automatically_derived]
926            impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
927                for #ty #ty_generics
928                #where_clause
929            {
930                const NAMES: ::juniper::macros::reflect::Types = &[
931                    <Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME,
932                    #( <#implemented_for as ::juniper::macros::reflect::BaseType<#scalar>>::NAME ),*
933                ];
934            }
935
936            #[automatically_derived]
937            impl #impl_generics ::juniper::macros::reflect::Implements<#scalar>
938                for #ty #ty_generics
939                #where_clause
940            {
941                const NAMES: ::juniper::macros::reflect::Types =
942                    &[#( <#implements as ::juniper::macros::reflect::BaseType<#scalar>>::NAME ),*];
943            }
944
945            #[automatically_derived]
946            impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
947                for #ty #ty_generics
948                #where_clause
949            {
950                const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
951            }
952
953            #[automatically_derived]
954            impl #impl_generics ::juniper::macros::reflect::Fields<#scalar>
955                for #ty #ty_generics
956                #where_clause
957            {
958                const NAMES: ::juniper::macros::reflect::Names = &[#(#fields),*];
959            }
960        }
961    }
962
963    /// Returns generated code implementing [`FieldMeta`] for each field of this
964    /// [GraphQL interface][1].
965    ///
966    /// [`FieldMeta`]: juniper::macros::reflect::FieldMeta
967    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
968    fn impl_field_meta_tokens(&self) -> TokenStream {
969        let ty = &self.enum_alias_ident;
970        let context = &self.context;
971        let scalar = &self.scalar;
972
973        let generics = self.impl_generics(false);
974        let (impl_generics, _, where_clause) = generics.split_for_impl();
975        let (_, ty_generics, _) = self.generics.split_for_impl();
976
977        self.fields
978            .iter()
979            .map(|field| {
980                let field_name = &field.name;
981                let mut return_ty = field.ty.clone();
982                generics.replace_type_with_defaults(&mut return_ty);
983
984                let (args_tys, args_names): (Vec<_>, Vec<_>) = field
985                    .arguments
986                    .iter()
987                    .flat_map(|vec| vec.iter())
988                    .filter_map(|arg| match arg {
989                        field::MethodArgument::Regular(arg) => Some((&arg.ty, &arg.name)),
990                        _ => None,
991                    })
992                    .unzip();
993
994                quote! {
995                    #[allow(non_snake_case)]
996                    #[automatically_derived]
997                    impl #impl_generics ::juniper::macros::reflect::FieldMeta<
998                        #scalar,
999                        { ::juniper::macros::reflect::fnv1a128(#field_name) }
1000                    > for #ty #ty_generics #where_clause {
1001                        type Context = #context;
1002                        type TypeInfo = ();
1003                        const TYPE: ::juniper::macros::reflect::Type =
1004                            <#return_ty as ::juniper::macros::reflect::BaseType<#scalar>>::NAME;
1005                        const SUB_TYPES: ::juniper::macros::reflect::Types =
1006                            <#return_ty as ::juniper::macros::reflect::BaseSubTypes<#scalar>>::NAMES;
1007                        const WRAPPED_VALUE: ::juniper::macros::reflect::WrappedValue =
1008                            <#return_ty as ::juniper::macros::reflect::WrappedType<#scalar>>::VALUE;
1009                        const ARGUMENTS: &'static [(
1010                            ::juniper::macros::reflect::Name,
1011                            ::juniper::macros::reflect::Type,
1012                            ::juniper::macros::reflect::WrappedValue,
1013                        )] = &[#( (
1014                            #args_names,
1015                            <#args_tys as ::juniper::macros::reflect::BaseType<#scalar>>::NAME,
1016                            <#args_tys as ::juniper::macros::reflect::WrappedType<#scalar>>::VALUE,
1017                        ) ),*];
1018                    }
1019                }
1020            })
1021            .collect()
1022    }
1023
1024    /// Returns generated code implementing [`Field`] trait for each field of
1025    /// this [GraphQL interface][1].
1026    ///
1027    /// [`Field`]: juniper::macros::reflect::Field
1028    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
1029    fn impl_field_tokens(&self) -> TokenStream {
1030        let ty = &self.enum_alias_ident;
1031        let scalar = &self.scalar;
1032        let const_scalar = self.scalar.default_ty();
1033
1034        let generics = self.impl_generics(false);
1035        let (impl_generics, _, where_clause) = generics.split_for_impl();
1036        let (_, ty_generics, _) = self.generics.split_for_impl();
1037
1038        let const_implemented_for = self
1039            .implemented_for
1040            .iter()
1041            .cloned()
1042            .map(|mut impl_for| {
1043                generics.replace_type_path_with_defaults(&mut impl_for);
1044                impl_for
1045            })
1046            .collect::<Vec<_>>();
1047        let implemented_for_idents = self
1048            .implemented_for
1049            .iter()
1050            .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident))
1051            .collect::<Vec<_>>();
1052
1053        self.fields
1054            .iter()
1055            .map(|field| {
1056                let field_name = &field.name;
1057                let mut return_ty = field.ty.clone();
1058                generics.replace_type_with_defaults(&mut return_ty);
1059
1060                let const_ty_generics = self.const_trait_generics();
1061
1062                let unreachable_arm = (self.implemented_for.is_empty()
1063                    || !self.generics.params.is_empty())
1064                .then(|| {
1065                    quote! { _ => unreachable!() }
1066                });
1067
1068                quote_spanned! { field.ident.span() =>
1069                    #[allow(non_snake_case)]
1070                    #[automatically_derived]
1071                    impl #impl_generics ::juniper::macros::reflect::Field<
1072                        #scalar,
1073                        { ::juniper::macros::reflect::fnv1a128(#field_name) }
1074                    > for #ty #ty_generics #where_clause {
1075                        fn call(
1076                            &self,
1077                            info: &Self::TypeInfo,
1078                            args: &::juniper::Arguments<'_, #scalar>,
1079                            executor: &::juniper::Executor<'_, '_, Self::Context, #scalar>,
1080                        ) -> ::juniper::ExecutionResult<#scalar> {
1081                            match self {
1082                                #( #ty::#implemented_for_idents(v) => {
1083                                    ::juniper::assert_field!(
1084                                        #ty #const_ty_generics,
1085                                        #const_implemented_for,
1086                                        #const_scalar,
1087                                        #field_name,
1088                                    );
1089
1090                                    <_ as ::juniper::macros::reflect::Field::<
1091                                        #scalar,
1092                                        { ::juniper::macros::reflect::fnv1a128(#field_name) },
1093                                    >>::call(v, info, args, executor)
1094                                } )*
1095                                #unreachable_arm
1096                            }
1097                        }
1098                    }
1099                }
1100            })
1101            .collect()
1102    }
1103
1104    /// Returns generated code implementing [`AsyncField`] trait for each field
1105    /// of this [GraphQL interface][1].
1106    ///
1107    /// [`AsyncField`]: juniper::macros::reflect::AsyncField
1108    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
1109    fn impl_async_field_tokens(&self) -> TokenStream {
1110        let ty = &self.enum_alias_ident;
1111        let scalar = &self.scalar;
1112        let const_scalar = self.scalar.default_ty();
1113
1114        let generics = self.impl_generics(true);
1115        let (impl_generics, _, where_clause) = generics.split_for_impl();
1116        let (_, ty_generics, _) = self.generics.split_for_impl();
1117
1118        let const_implemented_for = self
1119            .implemented_for
1120            .iter()
1121            .cloned()
1122            .map(|mut impl_for| {
1123                generics.replace_type_path_with_defaults(&mut impl_for);
1124                impl_for
1125            })
1126            .collect::<Vec<_>>();
1127        let implemented_for_idents = self
1128            .implemented_for
1129            .iter()
1130            .filter_map(|ty| ty.path.segments.last().map(|seg| &seg.ident))
1131            .collect::<Vec<_>>();
1132
1133        self.fields
1134            .iter()
1135            .map(|field| {
1136                let field_name = &field.name;
1137                let mut return_ty = field.ty.clone();
1138                generics.replace_type_with_defaults(&mut return_ty);
1139
1140                let const_ty_generics = self.const_trait_generics();
1141
1142                let unreachable_arm = (self.implemented_for.is_empty()
1143                    || !self.generics.params.is_empty())
1144                .then(|| {
1145                    quote! { _ => unreachable!() }
1146                });
1147
1148                quote_spanned! { field.ident.span() =>
1149                    #[allow(non_snake_case)]
1150                    #[automatically_derived]
1151                    impl #impl_generics ::juniper::macros::reflect::AsyncField<
1152                        #scalar,
1153                        { ::juniper::macros::reflect::fnv1a128(#field_name) }
1154                    > for #ty #ty_generics #where_clause {
1155                        fn call<'b>(
1156                            &'b self,
1157                            info: &'b Self::TypeInfo,
1158                            args: &'b ::juniper::Arguments<'_, #scalar>,
1159                            executor: &'b ::juniper::Executor<'_, '_, Self::Context, #scalar>,
1160                        ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
1161                            match self {
1162                                #( #ty::#implemented_for_idents(v) => {
1163                                    ::juniper::assert_field!(
1164                                        #ty #const_ty_generics,
1165                                        #const_implemented_for,
1166                                        #const_scalar,
1167                                        #field_name,
1168                                    );
1169
1170                                    <_ as ::juniper::macros::reflect::AsyncField<
1171                                        #scalar,
1172                                        { ::juniper::macros::reflect::fnv1a128(#field_name) },
1173                                    >>::call(v, info, args, executor)
1174                                } )*
1175                                #unreachable_arm
1176                            }
1177                        }
1178                    }
1179                }
1180            })
1181            .collect()
1182    }
1183
1184    /// Returns generated code for the [`GraphQLValue::concrete_type_name`][0]
1185    /// method, which returns name of the underlying [`implementers`][1] GraphQL
1186    /// type contained in this enum.
1187    ///
1188    /// [0]: juniper::GraphQLValue::concrete_type_name
1189    /// [1]: Self::implementers
1190    #[must_use]
1191    fn method_concrete_type_name_tokens(&self) -> TokenStream {
1192        let scalar = &self.scalar;
1193
1194        let match_arms = self
1195            .implemented_for
1196            .iter()
1197            .filter_map(|ty| ty.path.segments.last().map(|seg| (&seg.ident, ty)))
1198            .map(|(ident, ty)| {
1199                quote! {
1200                    Self::#ident(v) => <
1201                        #ty as ::juniper::GraphQLValue<#scalar>
1202                    >::concrete_type_name(v, context, info),
1203                }
1204            });
1205
1206        let non_exhaustive_match_arm =
1207            (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1208                quote! { _ => unreachable!(), }
1209            });
1210
1211        quote! {
1212            match self {
1213                #( #match_arms )*
1214                #non_exhaustive_match_arm
1215            }
1216        }
1217    }
1218
1219    /// Returns generated code for the
1220    /// [`GraphQLValueAsync::resolve_into_type_async`][0] method, which
1221    /// downcasts this enum into its underlying [`implementers`][1] type
1222    /// asynchronously.
1223    ///
1224    /// [0]: juniper::GraphQLValueAsync::resolve_into_type_async
1225    /// [1]: Self::implementers
1226    #[must_use]
1227    fn method_resolve_into_type_async_tokens(&self) -> TokenStream {
1228        let resolving_code = gen::async_resolving_code(None);
1229
1230        let match_arms = self.implemented_for.iter().filter_map(|ty| {
1231            ty.path.segments.last().map(|ident| {
1232                quote! {
1233                    Self::#ident(v) => {
1234                        let fut = ::juniper::futures::future::ready(v);
1235                        #resolving_code
1236                    }
1237                }
1238            })
1239        });
1240        let non_exhaustive_match_arm =
1241            (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1242                quote! { _ => unreachable!(), }
1243            });
1244
1245        quote! {
1246            match self {
1247                #( #match_arms )*
1248                #non_exhaustive_match_arm
1249            }
1250        }
1251    }
1252
1253    /// Returns generated code for the [`GraphQLValue::resolve_into_type`][0]
1254    /// method, which resolves this enum into its underlying
1255    /// [`implementers`][1] type synchronously.
1256    ///
1257    /// [0]: juniper::GraphQLValue::resolve_into_type
1258    /// [1]: Self::implementers
1259    #[must_use]
1260    fn method_resolve_into_type_tokens(&self) -> TokenStream {
1261        let resolving_code = gen::sync_resolving_code();
1262
1263        let match_arms = self.implemented_for.iter().filter_map(|ty| {
1264            ty.path.segments.last().map(|ident| {
1265                quote! {
1266                    Self::#ident(res) => #resolving_code,
1267                }
1268            })
1269        });
1270
1271        let non_exhaustive_match_arm =
1272            (!self.generics.params.is_empty() || self.implemented_for.is_empty()).then(|| {
1273                quote! { _ => unreachable!(), }
1274            });
1275
1276        quote! {
1277            match self {
1278                #( #match_arms )*
1279                #non_exhaustive_match_arm
1280            }
1281        }
1282    }
1283
1284    /// Returns trait generics replaced with the default values for usage in a
1285    /// `const` context.
1286    #[must_use]
1287    fn const_trait_generics(&self) -> syn::PathArguments {
1288        struct GenericsForConst(syn::AngleBracketedGenericArguments);
1289
1290        impl Visit<'_> for GenericsForConst {
1291            fn visit_generic_param(&mut self, param: &syn::GenericParam) {
1292                let arg = match param {
1293                    syn::GenericParam::Lifetime(_) => parse_quote! { 'static },
1294                    syn::GenericParam::Type(ty) => {
1295                        if ty.default.is_none() {
1296                            parse_quote! { ::juniper::DefaultScalarValue }
1297                        } else {
1298                            return;
1299                        }
1300                    }
1301                    syn::GenericParam::Const(c) => {
1302                        if c.default.is_none() {
1303                            // This hack works because only `min_const_generics`
1304                            // are enabled for now.
1305                            // TODO: Replace this once full `const_generics` are
1306                            //       available.
1307                            //       Maybe with `<_ as Default>::default()`?
1308                            parse_quote!({ 0_u8 as _ })
1309                        } else {
1310                            return;
1311                        }
1312                    }
1313                };
1314                self.0.args.push(arg)
1315            }
1316        }
1317
1318        let mut visitor = GenericsForConst(parse_quote!( <> ));
1319        visitor.visit_generics(&self.generics);
1320        syn::PathArguments::AngleBracketed(visitor.0)
1321    }
1322
1323    /// Returns prepared [`syn::Generics`] for [`GraphQLType`] trait (and
1324    /// similar) implementation of this enum.
1325    ///
1326    /// If `for_async` is `true`, then additional predicates are added to suit
1327    /// the [`GraphQLAsyncValue`] trait (and similar) requirements.
1328    ///
1329    /// [`GraphQLAsyncValue`]: juniper::GraphQLAsyncValue
1330    /// [`GraphQLType`]: juniper::GraphQLType
1331    #[must_use]
1332    fn impl_generics(&self, for_async: bool) -> syn::Generics {
1333        let mut generics = self.generics.clone();
1334
1335        let scalar = &self.scalar;
1336        if scalar.is_implicit_generic() {
1337            generics.params.push(parse_quote! { #scalar });
1338        }
1339        if scalar.is_generic() {
1340            generics
1341                .make_where_clause()
1342                .predicates
1343                .push(parse_quote! { #scalar: ::juniper::ScalarValue });
1344        }
1345        if let Some(bound) = scalar.bounds() {
1346            generics.make_where_clause().predicates.push(bound);
1347        }
1348
1349        if for_async {
1350            let self_ty = if self.generics.lifetimes().next().is_some() {
1351                // Modify lifetime names to omit "lifetime name `'a` shadows a
1352                // lifetime name that is already in scope" error.
1353                let mut generics = self.generics.clone();
1354                for lt in generics.lifetimes_mut() {
1355                    let ident = lt.lifetime.ident.unraw();
1356                    lt.lifetime.ident = format_ident!("__fa__{ident}");
1357                }
1358
1359                let lifetimes = generics.lifetimes().map(|lt| &lt.lifetime);
1360                let ty = &self.enum_alias_ident;
1361                let (_, ty_generics, _) = generics.split_for_impl();
1362
1363                quote! { for<#( #lifetimes ),*> #ty #ty_generics }
1364            } else {
1365                quote! { Self }
1366            };
1367            generics
1368                .make_where_clause()
1369                .predicates
1370                .push(parse_quote! { #self_ty: ::core::marker::Sync });
1371
1372            if scalar.is_generic() {
1373                generics
1374                    .make_where_clause()
1375                    .predicates
1376                    .push(parse_quote! { #scalar: ::core::marker::Send + ::core::marker::Sync });
1377            }
1378        }
1379
1380        generics
1381    }
1382
1383    /// Indicates whether this enum has non-exhaustive phantom variant to hold
1384    /// type parameters.
1385    #[must_use]
1386    fn has_phantom_variant(&self) -> bool {
1387        !self.generics.params.is_empty()
1388    }
1389}