diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5319058..675ec3cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,8 +21,7 @@ jobs: ################ pr: - if: ${{ github.event_name == 'pull_request' - && !contains(github.event.head_commit.message, '[skip ci]') }} + if: ${{ github.event_name == 'pull_request' }} needs: - clippy - example @@ -43,9 +42,6 @@ jobs: ########################## clippy: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -58,9 +54,6 @@ jobs: - run: make cargo.lint rustfmt: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -80,9 +73,6 @@ jobs: ########### example: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} strategy: fail-fast: false matrix: @@ -111,9 +101,6 @@ jobs: - run: cargo check -p example_${{ matrix.example }} feature: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} strategy: fail-fast: false matrix: @@ -174,9 +161,6 @@ jobs: - run: cargo package -p ${{ steps.crate.outputs.NAME }} test: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} strategy: fail-fast: false matrix: @@ -230,9 +214,6 @@ jobs: - run: make test.cargo crate=${{ matrix.crate }} wasm: - if: ${{ github.ref == 'refs/heads/master' - || startsWith(github.ref, 'refs/tags/juniper') - || !contains(github.event.head_commit.message, '[skip ci]') }} strategy: fail-fast: false matrix: @@ -264,9 +245,7 @@ jobs: release-check: name: Check release automation - if: ${{ !startsWith(github.ref, 'refs/tags/juniper') - && (github.ref == 'refs/heads/master' - || !contains(github.event.head_commit.message, '[skip ci]')) }} + if: ${{ !startsWith(github.ref, 'refs/tags/juniper') }} strategy: fail-fast: false matrix: diff --git a/book/src/types/interfaces.md b/book/src/types/interfaces.md index aa9c543e..949344f9 100644 --- a/book/src/types/interfaces.md +++ b/book/src/types/interfaces.md @@ -77,6 +77,190 @@ struct Human { ``` +### Interfaces implementing other interfaces + +GraphQL allows implementing interfaces on other interfaces in addition to objects. + +```rust +# extern crate juniper; +use juniper::{graphql_interface, graphql_object, ID}; + +#[graphql_interface(for = [HumanValue, Luke])] +struct Node { + id: ID, +} + +#[graphql_interface(impl = NodeValue, for = Luke)] +struct Human { + id: ID, + home_planet: String, +} + +struct Luke { + id: ID, +} + +#[graphql_object(impl = [HumanValue, NodeValue])] +impl Luke { + fn id(&self) -> &ID { + &self.id + } + + // As `String` and `&str` aren't distinguished by + // GraphQL spec, you can use them interchangeably. + // Same is applied for `Cow<'a, str>`. + // ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ + fn home_planet() -> &'static str { + "Tatooine" + } +} +# +# fn main() {} +``` + +> __NOTE:__ Every interface has to specify all other interfaces/objects it implements or implemented for. Missing one of `for = ` or `impl = ` attributes is a compile-time error. + +```compile_fail +# extern crate juniper; +use juniper::{graphql_interface, GraphQLObject}; + +#[derive(GraphQLObject)] +pub struct ObjA { + id: String, +} + +#[graphql_interface(for = ObjA)] +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at +// 'Failed to implement interface `Character` on `ObjA`: missing interface reference in implementer's `impl` attribute.' +struct Character { + id: String, +} + +fn main() {} +``` + + +### GraphQL subtyping and additional `null`able fields + +GraphQL allows implementers (both objects and other interfaces) to return "subtypes" instead of an original value. Basically, this allows you to impose additional bounds on the implementation. + +Valid "subtypes" are: +- interface implementer instead of an interface itself: + - `I implements T` in place of a `T`; + - `Vec` in place of a `Vec`. +- non-null value in place of a nullable: + - `T` in place of a `Option`; + - `Vec` in place of a `Vec>`. + +These rules are recursively applied, so `Vec>` is a valid "subtype" of a `Option>>>>`. + +Also, GraphQL allows implementers to add `null`able fields, which aren't present on an original interface. + +```rust +# extern crate juniper; +use juniper::{graphql_interface, graphql_object, ID}; + +#[graphql_interface(for = [HumanValue, Luke])] +struct Node { + id: ID, +} + +#[graphql_interface(for = HumanConnectionValue)] +struct Connection { + nodes: Vec, +} + +#[graphql_interface(impl = NodeValue, for = Luke)] +struct Human { + id: ID, + home_planet: String, +} + +#[graphql_interface(impl = ConnectionValue)] +struct HumanConnection { + nodes: Vec, + // ^^^^^^^^^^ notice not `NodeValue` + // This can happen, because every `Human` is a `Node` too, so we are just + // imposing additional bounds, which still can be resolved with + // `... on Connection { nodes }`. +} + +struct Luke { + id: ID, +} + +#[graphql_object(impl = [HumanValue, NodeValue])] +impl Luke { + fn id(&self) -> &ID { + &self.id + } + + fn home_planet(language: Option) -> &'static str { + // ^^^^^^^^^^^^^^ + // Notice additional `null`able field, which is missing on `Human`. + // Resolving `...on Human { homePlanet }` will provide `None` for this + // argument. + match language.as_deref() { + None | Some("en") => "Tatooine", + Some("ko") => "타투인", + _ => todo!(), + } + } +} +# +# fn main() {} +``` + +Violating GraphQL "subtyping" or additional nullable field rules is a compile-time error. + +```compile_fail +# extern crate juniper; +use juniper::{graphql_interface, graphql_object}; + +pub struct ObjA { + id: String, +} + +#[graphql_object(impl = CharacterValue)] +impl ObjA { + fn id(&self, is_present: bool) -> &str { +// ^^ the evaluated program panicked at +// 'Failed to implement interface `Character` on `ObjA`: Field `id`: Argument `isPresent` of type `Boolean!` +// isn't present on the interface and so has to be nullable.' + is_present.then(|| self.id.as_str()).unwrap_or("missing") + } +} + +#[graphql_interface(for = ObjA)] +struct Character { + id: String, +} +# +# fn main() {} +``` + +```compile_fail +# extern crate juniper; +use juniper::{graphql_interface, GraphQLObject}; + +#[derive(GraphQLObject)] +#[graphql(impl = CharacterValue)] +pub struct ObjA { + id: Vec, +// ^^ the evaluated program panicked at +// 'Failed to implement interface `Character` on `ObjA`: Field `id`: implementor is expected to return a subtype of +// interface's return object: `[String!]!` is not a subtype of `String!`.' +} + +#[graphql_interface(for = ObjA)] +struct Character { + id: String, +} +# +# fn main() {} +``` + + ### Ignoring trait methods We may want to omit some trait methods to be assumed as [GraphQL interface][1] fields and ignore them. diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md index 1bff5bca..7a5aa27a 100644 --- a/juniper/CHANGELOG.md +++ b/juniper/CHANGELOG.md @@ -31,6 +31,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi - Forbade default implementations of non-ignored trait methods. - Supported coercion of additional `null`able arguments and return sub-typing on implementer. - Supported `rename_all = ""` attribute argument influencing all its fields and their arguments. ([#971]) + - Supported interfaces implementing other interfaces. ([#1028]) - Split `#[derive(GraphQLScalarValue)]` macro into: - `#[derive(GraphQLScalar)]` for implementing GraphQL scalar: ([#1017]) - Supported generic `ScalarValue`. @@ -94,6 +95,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi [#1017]: /../../pull/1017 [#1025]: /../../pull/1025 [#1026]: /../../pull/1026 +[#1028]: /../../pull/1028 [#1051]: /../../issues/1051 [#1054]: /../../pull/1054 [#1057]: /../../pull/1057 diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index 5c5fbc70..bbf55964 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -38,7 +38,7 @@ schema-language = ["graphql-parser"] anyhow = { version = "1.0.32", default-features = false, optional = true } async-trait = "0.1.39" bigdecimal = { version = "0.3", optional = true } -bson = { version = "2.0", features = ["chrono-0_4"], optional = true } +bson = { version = "2.3", features = ["chrono-0_4"], optional = true } chrono = { version = "0.4", features = ["alloc"], default-features = false, optional = true } chrono-tz = { version = "0.6", default-features = false, optional = true } fnv = "1.0.3" diff --git a/juniper/src/executor_tests/introspection/mod.rs b/juniper/src/executor_tests/introspection/mod.rs index 25eff845..ed59efc7 100644 --- a/juniper/src/executor_tests/introspection/mod.rs +++ b/juniper/src/executor_tests/introspection/mod.rs @@ -247,7 +247,7 @@ async fn interface_introspection() { ); assert_eq!( type_info.get_field_value("interfaces"), - Some(&graphql_value!(null)), + Some(&graphql_value!([])), ); assert_eq!( type_info.get_field_value("enumValues"), diff --git a/juniper/src/integrations/bson.rs b/juniper/src/integrations/bson.rs index f22691b2..8d904025 100644 --- a/juniper/src/integrations/bson.rs +++ b/juniper/src/integrations/bson.rs @@ -28,7 +28,10 @@ mod utc_date_time { use super::*; pub(super) fn to_output(v: &UtcDateTime) -> Value { - Value::scalar((*v).to_rfc3339_string()) + Value::scalar( + (*v).try_to_rfc3339_string() + .unwrap_or_else(|e| panic!("failed to format `UtcDateTime` as RFC3339: {}", e)), + ) } pub(super) fn from_input(v: &InputValue) -> Result { diff --git a/juniper/src/macros/reflect.rs b/juniper/src/macros/reflect.rs index e7cb1f30..33ea79ab 100644 --- a/juniper/src/macros/reflect.rs +++ b/juniper/src/macros/reflect.rs @@ -409,6 +409,38 @@ macro_rules! assert_interfaces_impls { }; } +/// Asserts that all [transitive interfaces][0] (the ones implemented by the +/// `$interface`) are also implemented by the `$implementor`. +/// +/// [0]: https://spec.graphql.org/October2021#sel-FAHbhBHCAACGB35P +#[macro_export] +macro_rules! assert_transitive_impls { + ($scalar: ty, $interface: ty, $implementor: ty $(, $transitive: ty)* $(,)?) => { + const _: () = { + $({ + let is_present = $crate::macros::reflect::str_exists_in_arr( + <$implementor as ::juniper::macros::reflect::BaseType<$scalar>>::NAME, + <$transitive as ::juniper::macros::reflect::BaseSubTypes<$scalar>>::NAMES, + ); + if !is_present { + const MSG: &str = $crate::const_concat!( + "Failed to implement interface `", + <$interface as $crate::macros::reflect::BaseType<$scalar>>::NAME, + "` on `", + <$implementor as $crate::macros::reflect::BaseType<$scalar>>::NAME, + "`: missing `impl = ` for transitive interface `", + <$transitive as $crate::macros::reflect::BaseType<$scalar>>::NAME, + "` on `", + <$implementor as $crate::macros::reflect::BaseType<$scalar>>::NAME, + "`." + ); + ::std::panic!("{}", MSG); + } + })* + }; + }; +} + /// Asserts validness of [`Field`] [`Arguments`] and returned [`Type`]. /// /// This assertion is a combination of [`assert_subtype`] and diff --git a/juniper/src/reflect/mod.rs b/juniper/src/reflect/mod.rs index 43d73827..ecaa6753 100644 --- a/juniper/src/reflect/mod.rs +++ b/juniper/src/reflect/mod.rs @@ -5,7 +5,7 @@ use crate::behavior; #[doc(inline)] pub use self::macros::{ assert_field, assert_field_args, assert_field_type, assert_has_field, assert_implemented_for, - assert_interfaces_impls, const_concat, format_type, + assert_interfaces_impls, assert_transitive_impls, const_concat, format_type, }; /// Name of a [GraphQL type][0] in a GraphQL schema. @@ -332,24 +332,22 @@ mod macros { #[macro_export] macro_rules! reflect_assert_implemented_for { ($behavior: ty, $implementor: ty $(, $interfaces: ty)* $(,)?) => { - const _: () = { - $({ - let is_present = $crate::reflect::str_exists_in_arr( + const _: () = { $({ + let is_present = $crate::reflect::str_exists_in_arr( + <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, + <$interfaces as $crate::reflect::BaseSubTypes<$behavior>>::NAMES, + ); + if !is_present { + const MSG: &str = $crate::reflect::const_concat!( + "Failed to implement interface `", + <$interfaces as $crate::reflect::BaseType<$behavior>>::NAME, + "` on `", <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, - <$interfaces as $crate::reflect::BaseSubTypes<$behavior>>::NAMES, + "`: missing implementer reference in interface's `for` attribute.", ); - if !is_present { - const MSG: &str = $crate::reflect::const_concat!( - "Failed to implement interface `", - <$interfaces as $crate::reflect::BaseType<$behavior>>::NAME, - "` on `", - <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, - "`: missing implementer reference in interface's `for` attribute.", - ); - ::std::panic!("{}", MSG); - } - })* - }; + ::std::panic!("{}", MSG); + } + })* }; }; } @@ -360,24 +358,52 @@ mod macros { #[macro_export] macro_rules! reflect_assert_interfaces_impls { ($behavior: ty, $interface: ty $(, $implementers: ty)* $(,)?) => { - const _: () = { - $({ - let is_present = $crate::reflect::str_exists_in_arr( + const _: () = { $({ + let is_present = $crate::reflect::str_exists_in_arr( + <$interface as $crate::reflect::BaseType<$behavior>>::NAME, + <$implementers as $crate::reflect::Implements<$behavior>>::NAMES, + ); + if !is_present { + const MSG: &str = $crate::reflect::const_concat!( + "Failed to implement interface `", <$interface as $crate::reflect::BaseType<$behavior>>::NAME, - <$implementers as $crate::reflect::Implements<$behavior>>::NAMES, + "` on `", + <$implementers as $crate::reflect::BaseType<$behavior>>::NAME, + "`: missing interface reference in implementer's `impl` attribute.", ); - if !is_present { - const MSG: &str = $crate::reflect::const_concat!( - "Failed to implement interface `", - <$interface as $crate::reflect::BaseType<$behavior>>::NAME, - "` on `", - <$implementers as $crate::reflect::BaseType<$behavior>>::NAME, - "`: missing interface reference in implementer's `impl` attribute.", - ); - ::std::panic!("{}", MSG); - } - })* - }; + ::std::panic!("{}", MSG); + } + })* }; + }; + } + + /// Asserts that all [transitive interfaces][0] (the ones implemented by the + /// `$interface`) are also implemented by the `$implementor`. + /// + /// [0]: https://spec.graphql.org/October2021#sel-FAHbhBHCAACGB35P + #[macro_export] + macro_rules! reflect_assert_transitive_impls { + ($behavior: ty, $interface: ty, $implementor: ty $(, $transitive: ty)* $(,)?) => { + const _: () = { $({ + let is_present = $crate::reflect::str_exists_in_arr( + <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, + <$transitive as $crate::reflect::BaseSubTypes<$behavior>>::NAMES, + ); + if !is_present { + const MSG: &str = $crate::reflect::const_concat!( + "Failed to implement interface `", + <$interface as $crate::reflect::BaseType<$behavior>>::NAME, + "` on `", + <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, + "`: missing `impl = ` for transitive interface `", + <$transitive as $crate::reflect::BaseType<$behavior>>::NAME, + "` on `", + <$implementor as $crate::reflect::BaseType<$behavior>>::NAME, + "`.", + ); + ::std::panic!("{}", MSG); + } + })* }; }; } @@ -843,6 +869,7 @@ mod macros { reflect_assert_has_field as assert_has_field, reflect_assert_implemented_for as assert_implemented_for, reflect_assert_interfaces_impls as assert_interfaces_impls, + reflect_assert_transitive_impls as assert_transitive_impls, reflect_const_concat as const_concat, reflect_format_type as format_type, }; } diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs index 47e7f705..d686a09c 100644 --- a/juniper/src/schema/meta.rs +++ b/juniper/src/schema/meta.rs @@ -137,6 +137,8 @@ pub struct InterfaceMeta<'a, S> { pub description: Option, #[doc(hidden)] pub fields: Vec>, + #[doc(hidden)] + pub interface_names: Vec, } /// Union type metadata @@ -675,6 +677,7 @@ impl<'a, S> InterfaceMeta<'a, S> { name, description: None, fields: fields.to_vec(), + interface_names: Vec::new(), } } @@ -687,6 +690,18 @@ impl<'a, S> InterfaceMeta<'a, S> { self } + /// Sets the `interfaces` this [`InterfaceMeta`] interface implements. + /// + /// Overwrites any previously set list of interfaces. + #[must_use] + pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> Self { + self.interface_names = interfaces + .iter() + .map(|t| t.innermost_name().to_owned()) + .collect(); + self + } + /// Wraps this [`InterfaceMeta`] type into a generic [`MetaType`]. pub fn into_meta(self) -> MetaType<'a, S> { MetaType::Interface(self) diff --git a/juniper/src/schema/schema.rs b/juniper/src/schema/schema.rs index 30906478..825bb43a 100644 --- a/juniper/src/schema/schema.rs +++ b/juniper/src/schema/schema.rs @@ -244,10 +244,16 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> { fn interfaces<'s>(&self, context: &'s SchemaType<'a, S>) -> Option>> { match self { - TypeType::Concrete(&MetaType::Object(ObjectMeta { - ref interface_names, - .. - })) => Some( + TypeType::Concrete( + &MetaType::Object(ObjectMeta { + ref interface_names, + .. + }) + | &MetaType::Interface(InterfaceMeta { + ref interface_names, + .. + }), + ) => Some( interface_names .iter() .filter_map(|n| context.type_by_name(n)) diff --git a/juniper/src/schema/translate/graphql_parser.rs b/juniper/src/schema/translate/graphql_parser.rs index dc0ab05d..c3864561 100644 --- a/juniper/src/schema/translate/graphql_parser.rs +++ b/juniper/src/schema/translate/graphql_parser.rs @@ -190,8 +190,11 @@ impl GraphQLParserTranslator { position: Pos::default(), description: x.description.as_ref().map(|s| From::from(s.as_str())), name: From::from(x.name.as_ref()), - // TODO: Support this with GraphQL October 2021 Edition. - implements_interfaces: vec![], + implements_interfaces: x + .interface_names + .iter() + .map(|s| From::from(s.as_str())) + .collect(), directives: vec![], fields: x .fields diff --git a/juniper/src/tests/schema_introspection.rs b/juniper/src/tests/schema_introspection.rs index 291c85f1..06a79325 100644 --- a/juniper/src/tests/schema_introspection.rs +++ b/juniper/src/tests/schema_introspection.rs @@ -1173,7 +1173,7 @@ pub(crate) fn schema_introspection_result() -> Value { } ], "inputFields": null, - "interfaces": null, + "interfaces": [], "enumValues": null, "possibleTypes": [ { @@ -2500,7 +2500,7 @@ pub(crate) fn schema_introspection_result_without_descriptions() -> Value { } ], "inputFields": null, - "interfaces": null, + "interfaces": [], "enumValues": null, "possibleTypes": [ { diff --git a/juniper/src/validation/rules/possible_fragment_spreads.rs b/juniper/src/validation/rules/possible_fragment_spreads.rs index ceb308c9..53ef05a3 100644 --- a/juniper/src/validation/rules/possible_fragment_spreads.rs +++ b/juniper/src/validation/rules/possible_fragment_spreads.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; use crate::{ ast::{Definition, Document, FragmentSpread, InlineFragment}, + meta::InterfaceMeta, parser::Spanning, schema::meta::MetaType, validation::{ValidatorContext, Visitor}, @@ -45,6 +46,23 @@ where .as_ref() .and_then(|s| ctx.schema.concrete_type_by_name(s.item)), ) { + // Even if there is no object type in the overlap of interfaces + // implementers, it's OK to spread in case `frag_type` implements + // `parent_type`. + // https://spec.graphql.org/October2021#sel-JALVFJNRDABABqDy5B + if let MetaType::Interface(InterfaceMeta { + interface_names, .. + }) = frag_type + { + let implements_parent = parent_type + .name() + .map(|parent| interface_names.iter().any(|i| i == parent)) + .unwrap_or_default(); + if implements_parent { + return; + } + } + if !ctx.schema.type_overlap(parent_type, frag_type) { ctx.report_error( &error_message( @@ -67,6 +85,23 @@ where ctx.parent_type(), self.fragment_types.get(spread.item.name.item), ) { + // Even if there is no object type in the overlap of interfaces + // implementers, it's OK to spread in case `frag_type` implements + // `parent_type`. + // https://spec.graphql.org/October2021/#sel-JALVFJNRDABABqDy5B + if let MetaType::Interface(InterfaceMeta { + interface_names, .. + }) = frag_type + { + let implements_parent = parent_type + .name() + .map(|parent| interface_names.iter().any(|i| i == parent)) + .unwrap_or_default(); + if implements_parent { + return; + } + } + if !ctx.schema.type_overlap(parent_type, frag_type) { ctx.report_error( &error_message( @@ -226,6 +261,27 @@ mod tests { ); } + #[test] + fn no_object_overlap_but_implements_parent() { + expect_passes_rule::<_, _, DefaultScalarValue>( + factory, + r#" + fragment beingFragment on Being { ...unpopulatedFragment } + fragment unpopulatedFragment on Unpopulated { name } + "#, + ); + } + + #[test] + fn no_object_overlap_but_implements_parent_inline() { + expect_passes_rule::<_, _, DefaultScalarValue>( + factory, + r#" + fragment beingFragment on Being { ...on Unpopulated { name } } + "#, + ); + } + #[test] fn different_object_into_object() { expect_fails_rule::<_, _, DefaultScalarValue>( diff --git a/juniper/src/validation/test_harness.rs b/juniper/src/validation/test_harness.rs index 5bba0a73..1772b639 100644 --- a/juniper/src/validation/test_harness.rs +++ b/juniper/src/validation/test_harness.rs @@ -20,6 +20,7 @@ use crate::{ struct Being; struct Pet; struct Canine; +struct Unpopulated; struct Dog; struct Cat; @@ -167,6 +168,41 @@ where } } +impl GraphQLType for Unpopulated +where + S: ScalarValue, +{ + fn name(_: &()) -> Option<&'static str> { + Some("Unpopulated") + } + + fn meta<'r>(i: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S> + where + S: 'r, + { + let fields = &[registry + .field::>("name", i) + .argument(registry.arg::>("surname", i))]; + + registry + .build_interface_type::(i, fields) + .interfaces(&[registry.get_type::(i)]) + .into_meta() + } +} + +impl GraphQLValue for Unpopulated +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + impl GraphQLType for DogCommand where S: ScalarValue, @@ -777,6 +813,8 @@ where where S: 'r, { + let _ = registry.get_type::(i); + let fields = [registry.field::("testInput", i).argument( registry.arg_with_default::( "input", diff --git a/juniper_codegen/src/derive_enum.rs b/juniper_codegen/src/derive_enum.rs deleted file mode 100644 index 458bc43e..00000000 --- a/juniper_codegen/src/derive_enum.rs +++ /dev/null @@ -1,153 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{ext::IdentExt, spanned::Spanned, Data, Fields}; - -use crate::{ - result::{GraphQLScope, UnsupportedAttribute}, - util::{self, span_container::SpanContainer, RenameRule}, -}; - -pub fn impl_enum(ast: syn::DeriveInput, error: GraphQLScope) -> syn::Result { - let ast_span = ast.span(); - - if !ast.generics.params.is_empty() { - return Err(error.custom_error(ast_span, "does not support generics or lifetimes")); - } - - let variants = match ast.data { - Data::Enum(enum_data) => enum_data.variants, - _ => return Err(error.custom_error(ast_span, "can only be applied to enums")), - }; - - // Parse attributes. - let attrs = util::ObjectAttributes::from_attrs(&ast.attrs)?; - let ident = &ast.ident; - let name = attrs - .name - .clone() - .map(SpanContainer::into_inner) - .unwrap_or_else(|| ident.unraw().to_string()); - - let fields = variants - .into_iter() - .filter_map(|field| { - let span = field.span(); - let field_attrs = match util::FieldAttributes::from_attrs( - &field.attrs, - util::FieldAttributeParseMode::Object, - ) { - Ok(attrs) => attrs, - Err(err) => { - proc_macro_error::emit_error!(err); - return None; - } - }; - - let field_name = field.ident; - let name = field_attrs - .name - .clone() - .map(SpanContainer::into_inner) - .unwrap_or_else(|| { - attrs - .rename - .unwrap_or(RenameRule::ScreamingSnakeCase) - .apply(&field_name.unraw().to_string()) - }); - - let resolver_code = quote!( #ident::#field_name ); - - let _type = match field.fields { - Fields::Unit => syn::parse_str(&field_name.to_string()).unwrap(), - _ => { - error.emit_custom( - field.fields.span(), - "all fields of the enum must be unnamed, e.g., None", - ); - return None; - } - }; - - if let Some(skip) = field_attrs.skip { - error.unsupported_attribute(skip.span(), UnsupportedAttribute::Skip); - return None; - } - - if name.starts_with("__") { - error.no_double_underscore(if let Some(name) = field_attrs.name { - name.span_ident() - } else { - field_name.span() - }); - } - - if let Some(default) = field_attrs.default { - error.unsupported_attribute_within( - default.span_ident(), - UnsupportedAttribute::Default, - ); - } - - Some(util::GraphQLTypeDefinitionField { - name, - _type, - args: Vec::new(), - description: field_attrs.description.map(SpanContainer::into_inner), - deprecation: field_attrs.deprecation.map(SpanContainer::into_inner), - resolver_code, - is_type_inferred: true, - is_async: false, - default: None, - span, - }) - }) - .collect::>(); - - proc_macro_error::abort_if_dirty(); - - if fields.is_empty() { - error.not_empty(ast_span); - } - if let Some(duplicates) = - crate::util::duplicate::Duplicate::find_by_key(&fields, |field| &field.name) - { - error.duplicate(duplicates.iter()) - } - - if !attrs.interfaces.is_empty() { - attrs.interfaces.iter().for_each(|elm| { - error.unsupported_attribute(elm.span(), UnsupportedAttribute::Interface) - }); - } - - if let Some(scalar) = attrs.scalar { - error.unsupported_attribute(scalar.span_ident(), UnsupportedAttribute::Scalar); - } - - if !attrs.is_internal && name.starts_with("__") { - error.no_double_underscore(if let Some(name) = attrs.name { - name.span_ident() - } else { - ident.span() - }); - } - - proc_macro_error::abort_if_dirty(); - - let definition = util::GraphQLTypeDefiniton { - name, - _type: syn::parse_str(&ast.ident.to_string()).unwrap(), - context: attrs.context.map(SpanContainer::into_inner), - scalar: None, - description: attrs.description.map(SpanContainer::into_inner), - fields, - // NOTICE: only unit variants allow -> no generics possible - generics: syn::Generics::default(), - interfaces: vec![], - include_type_generics: true, - generic_scalar: true, - no_async: attrs.no_async.is_some(), - }; - - Ok(definition.into_enum_tokens()) -} diff --git a/juniper_codegen/src/graphql_enum/derive.rs b/juniper_codegen/src/graphql_enum/derive.rs new file mode 100644 index 00000000..7600226e --- /dev/null +++ b/juniper_codegen/src/graphql_enum/derive.rs @@ -0,0 +1,147 @@ +//! Code generation for `#[derive(GraphQLEnum)]` macro. + +use proc_macro2::TokenStream; +use quote::ToTokens as _; +use std::collections::HashSet; +use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned}; + +use crate::{ + common::scalar, + result::GraphQLScope, + util::{span_container::SpanContainer, RenameRule}, +}; + +use super::{ContainerAttr, Definition, ValueDefinition, VariantAttr}; + +/// [`GraphQLScope`] of errors for `#[derive(GraphQLEnum)]` macro. +const ERR: GraphQLScope = GraphQLScope::EnumDerive; + +/// Expands `#[derive(GraphQLEnum)]` macro into generated code. +pub(crate) fn expand(input: TokenStream) -> syn::Result { + let ast = syn::parse2::(input)?; + let attr = ContainerAttr::from_attrs("graphql", &ast.attrs)?; + + let data = if let syn::Data::Enum(data) = &ast.data { + data + } else { + return Err(ERR.custom_error(ast.span(), "can only be derived on enums")); + }; + + let mut has_ignored_variants = false; + let renaming = attr + .rename_values + .map(SpanContainer::into_inner) + .unwrap_or(RenameRule::ScreamingSnakeCase); + let values = data + .variants + .iter() + .filter_map(|v| { + parse_value(v, renaming).or_else(|| { + has_ignored_variants = true; + None + }) + }) + .collect::>(); + + proc_macro_error::abort_if_dirty(); + + if values.is_empty() { + return Err(ERR.custom_error( + data.variants.span(), + "expected at least 1 non-ignored enum variant", + )); + } + + let unique_values = values.iter().map(|v| &v.name).collect::>(); + if unique_values.len() != values.len() { + return Err(ERR.custom_error( + data.variants.span(), + "expected all GraphQL enum values to have unique names", + )); + } + + let name = attr + .name + .clone() + .map(SpanContainer::into_inner) + .unwrap_or_else(|| ast.ident.unraw().to_string()) + .into_boxed_str(); + if !attr.is_internal && name.starts_with("__") { + ERR.no_double_underscore( + attr.name + .as_ref() + .map(SpanContainer::span_ident) + .unwrap_or_else(|| ast.ident.span()), + ); + } + + let context = attr + .context + .map_or_else(|| parse_quote! { () }, SpanContainer::into_inner); + + let description = attr.description.map(|d| d.into_inner().into_boxed_str()); + + let scalar = scalar::Type::parse(attr.scalar.as_deref(), &ast.generics); + + proc_macro_error::abort_if_dirty(); + + let definition = Definition { + ident: ast.ident, + generics: ast.generics, + name, + description, + context, + scalar, + values, + has_ignored_variants, + }; + + Ok(definition.into_token_stream()) +} + +/// Parses a [`ValueDefinition`] from the given Rust enum variant definition. +/// +/// Returns [`None`] if the parsing fails, or the enum variant is ignored. +fn parse_value(v: &syn::Variant, renaming: RenameRule) -> Option { + let attr = VariantAttr::from_attrs("graphql", &v.attrs) + .map_err(|e| proc_macro_error::emit_error!(e)) + .ok()?; + + if attr.ignore.is_some() { + return None; + } + + if !v.fields.is_empty() { + err_variant_with_fields(&v.fields)?; + } + + let name = attr + .name + .map_or_else( + || renaming.apply(&v.ident.unraw().to_string()), + SpanContainer::into_inner, + ) + .into_boxed_str(); + + let description = attr.description.map(|d| d.into_inner().into_boxed_str()); + + let deprecated = attr.deprecated.map(|desc| { + desc.into_inner() + .as_ref() + .map(|lit| lit.value().into_boxed_str()) + }); + + Some(ValueDefinition { + ident: v.ident.clone(), + name, + description, + deprecated, + }) +} + +/// Emits "no fields allowed for non-ignored variants" [`syn::Error`] pointing +/// to the given `span`. +pub fn err_variant_with_fields(span: &S) -> Option { + ERR.emit_custom(span.span(), "no fields allowed for non-ignored variants"); + None +} diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs new file mode 100644 index 00000000..8556d8b6 --- /dev/null +++ b/juniper_codegen/src/graphql_enum/mod.rs @@ -0,0 +1,790 @@ +//! Code generation for [GraphQL enums][0]. +//! +//! [0]: https://spec.graphql.org/October2021#sec-Enums + +pub(crate) mod derive; + +use std::convert::TryInto as _; + +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::{ + ext::IdentExt as _, + parse::{Parse, ParseStream}, + parse_quote, + spanned::Spanned as _, + token, +}; + +use crate::{ + common::{ + parse::{ + attr::{err, OptionExt as _}, + ParseBufferExt as _, + }, + scalar, + }, + util::{ + filter_attrs, get_deprecated, get_doc_comment, span_container::SpanContainer, RenameRule, + }, +}; + +/// Available arguments behind `#[graphql]` attribute placed on a Rust enum +/// definition, when generating code for a [GraphQL enum][0] type. +/// +/// [0]: https://spec.graphql.org/October2021#sec-Enums +#[derive(Debug, Default)] +struct ContainerAttr { + /// Explicitly specified name of this [GraphQL enum][0]. + /// + /// If [`None`], then Rust enum name will be used by default. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + name: Option>, + + /// Explicitly specified [description][2] of this [GraphQL enum][0]. + /// + /// If [`None`], then Rust doc comment will be used as [description][2], if + /// any. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + /// [2]: https://spec.graphql.org/October2021#sec-Descriptions + description: Option>, + + /// Explicitly specified type of [`Context`] to use for resolving this + /// [GraphQL enum][0] type with. + /// + /// If [`None`], then unit type `()` is assumed as a type of [`Context`]. + /// + /// [`Context`]: juniper::Context + /// [0]: https://spec.graphql.org/October2021#sec-Enums + context: Option>, + + /// Explicitly specified type (or type parameter with its bounds) of + /// [`ScalarValue`] to resolve this [GraphQL enum][0] type with. + /// + /// If [`None`], then generated code will be generic over any + /// [`ScalarValue`] type. + /// + /// [`GraphQLType`]: juniper::GraphQLType + /// [`ScalarValue`]: juniper::ScalarValue + /// [0]: https://spec.graphql.org/October2021#sec-Enums + scalar: Option>, + + /// Explicitly specified [`RenameRule`] for all [values][1] of this + /// [GraphQL enum][0]. + /// + /// If [`None`], then the [`RenameRule::ScreamingSnakeCase`] rule will be + /// applied by default. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + /// [1]: https://spec.graphql.org/October2021#EnumValuesDefinition + rename_values: Option>, + + /// Indicator whether the generated code is intended to be used only inside + /// the [`juniper`] library. + is_internal: bool, +} + +impl Parse for ContainerAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + let mut out = Self::default(); + while !input.is_empty() { + let ident = input.parse_any_ident()?; + match ident.to_string().as_str() { + "name" => { + input.parse::()?; + let name = input.parse::()?; + out.name + .replace(SpanContainer::new( + ident.span(), + Some(name.span()), + name.value(), + )) + .none_or_else(|_| err::dup_arg(&ident))? + } + "desc" | "description" => { + input.parse::()?; + let desc = input.parse::()?; + out.description + .replace(SpanContainer::new( + ident.span(), + Some(desc.span()), + desc.value(), + )) + .none_or_else(|_| err::dup_arg(&ident))? + } + "ctx" | "context" | "Context" => { + input.parse::()?; + let ctx = input.parse::()?; + out.context + .replace(SpanContainer::new(ident.span(), Some(ctx.span()), ctx)) + .none_or_else(|_| err::dup_arg(&ident))? + } + "scalar" | "Scalar" | "ScalarValue" => { + input.parse::()?; + let scl = input.parse::()?; + out.scalar + .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl)) + .none_or_else(|_| err::dup_arg(&ident))? + } + "rename_all" => { + input.parse::()?; + let val = input.parse::()?; + out.rename_values + .replace(SpanContainer::new( + ident.span(), + Some(val.span()), + val.try_into()?, + )) + .none_or_else(|_| err::dup_arg(&ident))?; + } + "internal" => { + out.is_internal = true; + } + name => { + return Err(err::unknown_arg(&ident, name)); + } + } + input.try_parse::()?; + } + Ok(out) + } +} + +impl ContainerAttr { + /// Tries to merge two [`ContainerAttr`]s into a single one, reporting about + /// duplicates, if any. + fn try_merge(self, mut another: Self) -> syn::Result { + Ok(Self { + name: try_merge_opt!(name: self, another), + description: try_merge_opt!(description: self, another), + context: try_merge_opt!(context: self, another), + scalar: try_merge_opt!(scalar: self, another), + rename_values: try_merge_opt!(rename_values: self, another), + is_internal: self.is_internal || another.is_internal, + }) + } + + /// Parses [`ContainerAttr`] from the given multiple `name`d + /// [`syn::Attribute`]s placed on a trait definition. + fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result { + let mut attr = filter_attrs(name, attrs) + .map(|attr| attr.parse_args()) + .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?; + + if attr.description.is_none() { + attr.description = get_doc_comment(attrs); + } + + Ok(attr) + } +} + +/// Available arguments behind `#[graphql]` attribute when generating code for +/// a [GraphQL enum][0]'s [value][1]. +/// +/// [0]: https://spec.graphql.org/October2021#sec-Enums +/// [1]: https://spec.graphql.org/October2021#sec-Enum-Value +#[derive(Debug, Default)] +struct VariantAttr { + /// Explicitly specified name of this [GraphQL enum value][1]. + /// + /// If [`None`], then Rust enum variant's name is used by default. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + name: Option>, + + /// Explicitly specified [description][2] of this [GraphQL enum value][1]. + /// + /// If [`None`], then Rust doc comment is used as [description][2], if any. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + /// [2]: https://spec.graphql.org/October2021#sec-Descriptions + description: Option>, + + /// Explicitly specified [deprecation][2] of this [GraphQL enum value][1]. + /// + /// If [`None`], then Rust `#[deprecated]` attribute is used as the + /// [deprecation][2], if any. + /// + /// If the inner [`Option`] is [`None`], then no [reason][3] was provided. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + /// [2]: https://spec.graphql.org/October2021#sec--deprecated + /// [3]: https://spec.graphql.org/October2021#sel-GAHnBZDACEDDGAA_6L + deprecated: Option>>, + + /// Explicitly specified marker for the Rust enum variant to be ignored and + /// not included into the code generated for a [GraphQL enum][0] + /// implementation. + /// + /// [0]: https://spec.graphql.org/October20210#sec-Enums + ignore: Option>, +} + +impl Parse for VariantAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + let mut out = Self::default(); + while !input.is_empty() { + let ident = input.parse_any_ident()?; + match ident.to_string().as_str() { + "name" => { + input.parse::()?; + let name = input.parse::()?; + out.name + .replace(SpanContainer::new( + ident.span(), + Some(name.span()), + name.value(), + )) + .none_or_else(|_| err::dup_arg(&ident))? + } + "desc" | "description" => { + input.parse::()?; + let desc = input.parse::()?; + out.description + .replace(SpanContainer::new( + ident.span(), + Some(desc.span()), + desc.value(), + )) + .none_or_else(|_| err::dup_arg(&ident))? + } + "deprecated" => { + let mut reason = None; + if input.is_next::() { + input.parse::()?; + reason = Some(input.parse::()?); + } + out.deprecated + .replace(SpanContainer::new( + ident.span(), + reason.as_ref().map(|r| r.span()), + reason, + )) + .none_or_else(|_| err::dup_arg(&ident))? + } + "ignore" | "skip" => out + .ignore + .replace(SpanContainer::new(ident.span(), None, ident.clone())) + .none_or_else(|_| err::dup_arg(&ident))?, + name => { + return Err(err::unknown_arg(&ident, name)); + } + } + input.try_parse::()?; + } + Ok(out) + } +} + +impl VariantAttr { + /// Tries to merge two [`VariantAttr`]s into a single one, reporting about + /// duplicates, if any. + fn try_merge(self, mut another: Self) -> syn::Result { + Ok(Self { + name: try_merge_opt!(name: self, another), + description: try_merge_opt!(description: self, another), + deprecated: try_merge_opt!(deprecated: self, another), + ignore: try_merge_opt!(ignore: self, another), + }) + } + + /// Parses [`VariantAttr`] from the given multiple `name`d + /// [`syn::Attribute`]s placed on a trait definition. + fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result { + let mut attr = filter_attrs(name, attrs) + .map(|attr| attr.parse_args()) + .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?; + + if attr.description.is_none() { + attr.description = get_doc_comment(attrs); + } + + if attr.deprecated.is_none() { + attr.deprecated = get_deprecated(attrs).map(|sc| { + let span = sc.span_ident(); + sc.map(|depr| depr.reason.map(|rsn| syn::LitStr::new(&rsn, span))) + }); + } + + Ok(attr) + } +} + +/// Representation of a [GraphQL enum value][1] for code generation. +/// +/// [1]: https://spec.graphql.org/October2021#sec-Enum-Value +#[derive(Debug)] +struct ValueDefinition { + /// [`Ident`] of the Rust enum variant behind this [GraphQL enum value][1]. + /// + /// [`Ident`]: syn::Ident + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + ident: syn::Ident, + + /// Name of this [GraphQL enum value][1] in GraphQL schema. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + name: Box, + + /// [Description][2] of this [GraphQL enum value][1] to put into GraphQL + /// schema. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + /// [2]: https://spec.graphql.org/October2021#sec-Descriptions + description: Option>, + + /// [Deprecation][2] of this [GraphQL enum value][1] to put into GraphQL + /// schema. + /// + /// If the inner [`Option`] is [`None`], then [deprecation][2] has no + /// [reason][3] attached. + /// + /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value + /// [2]: https://spec.graphql.org/October2021#sec--deprecated + /// [3]: https://spec.graphql.org/October2021#sel-GAHnBZDACEDDGAA_6L + deprecated: Option>>, +} + +/// Representation of a [GraphQL enum][0] for code generation. +/// +/// [0]: https://spec.graphql.org/October2021#sec-Enums +struct Definition { + /// [`Ident`] of the Rust enum behind this [GraphQL enum][0]. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + ident: syn::Ident, + + /// [`syn::Generics`] of the Rust enum behind this [GraphQL enum][0]. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + generics: syn::Generics, + + /// Name of this [GraphQL enum][0] in GraphQL schema. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + name: Box, + + /// [Description][2] of this [GraphQL enum][0] to put into GraphQL schema. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + /// [2]: https://spec.graphql.org/October2021#sec-Descriptions + description: Option>, + + /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with + /// for this [GraphQL enum][0]. + /// + /// [`GraphQLType`]: juniper::GraphQLType + /// [`Context`]: juniper::Context + /// [0]: https://spec.graphql.org/October2021#sec-Enums + context: syn::Type, + + /// [`ScalarValue`] parametrization to generate [`GraphQLType`] + /// implementation with for this [GraphQL enum][0]. + /// + /// [`GraphQLType`]: juniper::GraphQLType + /// [`ScalarValue`]: juniper::ScalarValue + /// [0]: https://spec.graphql.org/October2021#sec-Enums + scalar: scalar::Type, + + /// [Values][1] of this [GraphQL enum][0]. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + /// [1]: https://spec.graphql.org/October2021#EnumValuesDefinition + values: Vec, + + /// Indicates whether the Rust enum behind this [GraphQL enum][0] contains + /// ignored variants. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Enums + has_ignored_variants: bool, +} + +impl ToTokens for Definition { + fn to_tokens(&self, into: &mut TokenStream) { + self.impl_input_and_output_type_tokens().to_tokens(into); + self.impl_graphql_type_tokens().to_tokens(into); + self.impl_graphql_value_tokens().to_tokens(into); + self.impl_graphql_value_async_tokens().to_tokens(into); + self.impl_from_input_value_tokens().to_tokens(into); + self.impl_to_input_value_tokens().to_tokens(into); + self.impl_reflection_traits_tokens().to_tokens(into); + } +} + +impl Definition { + /// Returns generated code implementing [`marker::IsOutputType`] trait for + /// this [GraphQL enum][0]. + /// + /// [`marker::IsOutputType`]: juniper::marker::IsOutputType + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_input_and_output_type_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + quote! { + #[automatically_derived] + impl#impl_generics ::juniper::marker::IsInputType<#scalar> + for #ident#ty_generics + #where_clause {} + + #[automatically_derived] + impl#impl_generics ::juniper::marker::IsOutputType<#scalar> + for #ident#ty_generics + #where_clause {} + } + } + + /// Returns generated code implementing [`GraphQLType`] trait for this + /// [GraphQL enum][0]. + /// + /// [`GraphQLType`]: juniper::GraphQLType + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_graphql_type_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + let name = &self.name; + let description = self + .description + .as_ref() + .map(|desc| quote! { .description(#desc) }); + + let variants_meta = self.values.iter().map(|v| { + let name = &v.name; + let description = v.description.as_ref().map_or_else( + || quote! { None }, + |desc| quote! { Some(String::from(#desc)) }, + ); + let deprecation_status = match &v.deprecated { + None => quote! { ::juniper::meta::DeprecationStatus::Current }, + Some(None) => quote! { + ::juniper::meta::DeprecationStatus::Deprecated(None) + }, + Some(Some(reason)) => { + quote! { + ::juniper::meta::DeprecationStatus::Deprecated( + Some(String::from(#reason)) + ) + } + } + }; + + quote! { + ::juniper::meta::EnumValue { + name: String::from(#name), + description: #description, + deprecation_status: #deprecation_status, + } + } + }); + + quote! { + #[automatically_derived] + impl#impl_generics ::juniper::GraphQLType<#scalar> + for #ident#ty_generics + #where_clause + { + fn name(_ : &Self::TypeInfo) -> Option<&'static str> { + Some(#name) + } + + fn meta<'r>( + info: &Self::TypeInfo, + registry: &mut ::juniper::Registry<'r, #scalar> + ) -> ::juniper::meta::MetaType<'r, #scalar> + where #scalar: 'r, + { + let variants = [#( #variants_meta ),*]; + + registry.build_enum_type::<#ident#ty_generics>(info, &variants) + #description + .into_meta() + } + } + } + } + + /// Returns generated code implementing [`GraphQLValue`] trait for this + /// [GraphQL enum][0]. + /// + /// [`GraphQLValue`]: juniper::GraphQLValue + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_graphql_value_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + let context = &self.context; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + let variants = self.values.iter().map(|v| { + let ident = &v.ident; + let name = &v.name; + + quote! { + Self::#ident => Ok(::juniper::Value::scalar(String::from(#name))), + } + }); + + let ignored = self.has_ignored_variants.then(|| { + quote! { + _ => Err(::juniper::FieldError::<#scalar>::from( + "Cannot resolve ignored enum variant", + )), + } + }); + + quote! { + impl#impl_generics ::juniper::GraphQLValue<#scalar> + for #ident#ty_generics + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } + + fn resolve( + &self, + _: &(), + _: Option<&[::juniper::Selection<#scalar>]>, + _: &::juniper::Executor, + ) -> ::juniper::ExecutionResult<#scalar> { + match self { + #( #variants )* + #ignored + } + } + } + } + } + + /// Returns generated code implementing [`GraphQLValueAsync`] trait for this + /// [GraphQL enum][0]. + /// + /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_graphql_value_async_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + + let generics = self.impl_generics(true); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + quote! { + impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> + for #ident#ty_generics + #where_clause + { + fn resolve_async<'__a>( + &'__a self, + info: &'__a Self::TypeInfo, + selection_set: Option<&'__a [::juniper::Selection<#scalar>]>, + executor: &'__a ::juniper::Executor, + ) -> ::juniper::BoxFuture<'__a, ::juniper::ExecutionResult<#scalar>> { + let v = ::juniper::GraphQLValue::resolve(self, info, selection_set, executor); + Box::pin(::juniper::futures::future::ready(v)) + } + } + } + } + + /// Returns generated code implementing [`FromInputValue`] trait for this + /// [GraphQL enum][0]. + /// + /// [`FromInputValue`]: juniper::FromInputValue + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_from_input_value_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + let variants = self.values.iter().map(|v| { + let ident = &v.ident; + let name = &v.name; + + quote! { + Some(#name) => Ok(Self::#ident), + } + }); + + quote! { + impl#impl_generics ::juniper::FromInputValue<#scalar> + for #ident#ty_generics + #where_clause + { + type Error = ::std::string::String; + + fn from_input_value(v: &::juniper::InputValue<#scalar>) -> Result { + match v.as_enum_value().or_else(|| v.as_string_value()) { + #( #variants )* + _ => Err(::std::format!("Unknown enum value: {}", v)), + } + } + } + } + } + + /// Returns generated code implementing [`ToInputValue`] trait for this + /// [GraphQL enum][0]. + /// + /// [`ToInputValue`]: juniper::ToInputValue + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_to_input_value_tokens(&self) -> TokenStream { + let ident = &self.ident; + let scalar = &self.scalar; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + let variants = self.values.iter().map(|v| { + let var_ident = &v.ident; + let name = &v.name; + + quote! { + #ident::#var_ident => ::juniper::InputValue::<#scalar>::scalar( + String::from(#name), + ), + } + }); + + let ignored = self.has_ignored_variants.then(|| { + quote! { + _ => panic!("Cannot resolve ignored enum variant"), + } + }); + + quote! { + impl#impl_generics ::juniper::ToInputValue<#scalar> + for #ident#ty_generics + #where_clause + { + fn to_input_value(&self) -> ::juniper::InputValue<#scalar> { + match self { + #( #variants )* + #ignored + } + } + } + } + } + + /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and + /// [`WrappedType`] traits for this [GraphQL enum][0]. + /// + /// [`BaseSubTypes`]: juniper::macros::reflect::BaseSubTypes + /// [`BaseType`]: juniper::macros::reflect::BaseType + /// [`WrappedType`]: juniper::macros::reflect::WrappedType + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_reflection_traits_tokens(&self) -> TokenStream { + let ident = &self.ident; + let name = &self.name; + let scalar = &self.scalar; + + let generics = self.impl_generics(false); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.generics.split_for_impl(); + + quote! { + impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar> + for #ident#ty_generics + #where_clause + { + const NAME: ::juniper::macros::reflect::Type = #name; + } + + impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar> + for #ident#ty_generics + #where_clause + { + const NAMES: ::juniper::macros::reflect::Types = + &[>::NAME]; + } + + impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar> + for #ident#ty_generics + #where_clause + { + const VALUE: ::juniper::macros::reflect::WrappedValue = 1; + } + } + } + + /// Returns prepared [`syn::Generics`] for [`GraphQLType`] trait (and + /// similar) implementation of this enum. + /// + /// If `for_async` is `true`, then additional predicates are added to suit + /// the [`GraphQLAsyncValue`] trait (and similar) requirements. + /// + /// [`GraphQLAsyncValue`]: juniper::GraphQLAsyncValue + /// [`GraphQLType`]: juniper::GraphQLType + fn impl_generics(&self, for_async: bool) -> syn::Generics { + let mut generics = self.generics.clone(); + + let scalar = &self.scalar; + if scalar.is_implicit_generic() { + generics.params.push(parse_quote! { #scalar }); + } + if scalar.is_generic() { + generics + .make_where_clause() + .predicates + .push(parse_quote! { #scalar: ::juniper::ScalarValue }); + } + if let Some(bound) = scalar.bounds() { + generics.make_where_clause().predicates.push(bound); + } + + if for_async { + let self_ty = if self.generics.lifetimes().next().is_some() { + // Modify lifetime names to omit "lifetime name `'a` shadows a + // lifetime name that is already in scope" error. + let mut generics = self.generics.clone(); + for lt in generics.lifetimes_mut() { + let ident = lt.lifetime.ident.unraw(); + lt.lifetime.ident = format_ident!("__fa__{}", ident); + } + + let lifetimes = generics.lifetimes().map(|lt| <.lifetime); + let ident = &self.ident; + let (_, ty_generics, _) = generics.split_for_impl(); + + quote! { for<#( #lifetimes ),*> #ident#ty_generics } + } else { + quote! { Self } + }; + generics + .make_where_clause() + .predicates + .push(parse_quote! { #self_ty: Sync }); + + if scalar.is_generic() { + generics + .make_where_clause() + .predicates + .push(parse_quote! { #scalar: Send + Sync }); + } + } + + generics + } +} diff --git a/juniper_codegen/src/graphql_interface/attr.rs b/juniper_codegen/src/graphql_interface/attr.rs index 505e02db..dc4a52ff 100644 --- a/juniper_codegen/src/graphql_interface/attr.rs +++ b/juniper_codegen/src/graphql_interface/attr.rs @@ -55,7 +55,8 @@ fn expand_on_trait( .name .clone() .map(SpanContainer::into_inner) - .unwrap_or_else(|| trait_ident.unraw().to_string()); + .unwrap_or_else(|| trait_ident.unraw().to_string()) + .into_boxed_str(); if !attr.is_internal && name.starts_with("__") { ERR.no_double_underscore( attr.name @@ -120,18 +121,23 @@ fn expand_on_trait( enum_ident, enum_alias_ident, name, - description: attr.description.as_deref().cloned(), + description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), fields, implemented_for: attr .implemented_for - .iter() - .map(|c| c.inner().clone()) + .into_iter() + .map(SpanContainer::into_inner) + .collect(), + implements: attr + .implements + .into_iter() + .map(SpanContainer::into_inner) .collect(), suppress_dead_code: None, - src_intra_doc_link: format!("trait@{}", trait_ident), + src_intra_doc_link: format!("trait@{}", trait_ident).into_boxed_str(), }; Ok(quote! { @@ -244,7 +250,8 @@ fn expand_on_derive_input( .name .clone() .map(SpanContainer::into_inner) - .unwrap_or_else(|| struct_ident.unraw().to_string()); + .unwrap_or_else(|| struct_ident.unraw().to_string()) + .into_boxed_str(); if !attr.is_internal && name.starts_with("__") { ERR.no_double_underscore( attr.name @@ -303,18 +310,23 @@ fn expand_on_derive_input( enum_ident, enum_alias_ident, name, - description: attr.description.as_deref().cloned(), + description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), fields, implemented_for: attr .implemented_for - .iter() - .map(|c| c.inner().clone()) + .into_iter() + .map(SpanContainer::into_inner) + .collect(), + implements: attr + .implements + .into_iter() + .map(SpanContainer::into_inner) .collect(), suppress_dead_code: None, - src_intra_doc_link: format!("struct@{}", struct_ident), + src_intra_doc_link: format!("struct@{}", struct_ident).into_boxed_str(), }; Ok(quote! { diff --git a/juniper_codegen/src/graphql_interface/derive.rs b/juniper_codegen/src/graphql_interface/derive.rs index 5cc51e7d..135b7c33 100644 --- a/juniper_codegen/src/graphql_interface/derive.rs +++ b/juniper_codegen/src/graphql_interface/derive.rs @@ -33,7 +33,8 @@ pub fn expand(input: TokenStream) -> syn::Result { .name .clone() .map(SpanContainer::into_inner) - .unwrap_or_else(|| struct_ident.unraw().to_string()); + .unwrap_or_else(|| struct_ident.unraw().to_string()) + .into_boxed_str(); if !attr.is_internal && name.starts_with("__") { ERR.no_double_underscore( attr.name @@ -93,18 +94,23 @@ pub fn expand(input: TokenStream) -> syn::Result { enum_ident, enum_alias_ident, name, - description: attr.description.as_deref().cloned(), + description: attr.description.map(|d| d.into_inner().into_boxed_str()), context, scalar, behavior: attr.behavior.map(|bh| bh.into_inner()).unwrap_or_default(), fields, implemented_for: attr .implemented_for - .iter() - .map(|c| c.inner().clone()) + .into_iter() + .map(SpanContainer::into_inner) + .collect(), + implements: attr + .implements + .into_iter() + .map(SpanContainer::into_inner) .collect(), suppress_dead_code: Some((ast.ident.clone(), data.fields.clone())), - src_intra_doc_link: format!("struct@{}", struct_ident), + src_intra_doc_link: format!("struct@{}", struct_ident).into_boxed_str(), } .into_token_stream()) } diff --git a/juniper_codegen/src/graphql_interface/mod.rs b/juniper_codegen/src/graphql_interface/mod.rs index fae35157..b8c642c8 100644 --- a/juniper_codegen/src/graphql_interface/mod.rs +++ b/juniper_codegen/src/graphql_interface/mod.rs @@ -81,13 +81,20 @@ struct Attr { /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces r#enum: Option>, - /// Explicitly specified Rust types of [GraphQL objects][2] implementing - /// this [GraphQL interface][1] type. + /// Explicitly specified Rust types of [GraphQL objects][2] or + /// [interfaces][1] implementing this [GraphQL interface][1] type. /// /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces /// [2]: https://spec.graphql.org/June2018/#sec-Objects implemented_for: HashSet>, + /// Explicitly specified [GraphQL interfaces, implemented][1] by this + /// [GraphQL interface][0]. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Interfaces + /// [1]: https://spec.graphql.org/October2021#sel-GAHbhBDABAB_E-0b + implements: HashSet>, + /// Explicitly specified type of [`Context`] to use for resolving this /// [GraphQL interface][1] type with. /// @@ -203,6 +210,18 @@ impl Parse for Attr { .none_or_else(|_| err::dup_arg(impler_span))?; } } + "impl" | "implements" => { + input.parse::()?; + for iface in input.parse_maybe_wrapped_and_punctuated::< + syn::TypePath, token::Bracket, token::Comma, + >()? { + let iface_span = iface.span(); + out + .implements + .replace(SpanContainer::new(ident.span(), Some(iface_span), iface)) + .none_or_else(|_| err::dup_arg(iface_span))?; + } + } "enum" => { input.parse::()?; let alias = input.parse::()?; @@ -251,6 +270,7 @@ impl Attr { scalar: try_merge_opt!(scalar: self, another), behavior: try_merge_opt!(behavior: self, another), implemented_for: try_merge_hashset!(implemented_for: self, another => span_joined), + implements: try_merge_hashset!(implements: self, another => span_joined), r#enum: try_merge_opt!(r#enum: self, another), asyncness: try_merge_opt!(asyncness: self, another), rename_fields: try_merge_opt!(rename_fields: self, another), @@ -302,15 +322,15 @@ struct Definition { /// [`implementers`]: Self::implementers enum_alias_ident: syn::Ident, - /// Name of this [GraphQL interface][1] in GraphQL schema. + /// Name of this [GraphQL interface][0] in GraphQL schema. /// - /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces - name: String, + /// [0]: https://spec.graphql.org/October2021#sec-Interfaces + name: Box, - /// Description of this [GraphQL interface][1] to put into GraphQL schema. + /// Description of this [GraphQL interface][0] to put into GraphQL schema. /// - /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces - description: Option, + /// [0]: https://spec.graphql.org/October2021#sec-Interfaces + description: Option>, /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with /// for this [GraphQL interface][1]. @@ -346,6 +366,12 @@ struct Definition { /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces implemented_for: Vec, + /// [GraphQL interfaces implemented][1] by this [GraphQL interface][0]. + /// + /// [0]: https://spec.graphql.org/October2021#sec-Interfaces + /// [1]: https://spec.graphql.org/October2021#sel-GAHbhBDABAB_E-0b + implements: Vec, + /// Unlike `#[graphql_interface]` maro, `#[derive(GraphQLInterface)]` can't /// append `#[allow(dead_code)]` to the unused struct, representing /// [GraphQL interface][1]. We generate hacky `const` which doesn't actually @@ -355,10 +381,10 @@ struct Definition { suppress_dead_code: Option<(syn::Ident, syn::Fields)>, /// Intra-doc link to the [`syn::Item`] defining this - /// [GraphQL interface][1]. + /// [GraphQL interface][0]. /// - /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces - src_intra_doc_link: String, + /// [0]: https://spec.graphql.org/October2021#sec-Interfaces + src_intra_doc_link: Box, } impl ToTokens for Definition { @@ -524,11 +550,6 @@ impl Definition { let (impl_generics, _, where_clause) = gens.split_for_impl(); let (_, ty_generics, _) = self.generics.split_for_impl(); - let implemented_for = &self.implemented_for; - let all_impled_for_unique = (implemented_for.len() > 1).then(|| { - quote! { ::juniper::sa::assert_type_ne_all!(#( #implemented_for ),*); } - }); - let suppress_dead_code = self.suppress_dead_code.as_ref().map(|(ident, fields)| { let const_gens = self.const_trait_generics(); let fields = fields.iter().map(|f| &f.ident); @@ -547,6 +568,49 @@ impl Definition { }} }); + let implemented_for = &self.implemented_for; + let all_impled_for_unique = (implemented_for.len() > 1).then(|| { + quote! { ::juniper::sa::assert_type_ne_all!(#( #implemented_for ),*); } + }); + + let mark_object_or_interface = self.implemented_for.iter().map(|impl_for| { + quote_spanned! { impl_for.span() => + trait GraphQLObjectOrInterface { + fn mark(); + } + + { + struct Object; + + impl GraphQLObjectOrInterface for T + where + S: ::juniper::ScalarValue, + T: ::juniper::marker::GraphQLObject, + { + fn mark() { + >::mark() + } + } + } + + { + struct Interface; + + impl GraphQLObjectOrInterface for T + where + S: ::juniper::ScalarValue, + T: ::juniper::marker::GraphQLInterface, + { + fn mark() { + >::mark() + } + } + } + + <#impl_for as GraphQLObjectOrInterface<#scalar, _>>::mark(); + } + }); + quote! { #[automatically_derived] impl#impl_generics ::juniper::marker::GraphQLInterface<#scalar> @@ -556,7 +620,7 @@ impl Definition { fn mark() { #suppress_dead_code #all_impled_for_unique - #( <#implemented_for as ::juniper::marker::GraphQLObject<#scalar>>::mark(); )* + #( { #mark_object_or_interface } )* } } } @@ -593,6 +657,25 @@ impl Definition { generics.replace_type_path_with_defaults(&mut ty); ty }); + let const_implements = self + .implements + .iter() + .cloned() + .map(|mut ty| { + generics.replace_type_path_with_defaults(&mut ty); + ty + }) + .collect::>(); + let transitive_checks = const_impl_for.clone().map(|const_impl_for| { + quote_spanned! { const_impl_for.span() => + ::juniper::assert_transitive_impls!( + #const_scalar, + #ty#ty_const_generics, + #const_impl_for, + #( #const_implements ),* + ); + } + }); quote! { #[automatically_derived] @@ -608,6 +691,12 @@ impl Definition { #ty#ty_const_generics, #( #const_impl_for ),* ); + ::juniper::assert_implemented_for!( + #const_scalar, + #ty#ty_const_generics, + #( #const_implements ),* + ); + #( #transitive_checks )* } } } @@ -640,6 +729,20 @@ impl Definition { a.cmp(&b) }); + // Sorting is required to preserve/guarantee the order of interfaces registered in schema. + let mut implements = self.implements.clone(); + implements.sort_unstable_by(|a, b| { + let (a, b) = (quote!(#a).to_string(), quote!(#b).to_string()); + a.cmp(&b) + }); + let impl_interfaces = (!implements.is_empty()).then(|| { + quote! { + .interfaces(&[ + #( registry.get_type::<#implements>(info), )* + ]) + } + }); + let fields_meta = self.fields.iter().map(|f| f.method_meta_tokens(None)); quote! { @@ -666,6 +769,7 @@ impl Definition { ]; registry.build_interface_type::<#ty#ty_generics>(info, &fields) #description + #impl_interfaces .into_meta() } } @@ -829,6 +933,7 @@ impl Definition { fn impl_reflection_traits_tokens(&self) -> TokenStream { let ty = &self.enum_alias_ident; let implemented_for = &self.implemented_for; + let implements = &self.implements; let scalar = &self.scalar; let name = &self.name; let fields = self.fields.iter().map(|f| &f.name); @@ -857,6 +962,15 @@ impl Definition { ]; } + #[automatically_derived] + impl#impl_generics ::juniper::macros::reflect::Implements<#scalar> + for #ty#ty_generics + #where_clause + { + const NAMES: ::juniper::macros::reflect::Types = + &[#( <#implements as ::juniper::macros::reflect::BaseType<#scalar>>::NAME ),*]; + } + #[automatically_derived] impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar> for #ty#ty_generics @@ -891,6 +1005,7 @@ impl Definition { let name = &self.name; let implers = &self.implemented_for; + let interfaces = &self.implements; let fields = self.fields.iter().map(|f| &f.name); quote! { @@ -911,6 +1026,15 @@ impl Definition { ]; } + #[automatically_derived] + impl#impl_gens ::juniper::reflect::Implements<#bh> for #ty + #where_clause + { + const NAMES: ::juniper::reflect::Types = &[#( + <#interfaces as ::juniper::reflect::BaseType<#bh>>::NAME + ),*]; + } + #[automatically_derived] impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty #where_clause diff --git a/juniper_codegen/src/lib.rs b/juniper_codegen/src/lib.rs index 1c7da4db..70c346ee 100644 --- a/juniper_codegen/src/lib.rs +++ b/juniper_codegen/src/lib.rs @@ -100,10 +100,10 @@ macro_rules! try_merge_hashset { }; } -mod derive_enum; mod derive_input_object; mod common; +mod graphql_enum; mod graphql_interface; mod graphql_object; mod graphql_scalar; @@ -115,17 +115,6 @@ use proc_macro::TokenStream; use proc_macro_error::{proc_macro_error, ResultExt as _}; use result::GraphQLScope; -#[proc_macro_error] -#[proc_macro_derive(GraphQLEnum, attributes(graphql))] -pub fn derive_enum(input: TokenStream) -> TokenStream { - let ast = syn::parse::(input).unwrap(); - let gen = derive_enum::impl_enum(ast, GraphQLScope::DeriveEnum); - match gen { - Ok(gen) => gen.into(), - Err(err) => proc_macro_error::abort!(err), - } -} - #[proc_macro_error] #[proc_macro_derive(GraphQLInputObject, attributes(graphql))] pub fn derive_input_object(input: TokenStream) -> TokenStream { @@ -137,6 +126,133 @@ pub fn derive_input_object(input: TokenStream) -> TokenStream { } } +/// `#[derive(GraphQLEnum)]` macro for deriving a [GraphQL enum][0] +/// implementation for Rust enums. +/// +/// The `#[graphql]` helper attribute is used for configuring the derived +/// implementation. Specifying multiple `#[graphql]` attributes on the same +/// definition is totally okay. They all will be treated as a single attribute. +/// +/// ```rust +/// use juniper::GraphQLEnum; +/// +/// #[derive(GraphQLEnum)] +/// enum Episode { +/// NewHope, +/// Empire, +/// Jedi, +/// } +/// ``` +/// +/// # Custom name, description and deprecation +/// +/// The name of a [GraphQL enum][0] or its [values][1] may be overridden with +/// the `name` attribute's argument. By default, a type name is used or a +/// variant name in `SCREAMING_SNAKE_CASE`. +/// +/// The description of a [GraphQL enum][0] or its [values][1] may be specified +/// either with the `description`/`desc` attribute's argument, or with a regular +/// Rust doc comment. +/// +/// [GraphQL enum value][1] may be deprecated by specifying the `deprecated` +/// attribute's argument, or with regular a Rust `#[deprecated]` attribute. +/// +/// ```rust +/// # use juniper::GraphQLEnum; +/// # +/// #[derive(GraphQLEnum)] +/// #[graphql( +/// // Rename the type for GraphQL by specifying the name here. +/// name = "AvailableEpisodes", +/// // You may also specify a description here. +/// // If present, doc comments will be ignored. +/// desc = "Possible episodes.", +/// )] +/// enum Episode { +/// /// Doc comment, also acting as description. +/// #[deprecated(note = "Don't use it")] +/// NewHope, +/// +/// #[graphql(name = "Jedi", desc = "Arguably the best one in the trilogy")] +/// #[graphql(deprecated = "Don't use it")] +/// Jedai, +/// +/// Empire, +/// } +/// ``` +/// +/// # Renaming policy +/// +/// By default, all [GraphQL enum values][1] are renamed in a +/// `SCREAMING_SNAKE_CASE` manner (so a `NewHope` Rust enum variant becomes a +/// `NEW_HOPE` [value][1] in GraphQL schema, and so on). This complies with +/// default GraphQL naming conventions as [demonstrated in spec][0]. +/// +/// However, if you need for some reason another naming convention, it's +/// possible to do so by using the `rename_all` attribute's argument. At the +/// moment, it supports the following policies only: `SCREAMING_SNAKE_CASE`, +/// `camelCase`, `none` (disables any renaming). +/// +/// ```rust +/// # use juniper::GraphQLEnum; +/// # +/// #[derive(GraphQLEnum)] +/// #[graphql(rename_all = "none")] // disables renaming +/// enum Episode { +/// NewHope, +/// Empire, +/// Jedi, +/// } +/// ``` +/// +/// # Ignoring enum variants +/// +/// To omit exposing a Rust enum variant in a GraphQL schema, use the `ignore` +/// attribute's argument directly on that variant. Only ignored Rust enum +/// variants are allowed to contain fields. +/// +/// ```rust +/// # use juniper::GraphQLEnum; +/// # +/// #[derive(GraphQLEnum)] +/// enum Episode { +/// NewHope, +/// Empire, +/// Jedi, +/// #[graphql(ignore)] +/// Legends(T), +/// } +/// ``` +/// +/// # Custom `ScalarValue` +/// +/// By default, `#[derive(GraphQLEnum)]` macro generates code, which is generic +/// over a [`ScalarValue`] type. This can be changed with the `scalar` +/// attribute's argument. +/// +/// ```rust +/// # use juniper::{DefaultScalarValue, GraphQLEnum}; +/// # +/// #[derive(GraphQLEnum)] +/// #[graphql(scalar = DefaultScalarValue)] +/// enum Episode { +/// NewHope, +/// Empire, +/// Jedi, +/// } +/// ``` +/// +/// [`ScalarValue`]: juniper::ScalarValue +/// [0]: https://spec.graphql.org/October2021#sec-Enums +/// [1]: https://spec.graphql.org/October2021#sec-Enum-Value +#[proc_macro_error] +#[proc_macro_derive(GraphQLEnum, attributes(graphql))] +pub fn derive_enum(input: TokenStream) -> TokenStream { + graphql_enum::derive::expand(input.into()) + .unwrap_or_abort() + .into() +} + /// `#[derive(GraphQLScalar)]` macro for deriving a [GraphQL scalar][0] /// implementation. /// @@ -757,6 +873,125 @@ pub fn derive_scalar_value(input: TokenStream) -> TokenStream { /// } /// ``` /// +/// # Interfaces implementing other interfaces +/// +/// GraphQL allows implementing interfaces on other interfaces in addition to +/// objects. +/// +/// > __NOTE:__ Every interface has to specify all other interfaces/objects it +/// > implements or is implemented for. Missing one of `for = ` or +/// > `impl = ` attributes is an understandable compile-time error. +/// +/// ```rust +/// # extern crate juniper; +/// use juniper::{graphql_interface, graphql_object, ID}; +/// +/// #[graphql_interface(for = [HumanValue, Luke])] +/// struct Node { +/// id: ID, +/// } +/// +/// #[graphql_interface(impl = NodeValue, for = Luke)] +/// struct Human { +/// id: ID, +/// home_planet: String, +/// } +/// +/// struct Luke { +/// id: ID, +/// } +/// +/// #[graphql_object(impl = [HumanValue, NodeValue])] +/// impl Luke { +/// fn id(&self) -> &ID { +/// &self.id +/// } +/// +/// // As `String` and `&str` aren't distinguished by +/// // GraphQL spec, you can use them interchangeably. +/// // Same is applied for `Cow<'a, str>`. +/// // ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄ +/// fn home_planet() -> &'static str { +/// "Tatooine" +/// } +/// } +/// ``` +/// +/// # GraphQL subtyping and additional `null`able fields +/// +/// GraphQL allows implementers (both objects and other interfaces) to return +/// "subtypes" instead of an original value. Basically, this allows you to +/// impose additional bounds on the implementation. +/// +/// Valid "subtypes" are: +/// - interface implementer instead of an interface itself: +/// - `I implements T` in place of a `T`; +/// - `Vec` in place of a `Vec`. +/// - non-`null` value in place of a `null`able: +/// - `T` in place of a `Option`; +/// - `Vec` in place of a `Vec>`. +/// +/// These rules are recursively applied, so `Vec>` is a +/// valid "subtype" of a `Option>>>>`. +/// +/// Also, GraphQL allows implementers to add `null`able fields, which aren't +/// present on an original interface. +/// +/// ```rust +/// # extern crate juniper; +/// use juniper::{graphql_interface, graphql_object, ID}; +/// +/// #[graphql_interface(for = [HumanValue, Luke])] +/// struct Node { +/// id: ID, +/// } +/// +/// #[graphql_interface(for = HumanConnectionValue)] +/// struct Connection { +/// nodes: Vec, +/// } +/// +/// #[graphql_interface(impl = NodeValue, for = Luke)] +/// struct Human { +/// id: ID, +/// home_planet: String, +/// } +/// +/// #[graphql_interface(impl = ConnectionValue)] +/// struct HumanConnection { +/// nodes: Vec, +/// // ^^^^^^^^^^ notice not `NodeValue` +/// // This can happen, because every `Human` is a `Node` too, so we are +/// // just imposing additional bounds, which still can be resolved with +/// // `... on Connection { nodes }`. +/// } +/// +/// struct Luke { +/// id: ID, +/// } +/// +/// #[graphql_object(impl = [HumanValue, NodeValue])] +/// impl Luke { +/// fn id(&self) -> &ID { +/// &self.id +/// } +/// +/// fn home_planet(language: Option) -> &'static str { +/// // ^^^^^^^^^^^^^^ +/// // Notice additional `null`able field, which is missing on `Human`. +/// // Resolving `...on Human { homePlanet }` will provide `None` for +/// // this argument. +/// match language.as_deref() { +/// None | Some("en") => "Tatooine", +/// Some("ko") => "타투인", +/// _ => todo!(), +/// } +/// } +/// } +/// # +/// # fn main() {} +/// ``` +/// /// # Renaming policy /// /// By default, all [GraphQL interface][1] fields and their arguments are renamed diff --git a/juniper_codegen/src/result.rs b/juniper_codegen/src/result.rs index 8b58339a..5c979d69 100644 --- a/juniper_codegen/src/result.rs +++ b/juniper_codegen/src/result.rs @@ -9,6 +9,7 @@ use std::fmt; pub const SPEC_URL: &str = "https://spec.graphql.org/June2018/"; pub enum GraphQLScope { + EnumDerive, InterfaceAttr, InterfaceDerive, ObjectAttr, @@ -19,19 +20,18 @@ pub enum GraphQLScope { UnionAttr, UnionDerive, DeriveInputObject, - DeriveEnum, } impl GraphQLScope { pub fn spec_section(&self) -> &str { match self { + Self::EnumDerive => "#sec-Enums", Self::InterfaceAttr | Self::InterfaceDerive => "#sec-Interfaces", Self::ObjectAttr | Self::ObjectDerive => "#sec-Objects", Self::ScalarAttr | Self::ScalarDerive => "#sec-Scalars", Self::ScalarValueDerive => "#sec-Scalars.Built-in-Scalars", Self::UnionAttr | Self::UnionDerive => "#sec-Unions", Self::DeriveInputObject => "#sec-Input-Objects", - Self::DeriveEnum => "#sec-Enums", } } } @@ -39,13 +39,13 @@ impl GraphQLScope { impl fmt::Display for GraphQLScope { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let name = match self { + Self::EnumDerive => "enum", Self::InterfaceAttr | Self::InterfaceDerive => "interface", Self::ObjectAttr | Self::ObjectDerive => "object", Self::ScalarAttr | Self::ScalarDerive => "scalar", Self::ScalarValueDerive => "built-in scalars", Self::UnionAttr | Self::UnionDerive => "union", Self::DeriveInputObject => "input object", - Self::DeriveEnum => "enum", }; write!(f, "GraphQL {}", name) } @@ -56,9 +56,7 @@ impl fmt::Display for GraphQLScope { pub enum UnsupportedAttribute { Skip, Interface, - Scalar, Deprecation, - Default, } impl GraphQLScope { diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs index d83cc000..19b70a0a 100644 --- a/juniper_codegen/src/util/mod.rs +++ b/juniper_codegen/src/util/mod.rs @@ -683,232 +683,6 @@ impl GraphQLTypeDefiniton { self.fields.iter().any(|field| field.is_async) } - pub fn into_enum_tokens(self) -> TokenStream { - let name = &self.name; - let ty = &self._type; - let context = self - .context - .as_ref() - .map(|ctx| quote!( #ctx )) - .unwrap_or_else(|| quote!(())); - - let scalar = self - .scalar - .as_ref() - .map(|s| quote!( #s )) - .unwrap_or_else(|| { - if self.generic_scalar { - // If generic_scalar is true, we always insert a generic scalar. - // See more comments below. - quote!(__S) - } else { - quote!(::juniper::DefaultScalarValue) - } - }); - - let description = self - .description - .as_ref() - .map(|description| quote!( .description(#description) )); - - let values = self.fields.iter().map(|variant| { - let variant_name = &variant.name; - - let descr = variant - .description - .as_ref() - .map(|description| quote!(Some(#description.to_string()))) - .unwrap_or_else(|| quote!(None)); - - let depr = variant - .deprecation - .as_ref() - .map(|deprecation| match deprecation.reason.as_ref() { - Some(reason) => quote!( ::juniper::meta::DeprecationStatus::Deprecated(Some(#reason.to_string())) ), - None => quote!( ::juniper::meta::DeprecationStatus::Deprecated(None) ), - }) - .unwrap_or_else(|| quote!(::juniper::meta::DeprecationStatus::Current)); - - quote!( - ::juniper::meta::EnumValue { - name: #variant_name.to_string(), - description: #descr, - deprecation_status: #depr, - }, - ) - }); - - let resolves = self.fields.iter().map(|variant| { - let variant_name = &variant.name; - let resolver_code = &variant.resolver_code; - - quote!( - &#resolver_code => ::juniper::Value::scalar(String::from(#variant_name)), - ) - }); - - let from_inputs = self.fields.iter().map(|variant| { - let variant_name = &variant.name; - let resolver_code = &variant.resolver_code; - - quote!( - Some(#variant_name) => Ok(#resolver_code), - ) - }); - - let to_inputs = self.fields.iter().map(|variant| { - let variant_name = &variant.name; - let resolver_code = &variant.resolver_code; - - quote!( - &#resolver_code => - ::juniper::InputValue::scalar(#variant_name.to_string()), - ) - }); - - let mut generics = self.generics.clone(); - - if self.scalar.is_none() && self.generic_scalar { - // No custom scalar specified, but always generic specified. - // Therefore we inject the generic scalar. - - generics.params.push(parse_quote!(__S)); - - let where_clause = generics.where_clause.get_or_insert(parse_quote!(where)); - // Insert ScalarValue constraint. - where_clause - .predicates - .push(parse_quote!(__S: ::juniper::ScalarValue)); - } - - let (impl_generics, _, where_clause) = generics.split_for_impl(); - - let mut where_async = where_clause.cloned().unwrap_or_else(|| parse_quote!(where)); - where_async - .predicates - .push(parse_quote!( #scalar: Send + Sync )); - where_async.predicates.push(parse_quote!(Self: Sync)); - - let _async = quote!( - impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty - #where_async - { - fn resolve_async<'a>( - &'a self, - info: &'a Self::TypeInfo, - selection_set: Option<&'a [::juniper::Selection<#scalar>]>, - executor: &'a ::juniper::Executor, - ) -> ::juniper::BoxFuture<'a, ::juniper::ExecutionResult<#scalar>> { - use ::juniper::futures::future; - let v = ::juniper::GraphQLValue::resolve(self, info, selection_set, executor); - Box::pin(future::ready(v)) - } - } - ); - - let mut body = quote!( - impl#impl_generics ::juniper::marker::IsInputType<#scalar> for #ty - #where_clause { } - - impl#impl_generics ::juniper::marker::IsOutputType<#scalar> for #ty - #where_clause { } - - impl#impl_generics ::juniper::GraphQLType<#scalar> for #ty - #where_clause - { - fn name(_: &()) -> Option<&'static str> { - Some(#name) - } - - fn meta<'r>( - _: &(), - registry: &mut ::juniper::Registry<'r, #scalar> - ) -> ::juniper::meta::MetaType<'r, #scalar> - where #scalar: 'r, - { - registry.build_enum_type::<#ty>(&(), &[ - #( #values )* - ]) - #description - .into_meta() - } - } - - impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty - #where_clause - { - type Context = #context; - type TypeInfo = (); - - fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { - >::name(info) - } - - fn resolve( - &self, - _: &(), - _: Option<&[::juniper::Selection<#scalar>]>, - _: &::juniper::Executor - ) -> ::juniper::ExecutionResult<#scalar> { - let v = match self { - #( #resolves )* - }; - Ok(v) - } - } - - impl#impl_generics ::juniper::FromInputValue<#scalar> for #ty - #where_clause - { - type Error = ::std::string::String; - - fn from_input_value( - v: &::juniper::InputValue<#scalar> - ) -> Result<#ty, Self::Error> { - match v.as_enum_value().or_else(|| v.as_string_value()) { - #( #from_inputs )* - _ => Err(format!("Unknown enum value: {}", v)), - } - } - } - - impl#impl_generics ::juniper::ToInputValue<#scalar> for #ty - #where_clause - { - fn to_input_value(&self) -> ::juniper::InputValue<#scalar> { - match self { - #( #to_inputs )* - } - } - } - - impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar> for #ty - #where_clause - { - const NAME: ::juniper::macros::reflect::Type = #name; - } - - impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar> for #ty - #where_clause - { - const NAMES: ::juniper::macros::reflect::Types = - &[>::NAME]; - } - - impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar> for #ty - #where_clause - { - const VALUE: ::juniper::macros::reflect::WrappedValue = 1; - } - ); - - if !self.no_async { - body.extend(_async) - } - - body - } - pub fn into_input_object_tokens(self) -> TokenStream { let name = &self.name; let ty = &self._type; diff --git a/juniper_codegen/src/util/span_container.rs b/juniper_codegen/src/util/span_container.rs index 370f17a7..8b4c6b58 100644 --- a/juniper_codegen/src/util/span_container.rs +++ b/juniper_codegen/src/util/span_container.rs @@ -45,10 +45,6 @@ impl SpanContainer { self.val } - pub fn inner(&self) -> &T { - &self.val - } - pub fn map U>(self, f: F) -> SpanContainer { SpanContainer { expr: self.expr, diff --git a/tests/codegen/Cargo.toml b/tests/codegen/Cargo.toml index eb513bf3..f08b1f1a 100644 --- a/tests/codegen/Cargo.toml +++ b/tests/codegen/Cargo.toml @@ -9,6 +9,6 @@ futures = "0.3.1" juniper = { path = "../../juniper" } [dev-dependencies] -serde_json = { version = "1.0" } +serde_json = "1.0" tokio = { version = "1.0", features = ["rt", "time", "macros"] } trybuild = "1.0.25" diff --git a/tests/codegen/fail/enum/derive_duplicated_value_names.rs b/tests/codegen/fail/enum/derive_duplicated_value_names.rs new file mode 100644 index 00000000..3044f379 --- /dev/null +++ b/tests/codegen/fail/enum/derive_duplicated_value_names.rs @@ -0,0 +1,10 @@ +use juniper::GraphQLEnum; + +#[derive(GraphQLEnum)] +enum Test { + Test, + #[graphql(name = "TEST")] + Test1, +} + +fn main() {} diff --git a/tests/codegen/fail/enum/derive_duplicated_value_names.stderr b/tests/codegen/fail/enum/derive_duplicated_value_names.stderr new file mode 100644 index 00000000..8b5ca830 --- /dev/null +++ b/tests/codegen/fail/enum/derive_duplicated_value_names.stderr @@ -0,0 +1,7 @@ +error: GraphQL enum expected all GraphQL enum values to have unique names + --> fail/enum/derive_duplicated_value_names.rs:5:5 + | +5 | / Test, +6 | | #[graphql(name = "TEST")] +7 | | Test1, + | |__________^ diff --git a/tests/codegen/fail/enum/derive_name_double_underscored.rs b/tests/codegen/fail/enum/derive_name_double_underscored.rs new file mode 100644 index 00000000..11c9d708 --- /dev/null +++ b/tests/codegen/fail/enum/derive_name_double_underscored.rs @@ -0,0 +1,8 @@ +use juniper::GraphQLEnum; + +#[derive(GraphQLEnum)] +enum __Test { + Test, +} + +fn main() {} diff --git a/tests/codegen/fail/enum/derive_name_double_underscored.stderr b/tests/codegen/fail/enum/derive_name_double_underscored.stderr new file mode 100644 index 00000000..6b00b6bd --- /dev/null +++ b/tests/codegen/fail/enum/derive_name_double_underscored.stderr @@ -0,0 +1,7 @@ +error: All types and directives defined within a schema must not have a name which begins with `__` (two underscores), as this is used exclusively by GraphQL’s introspection system. + --> fail/enum/derive_name_double_underscored.rs:4:6 + | +4 | enum __Test { + | ^^^^^^ + | + = note: https://spec.graphql.org/June2018/#sec-Schema diff --git a/tests/codegen/fail/enum/derive_no_fields.rs b/tests/codegen/fail/enum/derive_no_fields.rs deleted file mode 100644 index f7df4e7d..00000000 --- a/tests/codegen/fail/enum/derive_no_fields.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[derive(juniper::GraphQLEnum)] -pub enum Test {} - -fn main() { } diff --git a/tests/codegen/fail/enum/derive_no_fields.stderr b/tests/codegen/fail/enum/derive_no_fields.stderr deleted file mode 100644 index 63715639..00000000 --- a/tests/codegen/fail/enum/derive_no_fields.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: GraphQL enum expects at least one field - --> fail/enum/derive_no_fields.rs:2:1 - | -2 | pub enum Test {} - | ^^^^^^^^^^^^^^^^ - | - = note: https://spec.graphql.org/June2018/#sec-Enums diff --git a/tests/codegen/fail/enum/derive_no_values.rs b/tests/codegen/fail/enum/derive_no_values.rs new file mode 100644 index 00000000..fe36fe44 --- /dev/null +++ b/tests/codegen/fail/enum/derive_no_values.rs @@ -0,0 +1,6 @@ +use juniper::GraphQLEnum; + +#[derive(GraphQLEnum)] +enum Test {} + +fn main() {} diff --git a/tests/codegen/fail/enum/derive_no_values.stderr b/tests/codegen/fail/enum/derive_no_values.stderr new file mode 100644 index 00000000..b9b26cae --- /dev/null +++ b/tests/codegen/fail/enum/derive_no_values.stderr @@ -0,0 +1,7 @@ +error: GraphQL enum expected at least 1 non-ignored enum variant + --> fail/enum/derive_no_values.rs:3:10 + | +3 | #[derive(GraphQLEnum)] + | ^^^^^^^^^^^ + | + = note: this error originates in the derive macro `GraphQLEnum` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/enum/derive_variant_with_field.rs b/tests/codegen/fail/enum/derive_variant_with_field.rs new file mode 100644 index 00000000..61ddd796 --- /dev/null +++ b/tests/codegen/fail/enum/derive_variant_with_field.rs @@ -0,0 +1,8 @@ +use juniper::GraphQLEnum; + +#[derive(GraphQLEnum)] +enum Test { + Variant(i32), +} + +fn main() {} diff --git a/tests/codegen/fail/enum/derive_variant_with_field.stderr b/tests/codegen/fail/enum/derive_variant_with_field.stderr new file mode 100644 index 00000000..96cae1a7 --- /dev/null +++ b/tests/codegen/fail/enum/derive_variant_with_field.stderr @@ -0,0 +1,7 @@ +error: GraphQL enum no fields allowed for non-ignored variants + --> fail/enum/derive_variant_with_field.rs:5:12 + | +5 | Variant(i32), + | ^^^^^ + | + = note: https://spec.graphql.org/June2018/#sec-Enums diff --git a/tests/codegen/fail/enum/derive_wrong_item.rs b/tests/codegen/fail/enum/derive_wrong_item.rs new file mode 100644 index 00000000..e31351f3 --- /dev/null +++ b/tests/codegen/fail/enum/derive_wrong_item.rs @@ -0,0 +1,6 @@ +use juniper::GraphQLEnum; + +#[derive(GraphQLEnum)] +struct Test {} + +fn main() {} diff --git a/tests/codegen/fail/enum/derive_wrong_item.stderr b/tests/codegen/fail/enum/derive_wrong_item.stderr new file mode 100644 index 00000000..3670fc04 --- /dev/null +++ b/tests/codegen/fail/enum/derive_wrong_item.stderr @@ -0,0 +1,5 @@ +error: GraphQL enum can only be derived on enums + --> fail/enum/derive_wrong_item.rs:4:1 + | +4 | struct Test {} + | ^^^^^^^^^^^^^^ diff --git a/tests/codegen/fail/input-object/derive_incompatible_object.stderr b/tests/codegen/fail/input-object/derive_incompatible_object.stderr index e8e2a3cc..6767eead 100644 --- a/tests/codegen/fail/input-object/derive_incompatible_object.stderr +++ b/tests/codegen/fail/input-object/derive_incompatible_object.stderr @@ -60,7 +60,7 @@ error[E0599]: no method named `to_input_value` found for struct `ObjectA` in the --> fail/input-object/derive_incompatible_object.rs:6:10 | 2 | struct ObjectA { - | -------------- method `to_input_value` not found for this + | ------- method `to_input_value` not found for this struct ... 6 | #[derive(juniper::GraphQLInputObject)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ObjectA` diff --git a/tests/codegen/fail/interface/struct/attr_cyclic_impl.rs b/tests/codegen/fail/interface/struct/attr_cyclic_impl.rs new file mode 100644 index 00000000..7681972a --- /dev/null +++ b/tests/codegen/fail/interface/struct/attr_cyclic_impl.rs @@ -0,0 +1,13 @@ +use juniper::graphql_interface; + +#[graphql_interface(impl = Node2Value, for = Node2Value)] +struct Node1 { + id: String, +} + +#[graphql_interface(impl = Node1Value, for = Node1Value)] +struct Node2 { + id: String, +} + +fn main() {} diff --git a/tests/codegen/fail/interface/struct/attr_cyclic_impl.stderr b/tests/codegen/fail/interface/struct/attr_cyclic_impl.stderr new file mode 100644 index 00000000..ed809a5a --- /dev/null +++ b/tests/codegen/fail/interface/struct/attr_cyclic_impl.stderr @@ -0,0 +1,26 @@ +error[E0391]: cycle detected when expanding type alias `Node1Value` + --> fail/interface/struct/attr_cyclic_impl.rs:3:46 + | +3 | #[graphql_interface(impl = Node2Value, for = Node2Value)] + | ^^^^^^^^^^ + | +note: ...which requires expanding type alias `Node2Value`... + --> fail/interface/struct/attr_cyclic_impl.rs:8:46 + | +8 | #[graphql_interface(impl = Node1Value, for = Node1Value)] + | ^^^^^^^^^^ + = note: ...which again requires expanding type alias `Node1Value`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when collecting item types in top-level module + --> fail/interface/struct/attr_cyclic_impl.rs:1:1 + | +1 | / use juniper::graphql_interface; +2 | | +3 | | #[graphql_interface(impl = Node2Value, for = Node2Value)] +4 | | struct Node1 { +... | +12 | | +13 | | fn main() {} + | |____________^ diff --git a/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr b/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr index c87ad2e0..a9f9fe37 100644 --- a/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr +++ b/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr @@ -9,3 +9,27 @@ error[E0412]: cannot find type `CharacterValue` in this scope | 4 | #[graphql(impl = CharacterValue)] | ^^^^^^^^^^^^^^ not found in this scope + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/struct/attr_missing_field.stderr b/tests/codegen/fail/interface/struct/attr_missing_field.stderr index 3d479ce5..37afdb39 100644 --- a/tests/codegen/fail/interface/struct/attr_missing_field.stderr +++ b/tests/codegen/fail/interface/struct/attr_missing_field.stderr @@ -22,6 +22,315 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ + | | + | referenced constant has errors + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/attr_missing_field.rs:11:5 | @@ -30,6 +339,158 @@ error[E0080]: evaluation of constant value failed | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/attr_missing_field.rs:11:5 | @@ -54,6 +515,314 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ + | | + | referenced constant has errors + | inside ` as AsyncField<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as AsyncField<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/attr_missing_field.rs:11:5 | @@ -61,3 +830,155 @@ error[E0080]: evaluation of constant value failed | ^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: Field `id` isn't implemented on `ObjA`.', $DIR/fail/interface/struct/attr_missing_field.rs:11:5 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_field.rs:11:5 + | +11 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.rs b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.rs new file mode 100644 index 00000000..590d1517 --- /dev/null +++ b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.rs @@ -0,0 +1,18 @@ +use juniper::graphql_interface; + +#[graphql_interface(for = Node2Value)] +struct Node1 { + id: String, +} + +#[graphql_interface(impl = Node1Value, for = Node3Value)] +struct Node2 { + id: String, +} + +#[graphql_interface(impl = Node2Value)] +struct Node3 { + id: String, +} + +fn main() {} diff --git a/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr new file mode 100644 index 00000000..389334dc --- /dev/null +++ b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr @@ -0,0 +1,7 @@ +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/attr_missing_transitive_impl.rs:8:46 + | +8 | #[graphql_interface(impl = Node1Value, for = Node3Value)] + | ^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Node2` on `Node3`: missing `impl = ` for transitive interface `Node1` on `Node3`.', $DIR/fail/interface/struct/attr_missing_transitive_impl.rs:8:46 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/struct/derive_cyclic_impl.rs b/tests/codegen/fail/interface/struct/derive_cyclic_impl.rs new file mode 100644 index 00000000..56d77cc6 --- /dev/null +++ b/tests/codegen/fail/interface/struct/derive_cyclic_impl.rs @@ -0,0 +1,15 @@ +use juniper::GraphQLInterface; + +#[derive(GraphQLInterface)] +#[graphql(impl = Node2Value, for = Node2Value)] +struct Node1 { + id: String, +} + +#[derive(GraphQLInterface)] +#[graphql(impl = Node1Value, for = Node1Value)] +struct Node2 { + id: String, +} + +fn main() {} diff --git a/tests/codegen/fail/interface/struct/derive_cyclic_impl.stderr b/tests/codegen/fail/interface/struct/derive_cyclic_impl.stderr new file mode 100644 index 00000000..28f960eb --- /dev/null +++ b/tests/codegen/fail/interface/struct/derive_cyclic_impl.stderr @@ -0,0 +1,26 @@ +error[E0391]: cycle detected when expanding type alias `Node1Value` + --> fail/interface/struct/derive_cyclic_impl.rs:4:36 + | +4 | #[graphql(impl = Node2Value, for = Node2Value)] + | ^^^^^^^^^^ + | +note: ...which requires expanding type alias `Node2Value`... + --> fail/interface/struct/derive_cyclic_impl.rs:10:36 + | +10 | #[graphql(impl = Node1Value, for = Node1Value)] + | ^^^^^^^^^^ + = note: ...which again requires expanding type alias `Node1Value`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when collecting item types in top-level module + --> fail/interface/struct/derive_cyclic_impl.rs:1:1 + | +1 | / use juniper::GraphQLInterface; +2 | | +3 | | #[derive(GraphQLInterface)] +4 | | #[graphql(impl = Node2Value, for = Node2Value)] +... | +14 | | +15 | | fn main() {} + | |____________^ diff --git a/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr b/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr index a4a80378..234878de 100644 --- a/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr +++ b/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr @@ -9,3 +9,27 @@ error[E0412]: cannot find type `CharacterValue` in this scope | 4 | #[graphql(impl = CharacterValue)] | ^^^^^^^^^^^^^^ not found in this scope + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/struct/derive_missing_field.stderr b/tests/codegen/fail/interface/struct/derive_missing_field.stderr index 1e1989bc..a9a91ec7 100644 --- a/tests/codegen/fail/interface/struct/derive_missing_field.stderr +++ b/tests/codegen/fail/interface/struct/derive_missing_field.stderr @@ -22,6 +22,315 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ + | | + | referenced constant has errors + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/derive_missing_field.rs:12:5 | @@ -30,6 +339,158 @@ error[E0080]: evaluation of constant value failed | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/derive_missing_field.rs:12:5 | @@ -54,6 +515,314 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ + | | + | referenced constant has errors + | inside ` as AsyncField<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as AsyncField<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/struct/derive_missing_field.rs:12:5 | @@ -61,3 +830,155 @@ error[E0080]: evaluation of constant value failed | ^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: Field `id` isn't implemented on `ObjA`.', $DIR/fail/interface/struct/derive_missing_field.rs:12:5 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_field.rs:12:5 + | +12 | id: String, + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.rs b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.rs new file mode 100644 index 00000000..446aae21 --- /dev/null +++ b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.rs @@ -0,0 +1,21 @@ +use juniper::GraphQLInterface; + +#[derive(GraphQLInterface)] +#[graphql(for = Node2Value)] +struct Node1 { + id: String, +} + +#[derive(GraphQLInterface)] +#[graphql(impl = Node1Value, for = Node3Value)] +struct Node2 { + id: String, +} + +#[derive(GraphQLInterface)] +#[graphql(impl = Node2Value)] +struct Node3 { + id: String, +} + +fn main() {} diff --git a/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr new file mode 100644 index 00000000..278b725f --- /dev/null +++ b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr @@ -0,0 +1,7 @@ +error[E0080]: evaluation of constant value failed + --> fail/interface/struct/derive_missing_transitive_impl.rs:10:36 + | +10 | #[graphql(impl = Node1Value, for = Node3Value)] + | ^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Node2` on `Node3`: missing `impl = ` for transitive interface `Node1` on `Node3`.', $DIR/fail/interface/struct/derive_missing_transitive_impl.rs:10:36 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/trait/cyclic_impl.rs b/tests/codegen/fail/interface/trait/cyclic_impl.rs new file mode 100644 index 00000000..6f5b7947 --- /dev/null +++ b/tests/codegen/fail/interface/trait/cyclic_impl.rs @@ -0,0 +1,13 @@ +use juniper::graphql_interface; + +#[graphql_interface(impl = Node2Value, for = Node2Value)] +trait Node1 { + fn id(&self) -> &str; +} + +#[graphql_interface(impl = Node1Value, for = Node1Value)] +trait Node2 { + fn id() -> String; +} + +fn main() {} diff --git a/tests/codegen/fail/interface/trait/cyclic_impl.stderr b/tests/codegen/fail/interface/trait/cyclic_impl.stderr new file mode 100644 index 00000000..9865861f --- /dev/null +++ b/tests/codegen/fail/interface/trait/cyclic_impl.stderr @@ -0,0 +1,26 @@ +error[E0391]: cycle detected when expanding type alias `Node1Value` + --> fail/interface/trait/cyclic_impl.rs:3:46 + | +3 | #[graphql_interface(impl = Node2Value, for = Node2Value)] + | ^^^^^^^^^^ + | +note: ...which requires expanding type alias `Node2Value`... + --> fail/interface/trait/cyclic_impl.rs:8:46 + | +8 | #[graphql_interface(impl = Node1Value, for = Node1Value)] + | ^^^^^^^^^^ + = note: ...which again requires expanding type alias `Node1Value`, completing the cycle + = note: type aliases cannot be recursive + = help: consider using a struct, enum, or union instead to break the cycle + = help: see for more information +note: cycle used when collecting item types in top-level module + --> fail/interface/trait/cyclic_impl.rs:1:1 + | +1 | / use juniper::graphql_interface; +2 | | +3 | | #[graphql_interface(impl = Node2Value, for = Node2Value)] +4 | | trait Node1 { +... | +12 | | +13 | | fn main() {} + | |____________^ diff --git a/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr b/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr index 5d546902..13696d8d 100644 --- a/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr +++ b/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr @@ -9,3 +9,27 @@ error[E0412]: cannot find type `CharacterValue` in this scope | 4 | #[graphql(impl = CharacterValue)] | ^^^^^^^^^^^^^^ not found in this scope + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/implementers_duplicate_pretty.rs:3:10 + | +3 | #[derive(GraphQLObject)] + | ^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/trait/missing_field.stderr b/tests/codegen/fail/interface/trait/missing_field.stderr index 6a6cda06..45913e16 100644 --- a/tests/codegen/fail/interface/trait/missing_field.stderr +++ b/tests/codegen/fail/interface/trait/missing_field.stderr @@ -22,6 +22,315 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ + | | + | referenced constant has errors + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/trait/missing_field.rs:11:8 | @@ -30,6 +339,158 @@ error[E0080]: evaluation of constant value failed | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/trait/missing_field.rs:11:8 | @@ -54,6 +515,314 @@ error[E0080]: erroneous constant used | = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: erroneous constant used + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: erroneous constant used + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ + | | + | referenced constant has errors + | inside ` as AsyncField<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36 + | inside ` as AsyncField<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59 + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0080]: evaluation of constant value failed --> fail/interface/trait/missing_field.rs:11:8 | @@ -61,3 +830,155 @@ error[E0080]: evaluation of constant value failed | ^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: Field `id` isn't implemented on `ObjA`.', $DIR/fail/interface/trait/missing_field.rs:11:8 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::const_concat` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: any use of this value will cause an error + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_field.rs:11:8 + | +11 | fn id(&self) -> &str; + | ^^ referenced constant has errors + | + = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/codegen/fail/interface/trait/missing_transitive_impl.rs b/tests/codegen/fail/interface/trait/missing_transitive_impl.rs new file mode 100644 index 00000000..2bc08fb0 --- /dev/null +++ b/tests/codegen/fail/interface/trait/missing_transitive_impl.rs @@ -0,0 +1,18 @@ +use juniper::graphql_interface; + +#[graphql_interface(for = Node2Value)] +trait Node1 { + fn id() -> String; +} + +#[graphql_interface(impl = Node1Value, for = Node3Value)] +trait Node2 { + fn id(&self) -> &str; +} + +#[graphql_interface(impl = Node2Value)] +trait Node3 { + fn id() -> &'static str; +} + +fn main() {} diff --git a/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr b/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr new file mode 100644 index 00000000..f120ac36 --- /dev/null +++ b/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr @@ -0,0 +1,7 @@ +error[E0080]: evaluation of constant value failed + --> fail/interface/trait/missing_transitive_impl.rs:8:46 + | +8 | #[graphql_interface(impl = Node1Value, for = Node3Value)] + | ^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Node2` on `Node3`: missing `impl = ` for transitive interface `Node1` on `Node3`.', $DIR/fail/interface/trait/missing_transitive_impl.rs:8:46 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/integration/src/codegen/derive_enum.rs b/tests/integration/src/codegen/derive_enum.rs deleted file mode 100644 index acaa49a8..00000000 --- a/tests/integration/src/codegen/derive_enum.rs +++ /dev/null @@ -1,133 +0,0 @@ -use fnv::FnvHashMap; -use juniper::{ - graphql_input_value, DefaultScalarValue, FromInputValue, GraphQLEnum, GraphQLType, Registry, - ToInputValue, -}; - -pub struct CustomContext {} - -impl juniper::Context for CustomContext {} - -#[derive(GraphQLEnum, Debug, PartialEq)] -#[graphql(name = "Some", description = "enum descr")] -enum SomeEnum { - Regular, - #[graphql(name = "FULL", description = "field descr", deprecated = "depr")] - Full, -} - -#[derive(juniper::GraphQLEnum, Debug, PartialEq)] -#[graphql(rename = "none")] -enum NoRenameEnum { - OneVariant, - AnotherVariant, -} - -/// Enum doc. -#[derive(GraphQLEnum)] -enum DocEnum { - /// Variant doc. - Foo, -} - -/// Doc 1.\ -/// Doc 2. -/// -/// Doc 4. -#[derive(GraphQLEnum, Debug, PartialEq)] -enum MultiDocEnum { - /// Variant 1. - /// Variant 2. - Foo, -} - -/// This is not used as the description. -#[derive(GraphQLEnum, Debug, PartialEq)] -#[graphql(description = "enum override")] -enum OverrideDocEnum { - /// This is not used as the description. - #[graphql(description = "variant override")] - Foo, -} - -#[derive(GraphQLEnum)] -#[graphql(context = CustomContext, noasync)] -enum ContextEnum { - A, -} - -#[test] -fn test_derived_enum() { - // Ensure that rename works. - assert_eq!( - >::name(&()), - Some("Some") - ); - - // Ensure validity of meta info. - let mut registry: Registry<'_> = Registry::new(FnvHashMap::default()); - let meta = SomeEnum::meta(&(), &mut registry); - - assert_eq!(meta.name(), Some("Some")); - assert_eq!(meta.description(), Some("enum descr")); - - // Test no rename variant. - assert_eq!( - <_ as ToInputValue>::to_input_value(&NoRenameEnum::AnotherVariant), - graphql_input_value!("AnotherVariant"), - ); - - // Test Regular variant. - assert_eq!( - <_ as ToInputValue>::to_input_value(&SomeEnum::Regular), - graphql_input_value!("REGULAR"), - ); - assert_eq!( - FromInputValue::::from_input_value(&graphql_input_value!(REGULAR)), - Ok(SomeEnum::Regular), - ); - - // Test FULL variant. - assert_eq!( - <_ as ToInputValue>::to_input_value(&SomeEnum::Full), - graphql_input_value!("FULL"), - ); - assert_eq!( - FromInputValue::::from_input_value(&graphql_input_value!(FULL)), - Ok(SomeEnum::Full) - ); -} - -#[test] -fn test_doc_comment() { - let mut registry: Registry<'_> = Registry::new(FnvHashMap::default()); - let meta = DocEnum::meta(&(), &mut registry); - assert_eq!(meta.description(), Some("Enum doc.")); -} - -#[test] -fn test_multi_doc_comment() { - let mut registry: Registry<'_> = Registry::new(FnvHashMap::default()); - let meta = MultiDocEnum::meta(&(), &mut registry); - assert_eq!(meta.description(), Some("Doc 1. Doc 2.\n\nDoc 4.")); -} - -#[test] -fn test_doc_comment_override() { - let mut registry: Registry<'_> = Registry::new(FnvHashMap::default()); - let meta = OverrideDocEnum::meta(&(), &mut registry); - assert_eq!(meta.description(), Some("enum override")); -} - -fn test_context(_t: T) -where - T: GraphQLType, -{ - // empty -} - -#[test] -fn test_doc_custom_context() { - test_context(ContextEnum::A); - // test_context(OverrideDocEnum::Foo); does not work -} diff --git a/tests/integration/src/codegen/enum_derive.rs b/tests/integration/src/codegen/enum_derive.rs new file mode 100644 index 00000000..24aed858 --- /dev/null +++ b/tests/integration/src/codegen/enum_derive.rs @@ -0,0 +1,932 @@ +//! Tests for `#[derive(GraphQLEnum)]` macro. + +use juniper::{ + execute, graphql_object, graphql_value, graphql_vars, parser::SourcePosition, + DefaultScalarValue, ExecutionError, FieldError, GraphQLEnum, ScalarValue, +}; + +use crate::util::{schema, schema_with_scalar}; + +mod trivial { + use super::*; + + #[derive(GraphQLEnum)] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } + + #[tokio::test] + async fn is_graphql_enum() { + const DOC: &str = r#"{ + __type(name: "Character") { + kind + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "ENUM"}}), vec![])), + ); + } + + #[tokio::test] + async fn uses_type_name() { + const DOC: &str = r#"{ + __type(name: "Character") { + name + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"name": "Character"}}), vec![])), + ); + } + + #[tokio::test] + async fn has_no_description() { + const DOC: &str = r#"{ + __type(name: "Character") { + description + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"description": null}}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + {"name": "HUMAN", "description": null}, + {"name": "DROID", "description": null}, + ]}}), + vec![], + )), + ); + } +} + +mod ignored_variant { + use super::*; + + #[derive(GraphQLEnum)] + enum Character { + Human, + #[allow(dead_code)] + #[graphql(ignore)] + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + + fn droid() -> Character { + Character::Droid + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } + + #[tokio::test] + async fn err_on_droid() { + const DOC: &str = r#"{ + droid + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!(null), + vec![ExecutionError::new( + SourcePosition::new(14, 1, 12), + &["droid"], + FieldError::from("Cannot resolve ignored enum variant"), + )], + )), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + {"name": "HUMAN", "description": null}, + ]}}), + vec![], + )), + ); + } +} + +mod ignored_generic_variant { + use super::*; + + #[derive(GraphQLEnum)] + enum Character { + Human, + Droid, + #[allow(dead_code)] + #[graphql(ignore)] + Ignored(T), + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character<()>) -> Character<()> { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + {"name": "HUMAN", "description": null}, + {"name": "DROID", "description": null}, + ]}}), + vec![], + )), + ); + } +} + +mod description_from_doc_comment { + use super::*; + + /// Character doc. + #[derive(GraphQLEnum)] + enum Character { + /// Human doc. + Human, + + /// Droid doc. + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } + + #[tokio::test] + async fn is_graphql_enum() { + const DOC: &str = r#"{ + __type(name: "Character") { + kind + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "ENUM"}}), vec![])), + ); + } + + #[tokio::test] + async fn uses_type_name() { + const DOC: &str = r#"{ + __type(name: "Character") { + name + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"name": "Character"}}), vec![])), + ); + } + + #[tokio::test] + async fn has_description() { + const DOC: &str = r#"{ + __type(name: "Character") { + description + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"description": "Character doc."}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + isDeprecated + deprecationReason + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + { + "name": "HUMAN", + "description": "Human doc.", + "isDeprecated": false, + "deprecationReason": null, + }, + { + "name": "DROID", + "description": "Droid doc.", + "isDeprecated": false, + "deprecationReason": null, + }, + ]}}), + vec![], + )), + ); + } +} + +mod deprecation_from_attr { + #![allow(deprecated)] + + use super::*; + + /// Character doc. + #[derive(GraphQLEnum)] + enum Character { + /// Human doc. + #[deprecated] + Human, + + /// Droid doc. + #[deprecated(note = "Reason")] + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn has_description() { + const DOC: &str = r#"{ + __type(name: "Character") { + description + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"description": "Character doc."}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"enumValues": []}}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values_with_deprecated() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + { + "name": "HUMAN", + "description": "Human doc.", + "isDeprecated": true, + "deprecationReason": null, + }, + { + "name": "DROID", + "description": "Droid doc.", + "isDeprecated": true, + "deprecationReason": "Reason", + }, + ]}}), + vec![], + )), + ); + } +} + +mod deprecation_from_graphql_attr { + #![allow(deprecated)] + + use super::*; + + /// Character doc. + #[derive(GraphQLEnum)] + enum Character { + /// Human doc. + #[graphql(deprecated)] + Human, + + /// Droid doc. + #[graphql(deprecated = "Reason")] + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn has_description() { + const DOC: &str = r#"{ + __type(name: "Character") { + description + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"description": "Character doc."}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"enumValues": []}}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values_with_deprecated() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + { + "name": "HUMAN", + "description": "Human doc.", + "isDeprecated": true, + "deprecationReason": null, + }, + { + "name": "DROID", + "description": "Droid doc.", + "isDeprecated": true, + "deprecationReason": "Reason", + }, + ]}}), + vec![], + )), + ); + } +} + +mod explicit_name_description_and_deprecation { + #![allow(deprecated)] + + use super::*; + + /// Doc comment. + #[derive(GraphQLEnum)] + #[graphql(name = "MyCharacter", desc = "Character doc.")] + enum Character { + /// Human doc. + #[graphql(name = "MY_HUMAN", desc = "My human doc.", deprecated = "Not used.")] + #[deprecated(note = "Should be omitted.")] + Human, + + /// Droid doc. + #[graphql(deprecated = "Reason")] + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn has_no_description() { + const DOC: &str = r#"{ + __type(name: "MyCharacter") { + description + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"description": "Character doc."}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "MyCharacter") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"enumValues": []}}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values_with_deprecated() { + const DOC: &str = r#"{ + __type(name: "MyCharacter") { + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + { + "name": "MY_HUMAN", + "description": "My human doc.", + "isDeprecated": true, + "deprecationReason": "Not used.", + }, + { + "name": "DROID", + "description": "Droid doc.", + "isDeprecated": true, + "deprecationReason": "Reason", + }, + ]}}), + vec![], + )), + ); + } +} + +mod renamed_all_fields { + use super::*; + + #[derive(GraphQLEnum)] + #[graphql(rename_all = "none")] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: Human) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "Human"}), vec![])), + ); + } + + #[tokio::test] + async fn has_enum_values() { + const DOC: &str = r#"{ + __type(name: "Character") { + enumValues { + name + description + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"enumValues": [ + {"name": "Human", "description": null}, + {"name": "Droid", "description": null}, + ]}}), + vec![], + )), + ); + } +} + +mod explicit_scalar { + use super::*; + + #[derive(GraphQLEnum)] + #[graphql(scalar = DefaultScalarValue)] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object(scalar = DefaultScalarValue)] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } +} + +mod custom_scalar { + use crate::custom_scalar::MyScalarValue; + + use super::*; + + #[derive(GraphQLEnum)] + #[graphql(scalar = MyScalarValue)] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object(scalar = MyScalarValue)] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema_with_scalar::(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } +} + +mod explicit_generic_scalar { + + use super::*; + + #[derive(GraphQLEnum)] + #[graphql(scalar = S)] + enum Character { + Human, + Droid, + #[allow(dead_code)] + #[graphql(ignore)] + Scalar(S), + } + + struct QueryRoot; + + #[graphql_object(scalar = S: ScalarValue)] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } +} + +mod bounded_generic_scalar { + use super::*; + + #[derive(GraphQLEnum)] + #[graphql(scalar = S: ScalarValue + Clone)] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn pass_as_is(character: Character) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } +} + +mod explicit_custom_context { + use super::*; + + struct CustomContext(String); + + impl juniper::Context for CustomContext {} + + #[derive(GraphQLEnum)] + #[graphql(context = CustomContext)] + enum Character { + Human, + Droid, + } + + struct QueryRoot; + + #[graphql_object(context = CustomContext)] + impl QueryRoot { + fn pass_as_is(character: Character, _ctx: &CustomContext) -> Character { + character + } + } + + #[tokio::test] + async fn resolves() { + const DOC: &str = r#"{ + passAsIs(character: HUMAN) + }"#; + + let schema = schema(QueryRoot); + let ctx = CustomContext("ctx".into()); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &ctx).await, + Ok((graphql_value!({"passAsIs": "HUMAN"}), vec![])), + ); + } +} diff --git a/tests/integration/src/codegen/interface_attr_struct.rs b/tests/integration/src/codegen/interface_attr_struct.rs index 388bae78..8d0e4f58 100644 --- a/tests/integration/src/codegen/interface_attr_struct.rs +++ b/tests/integration/src/codegen/interface_attr_struct.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use juniper::{ execute, graphql_interface, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, - FieldError, FieldResult, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, + FieldError, FieldResult, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, ID, }; use crate::util::{schema, schema_with_scalar}; @@ -2539,6 +2539,537 @@ mod nullable_argument_subtyping { } } +mod simple_subtyping { + use super::*; + + #[graphql_interface(for = [ResourceValue, Endpoint])] + struct Node { + id: Option, + } + + #[graphql_interface(impl = NodeValue, for = Endpoint)] + struct Resource { + id: ID, + url: Option, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [ResourceValue, NodeValue])] + struct Endpoint { + id: ID, + url: String, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn node() -> NodeValue { + Endpoint { + id: ID::from("1".to_owned()), + url: "2".to_owned(), + } + .into() + } + + fn resource() -> ResourceValue { + Endpoint { + id: ID::from("3".to_owned()), + url: "4".to_owned(), + } + .into() + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_node() { + const DOC: &str = r#"{ + node { + id + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"node": {"id": "1"}}), vec![])), + ); + } + + #[tokio::test] + async fn resolves_node_on_resource() { + const DOC: &str = r#"{ + node { + ... on Resource { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_node_on_endpoint() { + const DOC: &str = r#"{ + node { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource() { + const DOC: &str = r#"{ + resource { + id + url + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource_on_endpoint() { + const DOC: &str = r#"{ + resource { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn registers_possible_types() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + possibleTypes {{ + kind + name + }} + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"possibleTypes": [ + {"kind": "OBJECT", "name": "Endpoint"}, + ]}}), + vec![], + )), + ); + } + } + + #[tokio::test] + async fn registers_interfaces() { + let schema = schema(QueryRoot); + + for (name, interfaces) in [ + ("Node", graphql_value!([])), + ( + "Resource", + graphql_value!([{"kind": "INTERFACE", "name": "Node"}]), + ), + ( + "Endpoint", + graphql_value!([ + {"kind": "INTERFACE", "name": "Node"}, + {"kind": "INTERFACE", "name": "Resource"}, + ]), + ), + ] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + interfaces {{ + kind + name + }} + }} + }}"#, + name, + ); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"interfaces": interfaces}}), + vec![], + )), + ); + } + } +} + +mod branching_subtyping { + use super::*; + + #[graphql_interface(for = [HumanValue, DroidValue, Luke, R2D2])] + struct Node { + id: ID, + } + + #[graphql_interface(for = [HumanConnection, DroidConnection])] + struct Connection { + nodes: Vec, + } + + #[graphql_interface(impl = NodeValue, for = Luke)] + struct Human { + id: ID, + home_planet: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct HumanConnection { + nodes: Vec, + } + + #[graphql_interface(impl = NodeValue, for = R2D2)] + struct Droid { + id: ID, + primary_function: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct DroidConnection { + nodes: Vec, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [HumanValue, NodeValue])] + struct Luke { + id: ID, + home_planet: String, + father: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [DroidValue, NodeValue])] + struct R2D2 { + id: ID, + primary_function: String, + charge: f64, + } + + enum QueryRoot { + Luke, + R2D2, + } + + #[graphql_object] + impl QueryRoot { + fn crew(&self) -> ConnectionValue { + match self { + Self::Luke => HumanConnection { + nodes: vec![Luke { + id: ID::new("1"), + home_planet: "earth".to_owned(), + father: "SPOILER".to_owned(), + } + .into()], + } + .into(), + Self::R2D2 => DroidConnection { + nodes: vec![R2D2 { + id: ID::new("2"), + primary_function: "roll".to_owned(), + charge: 146.0, + } + .into()], + } + .into(), + } + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Connection", "Human", "Droid"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_human_connection() { + const DOC: &str = r#"{ + crew { + ... on HumanConnection { + nodes { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_human() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Human { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_luke() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Luke { + id + homePlanet + father + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + "father": "SPOILER", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid_connection() { + const DOC: &str = r#"{ + crew { + ... on DroidConnection { + nodes { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Droid { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_r2d2() { + const DOC: &str = r#"{ + crew { + nodes { + ... on R2D2 { + id + primaryFunction + charge + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + "charge": 146.0, + }], + }}), + vec![], + )), + ); + } +} + mod preserves_visibility { use super::*; diff --git a/tests/integration/src/codegen/interface_attr_trait.rs b/tests/integration/src/codegen/interface_attr_trait.rs index a81a758b..150820fa 100644 --- a/tests/integration/src/codegen/interface_attr_trait.rs +++ b/tests/integration/src/codegen/interface_attr_trait.rs @@ -3,7 +3,7 @@ use juniper::{ execute, graphql_interface, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, Executor, FieldError, FieldResult, GraphQLInputObject, GraphQLObject, GraphQLUnion, - IntoFieldError, ScalarValue, + IntoFieldError, ScalarValue, ID, }; use crate::util::{schema, schema_with_scalar}; @@ -3378,6 +3378,537 @@ mod nullable_argument_subtyping { } } +mod simple_subtyping { + use super::*; + + #[graphql_interface(for = [ResourceValue, Endpoint])] + trait Node { + fn id() -> Option; + } + + #[graphql_interface(impl = NodeValue, for = Endpoint)] + trait Resource { + fn id(&self) -> &ID; + fn url(&self) -> Option<&str>; + } + + #[derive(GraphQLObject)] + #[graphql(impl = [ResourceValue, NodeValue])] + struct Endpoint { + id: ID, + url: String, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn node() -> NodeValue { + Endpoint { + id: ID::from("1".to_owned()), + url: "2".to_owned(), + } + .into() + } + + fn resource() -> ResourceValue { + Endpoint { + id: ID::from("3".to_owned()), + url: "4".to_owned(), + } + .into() + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_node() { + const DOC: &str = r#"{ + node { + id + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"node": {"id": "1"}}), vec![])), + ); + } + + #[tokio::test] + async fn resolves_node_on_resource() { + const DOC: &str = r#"{ + node { + ... on Resource { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_node_on_endpoint() { + const DOC: &str = r#"{ + node { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource() { + const DOC: &str = r#"{ + resource { + id + url + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource_on_endpoint() { + const DOC: &str = r#"{ + resource { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn registers_possible_types() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + possibleTypes {{ + kind + name + }} + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"possibleTypes": [ + {"kind": "OBJECT", "name": "Endpoint"}, + ]}}), + vec![], + )), + ); + } + } + + #[tokio::test] + async fn registers_interfaces() { + let schema = schema(QueryRoot); + + for (name, interfaces) in [ + ("Node", graphql_value!([])), + ( + "Resource", + graphql_value!([{"kind": "INTERFACE", "name": "Node"}]), + ), + ( + "Endpoint", + graphql_value!([ + {"kind": "INTERFACE", "name": "Node"}, + {"kind": "INTERFACE", "name": "Resource"}, + ]), + ), + ] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + interfaces {{ + kind + name + }} + }} + }}"#, + name, + ); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"interfaces": interfaces}}), + vec![], + )), + ); + } + } +} + +mod branching_subtyping { + use super::*; + + #[graphql_interface(for = [HumanValue, DroidValue, Luke, R2D2])] + trait Node { + fn id() -> ID; + } + + #[graphql_interface(for = [HumanConnection, DroidConnection])] + trait Connection { + fn nodes(&self) -> &[NodeValue]; + } + + #[graphql_interface(impl = NodeValue, for = Luke)] + trait Human { + fn id(&self) -> &ID; + fn home_planet(&self) -> &str; + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct HumanConnection { + nodes: Vec, + } + + #[graphql_interface(impl = NodeValue, for = R2D2)] + trait Droid { + fn id() -> ID; + fn primary_function() -> String; + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct DroidConnection { + nodes: Vec, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [HumanValue, NodeValue])] + struct Luke { + id: ID, + home_planet: String, + father: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [DroidValue, NodeValue])] + struct R2D2 { + id: ID, + primary_function: String, + charge: f64, + } + + enum QueryRoot { + Luke, + R2D2, + } + + #[graphql_object] + impl QueryRoot { + fn crew(&self) -> ConnectionValue { + match self { + Self::Luke => HumanConnection { + nodes: vec![Luke { + id: ID::new("1"), + home_planet: "earth".to_owned(), + father: "SPOILER".to_owned(), + } + .into()], + } + .into(), + Self::R2D2 => DroidConnection { + nodes: vec![R2D2 { + id: ID::new("2"), + primary_function: "roll".to_owned(), + charge: 146.0, + } + .into()], + } + .into(), + } + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Connection", "Human", "Droid"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_human_connection() { + const DOC: &str = r#"{ + crew { + ... on HumanConnection { + nodes { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_human() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Human { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_luke() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Luke { + id + homePlanet + father + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + "father": "SPOILER", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid_connection() { + const DOC: &str = r#"{ + crew { + ... on DroidConnection { + nodes { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Droid { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_r2d2() { + const DOC: &str = r#"{ + crew { + nodes { + ... on R2D2 { + id + primaryFunction + charge + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + "charge": 146.0, + }], + }}), + vec![], + )), + ); + } +} + mod preserves_visibility { use super::*; diff --git a/tests/integration/src/codegen/interface_derive.rs b/tests/integration/src/codegen/interface_derive.rs index 7882f717..bbc6a79a 100644 --- a/tests/integration/src/codegen/interface_derive.rs +++ b/tests/integration/src/codegen/interface_derive.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use juniper::{ execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, FieldError, - FieldResult, GraphQLInterface, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, + FieldResult, GraphQLInterface, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, ID, }; use crate::util::{schema, schema_with_scalar}; @@ -2559,6 +2559,543 @@ mod nullable_argument_subtyping { } } +mod simple_subtyping { + use super::*; + + #[derive(GraphQLInterface)] + #[graphql(for = [ResourceValue, Endpoint])] + struct Node { + id: Option, + } + + #[derive(GraphQLInterface)] + #[graphql(impl = NodeValue, for = Endpoint)] + struct Resource { + id: ID, + url: Option, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [ResourceValue, NodeValue])] + struct Endpoint { + id: ID, + url: String, + } + + struct QueryRoot; + + #[graphql_object] + impl QueryRoot { + fn node() -> NodeValue { + Endpoint { + id: ID::from("1".to_owned()), + url: "2".to_owned(), + } + .into() + } + + fn resource() -> ResourceValue { + Endpoint { + id: ID::from("3".to_owned()), + url: "4".to_owned(), + } + .into() + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_node() { + const DOC: &str = r#"{ + node { + id + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"node": {"id": "1"}}), vec![])), + ); + } + + #[tokio::test] + async fn resolves_node_on_resource() { + const DOC: &str = r#"{ + node { + ... on Resource { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_node_on_endpoint() { + const DOC: &str = r#"{ + node { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"node": { + "id": "1", + "url": "2", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource() { + const DOC: &str = r#"{ + resource { + id + url + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_resource_on_endpoint() { + const DOC: &str = r#"{ + resource { + ... on Endpoint { + id + url + } + } + }"#; + + let schema = schema(QueryRoot); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"resource": { + "id": "3", + "url": "4", + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn registers_possible_types() { + for name in ["Node", "Resource"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + possibleTypes {{ + kind + name + }} + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"possibleTypes": [ + {"kind": "OBJECT", "name": "Endpoint"}, + ]}}), + vec![], + )), + ); + } + } + + #[tokio::test] + async fn registers_interfaces() { + let schema = schema(QueryRoot); + + for (name, interfaces) in [ + ("Node", graphql_value!([])), + ( + "Resource", + graphql_value!([{"kind": "INTERFACE", "name": "Node"}]), + ), + ( + "Endpoint", + graphql_value!([ + {"kind": "INTERFACE", "name": "Node"}, + {"kind": "INTERFACE", "name": "Resource"}, + ]), + ), + ] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + interfaces {{ + kind + name + }} + }} + }}"#, + name, + ); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"__type": {"interfaces": interfaces}}), + vec![], + )), + ); + } + } +} + +mod branching_subtyping { + use super::*; + + #[derive(GraphQLInterface)] + #[graphql(for = [HumanValue, DroidValue, Luke, R2D2])] + struct Node { + id: ID, + } + + #[derive(GraphQLInterface)] + #[graphql(for = [HumanConnection, DroidConnection])] + struct Connection { + nodes: Vec, + } + + #[derive(GraphQLInterface)] + #[graphql(impl = NodeValue, for = Luke)] + struct Human { + id: ID, + home_planet: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct HumanConnection { + nodes: Vec, + } + + #[derive(GraphQLInterface)] + #[graphql(impl = NodeValue, for = R2D2)] + struct Droid { + id: ID, + primary_function: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = ConnectionValue)] + struct DroidConnection { + nodes: Vec, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [HumanValue, NodeValue])] + struct Luke { + id: ID, + home_planet: String, + father: String, + } + + #[derive(GraphQLObject)] + #[graphql(impl = [DroidValue, NodeValue])] + struct R2D2 { + id: ID, + primary_function: String, + charge: f64, + } + + enum QueryRoot { + Luke, + R2D2, + } + + #[graphql_object] + impl QueryRoot { + fn crew(&self) -> ConnectionValue { + match self { + Self::Luke => HumanConnection { + nodes: vec![Luke { + id: ID::new("1"), + home_planet: "earth".to_owned(), + father: "SPOILER".to_owned(), + } + .into()], + } + .into(), + Self::R2D2 => DroidConnection { + nodes: vec![R2D2 { + id: ID::new("2"), + primary_function: "roll".to_owned(), + charge: 146.0, + } + .into()], + } + .into(), + } + } + } + + #[tokio::test] + async fn is_graphql_interface() { + for name in ["Node", "Connection", "Human", "Droid"] { + let doc = format!( + r#"{{ + __type(name: "{}") {{ + kind + }} + }}"#, + name, + ); + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(&doc, None, &schema, &graphql_vars! {}, &()).await, + Ok((graphql_value!({"__type": {"kind": "INTERFACE"}}), vec![])), + ); + } + } + + #[tokio::test] + async fn resolves_human_connection() { + const DOC: &str = r#"{ + crew { + ... on HumanConnection { + nodes { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_human() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Human { + id + homePlanet + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_luke() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Luke { + id + homePlanet + father + } + } + } + }"#; + + let schema = schema(QueryRoot::Luke); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "1", + "homePlanet": "earth", + "father": "SPOILER", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid_connection() { + const DOC: &str = r#"{ + crew { + ... on DroidConnection { + nodes { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid() { + const DOC: &str = r#"{ + crew { + nodes { + ... on Droid { + id + primaryFunction + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + }], + }}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_r2d2() { + const DOC: &str = r#"{ + crew { + nodes { + ... on R2D2 { + id + primaryFunction + charge + } + } + } + }"#; + + let schema = schema(QueryRoot::R2D2); + + assert_eq!( + execute(DOC, None, &schema, &graphql_vars! {}, &()).await, + Ok(( + graphql_value!({"crew": { + "nodes": [{ + "id": "2", + "primaryFunction": "roll", + "charge": 146.0, + }], + }}), + vec![], + )), + ); + } +} + mod preserves_visibility { use super::*; diff --git a/tests/integration/src/codegen/mod.rs b/tests/integration/src/codegen/mod.rs index 3a709c66..830f6e1a 100644 --- a/tests/integration/src/codegen/mod.rs +++ b/tests/integration/src/codegen/mod.rs @@ -1,6 +1,6 @@ -mod derive_enum; mod derive_input_object; mod derive_object_with_raw_idents; +mod enum_derive; mod interface_attr_struct; mod interface_attr_trait; mod interface_derive;