From f363b0d79ef04c6e2db6c77827174876ca8a38ea Mon Sep 17 00:00:00 2001 From: Kai Ren <tyranron@gmail.com> Date: Tue, 30 Jan 2024 16:41:11 +0100 Subject: [PATCH] Preserve input body when attribute macro expansion fails (#1245, #1244) --- juniper_codegen/CHANGELOG.md | 3 ++- juniper_codegen/src/common/diagnostic.rs | 20 +++++++++++++++-- juniper_codegen/src/lib.rs | 10 ++++----- .../struct/attr_fields_duplicate.stderr | 6 +++++ .../interface/trait/fields_duplicate.stderr | 6 +++++ .../fail/interface/trait/wrong_syntax.rs | 13 +++++++++++ .../fail/interface/trait/wrong_syntax.stderr | 22 +++++++++++++++++++ .../object/attr_field_double_underscored.rs | 2 +- .../attr_field_double_underscored.stderr | 11 +++++----- .../fail/object/attr_fields_duplicate.stderr | 6 +++++ .../codegen/fail/object/attr_wrong_syntax.rs | 14 ++++++++++++ .../fail/object/attr_wrong_syntax.stderr | 15 +++++++++++++ .../argument_double_underscored.rs | 7 +++--- .../argument_double_underscored.stderr | 4 ++-- .../subscription/argument_non_input_type.rs | 8 +++---- .../argument_non_input_type.stderr | 8 +++---- .../argument_wrong_default_array.rs | 8 +++---- .../subscription/field_double_underscored.rs | 9 ++++---- .../field_double_underscored.stderr | 13 +++++------ .../field_non_output_return_type.rs | 8 +++---- .../fail/subscription/field_not_async.rs | 7 +++--- .../fail/subscription/field_not_async.stderr | 4 ++-- .../fail/subscription/fields_duplicate.rs | 9 ++++---- .../fail/subscription/fields_duplicate.stderr | 10 +++++++-- .../subscription/name_double_underscored.rs | 7 +++--- .../name_double_underscored.stderr | 4 ++-- .../codegen/fail/subscription/wrong_syntax.rs | 19 ++++++++++++++++ .../fail/subscription/wrong_syntax.stderr | 15 +++++++++++++ .../union/trait_with_attr_on_method.stderr | 6 +++++ 29 files changed, 211 insertions(+), 63 deletions(-) create mode 100644 tests/codegen/fail/interface/trait/wrong_syntax.rs create mode 100644 tests/codegen/fail/interface/trait/wrong_syntax.stderr create mode 100644 tests/codegen/fail/object/attr_wrong_syntax.rs create mode 100644 tests/codegen/fail/object/attr_wrong_syntax.stderr create mode 100644 tests/codegen/fail/subscription/wrong_syntax.rs create mode 100644 tests/codegen/fail/subscription/wrong_syntax.stderr diff --git a/juniper_codegen/CHANGELOG.md b/juniper_codegen/CHANGELOG.md index aad31ee3..7c53fd57 100644 --- a/juniper_codegen/CHANGELOG.md +++ b/juniper_codegen/CHANGELOG.md @@ -10,7 +10,7 @@ All user visible changes to `juniper_codegen` crate will be documented in this f ### BC Breaks -- `#[graphql_object]` and `#[graphql_subscription]` expansions now preserve defined `impl` blocks "as is" and reuse defined methods in opaque way. ([#971]) +- `#[graphql_object]` and `#[graphql_subscription]` expansions now preserve defined `impl` blocks "as is" and reuse defined methods in opaque way. ([#971], [#1245]) - Renamed `rename = "<policy>"` attribute argument to `rename_all = "<policy>"` (following `serde` style). ([#971]) - Redesigned `#[graphql_interface]` macro: ([#1009]) - Removed support for `dyn` attribute argument (interface values as trait objects). @@ -61,6 +61,7 @@ All user visible changes to `juniper_codegen` crate will be documented in this f [#1051]: /../../issues/1051 [#1054]: /../../pull/1054 [#1157]: /../../pull/1157 +[#1245]: /../../pull/1245 diff --git a/juniper_codegen/src/common/diagnostic.rs b/juniper_codegen/src/common/diagnostic.rs index 87556bf6..15a8d0ef 100644 --- a/juniper_codegen/src/common/diagnostic.rs +++ b/juniper_codegen/src/common/diagnostic.rs @@ -2,7 +2,9 @@ use std::fmt; use proc_macro2::Span; -pub(crate) use self::polyfill::{abort_if_dirty, emit_error, entry_point, Diagnostic, ResultExt}; +pub(crate) use self::polyfill::{ + abort_if_dirty, emit_error, entry_point, entry_point_with_preserved_body, Diagnostic, ResultExt, +}; /// URL of the GraphQL specification (October 2021 Edition). pub(crate) const SPEC_URL: &str = "https://spec.graphql.org/October2021"; @@ -258,6 +260,18 @@ mod polyfill { /// This is the entry point for a macro to support [`Diagnostic`]s. pub(crate) fn entry_point<F>(f: F) -> proc_macro::TokenStream + where + F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, + { + entry_point_with_preserved_body(TokenStream::new(), f) + } + + /// This is the entry point for an attribute macro to support [`Diagnostic`]s, while preserving + /// the `body` input [`proc_macro::TokenStream`] on errors. + pub(crate) fn entry_point_with_preserved_body<F>( + body: impl Into<TokenStream>, + f: F, + ) -> proc_macro::TokenStream where F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, { @@ -267,7 +281,9 @@ mod polyfill { ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1)); let gen_error = || { - quote! { #( #err_storage )* } + let body = body.into(); + + quote! { #body #( #err_storage )* } }; match caught { diff --git a/juniper_codegen/src/lib.rs b/juniper_codegen/src/lib.rs index e6c81b60..d69cd714 100644 --- a/juniper_codegen/src/lib.rs +++ b/juniper_codegen/src/lib.rs @@ -756,7 +756,7 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream { /// [`ScalarValue`]: juniper::ScalarValue #[proc_macro_attribute] pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream { - diagnostic::entry_point(|| { + diagnostic::entry_point_with_preserved_body(body.clone(), || { graphql_scalar::attr::expand(attr.into(), body.into()) .unwrap_or_abort() .into() @@ -1318,7 +1318,7 @@ pub fn derive_scalar_value(input: TokenStream) -> TokenStream { /// [4]: https://doc.rust-lang.org/stable/std/primitive.unit.html #[proc_macro_attribute] pub fn graphql_interface(attr: TokenStream, body: TokenStream) -> TokenStream { - diagnostic::entry_point(|| { + diagnostic::entry_point_with_preserved_body(body.clone(), || { self::graphql_interface::attr::expand(attr.into(), body.into()) .unwrap_or_abort() .into() @@ -1825,7 +1825,7 @@ pub fn derive_object(body: TokenStream) -> TokenStream { /// [1]: https://spec.graphql.org/October2021#sec-Objects #[proc_macro_attribute] pub fn graphql_object(attr: TokenStream, body: TokenStream) -> TokenStream { - diagnostic::entry_point(|| { + diagnostic::entry_point_with_preserved_body(body.clone(), || { self::graphql_object::attr::expand(attr.into(), body.into()) .unwrap_or_abort() .into() @@ -1879,7 +1879,7 @@ pub fn graphql_object(attr: TokenStream, body: TokenStream) -> TokenStream { /// [1]: https://spec.graphql.org/October2021#sec-Subscription #[proc_macro_attribute] pub fn graphql_subscription(attr: TokenStream, body: TokenStream) -> TokenStream { - diagnostic::entry_point(|| { + diagnostic::entry_point_with_preserved_body(body.clone(), || { self::graphql_subscription::attr::expand(attr.into(), body.into()) .unwrap_or_abort() .into() @@ -2486,7 +2486,7 @@ pub fn derive_union(body: TokenStream) -> TokenStream { /// [4]: https://doc.rust-lang.org/stable/std/primitive.unit.html #[proc_macro_attribute] pub fn graphql_union(attr: TokenStream, body: TokenStream) -> TokenStream { - diagnostic::entry_point(|| { + diagnostic::entry_point_with_preserved_body(body.clone(), || { self::graphql_union::attr::expand(attr.into(), body.into()) .unwrap_or_abort() .into() diff --git a/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr b/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr index cad33766..d998a582 100644 --- a/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr +++ b/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr @@ -4,3 +4,9 @@ error: GraphQL interface must have a different name for each field | 4 | struct Character { | ^^^^^^ + +error: cannot find attribute `graphql` in this scope + --> fail/interface/struct/attr_fields_duplicate.rs:7:7 + | +7 | #[graphql(name = "id")] + | ^^^^^^^ diff --git a/tests/codegen/fail/interface/trait/fields_duplicate.stderr b/tests/codegen/fail/interface/trait/fields_duplicate.stderr index 19bcfb51..5eb97986 100644 --- a/tests/codegen/fail/interface/trait/fields_duplicate.stderr +++ b/tests/codegen/fail/interface/trait/fields_duplicate.stderr @@ -4,3 +4,9 @@ error: GraphQL interface must have a different name for each field | 4 | trait Character { | ^^^^^ + +error: cannot find attribute `graphql` in this scope + --> fail/interface/trait/fields_duplicate.rs:7:7 + | +7 | #[graphql(name = "id")] + | ^^^^^^^ diff --git a/tests/codegen/fail/interface/trait/wrong_syntax.rs b/tests/codegen/fail/interface/trait/wrong_syntax.rs new file mode 100644 index 00000000..bd76f94d --- /dev/null +++ b/tests/codegen/fail/interface/trait/wrong_syntax.rs @@ -0,0 +1,13 @@ +use juniper::graphql_interface; + +#[graphql_interface] +trait Character { + fn id(&self) -> &str; + + #[graphql(ignore)] + fn id2(&self) -> &str { + self.self.id() + } +} + +fn main() {} diff --git a/tests/codegen/fail/interface/trait/wrong_syntax.stderr b/tests/codegen/fail/interface/trait/wrong_syntax.stderr new file mode 100644 index 00000000..17c04567 --- /dev/null +++ b/tests/codegen/fail/interface/trait/wrong_syntax.stderr @@ -0,0 +1,22 @@ +error: #[graphql_interface] attribute is applicable to trait and struct definitions only + --> fail/interface/trait/wrong_syntax.rs:3:1 + | +3 | #[graphql_interface] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `graphql_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot find attribute `graphql` in this scope + --> fail/interface/trait/wrong_syntax.rs:7:7 + | +7 | #[graphql(ignore)] + | ^^^^^^^ + +error[E0609]: no field `self` on type `&Self` + --> fail/interface/trait/wrong_syntax.rs:9:14 + | +4 | trait Character { + | --------------- type parameter 'Self' declared here +... +9 | self.self.id() + | ^^^^ diff --git a/tests/codegen/fail/object/attr_field_double_underscored.rs b/tests/codegen/fail/object/attr_field_double_underscored.rs index ff854d0a..b00e7488 100644 --- a/tests/codegen/fail/object/attr_field_double_underscored.rs +++ b/tests/codegen/fail/object/attr_field_double_underscored.rs @@ -3,7 +3,7 @@ use juniper::graphql_object; struct ObjA; #[graphql_object] -impl Character for ObjA { +impl ObjA { fn __id(&self) -> &str { "funA" } diff --git a/tests/codegen/fail/object/attr_field_double_underscored.stderr b/tests/codegen/fail/object/attr_field_double_underscored.stderr index 48c6275a..db2d9dc1 100644 --- a/tests/codegen/fail/object/attr_field_double_underscored.stderr +++ b/tests/codegen/fail/object/attr_field_double_underscored.stderr @@ -1,7 +1,6 @@ -error: #[graphql_object] attribute is applicable to non-trait `impl` blocks only - --> fail/object/attr_field_double_underscored.rs:5:1 +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. + · note: https://spec.graphql.org/October2021#sec-Schema + --> fail/object/attr_field_double_underscored.rs:7:8 | -5 | #[graphql_object] - | ^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `graphql_object` (in Nightly builds, run with -Z macro-backtrace for more info) +7 | fn __id(&self) -> &str { + | ^^^^ diff --git a/tests/codegen/fail/object/attr_fields_duplicate.stderr b/tests/codegen/fail/object/attr_fields_duplicate.stderr index 49716590..d34fbecc 100644 --- a/tests/codegen/fail/object/attr_fields_duplicate.stderr +++ b/tests/codegen/fail/object/attr_fields_duplicate.stderr @@ -4,3 +4,9 @@ error: GraphQL object must have a different name for each field | 6 | impl ObjA { | ^^^^ + +error: cannot find attribute `graphql` in this scope + --> fail/object/attr_fields_duplicate.rs:11:7 + | +11 | #[graphql(name = "id")] + | ^^^^^^^ diff --git a/tests/codegen/fail/object/attr_wrong_syntax.rs b/tests/codegen/fail/object/attr_wrong_syntax.rs new file mode 100644 index 00000000..695feef5 --- /dev/null +++ b/tests/codegen/fail/object/attr_wrong_syntax.rs @@ -0,0 +1,14 @@ +use juniper::graphql_object; + +struct MyObject { + my_field: i32, +} + +#[graphql_object] +impl MyObject { + fn my_field(&self) -> i32 { + self.self.my_field + } +} + +fn main() {} diff --git a/tests/codegen/fail/object/attr_wrong_syntax.stderr b/tests/codegen/fail/object/attr_wrong_syntax.stderr new file mode 100644 index 00000000..b7002d3e --- /dev/null +++ b/tests/codegen/fail/object/attr_wrong_syntax.stderr @@ -0,0 +1,15 @@ +error: #[graphql_object] attribute is applicable to non-trait `impl` blocks only + --> fail/object/attr_wrong_syntax.rs:7:1 + | +7 | #[graphql_object] + | ^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `graphql_object` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0609]: no field `self` on type `&MyObject` + --> fail/object/attr_wrong_syntax.rs:10:14 + | +10 | self.self.my_field + | ^^^^ unknown field + | + = note: available fields are: `my_field` diff --git a/tests/codegen/fail/subscription/argument_double_underscored.rs b/tests/codegen/fail/subscription/argument_double_underscored.rs index fe01fc69..aaaec96d 100644 --- a/tests/codegen/fail/subscription/argument_double_underscored.rs +++ b/tests/codegen/fail/subscription/argument_double_underscored.rs @@ -1,14 +1,15 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct Obj; #[graphql_subscription] impl Obj { - async fn id(&self, __num: i32) -> Stream<'static, &'static str> { + async fn id(&self, __num: i32) -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funA"))) } } diff --git a/tests/codegen/fail/subscription/argument_double_underscored.stderr b/tests/codegen/fail/subscription/argument_double_underscored.stderr index a79c53eb..8866daaa 100644 --- a/tests/codegen/fail/subscription/argument_double_underscored.stderr +++ b/tests/codegen/fail/subscription/argument_double_underscored.stderr @@ -1,6 +1,6 @@ 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. · note: https://spec.graphql.org/October2021#sec-Schema - --> fail/subscription/argument_double_underscored.rs:11:24 + --> fail/subscription/argument_double_underscored.rs:12:24 | -11 | async fn id(&self, __num: i32) -> Stream<'static, &'static str> { +12 | async fn id(&self, __num: i32) -> BoxStream<'static, &'static str> { | ^^^^^ diff --git a/tests/codegen/fail/subscription/argument_non_input_type.rs b/tests/codegen/fail/subscription/argument_non_input_type.rs index 90b24bb2..0bcd0560 100644 --- a/tests/codegen/fail/subscription/argument_non_input_type.rs +++ b/tests/codegen/fail/subscription/argument_non_input_type.rs @@ -1,9 +1,9 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; -use futures::{future, stream}; +use futures::{stream, Stream}; use juniper::{graphql_subscription, GraphQLObject}; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; #[derive(GraphQLObject)] struct ObjA { @@ -14,7 +14,7 @@ struct ObjB; #[graphql_subscription] impl ObjB { - async fn id(&self, obj: ObjA) -> Stream<'static, &'static str> { + async fn id(&self, obj: ObjA) -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funA"))) } } diff --git a/tests/codegen/fail/subscription/argument_non_input_type.stderr b/tests/codegen/fail/subscription/argument_non_input_type.stderr index baded3fd..3022c6b4 100644 --- a/tests/codegen/fail/subscription/argument_non_input_type.stderr +++ b/tests/codegen/fail/subscription/argument_non_input_type.stderr @@ -1,7 +1,7 @@ warning: unused variable: `obj` --> fail/subscription/argument_non_input_type.rs:17:24 | -17 | async fn id(&self, obj: ObjA) -> Stream<'static, &'static str> { +17 | async fn id(&self, obj: ObjA) -> BoxStream<'static, &'static str> { | ^^^ help: if this is intentional, prefix it with an underscore: `_obj` | = note: `#[warn(unused_variables)]` on by default @@ -9,7 +9,7 @@ warning: unused variable: `obj` error[E0277]: the trait bound `ObjA: IsInputType<__S>` is not satisfied --> fail/subscription/argument_non_input_type.rs:17:29 | -17 | async fn id(&self, obj: ObjA) -> Stream<'static, &'static str> { +17 | async fn id(&self, obj: ObjA) -> BoxStream<'static, &'static str> { | ^^^^ the trait `IsInputType<__S>` is not implemented for `ObjA` | = help: the following other types implement trait `IsInputType<S>`: @@ -29,7 +29,7 @@ error[E0277]: the trait bound `ObjA: FromInputValue<__S>` is not satisfied 15 | #[graphql_subscription] | ----------------------- required by a bound introduced by this call 16 | impl ObjB { -17 | async fn id(&self, obj: ObjA) -> Stream<'static, &'static str> { +17 | async fn id(&self, obj: ObjA) -> BoxStream<'static, &'static str> { | ^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjA` | = help: the following other types implement trait `FromInputValue<S>`: @@ -72,7 +72,7 @@ error[E0277]: the trait bound `ObjA: FromInputValue<__S>` is not satisfied error[E0277]: the trait bound `ObjA: FromInputValue<__S>` is not satisfied --> fail/subscription/argument_non_input_type.rs:17:29 | -17 | async fn id(&self, obj: ObjA) -> Stream<'static, &'static str> { +17 | async fn id(&self, obj: ObjA) -> BoxStream<'static, &'static str> { | ^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjA` | = help: the following other types implement trait `FromInputValue<S>`: diff --git a/tests/codegen/fail/subscription/argument_wrong_default_array.rs b/tests/codegen/fail/subscription/argument_wrong_default_array.rs index c0ec6863..4db4caea8 100644 --- a/tests/codegen/fail/subscription/argument_wrong_default_array.rs +++ b/tests/codegen/fail/subscription/argument_wrong_default_array.rs @@ -1,9 +1,9 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; -use futures::{future, stream}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct ObjA; @@ -12,7 +12,7 @@ impl ObjA { async fn wrong( &self, #[graphql(default = [true, false, false])] input: [bool; 2], - ) -> Stream<'static, bool> { + ) -> BoxStream<'static, bool> { Box::pin(stream::once(future::ready(input[0]))) } } diff --git a/tests/codegen/fail/subscription/field_double_underscored.rs b/tests/codegen/fail/subscription/field_double_underscored.rs index 686dccc2..cbc40783 100644 --- a/tests/codegen/fail/subscription/field_double_underscored.rs +++ b/tests/codegen/fail/subscription/field_double_underscored.rs @@ -1,14 +1,15 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct ObjA; #[graphql_subscription] -impl Character for ObjA { - async fn __id() -> Stream<'static, &'static str> { +impl ObjA { + async fn __id() -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funA"))) } } diff --git a/tests/codegen/fail/subscription/field_double_underscored.stderr b/tests/codegen/fail/subscription/field_double_underscored.stderr index c22772ab..271f188a 100644 --- a/tests/codegen/fail/subscription/field_double_underscored.stderr +++ b/tests/codegen/fail/subscription/field_double_underscored.stderr @@ -1,7 +1,6 @@ -error: #[graphql_subscription] attribute is applicable to non-trait `impl` blocks only - --> fail/subscription/field_double_underscored.rs:9:1 - | -9 | #[graphql_subscription] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `graphql_subscription` (in Nightly builds, run with -Z macro-backtrace for more info) +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. + · note: https://spec.graphql.org/October2021#sec-Schema + --> fail/subscription/field_double_underscored.rs:12:14 + | +12 | async fn __id() -> BoxStream<'static, &'static str> { + | ^^^^ diff --git a/tests/codegen/fail/subscription/field_non_output_return_type.rs b/tests/codegen/fail/subscription/field_non_output_return_type.rs index 8cc91854..071ea61b 100644 --- a/tests/codegen/fail/subscription/field_non_output_return_type.rs +++ b/tests/codegen/fail/subscription/field_non_output_return_type.rs @@ -1,9 +1,9 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; -use futures::{future, stream}; +use futures::{stream, Stream}; use juniper::{graphql_subscription, GraphQLInputObject}; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; #[derive(GraphQLInputObject)] struct ObjB { @@ -14,7 +14,7 @@ struct ObjA; #[graphql_subscription] impl ObjA { - async fn id(&self) -> Stream<'static, ObjB> { + async fn id(&self) -> BoxStream<'static, ObjB> { Box::pin(stream::once(future::ready(ObjB { id: 34 }))) } } diff --git a/tests/codegen/fail/subscription/field_not_async.rs b/tests/codegen/fail/subscription/field_not_async.rs index f9cfb5b5..9e1312a1 100644 --- a/tests/codegen/fail/subscription/field_not_async.rs +++ b/tests/codegen/fail/subscription/field_not_async.rs @@ -1,14 +1,15 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct ObjA; #[graphql_subscription] impl ObjA { - fn id(&self) -> Stream<'static, bool> { + fn id(&self) -> BoxStream<'static, bool> { Box::pin(stream::once(future::ready(true))) } } diff --git a/tests/codegen/fail/subscription/field_not_async.stderr b/tests/codegen/fail/subscription/field_not_async.stderr index d1c63681..45cb105f 100644 --- a/tests/codegen/fail/subscription/field_not_async.stderr +++ b/tests/codegen/fail/subscription/field_not_async.stderr @@ -1,7 +1,7 @@ error: GraphQL object synchronous resolvers are not supported · note: https://spec.graphql.org/October2021#sec-Objects · note: Specify that this function is async: `async fn foo()` - --> fail/subscription/field_not_async.rs:11:5 + --> fail/subscription/field_not_async.rs:12:5 | -11 | fn id(&self) -> Stream<'static, bool> { +12 | fn id(&self) -> BoxStream<'static, bool> { | ^^ diff --git a/tests/codegen/fail/subscription/fields_duplicate.rs b/tests/codegen/fail/subscription/fields_duplicate.rs index 22ccc977..ad9c01de 100644 --- a/tests/codegen/fail/subscription/fields_duplicate.rs +++ b/tests/codegen/fail/subscription/fields_duplicate.rs @@ -1,19 +1,20 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct ObjA; #[graphql_subscription] impl ObjA { - async fn id(&self) -> Stream<'static, &'static str> { + async fn id(&self) -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funA"))) } #[graphql(name = "id")] - async fn id2(&self) -> Stream<'static, &'static str> { + async fn id2(&self) -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funB"))) } } diff --git a/tests/codegen/fail/subscription/fields_duplicate.stderr b/tests/codegen/fail/subscription/fields_duplicate.stderr index c3c43abd..f40d76fa 100644 --- a/tests/codegen/fail/subscription/fields_duplicate.stderr +++ b/tests/codegen/fail/subscription/fields_duplicate.stderr @@ -1,6 +1,12 @@ error: GraphQL object must have a different name for each field · note: https://spec.graphql.org/October2021#sec-Objects - --> fail/subscription/fields_duplicate.rs:10:6 + --> fail/subscription/fields_duplicate.rs:11:6 | -10 | impl ObjA { +11 | impl ObjA { | ^^^^ + +error: cannot find attribute `graphql` in this scope + --> fail/subscription/fields_duplicate.rs:16:7 + | +16 | #[graphql(name = "id")] + | ^^^^^^^ diff --git a/tests/codegen/fail/subscription/name_double_underscored.rs b/tests/codegen/fail/subscription/name_double_underscored.rs index d9911148..a26874fb 100644 --- a/tests/codegen/fail/subscription/name_double_underscored.rs +++ b/tests/codegen/fail/subscription/name_double_underscored.rs @@ -1,14 +1,15 @@ -use std::pin::Pin; +use std::{future, pin::Pin}; +use futures::{stream, Stream}; use juniper::graphql_subscription; -type Stream<'a, I> = Pin<Box<dyn futures::Stream<Item = I> + Send + 'a>>; +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; struct __Obj; #[graphql_subscription] impl __Obj { - fn id(&self) -> Stream<'static, &'static str> { + fn id(&self) -> BoxStream<'static, &'static str> { Box::pin(stream::once(future::ready("funA"))) } } diff --git a/tests/codegen/fail/subscription/name_double_underscored.stderr b/tests/codegen/fail/subscription/name_double_underscored.stderr index 607414ec..d7a0ba65 100644 --- a/tests/codegen/fail/subscription/name_double_underscored.stderr +++ b/tests/codegen/fail/subscription/name_double_underscored.stderr @@ -1,6 +1,6 @@ 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. · note: https://spec.graphql.org/October2021#sec-Schema - --> fail/subscription/name_double_underscored.rs:10:6 + --> fail/subscription/name_double_underscored.rs:11:6 | -10 | impl __Obj { +11 | impl __Obj { | ^^^^^ diff --git a/tests/codegen/fail/subscription/wrong_syntax.rs b/tests/codegen/fail/subscription/wrong_syntax.rs new file mode 100644 index 00000000..f99d2697 --- /dev/null +++ b/tests/codegen/fail/subscription/wrong_syntax.rs @@ -0,0 +1,19 @@ +use std::{future, pin::Pin}; + +use futures::{stream, Stream}; +use juniper::graphql_subscription; + +type BoxStream<'a, I> = Pin<Box<dyn Stream<Item = I> + Send + 'a>>; + +struct ObjA { + field: bool +} + +#[graphql_subscription] +impl ObjA { + fn id(&self) -> BoxStream<'static, bool> { + Box::pin(stream::once(future::ready(self.self.field))) + } +} + +fn main() {} diff --git a/tests/codegen/fail/subscription/wrong_syntax.stderr b/tests/codegen/fail/subscription/wrong_syntax.stderr new file mode 100644 index 00000000..7994ddc9 --- /dev/null +++ b/tests/codegen/fail/subscription/wrong_syntax.stderr @@ -0,0 +1,15 @@ +error: #[graphql_subscription] attribute is applicable to non-trait `impl` blocks only + --> fail/subscription/wrong_syntax.rs:12:1 + | +12 | #[graphql_subscription] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the attribute macro `graphql_subscription` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0609]: no field `self` on type `&ObjA` + --> fail/subscription/wrong_syntax.rs:15:50 + | +15 | Box::pin(stream::once(future::ready(self.self.field))) + | ^^^^ unknown field + | + = note: available fields are: `field` diff --git a/tests/codegen/fail/union/trait_with_attr_on_method.stderr b/tests/codegen/fail/union/trait_with_attr_on_method.stderr index 9341e9bb..b207dced 100644 --- a/tests/codegen/fail/union/trait_with_attr_on_method.stderr +++ b/tests/codegen/fail/union/trait_with_attr_on_method.stderr @@ -5,3 +5,9 @@ error: GraphQL union cannot use #[graphql(with = ...)] attribute on a trait meth | 5 | #[graphql(with = something)] | ^^^^ + +error: cannot find attribute `graphql` in this scope + --> fail/union/trait_with_attr_on_method.rs:5:7 + | +5 | #[graphql(with = something)] + | ^^^^^^^