diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 675ec3cd..23b3981f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -29,6 +29,7 @@ jobs:
       - release-check
       - rustfmt
       - test
+      - test-book
       - wasm
     runs-on: ubuntu-latest
     steps:
@@ -171,7 +172,6 @@ jobs:
           - juniper_graphql_ws
           - juniper_integration_tests
           - juniper_codegen_tests
-          - juniper_book_tests
           - juniper_actix
           - juniper_hyper
           - juniper_iron
@@ -194,14 +194,6 @@ jobs:
             os: macOS
           - crate: juniper_codegen_tests
             os: windows
-          - crate: juniper_book_tests
-            toolchain: beta
-          - crate: juniper_book_tests
-            toolchain: nightly
-          # TODO: LLVM ERROR: out of memory
-          - crate: juniper_integration_tests
-            os: windows
-
     runs-on: ${{ matrix.os }}-latest
     steps:
       - uses: actions/checkout@v3
@@ -213,6 +205,34 @@ jobs:
 
       - run: make test.cargo crate=${{ matrix.crate }}
 
+  test-book:
+    name: test Book
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - ubuntu
+          - macOS
+          # TODO: Re-enable once rust-lang/rust#99466 is fixed:
+          #       https://github.com/rust-lang/rust/issues/99466
+          #- windows
+        toolchain:
+          - stable
+          - beta
+          - nightly
+    runs-on: ${{ matrix.os }}-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.toolchain }}
+          override: true
+
+      - run: cargo install mdbook
+
+      - run: make test.book
+
   wasm:
     strategy:
       fail-fast: false
@@ -281,6 +301,7 @@ jobs:
       - package
       - rustfmt
       - test
+      - test-book
       - wasm
     if: ${{ startsWith(github.ref, 'refs/tags/juniper') }}
     runs-on: ubuntu-latest
@@ -304,7 +325,7 @@ jobs:
       - name: Parse CHANGELOG link
         id: changelog
         run: echo ::set-output
-                  name=LINK::https://github.com/${{ github.repository }}/blob/${{ steps.crate.outputs.NAME }}%40${{ steps.release.outputs.VERSION }}//${{ steps.crate.outputs.NAME }}/CHANGELOG.md#$(sed -n '/^## \[${{ steps.release.outputs.VERSION }}\]/{s/^## \[\(.*\)\][^0-9]*\([0-9].*\)/\1--\2/;s/[^0-9a-z-]*//g;p;}' ${{ steps.crate.outputs.NAME }}/CHANGELOG.md)
+                  name=LINK::${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.crate.outputs.NAME }}%40${{ steps.release.outputs.VERSION }}//${{ steps.crate.outputs.NAME }}/CHANGELOG.md#$(sed -n '/^## \[${{ steps.release.outputs.VERSION }}\]/{s/^## \[\(.*\)\][^0-9]*\([0-9].*\)/\1--\2/;s/[^0-9a-z-]*//g;p;}' ${{ steps.crate.outputs.NAME }}/CHANGELOG.md)
 
       - uses: softprops/action-gh-release@v1
         env:
@@ -347,19 +368,17 @@ jobs:
 
   deploy-book:
     name: deploy Book
-    needs: ["test"]
+    needs: ["test", "test-book"]
     if: ${{ github.ref == 'refs/heads/master'
-            || startsWith(github.ref, 'refs/tags/juniper@') }}
+         || startsWith(github.ref, 'refs/tags/juniper@') }}
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
       - uses: peaceiris/actions-mdbook@v1
 
-      - run: make book.build out=gh-pages/master
-        if: ${{ github.ref == 'refs/heads/master' }}
-
-      - run: make book.build out=gh-pages
-        if: ${{ startsWith(github.ref, 'refs/tags/juniper@') }}
+      - run: make book.build out=gh-pages${{ (github.ref == 'refs/heads/master'
+                                              && '/master')
+                                          ||     '' }}
 
       - name: Deploy to GitHub Pages
         uses: peaceiris/actions-gh-pages@v3
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 974fe42f..015f03f8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,19 +17,16 @@ Before submitting a PR, you should follow these steps to prevent redundant churn
 
 Consistent formatting is enforced on the CI.
 
-Before you submit your PR, you should run `cargo fmt` in the root directory.
+Before you submit your PR, you should run `cargo +nightly fmt --all` in the root directory (or use the `make fmt` shortcut).
 
-Formatting should be run on the **stable** compiler. 
-(You can do `rustup run stable cargo fmt` when developing on nightly)
+Formatting should be run on the **nightly** compiler.
 
 ### Run all tests
 
-To run all available tests, including verifying the code examples in the book,
-you can use [cargo-make](https://github.com/sagiegurari/cargo-make).
+To run all available tests, including verifying the code examples in the book:
 
-1. Install cargo-make with `cargo install cargo-make`
-2. Run `cargo make ci-flow` in the root directory
-   (You can do `rustup run nightly cargo make ci-flow` to run all tests when developing on stable)
+1. Run `cargo test` in the root directory.
+2. Run `make test.book` in the root directory.
 
 ### Update the CHANGELOG
 
diff --git a/Cargo.toml b/Cargo.toml
index 1a97d16a..9b94e2fa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,6 @@
 [workspace]
 members = [
     "benches",
-    "book/tests",
     "examples/basic_subscriptions",
     "examples/warp_async",
     "examples/warp_subscriptions",
diff --git a/Makefile b/Makefile
index e6a566bf..7f5755be 100644
--- a/Makefile
+++ b/Makefile
@@ -87,10 +87,14 @@ cargo.test: test.cargo
 # Run Rust tests of Book.
 #
 # Usage:
-#	make test.book
+#	make test.book [clean=(no|yes)]
 
 test.book:
-	@make test.cargo crate=juniper_book_tests
+ifeq ($(clean),yes)
+	cargo clean
+endif
+	cargo build
+	mdbook test book -L target/debug/deps
 
 
 # Run Rust tests of project crates.
diff --git a/README.md b/README.md
index 3bd50048..5a028b05 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ see the [actix][actix_examples], [hyper][hyper_examples], [rocket][rocket_exampl
 ## Features
 
 Juniper supports the full GraphQL query language according to the
-[specification][graphql_spec], including interfaces, unions, schema
+[specification (October 2021)][graphql_spec], including interfaces, unions, schema
 introspection, and validations. It can also output the schema in the [GraphQL Schema Language][schema_language].
 
 As an exception to other GraphQL libraries for other languages, Juniper builds
@@ -97,7 +97,7 @@ Juniper has not reached 1.0 yet, thus some API instability should be expected.
 [graphiql]: https://github.com/graphql/graphiql
 [playground]: https://github.com/prisma/graphql-playground
 [iron]: https://github.com/iron/iron
-[graphql_spec]: http://facebook.github.io/graphql
+[graphql_spec]: https://spec.graphql.org/October2021
 [schema_language]: https://graphql.org/learn/schema/#type-language
 [schema_approach]: https://blog.logrocket.com/code-first-vs-schema-first-development-graphql/
 [test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/juniper/src/tests/fixtures/starwars/schema.rs
diff --git a/benches/Cargo.toml b/benches/Cargo.toml
index c5014f5a..57a1c9d4 100644
--- a/benches/Cargo.toml
+++ b/benches/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "juniper_benchmarks"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 authors = ["Christoph Herzog <chris@theduke.at>"]
 publish = false
 
diff --git a/benches/benches/benchmark.rs b/benches/benches/benchmark.rs
index 7aa5da65..c2ba501c 100644
--- a/benches/benches/benchmark.rs
+++ b/benches/benches/benchmark.rs
@@ -38,7 +38,7 @@ fn bench_sync_vs_async_users_flat_instant(c: &mut Criterion) {
                 b.iter(|| {
                     j::execute_sync(
                         SYNC_QUERY,
-                        vec![("ids".to_string(), ids.clone())].into_iter().collect(),
+                        vec![("ids".to_owned(), ids.clone())].into_iter().collect(),
                     )
                 })
             },
@@ -58,7 +58,7 @@ fn bench_sync_vs_async_users_flat_instant(c: &mut Criterion) {
             b.iter(|| {
                 let f = j::execute(
                     ASYNC_QUERY,
-                    vec![("ids".to_string(), ids.clone())].into_iter().collect(),
+                    vec![("ids".to_owned(), ids.clone())].into_iter().collect(),
                 );
                 rt.block_on(f)
             })
@@ -77,7 +77,7 @@ fn bench_sync_vs_async_users_flat_instant(c: &mut Criterion) {
             b.iter(|| {
                 let f = j::execute(
                     ASYNC_QUERY,
-                    vec![("ids".to_string(), ids.clone())].into_iter().collect(),
+                    vec![("ids".to_owned(), ids.clone())].into_iter().collect(),
                 );
                 rt.block_on(f)
             })
diff --git a/benches/src/lib.rs b/benches/src/lib.rs
index 526d0043..c8ad5b51 100644
--- a/benches/src/lib.rs
+++ b/benches/src/lib.rs
@@ -11,11 +11,11 @@ pub type QueryResult = Result<
     String,
 >;
 
-pub struct Context {}
+pub struct Context;
 
 impl Context {
     fn new() -> Self {
-        Self {}
+        Self
     }
 }
 
@@ -51,8 +51,8 @@ impl User {
         Self {
             id,
             kind: UserKind::Admin,
-            username: "userx".to_string(),
-            email: "userx@domain.com".to_string(),
+            username: "userx".into(),
+            email: "userx@domain.com".into(),
             gender: Some(Gender::Female),
         }
     }
@@ -97,7 +97,7 @@ pub fn new_schema() -> RootNode<'static, Query, EmptyMutation<Context>, EmptySub
 pub fn execute_sync(query: &str, vars: Variables) -> QueryResult {
     let root = new_schema();
     let ctx = Context::new();
-    juniper::execute_sync(query, None, &root, &vars, &ctx).map_err(|e| format!("{:?}", e))
+    juniper::execute_sync(query, None, &root, &vars, &ctx).map_err(|e| format!("{e:?}"))
 }
 
 pub async fn execute(query: &str, vars: Variables) -> QueryResult {
@@ -105,5 +105,5 @@ pub async fn execute(query: &str, vars: Variables) -> QueryResult {
     let ctx = Context::new();
     juniper::execute(query, None, &root, &vars, &ctx)
         .await
-        .map_err(|e| format!("{:?}", e))
+        .map_err(|e| format!("{e:?}"))
 }
diff --git a/book/README.md b/book/README.md
index f4b28d98..93ac3407 100644
--- a/book/README.md
+++ b/book/README.md
@@ -47,21 +47,8 @@ The output will be in the `_rendered/` directory.
 
 To run the tests validating all code examples in the book, run:
 ```bash
-cd tests/
-cargo test
-
-# or from project root dir:
-cargo test -p juniper_book_tests
+mdbook test -L ../target/debug/deps
 
 # or via shortcut from project root dir:
 make test.book
 ```
-
-
-
-
-## Test setup
-
-All Rust code examples in the book are compiled on the CI.
-
-This is done using the [skeptic](https://github.com/budziq/rust-skeptic) crate.
diff --git a/book/book.toml b/book/book.toml
index 9fc67124..9dad3932 100644
--- a/book/book.toml
+++ b/book/book.toml
@@ -13,4 +13,4 @@ create-missing = false
 git_repository_url = "https://github.com/graphql-rs/juniper"
 
 [rust]
-edition = "2018"
+edition = "2021"
diff --git a/book/src/README.md b/book/src/README.md
index 07968a55..367f16cd 100644
--- a/book/src/README.md
+++ b/book/src/README.md
@@ -21,7 +21,7 @@ embedded [Graphiql][graphiql] for easy debugging.
 ## Features
 
 Juniper supports the full GraphQL query language according to the
-[specification][graphql_spec], including interfaces, unions, schema
+[specification (October 2021)][graphql_spec], including interfaces, unions, schema
 introspection, and validations.
 It does not, however, support the schema language.
 
@@ -57,7 +57,7 @@ Juniper has not reached 1.0 yet, thus some API instability should be expected.
 [graphql]: http://graphql.org
 [graphiql]: https://github.com/graphql/graphiql
 [iron]: https://github.com/iron/iron
-[graphql_spec]: http://facebook.github.io/graphql
+[graphql_spec]: https://spec.graphql.org/October2021
 [test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/juniper/src/tests/schema.rs
 [tokio]: https://github.com/tokio-rs/tokio
 [hyper_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_hyper/examples
diff --git a/book/src/advanced/dataloaders.md b/book/src/advanced/dataloaders.md
index 560f6048..ef03afc1 100644
--- a/book/src/advanced/dataloaders.md
+++ b/book/src/advanced/dataloaders.md
@@ -68,7 +68,7 @@ use std::env;
 
 pub fn get_db_conn() -> Connection {
     let pg_connection_string = env::var("DATABASE_URI").expect("need a db uri");
-    println!("Connecting to {}", pg_connection_string);
+    println!("Connecting to {pg_connection_string}");
     let conn = Connection::connect(&pg_connection_string[..], TlsMode::None).unwrap();
     println!("Connection is fine");
     conn
@@ -101,7 +101,7 @@ impl BatchFn<i32, Cult> for CultBatcher {
 
     // A hashmap is used, as we need to return an array which maps each original key to a Cult.
     async fn load(&self, keys: &[i32]) -> HashMap<i32, Cult> {
-        println!("load cult batch {:?}", keys);
+        println!("load cult batch {keys:?}");
         let mut cult_hashmap = HashMap::new();
         get_cult_by_ids(&mut cult_hashmap, keys.to_vec());
         cult_hashmap
diff --git a/book/src/advanced/introspection.md b/book/src/advanced/introspection.md
index 3fabcb73..d7bc7c2f 100644
--- a/book/src/advanced/introspection.md
+++ b/book/src/advanced/introspection.md
@@ -66,7 +66,7 @@ type Schema = juniper::RootNode<
 
 fn main() {
     // Create a context object.
-    let ctx = Context{};
+    let ctx = Context;
 
     // Run the built-in introspection query.
     let (res, _errors) = juniper::introspect(
diff --git a/book/src/advanced/subscriptions.md b/book/src/advanced/subscriptions.md
index 90877c42..51200b10 100644
--- a/book/src/advanced/subscriptions.md
+++ b/book/src/advanced/subscriptions.md
@@ -25,9 +25,11 @@ This example shows a subscription operation that returns two events, the strings
 sequentially: 
 
 ```rust
-# use juniper::{graphql_object, graphql_subscription, FieldError};
-# use futures::Stream;
+# extern crate futures;
+# extern crate juniper;
 # use std::pin::Pin;
+# use futures::Stream;
+# use juniper::{graphql_object, graphql_subscription, FieldError};
 #
 # #[derive(Clone)]
 # pub struct Database;
@@ -80,7 +82,6 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
 # extern crate juniper;
 # extern crate juniper_subscriptions;
 # extern crate serde_json;
-# extern crate tokio;
 # use juniper::{
 #     http::GraphQLRequest,
 #     graphql_object, graphql_subscription, 
@@ -98,7 +99,7 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
 # 
 # impl Database {
 #     fn new() -> Self {
-#         Self {}
+#         Self
 #     }
 # }
 # 
@@ -126,7 +127,7 @@ where [`Connection`][Connection] is a `Stream` of values returned by the operati
 type Schema = RootNode<'static, Query, EmptyMutation<Database>, Subscription>;
 
 fn schema() -> Schema {
-    Schema::new(Query {}, EmptyMutation::new(), Subscription {})
+    Schema::new(Query, EmptyMutation::new(), Subscription)
 }
 
 async fn run_subscription() {
diff --git a/book/src/quickstart.md b/book/src/quickstart.md
index b8ff7226..770b86a6 100644
--- a/book/src/quickstart.md
+++ b/book/src/quickstart.md
@@ -130,7 +130,7 @@ impl Mutation {
 type Schema = juniper::RootNode<'static, Query, Mutation, EmptySubscription<Context>>;
 #
 # fn main() {
-#   let _ = Schema::new(Query, Mutation{}, EmptySubscription::new());
+#   let _ = Schema::new(Query, Mutation, EmptySubscription::new());
 # }
 ```
 
diff --git a/book/src/servers/iron.md b/book/src/servers/iron.md
index 9c81fc4b..38782c36 100644
--- a/book/src/servers/iron.md
+++ b/book/src/servers/iron.md
@@ -50,7 +50,7 @@ struct Root;
 #[juniper::graphql_object]
 impl Root {
     fn foo() -> String {
-        "Bar".to_owned()
+        "Bar".into()
     }
 }
 
diff --git a/book/src/types/interfaces.md b/book/src/types/interfaces.md
index 949344f9..87b72348 100644
--- a/book/src/types/interfaces.md
+++ b/book/src/types/interfaces.md
@@ -227,7 +227,7 @@ impl ObjA {
 //     ^^ 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")
+        is_present.then_some(&self.id).unwrap_or("missing")
     }
 }
 
@@ -473,9 +473,9 @@ struct Droid {
 
 
 
-[1]: https://spec.graphql.org/June2018/#sec-Interfaces
+[1]: https://spec.graphql.org/October2021#sec-Interfaces
 [2]: https://doc.rust-lang.org/reference/types/trait-object.html
 [3]: https://docs.rs/juniper/latest/juniper/trait.ScalarValue.html
 [4]: https://docs.rs/juniper/latest/juniper/struct.Executor.html
-[5]: https://spec.graphql.org/June2018/#sec-Objects
+[5]: https://spec.graphql.org/October2021#sec-Objects
 [6]: https://docs.rs/juniper/0.14.2/juniper/trait.Context.html
diff --git a/book/src/types/objects/complex_fields.md b/book/src/types/objects/complex_fields.md
index 86d310ec..f8aa1399 100644
--- a/book/src/types/objects/complex_fields.md
+++ b/book/src/types/objects/complex_fields.md
@@ -157,7 +157,7 @@ They can have custom descriptions and default values.
 # extern crate juniper;
 # use juniper::graphql_object;
 #
-struct Person {}
+struct Person;
 
 #[graphql_object]
 impl Person {
@@ -177,7 +177,7 @@ impl Person {
         #[graphql(default)]
         arg2: i32,
     ) -> String {
-        format!("{} {}", arg1, arg2)
+        format!("{arg1} {arg2}")
     }
 }
 #
diff --git a/book/src/types/objects/error_handling.md b/book/src/types/objects/error_handling.md
index 4adc269f..5404c4bf 100644
--- a/book/src/types/objects/error_handling.md
+++ b/book/src/types/objects/error_handling.md
@@ -60,7 +60,7 @@ there - those errors are automatically converted into `FieldError`.
 
 ## Error payloads, `null`, and partial errors
 
-Juniper's error behavior conforms to the [GraphQL specification](https://spec.graphql.org/June2018/#sec-Errors-and-Non-Nullability).
+Juniper's error behavior conforms to the [GraphQL specification](https://spec.graphql.org/October2021#sec-Handling-Field-Errors).
 
 When a field returns an error, the field's result is replaced by `null`, an
 additional `errors` object is created at the top level of the response, and the
@@ -168,7 +168,7 @@ impl Example {
 # fn main() {}
 ```
 
-The specified structured error information is included in the [`extensions`](https://facebook.github.io/graphql/June2018/#sec-Errors) key:
+The specified structured error information is included in the [`extensions`](https://spec.graphql.org/October2021#sec-Errors) key:
 
 ```json
 {
@@ -242,15 +242,15 @@ impl Mutation {
 
         if !(10 <= name.len() && name.len() <= 100) {
             errors.push(ValidationError {
-                field: "name".to_string(),
-                message: "between 10 and 100".to_string()
+                field: "name".into(),
+                message: "between 10 and 100".into(),
             });
         }
 
         if !(1 <= quantity && quantity <= 10) {
             errors.push(ValidationError {
-                field: "quantity".to_string(),
-                message: "between 1 and 10".to_string()
+                field: "quantity".into(),
+                message: "between 1 and 10".into(),
             });
         }
 
@@ -338,11 +338,11 @@ impl Mutation {
         };
 
         if !(10 <= name.len() && name.len() <= 100) {
-            error.name = Some("between 10 and 100".to_string());
+            error.name = Some("between 10 and 100".into());
         }
 
         if !(1 <= quantity && quantity <= 10) {
-            error.quantity = Some("between 1 and 10".to_string());
+            error.quantity = Some("between 1 and 10".into());
         }
 
         if error.name.is_none() && error.quantity.is_none() {
@@ -436,11 +436,11 @@ impl Mutation {
         };
 
         if !(10 <= name.len() && name.len() <= 100) {
-            error.name = Some("between 10 and 100".to_string());
+            error.name = Some("between 10 and 100".into());
         }
 
         if !(1 <= quantity && quantity <= 10) {
-            error.quantity = Some("between 1 and 10".to_string());
+            error.quantity = Some("between 1 and 10".into());
         }
 
         if error.name.is_none() && error.quantity.is_none() {
diff --git a/book/src/types/objects/using_contexts.md b/book/src/types/objects/using_contexts.md
index 027b61a6..a795e09c 100644
--- a/book/src/types/objects/using_contexts.md
+++ b/book/src/types/objects/using_contexts.md
@@ -97,6 +97,7 @@ Context cannot be specified by a mutable reference, because concurrent fields re
 For example, when using async runtime with [work stealing][2] (like `tokio`), which obviously requires thread safety in addition, you will need to use a corresponding async version of `RwLock`:
 ```rust
 # extern crate juniper;
+# extern crate tokio;
 # use std::collections::HashMap;
 # use juniper::graphql_object;
 use tokio::sync::RwLock;
diff --git a/book/src/types/scalars.md b/book/src/types/scalars.md
index a17e07a2..8fbe88ed 100644
--- a/book/src/types/scalars.md
+++ b/book/src/types/scalars.md
@@ -24,10 +24,10 @@ Juniper has built-in support for:
 * `String` and `&str` as `String`
 * `bool` as `Boolean`
 * `juniper::ID` as `ID`. This type is defined [in the
-  spec](http://facebook.github.io/graphql/#sec-ID) as a type that is serialized
+  spec](https://spec.graphql.org/October2021#sec-ID) as a type that is serialized
   as a string but can be parsed from both a string and an integer.
 
-Note that there is no built-in support for `i64`/`u64`, as the GraphQL spec [doesn't define any built-in scalars for `i64`/`u64` by default](https://spec.graphql.org/June2018/#sec-Int). You may wish to leverage a [custom GraphQL scalar](#custom-scalars) in your schema to support them.
+Note that there is no built-in support for `i64`/`u64`, as the GraphQL spec [doesn't define any built-in scalars for `i64`/`u64` by default](https://spec.graphql.org/October2021#sec-Int). You may wish to leverage a [custom GraphQL scalar](#custom-scalars) in your schema to support them.
 
 **Third party types**:
 
@@ -114,6 +114,7 @@ All the methods used from newtype's field can be replaced with attributes:
 ### `#[graphql(to_output_with = <fn>)]` attribute
 
 ```rust
+# extern crate juniper;
 # use juniper::{GraphQLScalar, ScalarValue, Value};
 #
 #[derive(GraphQLScalar)]
@@ -131,6 +132,7 @@ fn to_output<S: ScalarValue>(v: &Incremented) -> Value<S> {
 ### `#[graphql(from_input_with = <fn>)]` attribute
 
 ```rust
+# extern crate juniper;
 # use juniper::{GraphQLScalar, InputValue, ScalarValue};
 #
 #[derive(GraphQLScalar)]
@@ -145,14 +147,13 @@ impl UserId {
         S: ScalarValue
     {
         input.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", input))
+            .ok_or_else(|| format!("Expected `String`, found: {input}"))
             .and_then(|str| {
                 str.strip_prefix("id: ")
                     .ok_or_else(|| {
                         format!(
                             "Expected `UserId` to begin with `id: `, \
-                             found: {}",
-                            input,
+                             found: {input}",
                         )
                     })
             })
@@ -166,6 +167,7 @@ impl UserId {
 ### `#[graphql(parse_token_with = <fn>]` or `#[graphql(parse_token(<types>)]` attributes
 
 ```rust
+# extern crate juniper;
 # use juniper::{
 #     GraphQLScalar, InputValue, ParseScalarResult, ParseScalarValue, 
 #     ScalarValue, ScalarToken, Value
@@ -190,7 +192,7 @@ where
     S: ScalarValue
 {
     match v {
-        StringOrInt::String(str) => Value::scalar(str.to_owned()),
+        StringOrInt::String(s) => Value::scalar(s.to_owned()),
         StringOrInt::Int(i) => Value::scalar(*i),
     }
 }
@@ -200,15 +202,12 @@ where
     S: ScalarValue
 {
     v.as_string_value()
-        .map(|s| StringOrInt::String(s.to_owned()))
+        .map(|s| StringOrInt::String(s.into()))
         .or_else(|| v.as_int_value().map(|i| StringOrInt::Int(i)))
-        .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+        .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
 }
 
-fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> 
-where
-    S: ScalarValue
-{
+fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
     <String as ParseScalarValue<S>>::from_str(value)
         .or_else(|_| <i32 as ParseScalarValue<S>>::from_str(value))
 }
@@ -228,6 +227,7 @@ Path can be simply `with = Self` (default path where macro expects resolvers to
 in case there is an impl block with custom resolvers:
 
 ```rust
+# extern crate juniper;
 # use juniper::{
 #     GraphQLScalar, InputValue, ParseScalarResult, ParseScalarValue,
 #     ScalarValue, ScalarToken, Value
@@ -243,7 +243,7 @@ enum StringOrInt {
 impl StringOrInt {
     fn to_output<S: ScalarValue>(&self) -> Value<S> {
         match self {
-            Self::String(str) => Value::scalar(str.to_owned()),
+            Self::String(s) => Value::scalar(s.to_owned()),
             Self::Int(i) => Value::scalar(*i),
         }
     }
@@ -253,12 +253,12 @@ impl StringOrInt {
         S: ScalarValue,
     {
         v.as_string_value()
-            .map(|s| Self::String(s.to_owned()))
+            .map(|s| Self::String(s.into()))
             .or_else(|| v.as_int_value().map(Self::Int))
-            .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
     }
   
-    fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S>
+    fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<S>
     where
         S: ScalarValue,
     {
@@ -273,6 +273,7 @@ impl StringOrInt {
 Or it can be path to a module, where custom resolvers are located.
 
 ```rust
+# extern crate juniper;
 # use juniper::{
 #     GraphQLScalar, InputValue, ParseScalarResult, ParseScalarValue, 
 #     ScalarValue, ScalarToken, Value
@@ -293,7 +294,7 @@ mod string_or_int {
         S: ScalarValue,
     {
         match v {
-            StringOrInt::String(str) => Value::scalar(str.to_owned()),
+            StringOrInt::String(s) => Value::scalar(s.to_owned()),
             StringOrInt::Int(i) => Value::scalar(*i),
         }
     }
@@ -303,12 +304,12 @@ mod string_or_int {
         S: ScalarValue,
     {
         v.as_string_value()
-            .map(|s| StringOrInt::String(s.to_owned()))
+            .map(|s| StringOrInt::String(s.into()))
             .or_else(|| v.as_int_value().map(StringOrInt::Int))
-            .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
     }
   
-    pub(super) fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S>
+    pub(super) fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<S>
     where
         S: ScalarValue,
     {
@@ -323,6 +324,7 @@ mod string_or_int {
 Also, you can partially override `#[graphql(with)]` attribute with other custom scalars.
 
 ```rust
+# extern crate juniper;
 # use juniper::{GraphQLScalar, InputValue, ParseScalarResult, ScalarValue, ScalarToken, Value};
 #
 #[derive(GraphQLScalar)]
@@ -338,7 +340,7 @@ impl StringOrInt {
         S: ScalarValue,
     {
         match self {
-            Self::String(str) => Value::scalar(str.to_owned()),
+            Self::String(s) => Value::scalar(s.to_owned()),
             Self::Int(i) => Value::scalar(*i),
         }
     }
@@ -348,9 +350,9 @@ impl StringOrInt {
         S: ScalarValue,
     {
         v.as_string_value()
-            .map(|s| Self::String(s.to_owned()))
+            .map(|s| Self::String(s.into()))
             .or_else(|| v.as_int_value().map(Self::Int))
-            .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
     }
 }
 #
@@ -403,8 +405,8 @@ mod date_scalar {
 
     pub(super) fn from_input(v: &InputValue<CustomScalarValue>) -> Result<Date, String> {
       v.as_string_value()
-          .ok_or_else(|| format!("Expected `String`, found: {}", v))
-          .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {}", e)))
+          .ok_or_else(|| format!("Expected `String`, found: {v}"))
+          .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {e}")))
     }
 }
 #
diff --git a/book/src/types/unions.md b/book/src/types/unions.md
index ac5d7db2..bfce7f77 100644
--- a/book/src/types/unions.md
+++ b/book/src/types/unions.md
@@ -130,7 +130,7 @@ impl Character {
 # fn main() {}
 ```
 
-With an external resolver function we can even declare a new [GraphQL union][1] variant where the Rust type is absent in the initial enum definition. The attribute syntax `#[graphql(on VariantType = resolver_fn)]` follows the [GraphQL syntax for dispatching union variants](https://spec.graphql.org/June2018/#example-f8163).
+With an external resolver function we can even declare a new [GraphQL union][1] variant where the Rust type is absent in the initial enum definition. The attribute syntax `#[graphql(on VariantType = resolver_fn)]` follows the [GraphQL syntax for dispatching union variants](https://spec.graphql.org/October2021#example-f8163).
 
 ```rust
 # #![allow(dead_code)]
@@ -485,7 +485,7 @@ enum Character {
 
 
 
-[1]: https://spec.graphql.org/June2018/#sec-Unions
+[1]: https://spec.graphql.org/October2021#sec-Unions
 [2]: https://docs.rs/juniper/latest/juniper/trait.ScalarValue.html
-[5]: https://spec.graphql.org/June2018/#sec-Interfaces
+[5]: https://spec.graphql.org/October2021#sec-Interfaces
 [6]: https://docs.rs/juniper/0.14.2/juniper/trait.Context.html
diff --git a/book/tests/Cargo.toml b/book/tests/Cargo.toml
deleted file mode 100644
index f73d6fb9..00000000
--- a/book/tests/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "juniper_book_tests"
-version = "0.0.0"
-edition = "2018"
-authors = ["Magnus Hallin <mhallin@fastmail.com>"]
-publish = false
-
-[dependencies]
-derive_more = "0.99"
-futures = "0.3"
-iron = "0.6"
-juniper = { path = "../../juniper" }
-juniper_iron = { path = "../../juniper_iron" }
-juniper_subscriptions = { path = "../../juniper_subscriptions" }
-mount = "0.4"
-serde_json = "1.0"
-skeptic = "0.13"
-tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "sync"] }
-uuid = "1.0"
-
-[build-dependencies]
-skeptic = "0.13"
diff --git a/book/tests/build.rs b/book/tests/build.rs
deleted file mode 100644
index 80e0cbe1..00000000
--- a/book/tests/build.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    let files = skeptic::markdown_files_of_directory("../src/");
-    skeptic::generate_doc_tests(&files);
-}
diff --git a/book/tests/src/lib.rs b/book/tests/src/lib.rs
deleted file mode 100644
index e1d5434b..00000000
--- a/book/tests/src/lib.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-#![deny(warnings)]
-
-include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
diff --git a/examples/actix_subscriptions/Cargo.toml b/examples/actix_subscriptions/Cargo.toml
index 9bab7b3b..9c200447 100644
--- a/examples/actix_subscriptions/Cargo.toml
+++ b/examples/actix_subscriptions/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "example_actix_subscriptions"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 authors = ["Mihai Dinculescu <mihai.dinculescu@outlook.com>"]
 publish = false
 
diff --git a/examples/actix_subscriptions/src/main.rs b/examples/actix_subscriptions/src/main.rs
index 66480242..6747105f 100644
--- a/examples/actix_subscriptions/src/main.rs
+++ b/examples/actix_subscriptions/src/main.rs
@@ -9,9 +9,9 @@ use actix_web::{
 };
 
 use juniper::{
-    graphql_object, graphql_subscription, graphql_value,
+    graphql_subscription, graphql_value,
     tests::fixtures::starwars::schema::{Database, Query},
-    EmptyMutation, FieldError, RootNode,
+    EmptyMutation, FieldError, GraphQLObject, RootNode,
 };
 use juniper_actix::{graphql_handler, playground_handler, subscriptions::subscriptions_handler};
 use juniper_graphql_ws::ConnectionConfig;
@@ -37,23 +37,12 @@ async fn graphql(
 
 struct Subscription;
 
+#[derive(GraphQLObject)]
 struct RandomHuman {
     id: String,
     name: String,
 }
 
-// TODO: remove this when async interfaces are merged
-#[graphql_object(context = Database)]
-impl RandomHuman {
-    fn id(&self) -> &str {
-        &self.id
-    }
-
-    fn name(&self) -> &str {
-        &self.name
-    }
-}
-
 type RandomHumanStream =
     Pin<Box<dyn futures::Stream<Item = Result<RandomHuman, FieldError>> + Send>>;
 
@@ -84,8 +73,8 @@ impl Subscription {
                     let human = context.get_human(&random_id).unwrap().clone();
 
                     yield Ok(RandomHuman {
-                        id: human.id().to_owned(),
-                        name: human.name().unwrap().to_owned(),
+                        id: human.id().into(),
+                        name: human.name().unwrap().into(),
                     })
                 }
             }
@@ -142,7 +131,7 @@ async fn main() -> std::io::Result<()> {
                     .finish()
             }))
     })
-    .bind(format!("{}:{}", "127.0.0.1", 8080))?
+    .bind("127.0.0.1:8080")?
     .run()
     .await
 }
diff --git a/examples/basic_subscriptions/Cargo.toml b/examples/basic_subscriptions/Cargo.toml
index f03bdef4..252bdbeb 100644
--- a/examples/basic_subscriptions/Cargo.toml
+++ b/examples/basic_subscriptions/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "example_basic_subscriptions"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 authors = ["Jordao Rosario <jordao.rosario01@gmail.com>"]
 publish = false
 
diff --git a/examples/basic_subscriptions/src/main.rs b/examples/basic_subscriptions/src/main.rs
index 82d4b46f..df523674 100644
--- a/examples/basic_subscriptions/src/main.rs
+++ b/examples/basic_subscriptions/src/main.rs
@@ -16,7 +16,7 @@ impl juniper::Context for Database {}
 
 impl Database {
     fn new() -> Self {
-        Self {}
+        Self
     }
 }
 
@@ -45,7 +45,7 @@ impl Subscription {
 type Schema = RootNode<'static, Query, EmptyMutation<Database>, Subscription>;
 
 fn schema() -> Schema {
-    Schema::new(Query {}, EmptyMutation::new(), Subscription {})
+    Schema::new(Query, EmptyMutation::new(), Subscription)
 }
 
 #[tokio::main]
diff --git a/examples/warp_async/Cargo.toml b/examples/warp_async/Cargo.toml
index 94208317..0f891304 100644
--- a/examples/warp_async/Cargo.toml
+++ b/examples/warp_async/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "example_warp_async"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 authors = ["Christoph Herzog <chris@theduke.at>"]
 publish = false
 
diff --git a/examples/warp_subscriptions/Cargo.toml b/examples/warp_subscriptions/Cargo.toml
index 6e22c5a7..da05cf99 100644
--- a/examples/warp_subscriptions/Cargo.toml
+++ b/examples/warp_subscriptions/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "example_warp_subscriptions"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 publish = false
 
 [dependencies]
diff --git a/examples/warp_subscriptions/src/main.rs b/examples/warp_subscriptions/src/main.rs
index abac06a5..4e4d4584 100644
--- a/examples/warp_subscriptions/src/main.rs
+++ b/examples/warp_subscriptions/src/main.rs
@@ -12,7 +12,7 @@ use juniper_warp::{playground_filter, subscriptions::serve_graphql_ws};
 use warp::{http::Response, Filter};
 
 #[derive(Clone)]
-struct Context {}
+struct Context;
 
 impl juniper::Context for Context {}
 
@@ -123,7 +123,7 @@ impl Subscription {
                     yield Ok(User {
                         id: counter,
                         kind: UserKind::Admin,
-                        name: "stream user".to_string(),
+                        name: "stream user".into(),
                     })
                 }
             }
@@ -149,11 +149,11 @@ async fn main() {
     let homepage = warp::path::end().map(|| {
         Response::builder()
             .header("content-type", "text/html")
-            .body("<html><h1>juniper_subscriptions demo</h1><div>visit <a href=\"/playground\">graphql playground</a></html>".to_string())
+            .body("<html><h1>juniper_subscriptions demo</h1><div>visit <a href=\"/playground\">graphql playground</a></html>")
     });
 
     let qm_schema = schema();
-    let qm_state = warp::any().map(move || Context {});
+    let qm_state = warp::any().map(|| Context);
     let qm_graphql_filter = juniper_warp::make_graphql_filter(qm_schema, qm_state.boxed());
 
     let root_node = Arc::new(schema());
@@ -165,10 +165,10 @@ async fn main() {
         .map(move |ws: warp::ws::Ws| {
             let root_node = root_node.clone();
             ws.on_upgrade(move |websocket| async move {
-                serve_graphql_ws(websocket, root_node, ConnectionConfig::new(Context {}))
+                serve_graphql_ws(websocket, root_node, ConnectionConfig::new(Context))
                     .map(|r| {
                         if let Err(e) = r {
-                            println!("Websocket error: {}", e);
+                            println!("Websocket error: {e}");
                         }
                     })
                     .await
diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md
index 7a5aa27a..bab5569f 100644
--- a/juniper/CHANGELOG.md
+++ b/juniper/CHANGELOG.md
@@ -27,7 +27,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
     - Removed support for `dyn` attribute argument (interface values as trait objects).
     - Removed support for `downcast` attribute argument (custom resolution into implementer types).
     - Removed support for `async` trait methods (not required anymore).
-    - Removed necessity of writing `impl Trait for Type` blocks (interfaces are implemented just by matching their fields now).
+    - Removed necessity of writing `impl Trait for Type` blocks (interfaces are implemented just by matching their fields now). ([#113])
     - Forbade default implementations of non-ignored trait methods.
     - Supported coercion of additional `null`able arguments and return sub-typing on implementer.
     - Supported `rename_all = "<policy>"` attribute argument influencing all its fields and their arguments. ([#971])
@@ -48,6 +48,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 - Reworked [`chrono` crate] integration GraphQL scalars according to [graphql-scalars.dev] specs: ([#1010])
     - Disabled `chrono` [Cargo feature] by default.
     - Removed `scalar-naivetime` [Cargo feature].
+- Removed lifetime parameter from `ParseError`, `GraphlQLError`, `GraphQLBatchRequest` and `GraphQLRequest`. ([#1081], [#528])
 
 ### Added
 
@@ -71,8 +72,13 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 - Unsupported expressions in `graphql_value!` macro. ([#996], [#503])
 - Incorrect GraphQL list coercion rules: `null` cannot be coerced to an `[Int!]!` or `[Int]!`. ([#1004])
 - All procedural macros expansion inside `macro_rules!`. ([#1054], [#1051])
+- Incorrect input value coercion with defaults. ([#1080], [#1073])
+- Incorrect error when explicit `null` provided for `null`able list input parameter. ([#1086], [#1085])
+- Stack overflow on nested GraphQL fragments. ([CVE-2022-31173])
 
+[#113]: /../../issues/113
 [#503]: /../../issues/503
+[#528]: /../../issues/528
 [#750]: /../../issues/750
 [#798]: /../../issues/798
 [#918]: /../../issues/918
@@ -100,7 +106,13 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
 [#1054]: /../../pull/1054
 [#1057]: /../../pull/1057
 [#1060]: /../../pull/1060
+[#1073]: /../../issues/1073
+[#1080]: /../../pull/1080
+[#1081]: /../../pull/1081
+[#1085]: /../../issues/1085
+[#1086]: /../../pull/1086
 [ba1ed85b]: /../../commit/ba1ed85b3c3dd77fbae7baf6bc4e693321a94083
+[CVE-2022-31173]: /../../security/advisories/GHSA-4rx6-g5vg-5f3j
 
 
 
diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml
index bbf55964..6a1121aa 100644
--- a/juniper/Cargo.toml
+++ b/juniper/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper"
 version = "0.16.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "GraphQL server library."
 license = "BSD-2-Clause"
 authors = [
diff --git a/juniper/src/ast.rs b/juniper/src/ast.rs
index 40cceee4..075e0e07 100644
--- a/juniper/src/ast.rs
+++ b/juniper/src/ast.rs
@@ -224,10 +224,10 @@ impl<'a> Type<'a> {
 impl<'a> fmt::Display for Type<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::Named(n) => write!(f, "{}", n),
-            Self::NonNullNamed(n) => write!(f, "{}!", n),
-            Self::List(t, _) => write!(f, "[{}]", t),
-            Self::NonNullList(t, _) => write!(f, "[{}]!", t),
+            Self::Named(n) => write!(f, "{n}"),
+            Self::NonNullNamed(n) => write!(f, "{n}!"),
+            Self::List(t, _) => write!(f, "[{t}]"),
+            Self::NonNullList(t, _) => write!(f, "[{t}]!"),
         }
     }
 }
@@ -248,12 +248,12 @@ impl<S> InputValue<S> {
 
     /// Construct an enum value.
     pub fn enum_value<T: AsRef<str>>(s: T) -> Self {
-        Self::Enum(s.as_ref().to_owned())
+        Self::Enum(s.as_ref().into())
     }
 
     /// Construct a variable value.
     pub fn variable<T: AsRef<str>>(v: T) -> Self {
-        Self::Variable(v.as_ref().to_owned())
+        Self::Variable(v.as_ref().into())
     }
 
     /// Constructs a [`Spanning::unlocated`] [`InputValue::List`].
@@ -295,7 +295,7 @@ impl<S> InputValue<S> {
             obj.into_iter()
                 .map(|(k, v)| {
                     (
-                        Spanning::unlocated(k.as_ref().to_owned()),
+                        Spanning::unlocated(k.as_ref().into()),
                         Spanning::unlocated(v),
                     )
                 })
@@ -308,25 +308,36 @@ impl<S> InputValue<S> {
         Self::Object(o)
     }
 
-    /// Resolve all variables to their values.
+    /// Resolves all variables of this [`InputValue`] to their actual `values`.
+    ///
+    /// If a variable is not present in the `values`:
+    /// - Returns [`None`] in case this is an [`InputValue::Variable`].
+    /// - Skips field in case of an [`InputValue::Object`] field.
+    /// - Replaces with an [`InputValue::Null`] in case of an
+    ///   [`InputValue::List`] element.
+    ///
+    /// This is done, because for an [`InputValue::Variable`] (or an
+    /// [`InputValue::Object`] field) a default value can be used later, if it's
+    /// provided. While on contrary, a single [`InputValue::List`] element
+    /// cannot have a default value.
     #[must_use]
-    pub fn into_const(self, vars: &Variables<S>) -> Self
+    pub fn into_const(self, values: &Variables<S>) -> Option<Self>
     where
         S: Clone,
     {
         match self {
-            Self::Variable(v) => vars.get(&v).map_or_else(InputValue::null, Clone::clone),
-            Self::List(l) => Self::List(
+            Self::Variable(v) => values.get(&v).cloned(),
+            Self::List(l) => Some(Self::List(
                 l.into_iter()
-                    .map(|s| s.map(|v| v.into_const(vars)))
+                    .map(|s| s.map(|v| v.into_const(values).unwrap_or_else(Self::null)))
                     .collect(),
-            ),
-            Self::Object(o) => Self::Object(
+            )),
+            Self::Object(o) => Some(Self::Object(
                 o.into_iter()
-                    .map(|(sk, sv)| (sk, sv.map(|v| v.into_const(vars))))
+                    .filter_map(|(sk, sv)| sv.and_then(|v| v.into_const(values)).map(|sv| (sk, sv)))
                     .collect(),
-            ),
-            v => v,
+            )),
+            v => Some(v),
         }
     }
 
@@ -505,13 +516,13 @@ impl<S: ScalarValue> fmt::Display for InputValue<S> {
             Self::Null => write!(f, "null"),
             Self::Scalar(s) => {
                 if let Some(s) = s.as_str() {
-                    write!(f, "\"{}\"", s)
+                    write!(f, "\"{s}\"")
                 } else {
-                    write!(f, "{}", s)
+                    write!(f, "{s}")
                 }
             }
-            Self::Enum(v) => write!(f, "{}", v),
-            Self::Variable(v) => write!(f, "${}", v),
+            Self::Enum(v) => write!(f, "{v}"),
+            Self::Variable(v) => write!(f, "${v}"),
             Self::List(v) => {
                 write!(f, "[")?;
                 for (i, spanning) in v.iter().enumerate() {
@@ -626,30 +637,30 @@ mod tests {
     #[test]
     fn test_input_value_fmt() {
         let value: InputValue = graphql_input_value!(null);
-        assert_eq!(format!("{}", value), "null");
+        assert_eq!(value.to_string(), "null");
 
         let value: InputValue = graphql_input_value!(123);
-        assert_eq!(format!("{}", value), "123");
+        assert_eq!(value.to_string(), "123");
 
         let value: InputValue = graphql_input_value!(12.3);
-        assert_eq!(format!("{}", value), "12.3");
+        assert_eq!(value.to_string(), "12.3");
 
         let value: InputValue = graphql_input_value!("FOO");
-        assert_eq!(format!("{}", value), "\"FOO\"");
+        assert_eq!(value.to_string(), "\"FOO\"");
 
         let value: InputValue = graphql_input_value!(true);
-        assert_eq!(format!("{}", value), "true");
+        assert_eq!(value.to_string(), "true");
 
         let value: InputValue = graphql_input_value!(BAR);
-        assert_eq!(format!("{}", value), "BAR");
+        assert_eq!(value.to_string(), "BAR");
 
         let value: InputValue = graphql_input_value!(@baz);
-        assert_eq!(format!("{}", value), "$baz");
+        assert_eq!(value.to_string(), "$baz");
 
         let value: InputValue = graphql_input_value!([1, 2]);
-        assert_eq!(format!("{}", value), "[1, 2]");
+        assert_eq!(value.to_string(), "[1, 2]");
 
         let value: InputValue = graphql_input_value!({"foo": 1,"bar": 2});
-        assert_eq!(format!("{}", value), "{foo: 1, bar: 2}");
+        assert_eq!(value.to_string(), "{foo: 1, bar: 2}");
     }
 }
diff --git a/juniper/src/behavior.rs b/juniper/src/behavior.rs
index 506cc384..cb1976cd 100644
--- a/juniper/src/behavior.rs
+++ b/juniper/src/behavior.rs
@@ -88,7 +88,7 @@ where
     B1: ?Sized,
     B2: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/executor/look_ahead.rs b/juniper/src/executor/look_ahead.rs
index 41bae7ee..b12231d6 100644
--- a/juniper/src/executor/look_ahead.rs
+++ b/juniper/src/executor/look_ahead.rs
@@ -112,12 +112,11 @@ pub struct LookAheadSelection<'a, S: 'a> {
     pub(super) children: Vec<ChildSelection<'a, S>>,
 }
 
-impl<'a, S> Default for LookAheadSelection<'a, S>
-where
-    S: ScalarValue,
-{
+// Implemented manually to omit redundant `S: Default` trait bound, imposed by
+// `#[derive(Default)]`.
+impl<'a, S: 'a> Default for LookAheadSelection<'a, S> {
     fn default() -> Self {
-        LookAheadSelection {
+        Self {
             name: "",
             alias: None,
             arguments: vec![],
diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs
index b0b7b08c..4cd8bffa 100644
--- a/juniper/src/executor/mod.rs
+++ b/juniper/src/executor/mod.rs
@@ -312,7 +312,7 @@ where
     type Type;
 
     #[doc(hidden)]
-    fn into(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S>;
+    fn into_resolvable(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S>;
 }
 
 impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for T
@@ -323,7 +323,7 @@ where
 {
     type Type = T;
 
-    fn into(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
+    fn into_resolvable(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
         Ok(Some((FromContext::from(ctx), self)))
     }
 }
@@ -336,7 +336,7 @@ where
 {
     type Type = T;
 
-    fn into(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
+    fn into_resolvable(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
         self.map(|v: T| Some((<T::Context as FromContext<C>>::from(ctx), v)))
             .map_err(IntoFieldError::into_field_error)
     }
@@ -349,7 +349,7 @@ where
 {
     type Type = T;
 
-    fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
+    fn into_resolvable(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
         Ok(Some(self))
     }
 }
@@ -362,7 +362,7 @@ where
     type Type = T;
 
     #[allow(clippy::type_complexity)]
-    fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S> {
+    fn into_resolvable(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S> {
         Ok(self.map(|(ctx, v)| (ctx, Some(v))))
     }
 }
@@ -375,7 +375,7 @@ where
 {
     type Type = T;
 
-    fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S2> {
+    fn into_resolvable(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S2> {
         self.map(Some).map_err(FieldError::map_scalar_value)
     }
 }
@@ -390,7 +390,7 @@ where
     type Type = T;
 
     #[allow(clippy::type_complexity)]
-    fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S2> {
+    fn into_resolvable(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S2> {
         self.map(|o| o.map(|(ctx, v)| (ctx, Some(v))))
             .map_err(FieldError::map_scalar_value)
     }
@@ -782,7 +782,7 @@ impl<'a> FieldPath<'a> {
             FieldPath::Root(_) => (),
             FieldPath::Field(name, _, parent) => {
                 parent.construct_path(acc);
-                acc.push((*name).to_owned());
+                acc.push((*name).into());
             }
         }
     }
@@ -799,7 +799,7 @@ impl<S> ExecutionError<S> {
     pub fn new(location: SourcePosition, path: &[&str], error: FieldError<S>) -> ExecutionError<S> {
         ExecutionError {
             location,
-            path: path.iter().map(|s| (*s).to_owned()).collect(),
+            path: path.iter().map(|s| (*s).into()).collect(),
             error,
         }
     }
@@ -822,13 +822,13 @@ impl<S> ExecutionError<S> {
 
 /// Create new `Executor` and start query/mutation execution.
 /// Returns `IsSubscription` error if subscription is passed.
-pub fn execute_validated_query<'a, 'b, QueryT, MutationT, SubscriptionT, S>(
+pub fn execute_validated_query<'b, QueryT, MutationT, SubscriptionT, S>(
     document: &'b Document<S>,
     operation: &'b Spanning<Operation<S>>,
     root_node: &RootNode<QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &QueryT::Context,
-) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>
 where
     S: ScalarValue,
     QueryT: GraphQLType<S>,
@@ -850,10 +850,10 @@ where
         defs.item
             .items
             .iter()
-            .filter_map(|&(ref name, ref def)| {
+            .filter_map(|(name, def)| {
                 def.default_value
                     .as_ref()
-                    .map(|i| (name.item.to_owned(), i.item.clone()))
+                    .map(|i| (name.item.into(), i.item.clone()))
             })
             .collect::<HashMap<String, InputValue<S>>>()
     });
@@ -922,7 +922,7 @@ pub async fn execute_validated_query_async<'a, 'b, QueryT, MutationT, Subscripti
     root_node: &RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &QueryT::Context,
-) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>
 where
     QueryT: GraphQLTypeAsync<S>,
     QueryT::TypeInfo: Sync,
@@ -951,7 +951,7 @@ where
             .filter_map(|&(ref name, ref def)| {
                 def.default_value
                     .as_ref()
-                    .map(|i| (name.item.to_owned(), i.item.clone()))
+                    .map(|i| (name.item.into(), i.item.clone()))
             })
             .collect::<HashMap<String, InputValue<S>>>()
     });
@@ -1019,10 +1019,10 @@ where
 }
 
 #[doc(hidden)]
-pub fn get_operation<'b, 'd, 'e, S>(
+pub fn get_operation<'b, 'd, S>(
     document: &'b Document<'d, S>,
     operation_name: Option<&str>,
-) -> Result<&'b Spanning<Operation<'d, S>>, GraphQLError<'e>>
+) -> Result<&'b Spanning<Operation<'d, S>>, GraphQLError>
 where
     S: ScalarValue,
 {
@@ -1066,7 +1066,7 @@ pub async fn resolve_validated_subscription<
     root_node: &'r RootNode<'r, QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &'r QueryT::Context,
-) -> Result<(Value<ValuesStream<'r, S>>, Vec<ExecutionError<S>>), GraphQLError<'r>>
+) -> Result<(Value<ValuesStream<'r, S>>, Vec<ExecutionError<S>>), GraphQLError>
 where
     'r: 'exec_ref,
     'd: 'r,
@@ -1098,7 +1098,7 @@ where
             .filter_map(|&(ref name, ref def)| {
                 def.default_value
                     .as_ref()
-                    .map(|i| (name.item.to_owned(), i.item.clone()))
+                    .map(|i| (name.item.into(), i.item.clone()))
             })
             .collect::<HashMap<String, InputValue<S>>>()
     });
@@ -1180,7 +1180,7 @@ impl<'r, S: 'r> Registry<'r, S> {
             if !self.types.contains_key(name) {
                 self.insert_placeholder(
                     validated_name.clone(),
-                    Type::NonNullNamed(Cow::Owned(name.to_string())),
+                    Type::NonNullNamed(Cow::Owned(name.into())),
                 );
                 let meta = T::meta(info, self);
                 self.types.insert(validated_name, meta);
@@ -1232,7 +1232,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         S: ScalarValue,
     {
         Field {
-            name: smartstring::SmartString::from(name),
+            name: name.into(),
             description: None,
             arguments: None,
             field_type: self.get_type::<I>(info),
@@ -1250,9 +1250,6 @@ impl<'r, S: 'r> Registry<'r, S> {
     }
 
     /// Creates an [`Argument`] with the provided default `value`.
-    ///
-    /// When called with type `T`, the actual [`Argument`] will be given the
-    /// type `Option<T>`.
     pub fn arg_with_default<T>(
         &mut self,
         name: &str,
@@ -1263,7 +1260,7 @@ impl<'r, S: 'r> Registry<'r, S> {
         T: GraphQLType<S> + ToInputValue<S> + FromInputValue<S>,
         S: ScalarValue,
     {
-        Argument::new(name, self.get_type::<Option<T>>(info)).default_value(value.to_input_value())
+        Argument::new(name, self.get_type::<T>(info)).default_value(value.to_input_value())
     }
 
     fn insert_placeholder(&mut self, name: Name, of_type: Type<'r>) {
@@ -1281,7 +1278,7 @@ impl<'r, S: 'r> Registry<'r, S> {
     {
         let name = T::name(info).expect("Scalar types must be named. Implement `name()`");
 
-        ScalarMeta::new::<T>(Cow::Owned(name.to_string()))
+        ScalarMeta::new::<T>(Cow::Owned(name.into()))
     }
 
     /// Builds a [`ScalarMeta`] information for the specified [`graphql::Type`],
@@ -1437,7 +1434,7 @@ impl<'r, S: 'r> Registry<'r, S> {
 
         let mut v = fields.to_vec();
         v.push(self.field::<String>("__typename", &()));
-        ObjectMeta::new(Cow::Owned(name.to_string()), &v)
+        ObjectMeta::new(Cow::Owned(name.into()), &v)
     }
 
     /// Creates an [`EnumMeta`] type out of the provided `values`.
@@ -1453,7 +1450,7 @@ impl<'r, S: 'r> Registry<'r, S> {
     {
         let name = T::name(info).expect("Enum types must be named. Implement `name()`");
 
-        EnumMeta::new::<T>(Cow::Owned(name.to_string()), values)
+        EnumMeta::new::<T>(Cow::Owned(name.into()), values)
     }
 
     /// Builds an [`EnumMeta`] information for the specified [`graphql::Type`],
@@ -1505,7 +1502,7 @@ impl<'r, S: 'r> Registry<'r, S> {
 
         let mut v = fields.to_vec();
         v.push(self.field::<String>("__typename", &()));
-        InterfaceMeta::new(Cow::Owned(name.to_string()), &v)
+        InterfaceMeta::new(Cow::Owned(name.into()), &v)
     }
 
     /// Creates an [`UnionMeta`] type of the given `types`.
@@ -1516,7 +1513,7 @@ impl<'r, S: 'r> Registry<'r, S> {
     {
         let name = T::name(info).expect("Union types must be named. Implement name()");
 
-        UnionMeta::new(Cow::Owned(name.to_string()), types)
+        UnionMeta::new(Cow::Owned(name.into()), types)
     }
 
     /// Creates an [`InputObjectMeta`] type with the given `args`.
@@ -1532,6 +1529,6 @@ impl<'r, S: 'r> Registry<'r, S> {
     {
         let name = T::name(info).expect("Input object types must be named. Implement name()");
 
-        InputObjectMeta::new::<T>(Cow::Owned(name.to_string()), args)
+        InputObjectMeta::new::<T>(Cow::Owned(name.into()), args)
     }
 }
diff --git a/juniper/src/executor_tests/async_await/mod.rs b/juniper/src/executor_tests/async_await/mod.rs
index 277c0197..228c53d3 100644
--- a/juniper/src/executor_tests/async_await/mod.rs
+++ b/juniper/src/executor_tests/async_await/mod.rs
@@ -1,5 +1,6 @@
 use crate::{
-    graphql_object, graphql_value, EmptyMutation, EmptySubscription, GraphQLEnum, RootNode, Value,
+    graphql_object, graphql_value, graphql_vars, EmptyMutation, EmptySubscription, GraphQLEnum,
+    RootNode, Value,
 };
 
 #[derive(GraphQLEnum)]
@@ -30,7 +31,7 @@ impl User {
         (0..10)
             .map(|index| User {
                 id: index,
-                name: format!("user{}", index),
+                name: format!("user{index}"),
                 kind: UserKind::User,
             })
             .collect()
@@ -55,7 +56,7 @@ impl Query {
     }
 
     async fn field_async_plain() -> String {
-        "field_async_plain".to_string()
+        "field_async_plain".into()
     }
 
     fn user(id: String) -> User {
@@ -86,8 +87,7 @@ async fn async_simple() {
         }
     "#;
 
-    let vars = Default::default();
-    let (res, errs) = crate::execute(doc, None, &schema, &vars, &())
+    let (res, errs) = crate::execute(doc, None, &schema, &graphql_vars! {}, &())
         .await
         .unwrap();
 
diff --git a/juniper/src/executor_tests/directives.rs b/juniper/src/executor_tests/directives.rs
index adc05594..1f902e69 100644
--- a/juniper/src/executor_tests/directives.rs
+++ b/juniper/src/executor_tests/directives.rs
@@ -35,7 +35,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let obj = result.as_object_value().expect("Result is not an object");
 
diff --git a/juniper/src/executor_tests/enums.rs b/juniper/src/executor_tests/enums.rs
index 69cda71d..11fa80ae 100644
--- a/juniper/src/executor_tests/enums.rs
+++ b/juniper/src/executor_tests/enums.rs
@@ -22,7 +22,7 @@ struct TestType;
 #[crate::graphql_object]
 impl TestType {
     fn to_string(color: Color) -> String {
-        format!("Color::{:?}", color)
+        format!("Color::{color:?}")
     }
 
     fn a_color() -> Color {
@@ -46,7 +46,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let obj = result.as_object_value().expect("Result is not an object");
 
diff --git a/juniper/src/executor_tests/executor.rs b/juniper/src/executor_tests/executor.rs
index a1da0673..06d93fc0 100644
--- a/juniper/src/executor_tests/executor.rs
+++ b/juniper/src/executor_tests/executor.rs
@@ -96,7 +96,7 @@ mod field_execution {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -180,7 +180,7 @@ mod merge_parallel_fragments {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -288,7 +288,7 @@ mod merge_parallel_inline_fragments {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -355,7 +355,7 @@ mod threads_context_correctly {
             &schema,
             &vars,
             &TestContext {
-                value: "Context value".to_owned(),
+                value: "Context value".into(),
             },
         )
         .await
@@ -363,7 +363,7 @@ mod threads_context_correctly {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!({"a": "Context value"}));
     }
@@ -410,7 +410,7 @@ mod dynamic_context_switching {
             let res = context
                 .items
                 .get(&key)
-                .ok_or(format!("Could not find key {}", key))
+                .ok_or(format!("Could not find key {key}"))
                 .map(|c| (c, ItemRef))?;
             Ok(res)
         }
@@ -420,7 +420,7 @@ mod dynamic_context_switching {
             key: i32,
         ) -> FieldResult<Option<(&InnerContext, ItemRef)>> {
             if key > 100 {
-                Err(format!("Key too large: {}", key))?;
+                Err(format!("Key too large: {key}"))?;
             }
             Ok(context.items.get(&key).map(|c| (c, ItemRef)))
         }
@@ -452,13 +452,13 @@ mod dynamic_context_switching {
                 (
                     0,
                     InnerContext {
-                        value: "First value".to_owned(),
+                        value: "First value".into(),
                     },
                 ),
                 (
                     1,
                     InnerContext {
-                        value: "Second value".to_owned(),
+                        value: "Second value".into(),
                     },
                 ),
             ]
@@ -472,7 +472,7 @@ mod dynamic_context_switching {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -500,13 +500,13 @@ mod dynamic_context_switching {
                 (
                     0,
                     InnerContext {
-                        value: "First value".to_owned(),
+                        value: "First value".into(),
                     },
                 ),
                 (
                     1,
                     InnerContext {
-                        value: "Second value".to_owned(),
+                        value: "Second value".into(),
                     },
                 ),
             ]
@@ -520,7 +520,7 @@ mod dynamic_context_switching {
 
         assert_eq!(errs, vec![]);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!({"first": {"value": "First value"}}));
     }
@@ -542,13 +542,13 @@ mod dynamic_context_switching {
                 (
                     0,
                     InnerContext {
-                        value: "First value".to_owned(),
+                        value: "First value".into(),
                     },
                 ),
                 (
                     1,
                     InnerContext {
-                        value: "Second value".to_owned(),
+                        value: "Second value".into(),
                     },
                 ),
             ]
@@ -569,7 +569,7 @@ mod dynamic_context_switching {
             )],
         );
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!(null));
     }
@@ -593,13 +593,13 @@ mod dynamic_context_switching {
                 (
                     0,
                     InnerContext {
-                        value: "First value".to_owned(),
+                        value: "First value".into(),
                     },
                 ),
                 (
                     1,
                     InnerContext {
-                        value: "Second value".to_owned(),
+                        value: "Second value".into(),
                     },
                 ),
             ]
@@ -620,7 +620,7 @@ mod dynamic_context_switching {
             )],
         );
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -647,13 +647,13 @@ mod dynamic_context_switching {
                 (
                     0,
                     InnerContext {
-                        value: "First value".to_owned(),
+                        value: "First value".into(),
                     },
                 ),
                 (
                     1,
                     InnerContext {
-                        value: "Second value".to_owned(),
+                        value: "Second value".into(),
                     },
                 ),
             ]
@@ -667,7 +667,7 @@ mod dynamic_context_switching {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!({"first": {"value": "First value"}}));
     }
@@ -752,7 +752,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -783,7 +783,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!(null));
 
@@ -811,7 +811,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!(null));
 
@@ -839,7 +839,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!({"inner": {"nullableField": null}}),);
 
@@ -867,7 +867,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!(null));
 
@@ -895,7 +895,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -926,7 +926,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(result, graphql_value!(null));
 
@@ -954,7 +954,7 @@ mod propagates_errors_to_nullable_fields {
             .await
             .expect("Execution failed");
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
diff --git a/juniper/src/executor_tests/interfaces_unions.rs b/juniper/src/executor_tests/interfaces_unions.rs
index c2551215..3e9fccf4 100644
--- a/juniper/src/executor_tests/interfaces_unions.rs
+++ b/juniper/src/executor_tests/interfaces_unions.rs
@@ -42,12 +42,12 @@ mod interface {
             Schema {
                 pets: vec![
                     Dog {
-                        name: "Odie".to_owned(),
+                        name: "Odie".into(),
                         woofs: true,
                     }
                     .into(),
                     Cat {
-                        name: "Garfield".to_owned(),
+                        name: "Garfield".into(),
                         meows: false,
                     }
                     .into(),
@@ -77,7 +77,7 @@ mod interface {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
@@ -170,11 +170,11 @@ mod union {
             Schema {
                 pets: vec![
                     Box::new(Dog {
-                        name: "Odie".to_owned(),
+                        name: "Odie".into(),
                         woofs: true,
                     }),
                     Box::new(Cat {
-                        name: "Garfield".to_owned(),
+                        name: "Garfield".into(),
                         meows: false,
                     }),
                 ],
@@ -205,7 +205,7 @@ mod union {
 
         assert_eq!(errs, []);
 
-        println!("Result: {:#?}", result);
+        println!("Result: {result:#?}");
 
         assert_eq!(
             result,
diff --git a/juniper/src/executor_tests/introspection/enums.rs b/juniper/src/executor_tests/introspection/enums.rs
index 127f45ab..c70a60e9 100644
--- a/juniper/src/executor_tests/introspection/enums.rs
+++ b/juniper/src/executor_tests/introspection/enums.rs
@@ -92,7 +92,7 @@ where
     F: Fn((&Object<DefaultScalarValue>, &Vec<Value<DefaultScalarValue>>)) -> (),
 {
     let schema = RootNode::new(
-        Root {},
+        Root,
         EmptyMutation::<()>::new(),
         EmptySubscription::<()>::new(),
     );
@@ -103,7 +103,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
diff --git a/juniper/src/executor_tests/introspection/input_object.rs b/juniper/src/executor_tests/introspection/input_object.rs
index f68b9796..2e70d088 100644
--- a/juniper/src/executor_tests/introspection/input_object.rs
+++ b/juniper/src/executor_tests/introspection/input_object.rs
@@ -76,9 +76,9 @@ struct FieldDescription {
 
 #[derive(GraphQLInputObject, Debug)]
 struct FieldWithDefaults {
-    #[graphql(default = "123")]
+    #[graphql(default = 123)]
     field_one: i32,
-    #[graphql(default = "456", description = "The second field")]
+    #[graphql(default = 456, description = "The second field")]
     field_two: i32,
 }
 
@@ -117,7 +117,7 @@ where
     F: Fn(&Object<DefaultScalarValue>, &Vec<Value<DefaultScalarValue>>) -> (),
 {
     let schema = RootNode::new(
-        Root {},
+        Root,
         EmptyMutation::<()>::new(),
         EmptySubscription::<()>::new(),
     );
@@ -128,7 +128,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
@@ -312,7 +312,7 @@ fn derive_derived() {
         format!(
             "{:?}",
             Derive {
-                field_one: "test".to_owned(),
+                field_one: "test".into(),
             },
         ),
         "Derive { field_one: \"test\" }"
@@ -462,6 +462,9 @@ async fn field_with_defaults_introspection() {
                 name
                 type {
                     name
+                    ofType {
+                        name
+                    }
                 }
                 defaultValue
             }
@@ -477,12 +480,12 @@ async fn field_with_defaults_introspection() {
         assert_eq!(fields.len(), 2);
         assert!(fields.contains(&graphql_value!({
             "name": "fieldOne",
-            "type": {"name": "Int"},
+            "type": {"name": null, "ofType": {"name": "Int"}},
             "defaultValue": "123",
         })));
         assert!(fields.contains(&graphql_value!({
             "name": "fieldTwo",
-            "type": {"name": "Int"},
+            "type": {"name": null, "ofType": {"name": "Int"}},
             "defaultValue": "456",
         })));
     })
diff --git a/juniper/src/executor_tests/introspection/mod.rs b/juniper/src/executor_tests/introspection/mod.rs
index ed59efc7..ee2501b2 100644
--- a/juniper/src/executor_tests/introspection/mod.rs
+++ b/juniper/src/executor_tests/introspection/mod.rs
@@ -69,7 +69,7 @@ async fn test_execution() {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     assert_eq!(
         result,
@@ -114,7 +114,7 @@ async fn enum_introspection() {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
@@ -223,7 +223,7 @@ async fn interface_introspection() {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
@@ -355,7 +355,7 @@ async fn object_introspection() {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
@@ -406,7 +406,7 @@ async fn object_introspection() {
 
     assert_eq!(fields.len(), 2);
 
-    println!("Fields: {:#?}", fields);
+    println!("Fields: {fields:#?}");
 
     assert!(fields.contains(&graphql_value!({
         "name": "sampleEnum",
@@ -444,9 +444,13 @@ async fn object_introspection() {
             "name": "second",
             "description": "The second number",
             "type": {
-                "name": "Int",
-                "kind": "SCALAR",
-                "ofType": null,
+                "name": null,
+                "kind": "NON_NULL",
+                "ofType": {
+                    "name": "Int",
+                    "kind": "SCALAR",
+                    "ofType": null,
+                },
             },
             "defaultValue": "123",
         }],
@@ -493,7 +497,7 @@ async fn scalar_introspection() {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
 
     let type_info = result
         .as_object_value()
diff --git a/juniper/src/executor_tests/variables.rs b/juniper/src/executor_tests/variables.rs
index 257f26c4..f49d4a23 100644
--- a/juniper/src/executor_tests/variables.rs
+++ b/juniper/src/executor_tests/variables.rs
@@ -23,7 +23,7 @@ impl TestComplexScalar {
         v.as_string_value()
             .filter(|s| *s == "SerializedValue")
             .map(|_| Self)
-            .ok_or_else(|| format!(r#"Expected "SerializedValue" string, found: {}"#, v))
+            .ok_or_else(|| format!(r#"Expected "SerializedValue" string, found: {v}"#))
     }
 }
 
@@ -49,7 +49,7 @@ struct ExampleInputObject {
 
 #[derive(GraphQLInputObject, Debug)]
 struct InputWithDefaults {
-    #[graphql(default = "123")]
+    #[graphql(default = 123)]
     a: i32,
 }
 
@@ -58,41 +58,47 @@ struct TestType;
 #[graphql_object]
 impl TestType {
     fn field_with_object_input(input: Option<TestInputObject>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn field_with_nullable_string_input(input: Option<String>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn field_with_non_nullable_string_input(input: String) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn field_with_default_argument_value(
         #[graphql(default = "Hello World")] input: String,
     ) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
+    }
+
+    fn nullable_field_with_default_argument_value(
+        #[graphql(default = "Hello World".to_owned())] input: Option<String>,
+    ) -> String {
+        format!("{input:?}")
     }
 
     fn field_with_nested_object_input(input: Option<TestNestedInputObject>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn list(input: Option<Vec<Option<String>>>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn nn_list(input: Vec<Option<String>>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn list_nn(input: Option<Vec<String>>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn nn_list_nn(input: Vec<String>) -> String {
-        format!("{:?}", input)
+        format!("{input:?}")
     }
 
     fn example_input(arg: ExampleInputObject) -> String {
@@ -104,11 +110,11 @@ impl TestType {
     }
 
     fn integer_input(value: i32) -> String {
-        format!("value: {}", value)
+        format!("value: {value}")
     }
 
     fn float_input(value: f64) -> String {
-        format!("value: {}", value)
+        format!("value: {value}")
     }
 }
 
@@ -128,7 +134,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:?}", result);
+    println!("Result: {result:?}");
 
     let obj = result.as_object_value().expect("Result is not an object");
 
@@ -791,13 +797,14 @@ async fn default_argument_when_not_provided() {
 }
 
 #[tokio::test]
-async fn default_argument_when_nullable_variable_not_provided() {
-    run_query(
-        r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#,
+async fn provided_variable_overwrites_default_value() {
+    run_variable_query(
+        r#"query q($input: String!) { fieldWithDefaultArgumentValue(input: $input) }"#,
+        graphql_vars! {"input": "Overwritten"},
         |result| {
             assert_eq!(
                 result.get_field_value("fieldWithDefaultArgumentValue"),
-                Some(&graphql_value!(r#""Hello World""#)),
+                Some(&graphql_value!(r#""Overwritten""#)),
             );
         },
     )
@@ -805,14 +812,28 @@ async fn default_argument_when_nullable_variable_not_provided() {
 }
 
 #[tokio::test]
-async fn default_argument_when_nullable_variable_set_to_null() {
+async fn default_argument_when_nullable_variable_not_provided() {
+    run_query(
+        r#"query q($input: String) { nullableFieldWithDefaultArgumentValue(input: $input) }"#,
+        |result| {
+            assert_eq!(
+                result.get_field_value("nullableFieldWithDefaultArgumentValue"),
+                Some(&graphql_value!(r#"Some("Hello World")"#)),
+            );
+        },
+    )
+    .await;
+}
+
+#[tokio::test]
+async fn null_when_nullable_variable_of_argument_with_default_value_set_to_null() {
     run_variable_query(
-        r#"query q($input: String) { fieldWithDefaultArgumentValue(input: $input) }"#,
+        r#"query q($input: String) { nullableFieldWithDefaultArgumentValue(input: $input) }"#,
         graphql_vars! {"input": null},
         |result| {
             assert_eq!(
-                result.get_field_value("fieldWithDefaultArgumentValue"),
-                Some(&graphql_value!(r#""Hello World""#)),
+                result.get_field_value("nullableFieldWithDefaultArgumentValue"),
+                Some(&graphql_value!(r#"None"#)),
             );
         },
     )
diff --git a/juniper/src/http/mod.rs b/juniper/src/http/mod.rs
index 17420de3..45e310be 100644
--- a/juniper/src/http/mod.rs
+++ b/juniper/src/http/mod.rs
@@ -60,11 +60,8 @@ where
         self.variables
             .as_ref()
             .and_then(|iv| {
-                iv.to_object_value().map(|o| {
-                    o.into_iter()
-                        .map(|(k, v)| (k.to_owned(), v.clone()))
-                        .collect()
-                })
+                iv.to_object_value()
+                    .map(|o| o.into_iter().map(|(k, v)| (k.into(), v.clone())).collect())
             })
             .unwrap_or_default()
     }
@@ -86,11 +83,11 @@ where
     ///
     /// This is a simple wrapper around the `execute_sync` function exposed at the
     /// top level of this crate.
-    pub fn execute_sync<'a, QueryT, MutationT, SubscriptionT>(
-        &'a self,
-        root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
+    pub fn execute_sync<QueryT, MutationT, SubscriptionT>(
+        &self,
+        root_node: &RootNode<QueryT, MutationT, SubscriptionT, S>,
         context: &QueryT::Context,
-    ) -> GraphQLResponse<'a, S>
+    ) -> GraphQLResponse<S>
     where
         S: ScalarValue,
         QueryT: GraphQLType<S>,
@@ -114,7 +111,7 @@ where
         &'a self,
         root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
         context: &'a QueryT::Context,
-    ) -> GraphQLResponse<'a, S>
+    ) -> GraphQLResponse<S>
     where
         QueryT: GraphQLTypeAsync<S>,
         QueryT::TypeInfo: Sync,
@@ -140,7 +137,7 @@ pub async fn resolve_into_stream<'req, 'rn, 'ctx, 'a, QueryT, MutationT, Subscri
     req: &'req GraphQLRequest<S>,
     root_node: &'rn RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
     context: &'ctx QueryT::Context,
-) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError>
 where
     'req: 'a,
     'rn: 'a,
@@ -166,16 +163,16 @@ where
 /// to JSON and send it over the wire. Use the `is_ok` method to determine
 /// whether to send a 200 or 400 HTTP status code.
 #[derive(Debug)]
-pub struct GraphQLResponse<'a, S = DefaultScalarValue>(
-    Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>,
+pub struct GraphQLResponse<S = DefaultScalarValue>(
+    Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>,
 );
 
-impl<'a, S> GraphQLResponse<'a, S>
+impl<S> GraphQLResponse<S>
 where
     S: ScalarValue,
 {
     /// Constructs new `GraphQLResponse` using the given result
-    pub fn from_result(r: Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>) -> Self {
+    pub fn from_result(r: Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>) -> Self {
         Self(r)
     }
 
@@ -193,12 +190,11 @@ where
     }
 }
 
-impl<'a, T> Serialize for GraphQLResponse<'a, T>
+impl<T> Serialize for GraphQLResponse<T>
 where
     T: Serialize + ScalarValue,
     Value<T>: Serialize,
     ExecutionError<T>: Serialize,
-    GraphQLError<'a>: Serialize,
 {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
@@ -272,7 +268,7 @@ where
         &'a self,
         root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
         context: &QueryT::Context,
-    ) -> GraphQLBatchResponse<'a, S>
+    ) -> GraphQLBatchResponse<S>
     where
         QueryT: GraphQLType<S>,
         MutationT: GraphQLType<S, Context = QueryT::Context>,
@@ -298,7 +294,7 @@ where
         &'a self,
         root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
         context: &'a QueryT::Context,
-    ) -> GraphQLBatchResponse<'a, S>
+    ) -> GraphQLBatchResponse<S>
     where
         QueryT: GraphQLTypeAsync<S>,
         QueryT::TypeInfo: Sync,
@@ -340,20 +336,17 @@ where
 /// wheter to send a 200 or 400 HTTP status code.
 #[derive(Serialize)]
 #[serde(untagged)]
-pub enum GraphQLBatchResponse<'a, S = DefaultScalarValue>
+pub enum GraphQLBatchResponse<S = DefaultScalarValue>
 where
     S: ScalarValue,
 {
     /// Result of a single operation in a GraphQL request.
-    Single(GraphQLResponse<'a, S>),
+    Single(GraphQLResponse<S>),
     /// Result of a batch operation in a GraphQL request.
-    Batch(Vec<GraphQLResponse<'a, S>>),
+    Batch(Vec<GraphQLResponse<S>>),
 }
 
-impl<'a, S> GraphQLBatchResponse<'a, S>
-where
-    S: ScalarValue,
-{
+impl<S: ScalarValue> GraphQLBatchResponse<S> {
     /// Returns if all the GraphQLResponse in this operation are ok,
     /// you can use it to determine wheter to send a 200 or 400 HTTP status code.
     pub fn is_ok(&self) -> bool {
@@ -639,20 +632,20 @@ pub mod tests {
                     "type":"connection_init",
                     "payload":{}
                 }"#
-                .to_owned(),
+                .into(),
             ),
             WsIntegrationMessage::Expect(
                 r#"{
                     "type":"connection_ack"
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT,
             ),
             WsIntegrationMessage::Expect(
                 r#"{
                     "type":"ka"
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT,
             ),
             WsIntegrationMessage::Send(
@@ -666,7 +659,7 @@ pub mod tests {
                         "query":"subscription { asyncHuman { id, name, homePlanet } }"
                     }
                 }"#
-                .to_owned(),
+                .into(),
             ),
             WsIntegrationMessage::Expect(
                 r#"{
@@ -682,7 +675,7 @@ pub mod tests {
                         }
                     }
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT,
             ),
         ];
@@ -692,7 +685,7 @@ pub mod tests {
 
     async fn test_ws_invalid_json<T: WsIntegration>(integration: &T) {
         let messages = vec![
-            WsIntegrationMessage::Send("invalid json".to_owned()),
+            WsIntegrationMessage::Send("invalid json".into()),
             WsIntegrationMessage::Expect(
                 r#"{
                     "type":"connection_error",
@@ -700,7 +693,7 @@ pub mod tests {
                         "message":"serde error: expected value at line 1 column 1"
                     }
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT,
             ),
         ];
@@ -715,20 +708,20 @@ pub mod tests {
                     "type":"connection_init",
                     "payload":{}
                 }"#
-                .to_owned(),
+                .into(),
             ),
             WsIntegrationMessage::Expect(
                 r#"{
                     "type":"connection_ack"
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT
             ),
             WsIntegrationMessage::Expect(
                 r#"{
                     "type":"ka"
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT
             ),
             WsIntegrationMessage::Send(
@@ -742,7 +735,7 @@ pub mod tests {
                         "query":"subscription { asyncHuman }"
                     }
                 }"#
-                .to_owned(),
+                .into(),
             ),
             WsIntegrationMessage::Expect(
                 r#"{
@@ -756,7 +749,7 @@ pub mod tests {
                         }]
                     }]
                 }"#
-                .to_owned(),
+                .into(),
                 WS_INTEGRATION_EXPECT_DEFAULT_TIMEOUT
             )
         ];
diff --git a/juniper/src/integrations/bigdecimal.rs b/juniper/src/integrations/bigdecimal.rs
index a1635fcc..3715536c 100644
--- a/juniper/src/integrations/bigdecimal.rs
+++ b/juniper/src/integrations/bigdecimal.rs
@@ -32,8 +32,6 @@ use crate::{graphql_scalar, InputValue, ScalarValue, Value};
 type BigDecimal = bigdecimal::BigDecimal;
 
 mod bigdecimal_scalar {
-    use std::convert::TryFrom as _;
-
     use super::*;
 
     pub(super) fn to_output<S: ScalarValue>(v: &BigDecimal) -> Value<S> {
@@ -45,13 +43,13 @@ mod bigdecimal_scalar {
             Ok(BigDecimal::from(i))
         } else if let Some(f) = v.as_float_value() {
             BigDecimal::try_from(f)
-                .map_err(|e| format!("Failed to parse `BigDecimal` from `Float`: {}", e))
+                .map_err(|e| format!("Failed to parse `BigDecimal` from `Float`: {e}"))
         } else {
             v.as_string_value()
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
                 .and_then(|s| {
                     BigDecimal::from_str(s)
-                        .map_err(|e| format!("Failed to parse `BigDecimal` from `String`: {}", e))
+                        .map_err(|e| format!("Failed to parse `BigDecimal` from `String`: {e}"))
                 })
         }
     }
@@ -88,11 +86,10 @@ mod test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{:?}`: {:?}",
-                input,
+                "failed to parse `{input:?}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {:?}", input);
+            assert_eq!(parsed.unwrap(), expected, "input: {input:?}");
         }
     }
 
@@ -110,7 +107,7 @@ mod test {
             let input: InputValue = input;
             let parsed = BigDecimal::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -126,7 +123,7 @@ mod test {
         ] {
             let actual: InputValue = BigDecimal::from_str(raw).unwrap().to_input_value();
 
-            assert_eq!(actual, graphql_input_value!((raw)), "on value: {}", raw);
+            assert_eq!(actual, graphql_input_value!((raw)), "on value: {raw}");
         }
     }
 }
diff --git a/juniper/src/integrations/bson.rs b/juniper/src/integrations/bson.rs
index 8d904025..20c88fbe 100644
--- a/juniper/src/integrations/bson.rs
+++ b/juniper/src/integrations/bson.rs
@@ -14,9 +14,9 @@ mod object_id {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<ObjectId, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
-                ObjectId::parse_str(s).map_err(|e| format!("Failed to parse `ObjectId`: {}", e))
+                ObjectId::parse_str(s).map_err(|e| format!("Failed to parse `ObjectId`: {e}"))
             })
     }
 }
@@ -30,16 +30,16 @@ mod utc_date_time {
     pub(super) fn to_output<S: ScalarValue>(v: &UtcDateTime) -> Value<S> {
         Value::scalar(
             (*v).try_to_rfc3339_string()
-                .unwrap_or_else(|e| panic!("failed to format `UtcDateTime` as RFC3339: {}", e)),
+                .unwrap_or_else(|e| panic!("failed to format `UtcDateTime` as RFC3339: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<UtcDateTime, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 UtcDateTime::parse_rfc3339_str(s)
-                    .map_err(|e| format!("Failed to parse `UtcDateTime`: {}", e))
+                    .map_err(|e| format!("Failed to parse `UtcDateTime`: {e}"))
             })
     }
 }
diff --git a/juniper/src/integrations/chrono.rs b/juniper/src/integrations/chrono.rs
index a0c6edc4..b1fb3a48 100644
--- a/juniper/src/integrations/chrono.rs
+++ b/juniper/src/integrations/chrono.rs
@@ -62,9 +62,9 @@ mod date {
         S: ScalarValue,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
-                Date::parse_from_str(s, FORMAT).map_err(|e| format!("Invalid `Date`: {}", e))
+                Date::parse_from_str(s, FORMAT).map_err(|e| format!("Invalid `Date`: {e}"))
             })
     }
 }
@@ -127,7 +127,7 @@ mod local_time {
         S: ScalarValue,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 // First, try to parse the most used format.
                 // At the end, try to parse the full format for the parsing
@@ -135,7 +135,7 @@ mod local_time {
                 LocalTime::parse_from_str(s, FORMAT_NO_MILLIS)
                     .or_else(|_| LocalTime::parse_from_str(s, FORMAT_NO_SECS))
                     .or_else(|_| LocalTime::parse_from_str(s, FORMAT))
-                    .map_err(|e| format!("Invalid `LocalTime`: {}", e))
+                    .map_err(|e| format!("Invalid `LocalTime`: {e}"))
             })
     }
 }
@@ -166,10 +166,10 @@ mod local_date_time {
         S: ScalarValue,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 LocalDateTime::parse_from_str(s, FORMAT)
-                    .map_err(|e| format!("Invalid `LocalDateTime`: {}", e))
+                    .map_err(|e| format!("Invalid `LocalDateTime`: {e}"))
             })
     }
 }
@@ -219,10 +219,10 @@ mod date_time {
         Tz: TimeZone + FromFixedOffset,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 DateTime::<FixedOffset>::parse_from_rfc3339(s)
-                    .map_err(|e| format!("Invalid `DateTime`: {}", e))
+                    .map_err(|e| format!("Invalid `DateTime`: {e}"))
                     .map(FromFixedOffset::from_fixed_offset)
             })
     }
@@ -345,11 +345,10 @@ mod date_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -372,7 +371,7 @@ mod date_test {
             let input: InputValue = input;
             let parsed = Date::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -394,7 +393,7 @@ mod date_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -420,11 +419,10 @@ mod local_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -451,7 +449,7 @@ mod local_time_test {
             let input: InputValue = input;
             let parsed = LocalTime::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -477,7 +475,7 @@ mod local_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -513,11 +511,10 @@ mod local_date_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -546,7 +543,7 @@ mod local_date_time_test {
             let input: InputValue = input;
             let parsed = LocalDateTime::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -570,7 +567,7 @@ mod local_date_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -635,11 +632,10 @@ mod date_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -673,7 +669,7 @@ mod date_time_test {
             let input: InputValue = input;
             let parsed = DateTime::<FixedOffset>::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -703,7 +699,7 @@ mod date_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
diff --git a/juniper/src/integrations/chrono_tz.rs b/juniper/src/integrations/chrono_tz.rs
index b6fa5732..8950f97f 100644
--- a/juniper/src/integrations/chrono_tz.rs
+++ b/juniper/src/integrations/chrono_tz.rs
@@ -34,10 +34,10 @@ mod tz {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<TimeZone, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 s.parse::<TimeZone>()
-                    .map_err(|e| format!("Failed to parse `TimeZone`: {}", e))
+                    .map_err(|e| format!("Failed to parse `TimeZone`: {e}"))
             })
     }
 }
diff --git a/juniper/src/integrations/rust_decimal.rs b/juniper/src/integrations/rust_decimal.rs
index 2e74db32..52a6d20c 100644
--- a/juniper/src/integrations/rust_decimal.rs
+++ b/juniper/src/integrations/rust_decimal.rs
@@ -34,8 +34,6 @@ use crate::{graphql_scalar, InputValue, ScalarValue, Value};
 type Decimal = rust_decimal::Decimal;
 
 mod rust_decimal_scalar {
-    use std::convert::TryFrom as _;
-
     use super::*;
 
     pub(super) fn to_output<S: ScalarValue>(v: &Decimal) -> Value<S> {
@@ -46,14 +44,13 @@ mod rust_decimal_scalar {
         if let Some(i) = v.as_int_value() {
             Ok(Decimal::from(i))
         } else if let Some(f) = v.as_float_value() {
-            Decimal::try_from(f)
-                .map_err(|e| format!("Failed to parse `Decimal` from `Float`: {}", e))
+            Decimal::try_from(f).map_err(|e| format!("Failed to parse `Decimal` from `Float`: {e}"))
         } else {
             v.as_string_value()
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
                 .and_then(|s| {
                     Decimal::from_str(s)
-                        .map_err(|e| format!("Failed to parse `Decimal` from `String`: {}", e))
+                        .map_err(|e| format!("Failed to parse `Decimal` from `String`: {e}"))
                 })
         }
     }
@@ -84,11 +81,10 @@ mod test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{:?}`: {:?}",
-                input,
+                "failed to parse `{input:?}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {:?}", input);
+            assert_eq!(parsed.unwrap(), expected, "input: {input:?}");
         }
     }
 
@@ -108,7 +104,7 @@ mod test {
             let input: InputValue = input;
             let parsed = Decimal::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -117,7 +113,7 @@ mod test {
         for raw in ["4.20", "0", "999.999999999", "875533788", "123", "43.44"] {
             let actual: InputValue = Decimal::from_str(raw).unwrap().to_input_value();
 
-            assert_eq!(actual, graphql_input_value!((raw)), "on value: {}", raw);
+            assert_eq!(actual, graphql_input_value!((raw)), "on value: {raw}");
         }
     }
 }
diff --git a/juniper/src/integrations/serde.rs b/juniper/src/integrations/serde.rs
index 31a0b600..38779964 100644
--- a/juniper/src/integrations/serde.rs
+++ b/juniper/src/integrations/serde.rs
@@ -1,8 +1,4 @@
-use std::{
-    convert::{TryFrom as _, TryInto as _},
-    fmt,
-    marker::PhantomData,
-};
+use std::{fmt, marker::PhantomData};
 
 use indexmap::IndexMap;
 use serde::{
@@ -42,7 +38,7 @@ impl<T: Serialize> Serialize for ExecutionError<T> {
     }
 }
 
-impl<'a> Serialize for GraphQLError<'a> {
+impl Serialize for GraphQLError {
     fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
         #[derive(Serialize)]
         struct Helper {
@@ -247,11 +243,11 @@ impl Serialize for SourcePosition {
     }
 }
 
-impl<'a> Serialize for Spanning<ParseError<'a>> {
+impl Serialize for Spanning<ParseError> {
     fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
         let mut map = ser.serialize_map(Some(2))?;
 
-        let msg = format!("{}", self.item);
+        let msg = self.item.to_string();
         map.serialize_key("message")?;
         map.serialize_value(&msg)?;
 
@@ -396,7 +392,7 @@ mod tests {
     #[test]
     fn error_extensions() {
         let mut obj: Object<DefaultScalarValue> = Object::with_capacity(1);
-        obj.add_field("foo".to_string(), Value::scalar("bar"));
+        obj.add_field("foo", Value::scalar("bar"));
         assert_eq!(
             to_string(&ExecutionError::at_origin(FieldError::new(
                 "foo error",
diff --git a/juniper/src/integrations/time.rs b/juniper/src/integrations/time.rs
index e05bf535..d2c88529 100644
--- a/juniper/src/integrations/time.rs
+++ b/juniper/src/integrations/time.rs
@@ -57,14 +57,14 @@ mod date {
     pub(super) fn to_output<S: ScalarValue>(v: &Date) -> Value<S> {
         Value::scalar(
             v.format(FORMAT)
-                .unwrap_or_else(|e| panic!("Failed to format `Date`: {}", e)),
+                .unwrap_or_else(|e| panic!("Failed to format `Date`: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Date, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
-            .and_then(|s| Date::parse(s, FORMAT).map_err(|e| format!("Invalid `Date`: {}", e)))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
+            .and_then(|s| Date::parse(s, FORMAT).map_err(|e| format!("Invalid `Date`: {e}")))
     }
 }
 
@@ -109,13 +109,13 @@ mod local_time {
             } else {
                 v.format(FORMAT)
             }
-            .unwrap_or_else(|e| panic!("Failed to format `LocalTime`: {}", e)),
+            .unwrap_or_else(|e| panic!("Failed to format `LocalTime`: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<LocalTime, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 // First, try to parse the most used format.
                 // At the end, try to parse the full format for the parsing
@@ -123,7 +123,7 @@ mod local_time {
                 LocalTime::parse(s, FORMAT_NO_MILLIS)
                     .or_else(|_| LocalTime::parse(s, FORMAT_NO_SECS))
                     .or_else(|_| LocalTime::parse(s, FORMAT))
-                    .map_err(|e| format!("Invalid `LocalTime`: {}", e))
+                    .map_err(|e| format!("Invalid `LocalTime`: {e}"))
             })
     }
 }
@@ -146,16 +146,15 @@ mod local_date_time {
     pub(super) fn to_output<S: ScalarValue>(v: &LocalDateTime) -> Value<S> {
         Value::scalar(
             v.format(FORMAT)
-                .unwrap_or_else(|e| panic!("Failed to format `LocalDateTime`: {}", e)),
+                .unwrap_or_else(|e| panic!("Failed to format `LocalDateTime`: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<LocalDateTime, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
-                LocalDateTime::parse(s, FORMAT)
-                    .map_err(|e| format!("Invalid `LocalDateTime`: {}", e))
+                LocalDateTime::parse(s, FORMAT).map_err(|e| format!("Invalid `LocalDateTime`: {e}"))
             })
     }
 }
@@ -186,15 +185,15 @@ mod date_time {
         Value::scalar(
             v.to_offset(UtcOffset::UTC)
                 .format(&Rfc3339)
-                .unwrap_or_else(|e| panic!("Failed to format `DateTime`: {}", e)),
+                .unwrap_or_else(|e| panic!("Failed to format `DateTime`: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<DateTime, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
-                DateTime::parse(s, &Rfc3339).map_err(|e| format!("Invalid `DateTime`: {}", e))
+                DateTime::parse(s, &Rfc3339).map_err(|e| format!("Invalid `DateTime`: {e}"))
             })
             .map(|dt| dt.to_offset(UtcOffset::UTC))
     }
@@ -228,16 +227,16 @@ mod utc_offset {
     pub(super) fn to_output<S: ScalarValue>(v: &UtcOffset) -> Value<S> {
         Value::scalar(
             v.format(UTC_OFFSET_FORMAT)
-                .unwrap_or_else(|e| panic!("Failed to format `UtcOffset`: {}", e)),
+                .unwrap_or_else(|e| panic!("Failed to format `UtcOffset`: {e}")),
         )
     }
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<UtcOffset, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 UtcOffset::parse(s, UTC_OFFSET_FORMAT)
-                    .map_err(|e| format!("Invalid `UtcOffset`: {}", e))
+                    .map_err(|e| format!("Invalid `UtcOffset`: {e}"))
             })
     }
 }
@@ -261,11 +260,10 @@ mod date_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -288,7 +286,7 @@ mod date_test {
             let input: InputValue = input;
             let parsed = Date::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -302,7 +300,7 @@ mod date_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -330,11 +328,10 @@ mod local_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -364,7 +361,7 @@ mod local_time_test {
             let input: InputValue = input;
             let parsed = LocalTime::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -378,7 +375,7 @@ mod local_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -402,11 +399,10 @@ mod local_date_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -437,7 +433,7 @@ mod local_date_time_test {
             let input: InputValue = input;
             let parsed = LocalDateTime::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -455,7 +451,7 @@ mod local_date_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -490,11 +486,10 @@ mod date_time_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -528,7 +523,7 @@ mod date_time_test {
             let input: InputValue = input;
             let parsed = DateTime::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -546,7 +541,7 @@ mod date_time_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
@@ -574,11 +569,10 @@ mod utc_offset_test {
 
             assert!(
                 parsed.is_ok(),
-                "failed to parse `{}`: {:?}",
-                raw,
+                "failed to parse `{raw}`: {:?}",
                 parsed.unwrap_err(),
             );
-            assert_eq!(parsed.unwrap(), expected, "input: {}", raw);
+            assert_eq!(parsed.unwrap(), expected, "input: {raw}");
         }
     }
 
@@ -607,7 +601,7 @@ mod utc_offset_test {
             let input: InputValue = input;
             let parsed = UtcOffset::from_input_value(&input);
 
-            assert!(parsed.is_err(), "allows input: {:?}", input);
+            assert!(parsed.is_err(), "allows input: {input:?}");
         }
     }
 
@@ -620,7 +614,7 @@ mod utc_offset_test {
         ] {
             let actual: InputValue = val.to_input_value();
 
-            assert_eq!(actual, expected, "on value: {}", val);
+            assert_eq!(actual, expected, "on value: {val}");
         }
     }
 }
diff --git a/juniper/src/integrations/url.rs b/juniper/src/integrations/url.rs
index e3764c6b..6121ac56 100644
--- a/juniper/src/integrations/url.rs
+++ b/juniper/src/integrations/url.rs
@@ -14,8 +14,8 @@ mod url_scalar {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Url, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
-            .and_then(|s| Url::parse(s).map_err(|e| format!("Failed to parse `Url`: {}", e)))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
+            .and_then(|s| Url::parse(s).map_err(|e| format!("Failed to parse `Url`: {e}")))
     }
 }
 
diff --git a/juniper/src/integrations/uuid.rs b/juniper/src/integrations/uuid.rs
index 37f71042..4fed7f5f 100644
--- a/juniper/src/integrations/uuid.rs
+++ b/juniper/src/integrations/uuid.rs
@@ -16,8 +16,8 @@ mod uuid_scalar {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Uuid, String> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
-            .and_then(|s| Uuid::parse_str(s).map_err(|e| format!("Failed to parse `Uuid`: {}", e)))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
+            .and_then(|s| Uuid::parse_str(s).map_err(|e| format!("Failed to parse `Uuid`: {e}")))
     }
 }
 
diff --git a/juniper/src/introspection/mod.rs b/juniper/src/introspection/mod.rs
index aedd4ef9..e59a492e 100644
--- a/juniper/src/introspection/mod.rs
+++ b/juniper/src/introspection/mod.rs
@@ -5,15 +5,12 @@ pub(crate) const INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS: &str =
 
 /// The desired GraphQL introspection format for the canonical query
 /// (<https://github.com/graphql/graphql-js/blob/90bd6ff72625173dd39a1f82cfad9336cfad8f65/src/utilities/getIntrospectionQuery.ts#L62>)
+#[derive(Clone, Copy, Debug, Default)]
 pub enum IntrospectionFormat {
     /// The canonical GraphQL introspection query.
+    #[default]
     All,
+
     /// The canonical GraphQL introspection query without descriptions.
     WithoutDescriptions,
 }
-
-impl Default for IntrospectionFormat {
-    fn default() -> Self {
-        IntrospectionFormat::All
-    }
-}
diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs
index 04ac5d69..d59f97cf 100644
--- a/juniper/src/lib.rs
+++ b/juniper/src/lib.rs
@@ -6,6 +6,7 @@
 
 // Required for using `juniper_codegen` macros inside this crate to resolve
 // absolute `::juniper` path correctly, without errors.
+extern crate core;
 extern crate self as juniper;
 
 use std::fmt;
@@ -98,8 +99,8 @@ pub use crate::{
 /// An error that prevented query execution
 #[derive(Debug, PartialEq)]
 #[allow(missing_docs)]
-pub enum GraphQLError<'a> {
-    ParseError(Spanning<ParseError<'a>>),
+pub enum GraphQLError {
+    ParseError(Spanning<ParseError>),
     ValidationError(Vec<RuleError>),
     NoOperationProvided,
     MultipleOperationsProvided,
@@ -108,26 +109,38 @@ pub enum GraphQLError<'a> {
     NotSubscription,
 }
 
-impl<'a> fmt::Display for GraphQLError<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+impl fmt::Display for GraphQLError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            GraphQLError::ParseError(error) => write!(f, "{}", error),
-            GraphQLError::ValidationError(errors) => {
-                for error in errors {
-                    writeln!(f, "{}", error)?;
+            Self::ParseError(e) => write!(f, "{e}"),
+            Self::ValidationError(errs) => {
+                for e in errs {
+                    writeln!(f, "{e}")?;
                 }
                 Ok(())
             }
-            GraphQLError::NoOperationProvided => write!(f, "No operation provided"),
-            GraphQLError::MultipleOperationsProvided => write!(f, "Multiple operations provided"),
-            GraphQLError::UnknownOperationName => write!(f, "Unknown operation name"),
-            GraphQLError::IsSubscription => write!(f, "Operation is a subscription"),
-            GraphQLError::NotSubscription => write!(f, "Operation is not a subscription"),
+            Self::NoOperationProvided => write!(f, "No operation provided"),
+            Self::MultipleOperationsProvided => write!(f, "Multiple operations provided"),
+            Self::UnknownOperationName => write!(f, "Unknown operation name"),
+            Self::IsSubscription => write!(f, "Operation is a subscription"),
+            Self::NotSubscription => write!(f, "Operation is not a subscription"),
         }
     }
 }
 
-impl<'a> std::error::Error for GraphQLError<'a> {}
+impl std::error::Error for GraphQLError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::ParseError(e) => Some(e),
+            Self::ValidationError(errs) => Some(errs.first()?),
+            Self::NoOperationProvided
+            | Self::MultipleOperationsProvided
+            | Self::UnknownOperationName
+            | Self::IsSubscription
+            | Self::NotSubscription => None,
+        }
+    }
+}
 
 /// Execute a query synchronously in a provided schema
 pub fn execute_sync<'a, S, QueryT, MutationT, SubscriptionT>(
@@ -136,7 +149,7 @@ pub fn execute_sync<'a, S, QueryT, MutationT, SubscriptionT>(
     root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &QueryT::Context,
-) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>
 where
     S: ScalarValue,
     QueryT: GraphQLType<S>,
@@ -175,7 +188,7 @@ pub async fn execute<'a, S, QueryT, MutationT, SubscriptionT>(
     root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &QueryT::Context,
-) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>
 where
     QueryT: GraphQLTypeAsync<S>,
     QueryT::TypeInfo: Sync,
@@ -219,7 +232,7 @@ pub async fn resolve_into_stream<'a, S, QueryT, MutationT, SubscriptionT>(
     root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
     variables: &Variables<S>,
     context: &'a QueryT::Context,
-) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError>
 where
     QueryT: GraphQLTypeAsync<S>,
     QueryT::TypeInfo: Sync,
@@ -262,7 +275,7 @@ pub fn introspect<'a, S, QueryT, MutationT, SubscriptionT>(
     root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
     context: &QueryT::Context,
     format: IntrospectionFormat,
-) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
+) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError>
 where
     S: ScalarValue,
     QueryT: GraphQLType<S>,
@@ -281,8 +294,8 @@ where
     )
 }
 
-impl<'a> From<Spanning<ParseError<'a>>> for GraphQLError<'a> {
-    fn from(f: Spanning<ParseError<'a>>) -> GraphQLError<'a> {
-        GraphQLError::ParseError(f)
+impl From<Spanning<ParseError>> for GraphQLError {
+    fn from(err: Spanning<ParseError>) -> Self {
+        Self::ParseError(err)
     }
 }
diff --git a/juniper/src/macros/graphql_vars.rs b/juniper/src/macros/graphql_vars.rs
index 2034e493..debd4201 100644
--- a/juniper/src/macros/graphql_vars.rs
+++ b/juniper/src/macros/graphql_vars.rs
@@ -222,37 +222,35 @@ mod tests {
 
         assert_eq!(
             vars! {"key": 123},
-            vec![("key".to_owned(), IV::scalar(123))]
+            vec![("key".into(), IV::scalar(123))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": "val"},
-            vec![("key".to_owned(), IV::scalar("val"))]
+            vec![("key".into(), IV::scalar("val"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": 1.23},
-            vec![("key".to_owned(), IV::scalar(1.23))]
+            vec![("key".into(), IV::scalar(1.23))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": 1 + 2},
-            vec![("key".to_owned(), IV::scalar(3))]
-                .into_iter()
-                .collect(),
+            vec![("key".into(), IV::scalar(3))].into_iter().collect(),
         );
         assert_eq!(
             vars! {"key": false},
-            vec![("key".to_owned(), IV::scalar(false))]
+            vec![("key".into(), IV::scalar(false))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": (val)},
-            vec![("key".to_owned(), IV::scalar(42))]
+            vec![("key".into(), IV::scalar(42))]
                 .into_iter()
                 .collect::<V>(),
         );
@@ -262,13 +260,13 @@ mod tests {
     fn r#enum() {
         assert_eq!(
             vars! {"key": ENUM},
-            vec![("key".to_owned(), IV::enum_value("ENUM"))]
+            vec![("key".into(), IV::enum_value("ENUM"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": lowercase},
-            vec![("key".to_owned(), IV::enum_value("lowercase"))]
+            vec![("key".into(), IV::enum_value("lowercase"))]
                 .into_iter()
                 .collect::<V>(),
         );
@@ -278,19 +276,19 @@ mod tests {
     fn variable() {
         assert_eq!(
             vars! {"key": @var},
-            vec![("key".to_owned(), IV::variable("var"))]
+            vec![("key".into(), IV::variable("var"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": @array},
-            vec![("key".to_owned(), IV::variable("array"))]
+            vec![("key".into(), IV::variable("array"))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": @object},
-            vec![("key".to_owned(), IV::variable("object"))]
+            vec![("key".into(), IV::variable("object"))]
                 .into_iter()
                 .collect::<V>(),
         );
@@ -302,68 +300,65 @@ mod tests {
 
         assert_eq!(
             vars! {"key": []},
-            vec![("key".to_owned(), IV::list(vec![]))]
+            vec![("key".into(), IV::list(vec![]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
             vars! {"key": [null]},
-            vec![("key".to_owned(), IV::list(vec![IV::Null]))]
+            vec![("key".into(), IV::list(vec![IV::Null]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
             vars! {"key": [1]},
-            vec![("key".to_owned(), IV::list(vec![IV::scalar(1)]))]
+            vec![("key".into(), IV::list(vec![IV::scalar(1)]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": [1 + 2]},
-            vec![("key".to_owned(), IV::list(vec![IV::scalar(3)]))]
+            vec![("key".into(), IV::list(vec![IV::scalar(3)]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": [(val)]},
-            vec![("key".to_owned(), IV::list(vec![IV::scalar(42)]))]
+            vec![("key".into(), IV::list(vec![IV::scalar(42)]))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
             vars! {"key": [ENUM]},
-            vec![("key".to_owned(), IV::list(vec![IV::enum_value("ENUM")]))]
+            vec![("key".into(), IV::list(vec![IV::enum_value("ENUM")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": [lowercase]},
-            vec![(
-                "key".to_owned(),
-                IV::list(vec![IV::enum_value("lowercase")])
-            )]
-            .into_iter()
-            .collect::<V>(),
+            vec![("key".into(), IV::list(vec![IV::enum_value("lowercase")]))]
+                .into_iter()
+                .collect::<V>(),
         );
 
         assert_eq!(
             vars! {"key": [@var]},
-            vec![("key".to_owned(), IV::list(vec![IV::variable("var")]))]
+            vec![("key".into(), IV::list(vec![IV::variable("var")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": [@array]},
-            vec![("key".to_owned(), IV::list(vec![IV::variable("array")]))]
+            vec![("key".into(), IV::list(vec![IV::variable("array")]))]
                 .into_iter()
                 .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": [@object]},
-            vec![("key".to_owned(), IV::list(vec![IV::variable("object")]))]
+            vec![("key".into(), IV::list(vec![IV::variable("object")]))]
                 .into_iter()
                 .collect::<V>(),
         );
@@ -371,7 +366,7 @@ mod tests {
         assert_eq!(
             vars! {"key": [1, [2], 3]},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::list(vec![
                     IV::scalar(1),
                     IV::list(vec![IV::scalar(2)]),
@@ -384,7 +379,7 @@ mod tests {
         assert_eq!(
             vars! {"key": [1, [2 + 3], 3]},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::list(vec![
                     IV::scalar(1),
                     IV::list(vec![IV::scalar(5)]),
@@ -397,7 +392,7 @@ mod tests {
         assert_eq!(
             vars! {"key": [1, [ENUM], (val)]},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::list(vec![
                     IV::scalar(1),
                     IV::list(vec![IV::enum_value("ENUM")]),
@@ -410,7 +405,7 @@ mod tests {
         assert_eq!(
             vars! {"key": [1 + 2, [(val)], @val]},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::list(vec![
                     IV::scalar(3),
                     IV::list(vec![IV::scalar(42)]),
@@ -423,7 +418,7 @@ mod tests {
         assert_eq!(
             vars! {"key": [1, [@val], ENUM]},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::list(vec![
                     IV::scalar(1),
                     IV::list(vec![IV::variable("val")]),
@@ -441,14 +436,14 @@ mod tests {
 
         assert_eq!(
             vars! {"key": {}},
-            vec![("key".to_owned(), IV::object(IndexMap::<String, _>::new()))]
+            vec![("key".into(), IV::object(IndexMap::<String, _>::new()))]
                 .into_iter()
                 .collect::<V>(),
         );
 
         assert_eq!(
             vars! {"key": {"key": null}},
-            vec![("key".to_owned(), IV::object(indexmap! {"key" => IV::Null}))]
+            vec![("key".into(), IV::object(indexmap! {"key" => IV::Null}))]
                 .into_iter()
                 .collect::<V>(),
         );
@@ -456,7 +451,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": 123}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::scalar(123)}),
             )]
             .into_iter()
@@ -464,17 +459,14 @@ mod tests {
         );
         assert_eq!(
             vars! {"key": {"key": 1 + 2}},
-            vec![(
-                "key".to_owned(),
-                IV::object(indexmap! {"key" => IV::scalar(3)}),
-            )]
-            .into_iter()
-            .collect::<V>(),
+            vec![("key".into(), IV::object(indexmap! {"key" => IV::scalar(3)}),)]
+                .into_iter()
+                .collect::<V>(),
         );
         assert_eq!(
             vars! {"key": {"key": (val)}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::scalar(42)}),
             )]
             .into_iter()
@@ -484,7 +476,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": []}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::list(vec![])}),
             )]
             .into_iter()
@@ -493,7 +485,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": [null]}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::Null])}),
             )]
             .into_iter()
@@ -502,7 +494,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": [1]}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(1)])}),
             )]
             .into_iter()
@@ -511,7 +503,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": [1 + 2]}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(3)])}),
             )]
             .into_iter()
@@ -520,7 +512,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": [(val)]}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::list(vec![IV::scalar(42)])}),
             )]
             .into_iter()
@@ -529,7 +521,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": ENUM}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::enum_value("ENUM")}),
             )]
             .into_iter()
@@ -538,7 +530,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": lowercase}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::enum_value("lowercase")}),
             )]
             .into_iter()
@@ -547,7 +539,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": @val}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::variable("val")}),
             )]
             .into_iter()
@@ -556,7 +548,7 @@ mod tests {
         assert_eq!(
             vars! {"key": {"key": @array}},
             vec![(
-                "key".to_owned(),
+                "key".into(),
                 IV::object(indexmap! {"key" => IV::variable("array")}),
             )]
             .into_iter()
@@ -581,7 +573,7 @@ mod tests {
             },
             vec![
                 (
-                    "inner".to_owned(),
+                    "inner".into(),
                     IV::object(indexmap! {
                         "key1" => IV::scalar(42),
                         "key2" => IV::scalar("val"),
@@ -607,7 +599,7 @@ mod tests {
                         ]),
                     }),
                 ),
-                ("more".to_owned(), IV::variable("var")),
+                ("more".into(), IV::variable("var")),
             ]
             .into_iter()
             .collect::<V>(),
diff --git a/juniper/src/macros/helper/mod.rs b/juniper/src/macros/helper/mod.rs
index f6565e03..e3e31926 100644
--- a/juniper/src/macros/helper/mod.rs
+++ b/juniper/src/macros/helper/mod.rs
@@ -41,8 +41,7 @@ where
 /// [`GraphQLType::name`]: crate::GraphQLType::name
 pub fn err_unnamed_type<S>(name: &str) -> FieldError<S> {
     FieldError::from(format!(
-        "Expected `{}` type to implement `GraphQLType::name`",
-        name,
+        "Expected `{name}` type to implement `GraphQLType::name`",
     ))
 }
 
diff --git a/juniper/src/parser/document.rs b/juniper/src/parser/document.rs
index cd891883..cb2b308f 100644
--- a/juniper/src/parser/document.rs
+++ b/juniper/src/parser/document.rs
@@ -22,7 +22,7 @@ use crate::{
 pub fn parse_document_source<'a, 'b, S>(
     s: &'a str,
     schema: &'b SchemaType<'b, S>,
-) -> UnlocatedParseResult<'a, OwnedDocument<'a, S>>
+) -> UnlocatedParseResult<OwnedDocument<'a, S>>
 where
     S: ScalarValue,
 {
@@ -34,7 +34,7 @@ where
 fn parse_document<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> UnlocatedParseResult<'a, OwnedDocument<'a, S>>
+) -> UnlocatedParseResult<OwnedDocument<'a, S>>
 where
     S: ScalarValue,
 {
@@ -52,7 +52,7 @@ where
 fn parse_definition<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> UnlocatedParseResult<'a, Definition<'a, S>>
+) -> UnlocatedParseResult<Definition<'a, S>>
 where
     S: ScalarValue,
 {
@@ -66,14 +66,14 @@ where
         Token::Name("fragment") => Ok(Definition::Fragment(parse_fragment_definition(
             parser, schema,
         )?)),
-        _ => Err(parser.next_token()?.map(ParseError::UnexpectedToken)),
+        _ => Err(parser.next_token()?.map(ParseError::unexpected_token)),
     }
 }
 
 fn parse_operation_definition<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> ParseResult<'a, Operation<'a, S>>
+) -> ParseResult<Operation<'a, S>>
 where
     S: ScalarValue,
 {
@@ -129,7 +129,7 @@ where
 fn parse_fragment_definition<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> ParseResult<'a, Fragment<'a, S>>
+) -> ParseResult<Fragment<'a, S>>
 where
     S: ScalarValue,
 {
@@ -139,7 +139,7 @@ where
     let name = match parser.expect_name() {
         Ok(n) => {
             if n.item == "on" {
-                return Err(n.map(|_| ParseError::UnexpectedToken(Token::Name("on"))));
+                return Err(n.map(|_| ParseError::UnexpectedToken("on".into())));
             } else {
                 n
             }
@@ -174,7 +174,7 @@ fn parse_optional_selection_set<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     fields: Option<&[&MetaField<'b, S>]>,
-) -> OptionParseResult<'a, Vec<Selection<'a, S>>>
+) -> OptionParseResult<Vec<Selection<'a, S>>>
 where
     S: ScalarValue,
 {
@@ -189,7 +189,7 @@ fn parse_selection_set<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     fields: Option<&[&MetaField<'b, S>]>,
-) -> ParseResult<'a, Vec<Selection<'a, S>>>
+) -> ParseResult<Vec<Selection<'a, S>>>
 where
     S: ScalarValue,
 {
@@ -204,7 +204,7 @@ fn parse_selection<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     fields: Option<&[&MetaField<'b, S>]>,
-) -> UnlocatedParseResult<'a, Selection<'a, S>>
+) -> UnlocatedParseResult<Selection<'a, S>>
 where
     S: ScalarValue,
 {
@@ -218,7 +218,7 @@ fn parse_fragment<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     fields: Option<&[&MetaField<'b, S>]>,
-) -> UnlocatedParseResult<'a, Selection<'a, S>>
+) -> UnlocatedParseResult<Selection<'a, S>>
 where
     S: ScalarValue,
 {
@@ -292,7 +292,7 @@ where
                 },
             )))
         }
-        _ => Err(parser.next_token()?.map(ParseError::UnexpectedToken)),
+        _ => Err(parser.next_token()?.map(ParseError::unexpected_token)),
     }
 }
 
@@ -300,7 +300,7 @@ fn parse_field<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     fields: Option<&[&MetaField<'b, S>]>,
-) -> ParseResult<'a, Field<'a, S>>
+) -> ParseResult<Field<'a, S>>
 where
     S: ScalarValue,
 {
@@ -351,7 +351,7 @@ fn parse_arguments<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     arguments: Option<&[Argument<'b, S>]>,
-) -> OptionParseResult<'a, Arguments<'a, S>>
+) -> OptionParseResult<Arguments<'a, S>>
 where
     S: ScalarValue,
 {
@@ -376,7 +376,7 @@ fn parse_argument<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
     arguments: Option<&[Argument<'b, S>]>,
-) -> ParseResult<'a, (Spanning<&'a str>, Spanning<InputValue<S>>)>
+) -> ParseResult<(Spanning<&'a str>, Spanning<InputValue<S>>)>
 where
     S: ScalarValue,
 {
@@ -395,21 +395,21 @@ where
     ))
 }
 
-fn parse_operation_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, OperationType> {
+fn parse_operation_type(parser: &mut Parser<'_>) -> ParseResult<OperationType> {
     match parser.peek().item {
         Token::Name("query") => Ok(parser.next_token()?.map(|_| OperationType::Query)),
         Token::Name("mutation") => Ok(parser.next_token()?.map(|_| OperationType::Mutation)),
         Token::Name("subscription") => {
             Ok(parser.next_token()?.map(|_| OperationType::Subscription))
         }
-        _ => Err(parser.next_token()?.map(ParseError::UnexpectedToken)),
+        _ => Err(parser.next_token()?.map(ParseError::unexpected_token)),
     }
 }
 
 fn parse_variable_definitions<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> OptionParseResult<'a, VariableDefinitions<'a, S>>
+) -> OptionParseResult<VariableDefinitions<'a, S>>
 where
     S: ScalarValue,
 {
@@ -433,7 +433,7 @@ where
 fn parse_variable_definition<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> ParseResult<'a, (Spanning<&'a str>, VariableDefinition<'a, S>)>
+) -> ParseResult<(Spanning<&'a str>, VariableDefinition<'a, S>)>
 where
     S: ScalarValue,
 {
@@ -473,7 +473,7 @@ where
 fn parse_directives<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> OptionParseResult<'a, Vec<Spanning<Directive<'a, S>>>>
+) -> OptionParseResult<Vec<Spanning<Directive<'a, S>>>>
 where
     S: ScalarValue,
 {
@@ -492,7 +492,7 @@ where
 fn parse_directive<'a, 'b, S>(
     parser: &mut Parser<'a>,
     schema: &'b SchemaType<'b, S>,
-) -> ParseResult<'a, Directive<'a, S>>
+) -> ParseResult<Directive<'a, S>>
 where
     S: ScalarValue,
 {
@@ -516,7 +516,7 @@ where
     ))
 }
 
-pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Type<'a>> {
+pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<Type<'a>> {
     let parsed_type = if let Some(Spanning {
         start: start_pos, ..
     }) = parser.skip(&Token::BracketOpen)?
@@ -541,10 +541,7 @@ pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Type<'a>> {
     })
 }
 
-fn wrap_non_null<'a>(
-    parser: &mut Parser<'a>,
-    inner: Spanning<Type<'a>>,
-) -> ParseResult<'a, Type<'a>> {
+fn wrap_non_null<'a>(parser: &mut Parser<'a>, inner: Spanning<Type<'a>>) -> ParseResult<Type<'a>> {
     let Spanning { end: end_pos, .. } = parser.expect(&Token::ExclamationMark)?;
 
     let wrapped = match inner.item {
diff --git a/juniper/src/parser/lexer.rs b/juniper/src/parser/lexer.rs
index c71c7ccf..3dd4a0e5 100644
--- a/juniper/src/parser/lexer.rs
+++ b/juniper/src/parser/lexer.rs
@@ -239,7 +239,7 @@ impl<'a> Lexer<'a> {
                 c if escaped => {
                     return Err(Spanning::zero_width(
                         &old_pos,
-                        LexerError::UnknownEscapeSequence(format!("\\{}", c)),
+                        LexerError::UnknownEscapeSequence(format!("\\{c}")),
                     ));
                 }
                 '\\' => escaped = true,
@@ -305,14 +305,14 @@ impl<'a> Lexer<'a> {
         if len != 4 {
             return Err(Spanning::zero_width(
                 start_pos,
-                LexerError::UnknownEscapeSequence("\\u".to_owned() + escape),
+                LexerError::UnknownEscapeSequence(format!("\\u{escape}")),
             ));
         }
 
         let code_point = u32::from_str_radix(escape, 16).map_err(|_| {
             Spanning::zero_width(
                 start_pos,
-                LexerError::UnknownEscapeSequence("\\u".to_owned() + escape),
+                LexerError::UnknownEscapeSequence(format!("\\u{escape}")),
             )
         })?;
 
@@ -338,7 +338,7 @@ impl<'a> Lexer<'a> {
 
         let mut end_idx = loop {
             if let Some((idx, ch)) = self.peek_char() {
-                if ch.is_digit(10) || (ch == '-' && last_idx == start_idx) {
+                if ch.is_ascii_digit() || (ch == '-' && last_idx == start_idx) {
                     if ch == '0' && last_char == '0' && last_idx == start_idx {
                         return Err(Spanning::zero_width(
                             &self.position,
@@ -367,7 +367,7 @@ impl<'a> Lexer<'a> {
             self.next_char();
             end_idx = loop {
                 if let Some((idx, ch)) = self.peek_char() {
-                    if ch.is_digit(10) {
+                    if ch.is_ascii_digit() {
                         self.next_char();
                     } else if last_idx == start_idx {
                         return Err(Spanning::zero_width(
@@ -396,7 +396,9 @@ impl<'a> Lexer<'a> {
 
                 end_idx = loop {
                     if let Some((idx, ch)) = self.peek_char() {
-                        if ch.is_digit(10) || (last_idx == start_idx && (ch == '-' || ch == '+')) {
+                        if ch.is_ascii_digit()
+                            || (last_idx == start_idx && (ch == '-' || ch == '+'))
+                        {
                             self.next_char();
                         } else if last_idx == start_idx {
                             // 1e is not a valid floating point number
@@ -483,9 +485,9 @@ impl<'a> Iterator for Lexer<'a> {
 impl<'a> fmt::Display for Token<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            Token::Name(name) => write!(f, "{}", name),
+            Token::Name(name) => write!(f, "{name}"),
             Token::Scalar(ScalarToken::Int(s)) | Token::Scalar(ScalarToken::Float(s)) => {
-                write!(f, "{}", s)
+                write!(f, "{s}")
             }
             Token::Scalar(ScalarToken::String(s)) => {
                 write!(f, "\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
@@ -527,15 +529,15 @@ fn is_number_start(c: char) -> bool {
 impl fmt::Display for LexerError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            LexerError::UnknownCharacter(c) => write!(f, "Unknown character \"{}\"", c),
+            LexerError::UnknownCharacter(c) => write!(f, "Unknown character \"{c}\""),
             LexerError::UnterminatedString => write!(f, "Unterminated string literal"),
             LexerError::UnknownCharacterInString(c) => {
-                write!(f, "Unknown character \"{}\" in string literal", c)
+                write!(f, "Unknown character \"{c}\" in string literal")
             }
             LexerError::UnknownEscapeSequence(ref s) => {
-                write!(f, "Unknown escape sequence \"{}\" in string", s)
+                write!(f, "Unknown escape sequence \"{s}\" in string")
             }
-            LexerError::UnexpectedCharacter(c) => write!(f, "Unexpected character \"{}\"", c),
+            LexerError::UnexpectedCharacter(c) => write!(f, "Unexpected character \"{c}\""),
             LexerError::UnexpectedEndOfFile => write!(f, "Unexpected end of input"),
             LexerError::InvalidNumber => write!(f, "Invalid number literal"),
         }
diff --git a/juniper/src/parser/parser.rs b/juniper/src/parser/parser.rs
index 4a066453..89ab697b 100644
--- a/juniper/src/parser/parser.rs
+++ b/juniper/src/parser/parser.rs
@@ -1,12 +1,16 @@
-use std::{fmt, result::Result};
+use std::{error::Error, fmt, result::Result};
+
+use smartstring::alias::String;
 
 use crate::parser::{Lexer, LexerError, Spanning, Token};
 
 /// Error while parsing a GraphQL query
 #[derive(Debug, PartialEq)]
-pub enum ParseError<'a> {
+pub enum ParseError {
     /// An unexpected token occurred in the source
-    UnexpectedToken(Token<'a>),
+    // TODO: Previously was `Token<'a>`.
+    //       Revisit on `graphql-parser` integration.
+    UnexpectedToken(String),
 
     /// The input source abruptly ended
     UnexpectedEndOfFile,
@@ -18,14 +22,51 @@ pub enum ParseError<'a> {
     ExpectedScalarError(&'static str),
 }
 
-#[doc(hidden)]
-pub type ParseResult<'a, T> = Result<Spanning<T>, Spanning<ParseError<'a>>>;
+impl fmt::Display for ParseError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::UnexpectedToken(token) => write!(f, "Unexpected \"{token}\""),
+            Self::UnexpectedEndOfFile => write!(f, "Unexpected end of input"),
+            Self::LexerError(e) => e.fmt(f),
+            Self::ExpectedScalarError(e) => e.fmt(f),
+        }
+    }
+}
+
+impl Error for ParseError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        match self {
+            Self::LexerError(e) => Some(e),
+            Self::ExpectedScalarError(_) | Self::UnexpectedToken(_) | Self::UnexpectedEndOfFile => {
+                None
+            }
+        }
+    }
+}
+
+impl ParseError {
+    /// Creates a [`ParseError::UnexpectedToken`] out of the provided [`Token`].
+    #[must_use]
+    pub fn unexpected_token(token: Token<'_>) -> Self {
+        use std::fmt::Write as _;
+
+        let mut s = String::new();
+        // PANIC: Unwrapping is OK here, as it may panic only on allocation
+        //        error.
+        write!(s, "{token}").unwrap();
+
+        Self::UnexpectedToken(s)
+    }
+}
 
 #[doc(hidden)]
-pub type UnlocatedParseResult<'a, T> = Result<T, Spanning<ParseError<'a>>>;
+pub type ParseResult<T> = Result<Spanning<T>, Spanning<ParseError>>;
 
 #[doc(hidden)]
-pub type OptionParseResult<'a, T> = Result<Option<Spanning<T>>, Spanning<ParseError<'a>>>;
+pub type UnlocatedParseResult<T> = Result<T, Spanning<ParseError>>;
+
+#[doc(hidden)]
+pub type OptionParseResult<T> = Result<Option<Spanning<T>>, Spanning<ParseError>>;
 
 #[doc(hidden)]
 #[derive(Debug)]
@@ -54,7 +95,7 @@ impl<'a> Parser<'a> {
     }
 
     #[doc(hidden)]
-    pub fn next_token(&mut self) -> ParseResult<'a, Token<'a>> {
+    pub fn next_token(&mut self) -> ParseResult<Token<'a>> {
         if self.tokens.len() == 1 {
             Err(Spanning::start_end(
                 &self.peek().start,
@@ -67,9 +108,9 @@ impl<'a> Parser<'a> {
     }
 
     #[doc(hidden)]
-    pub fn expect(&mut self, expected: &Token) -> ParseResult<'a, Token<'a>> {
+    pub fn expect(&mut self, expected: &Token) -> ParseResult<Token<'a>> {
         if &self.peek().item != expected {
-            Err(self.next_token()?.map(ParseError::UnexpectedToken))
+            Err(self.next_token()?.map(ParseError::unexpected_token))
         } else {
             self.next_token()
         }
@@ -79,7 +120,7 @@ impl<'a> Parser<'a> {
     pub fn skip(
         &mut self,
         expected: &Token,
-    ) -> Result<Option<Spanning<Token<'a>>>, Spanning<ParseError<'a>>> {
+    ) -> Result<Option<Spanning<Token<'a>>>, Spanning<ParseError>> {
         if &self.peek().item == expected {
             Ok(Some(self.next_token()?))
         } else if self.peek().item == Token::EndOfFile {
@@ -98,10 +139,10 @@ impl<'a> Parser<'a> {
         opening: &Token,
         parser: F,
         closing: &Token,
-    ) -> ParseResult<'a, Vec<Spanning<T>>>
+    ) -> ParseResult<Vec<Spanning<T>>>
     where
         T: fmt::Debug,
-        F: Fn(&mut Parser<'a>) -> ParseResult<'a, T>,
+        F: Fn(&mut Parser<'a>) -> ParseResult<T>,
     {
         let Spanning {
             start: start_pos, ..
@@ -123,10 +164,10 @@ impl<'a> Parser<'a> {
         opening: &Token,
         parser: F,
         closing: &Token,
-    ) -> ParseResult<'a, Vec<Spanning<T>>>
+    ) -> ParseResult<Vec<Spanning<T>>>
     where
         T: fmt::Debug,
-        F: Fn(&mut Parser<'a>) -> ParseResult<'a, T>,
+        F: Fn(&mut Parser<'a>) -> ParseResult<T>,
     {
         let Spanning {
             start: start_pos, ..
@@ -148,10 +189,10 @@ impl<'a> Parser<'a> {
         opening: &Token,
         parser: F,
         closing: &Token,
-    ) -> ParseResult<'a, Vec<T>>
+    ) -> ParseResult<Vec<T>>
     where
         T: fmt::Debug,
-        F: Fn(&mut Parser<'a>) -> UnlocatedParseResult<'a, T>,
+        F: Fn(&mut Parser<'a>) -> UnlocatedParseResult<T>,
     {
         let Spanning {
             start: start_pos, ..
@@ -168,7 +209,7 @@ impl<'a> Parser<'a> {
     }
 
     #[doc(hidden)]
-    pub fn expect_name(&mut self) -> ParseResult<'a, &'a str> {
+    pub fn expect_name(&mut self) -> ParseResult<&'a str> {
         match *self.peek() {
             Spanning {
                 item: Token::Name(_),
@@ -188,20 +229,7 @@ impl<'a> Parser<'a> {
                 &self.peek().end,
                 ParseError::UnexpectedEndOfFile,
             )),
-            _ => Err(self.next_token()?.map(ParseError::UnexpectedToken)),
+            _ => Err(self.next_token()?.map(ParseError::unexpected_token)),
         }
     }
 }
-
-impl<'a> fmt::Display for ParseError<'a> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ParseError::UnexpectedToken(ref token) => write!(f, "Unexpected \"{}\"", token),
-            ParseError::UnexpectedEndOfFile => write!(f, "Unexpected end of input"),
-            ParseError::LexerError(ref err) => err.fmt(f),
-            ParseError::ExpectedScalarError(err) => err.fmt(f),
-        }
-    }
-}
-
-impl<'a> std::error::Error for ParseError<'a> {}
diff --git a/juniper/src/parser/tests/document.rs b/juniper/src/parser/tests/document.rs
index bb28074b..65018a3d 100644
--- a/juniper/src/parser/tests/document.rs
+++ b/juniper/src/parser/tests/document.rs
@@ -16,18 +16,15 @@ where
         s,
         &SchemaType::new::<QueryRoot, MutationRoot, SubscriptionRoot>(&(), &(), &()),
     )
-    .expect(&format!("Parse error on input {:#?}", s))
+    .expect(&format!("Parse error on input {s:#?}"))
 }
 
-fn parse_document_error<'a, S>(s: &'a str) -> Spanning<ParseError<'a>>
-where
-    S: ScalarValue,
-{
+fn parse_document_error<S: ScalarValue>(s: &str) -> Spanning<ParseError> {
     match parse_document_source::<S>(
         s,
         &SchemaType::new::<QueryRoot, MutationRoot, SubscriptionRoot>(&(), &(), &()),
     ) {
-        Ok(doc) => panic!("*No* parse error on input {:#?} =>\n{:#?}", s, doc),
+        Ok(doc) => panic!("*No* parse error on input {s:#?} =>\n{doc:#?}"),
         Err(err) => err,
     }
 }
@@ -136,7 +133,7 @@ fn errors() {
         Spanning::start_end(
             &SourcePosition::new(36, 1, 19),
             &SourcePosition::new(40, 1, 23),
-            ParseError::UnexpectedToken(Token::Name("Type"))
+            ParseError::UnexpectedToken("Type".into())
         )
     );
 
@@ -145,7 +142,7 @@ fn errors() {
         Spanning::start_end(
             &SourcePosition::new(8, 0, 8),
             &SourcePosition::new(9, 0, 9),
-            ParseError::UnexpectedToken(Token::CurlyClose)
+            ParseError::unexpected_token(Token::CurlyClose)
         )
     );
 }
diff --git a/juniper/src/parser/tests/lexer.rs b/juniper/src/parser/tests/lexer.rs
index a08dbfaa..7b295270 100644
--- a/juniper/src/parser/tests/lexer.rs
+++ b/juniper/src/parser/tests/lexer.rs
@@ -13,8 +13,8 @@ fn tokenize_to_vec<'a>(s: &'a str) -> Vec<Spanning<Token<'a>>> {
                     break;
                 }
             }
-            Some(Err(e)) => panic!("Error in input stream: {:#?} for {:#?}", e, s),
-            None => panic!("EOF before EndOfFile token in {:#?}", s),
+            Some(Err(e)) => panic!("Error in input stream: {e:#?} for {s:#?}"),
+            None => panic!("EOF before EndOfFile token in {s:#?}"),
         }
     }
 
@@ -37,13 +37,13 @@ fn tokenize_error(s: &str) -> Spanning<LexerError> {
         match lexer.next() {
             Some(Ok(t)) => {
                 if t.item == Token::EndOfFile {
-                    panic!("Tokenizer did not return error for {:#?}", s);
+                    panic!("Tokenizer did not return error for {s:#?}");
                 }
             }
             Some(Err(e)) => {
                 return e;
             }
-            None => panic!("Tokenizer did not return error for {:#?}", s),
+            None => panic!("Tokenizer did not return error for {s:#?}"),
         }
     }
 }
@@ -196,7 +196,7 @@ fn strings() {
         Spanning::start_end(
             &SourcePosition::new(0, 0, 0),
             &SourcePosition::new(34, 0, 34),
-            Token::Scalar(ScalarToken::String(r#"unicode \u1234\u5678\u90AB\uCDEF"#))
+            Token::Scalar(ScalarToken::String(r#"unicode \u1234\u5678\u90AB\uCDEF"#)),
         )
     );
 }
@@ -207,7 +207,7 @@ fn string_errors() {
         tokenize_error("\""),
         Spanning::zero_width(
             &SourcePosition::new(1, 0, 1),
-            LexerError::UnterminatedString
+            LexerError::UnterminatedString,
         )
     );
 
@@ -215,7 +215,7 @@ fn string_errors() {
         tokenize_error("\"no end quote"),
         Spanning::zero_width(
             &SourcePosition::new(13, 0, 13),
-            LexerError::UnterminatedString
+            LexerError::UnterminatedString,
         )
     );
 
@@ -223,7 +223,7 @@ fn string_errors() {
         tokenize_error("\"contains unescaped \u{0007} control char\""),
         Spanning::zero_width(
             &SourcePosition::new(20, 0, 20),
-            LexerError::UnknownCharacterInString('\u{0007}')
+            LexerError::UnknownCharacterInString('\u{0007}'),
         )
     );
 
@@ -231,7 +231,7 @@ fn string_errors() {
         tokenize_error("\"null-byte is not \u{0000} end of file\""),
         Spanning::zero_width(
             &SourcePosition::new(18, 0, 18),
-            LexerError::UnknownCharacterInString('\u{0000}')
+            LexerError::UnknownCharacterInString('\u{0000}'),
         )
     );
 
@@ -239,7 +239,7 @@ fn string_errors() {
         tokenize_error("\"multi\nline\""),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnterminatedString
+            LexerError::UnterminatedString,
         )
     );
 
@@ -247,7 +247,7 @@ fn string_errors() {
         tokenize_error("\"multi\rline\""),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnterminatedString
+            LexerError::UnterminatedString,
         )
     );
 
@@ -255,7 +255,7 @@ fn string_errors() {
         tokenize_error(r#""bad \z esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\z".to_owned())
+            LexerError::UnknownEscapeSequence("\\z".into()),
         )
     );
 
@@ -263,7 +263,7 @@ fn string_errors() {
         tokenize_error(r#""bad \x esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\x".to_owned())
+            LexerError::UnknownEscapeSequence("\\x".into()),
         )
     );
 
@@ -271,7 +271,7 @@ fn string_errors() {
         tokenize_error(r#""bad \u1 esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\u1".to_owned())
+            LexerError::UnknownEscapeSequence("\\u1".into()),
         )
     );
 
@@ -279,7 +279,7 @@ fn string_errors() {
         tokenize_error(r#""bad \u0XX1 esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\u0XX1".to_owned())
+            LexerError::UnknownEscapeSequence("\\u0XX1".into()),
         )
     );
 
@@ -287,7 +287,7 @@ fn string_errors() {
         tokenize_error(r#""bad \uXXXX esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\uXXXX".to_owned())
+            LexerError::UnknownEscapeSequence("\\uXXXX".into()),
         )
     );
 
@@ -295,7 +295,7 @@ fn string_errors() {
         tokenize_error(r#""bad \uFXXX esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\uFXXX".to_owned())
+            LexerError::UnknownEscapeSequence("\\uFXXX".into()),
         )
     );
 
@@ -303,7 +303,7 @@ fn string_errors() {
         tokenize_error(r#""bad \uXXXF esc""#),
         Spanning::zero_width(
             &SourcePosition::new(6, 0, 6),
-            LexerError::UnknownEscapeSequence("\\uXXXF".to_owned())
+            LexerError::UnknownEscapeSequence("\\uXXXF".into()),
         )
     );
 
@@ -349,9 +349,7 @@ fn numbers() {
             Token::Scalar(ScalarToken::Float(actual)) => {
                 assert!(
                     expected == actual,
-                    "[expected] {} != {} [actual]",
-                    expected,
-                    actual
+                    "[expected] {expected} != {actual} [actual]",
                 );
             }
             _ => assert!(false),
@@ -662,39 +660,32 @@ fn punctuation_error() {
 
 #[test]
 fn display() {
-    assert_eq!(format!("{}", Token::Name("identifier")), "identifier");
-
-    assert_eq!(format!("{}", Token::Scalar(ScalarToken::Int("123"))), "123");
-
-    assert_eq!(
-        format!("{}", Token::Scalar(ScalarToken::Float("4.5"))),
-        "4.5"
-    );
-
-    assert_eq!(
-        format!("{}", Token::Scalar(ScalarToken::String("some string"))),
-        "\"some string\""
-    );
-
-    assert_eq!(
-        format!(
-            "{}",
-            Token::Scalar(ScalarToken::String("string with \\ escape and \" quote"))
+    for (input, expected) in [
+        (Token::Name("identifier"), "identifier"),
+        (Token::Scalar(ScalarToken::Int("123")), "123"),
+        (Token::Scalar(ScalarToken::Float("4.5")), "4.5"),
+        (
+            Token::Scalar(ScalarToken::String("some string")),
+            "\"some string\"",
         ),
-        "\"string with \\\\ escape and \\\" quote\""
-    );
-
-    assert_eq!(format!("{}", Token::ExclamationMark), "!");
-    assert_eq!(format!("{}", Token::Dollar), "$");
-    assert_eq!(format!("{}", Token::ParenOpen), "(");
-    assert_eq!(format!("{}", Token::ParenClose), ")");
-    assert_eq!(format!("{}", Token::BracketOpen), "[");
-    assert_eq!(format!("{}", Token::BracketClose), "]");
-    assert_eq!(format!("{}", Token::CurlyOpen), "{");
-    assert_eq!(format!("{}", Token::CurlyClose), "}");
-    assert_eq!(format!("{}", Token::Ellipsis), "...");
-    assert_eq!(format!("{}", Token::Colon), ":");
-    assert_eq!(format!("{}", Token::Equals), "=");
-    assert_eq!(format!("{}", Token::At), "@");
-    assert_eq!(format!("{}", Token::Pipe), "|");
+        (
+            Token::Scalar(ScalarToken::String("string with \\ escape and \" quote")),
+            "\"string with \\\\ escape and \\\" quote\"",
+        ),
+        (Token::ExclamationMark, "!"),
+        (Token::Dollar, "$"),
+        (Token::ParenOpen, "("),
+        (Token::ParenClose, ")"),
+        (Token::BracketOpen, "["),
+        (Token::BracketClose, "]"),
+        (Token::CurlyOpen, "{"),
+        (Token::CurlyClose, "}"),
+        (Token::Ellipsis, "..."),
+        (Token::Colon, ":"),
+        (Token::Equals, "="),
+        (Token::At, "@"),
+        (Token::Pipe, "|"),
+    ] {
+        assert_eq!(input.to_string(), expected);
+    }
 }
diff --git a/juniper/src/parser/tests/value.rs b/juniper/src/parser/tests/value.rs
index 8dbe78bd..e10a4ab3 100644
--- a/juniper/src/parser/tests/value.rs
+++ b/juniper/src/parser/tests/value.rs
@@ -65,11 +65,11 @@ where
     S: ScalarValue,
 {
     let mut lexer = Lexer::new(s);
-    let mut parser = Parser::new(&mut lexer).expect(&format!("Lexer error on input {:#?}", s));
+    let mut parser = Parser::new(&mut lexer).expect(&format!("Lexer error on input {s:#?}"));
     let schema = SchemaType::new::<Query, EmptyMutation<()>, EmptySubscription<()>>(&(), &(), &());
 
     parse_value_literal(&mut parser, false, &schema, Some(meta))
-        .expect(&format!("Parse error on input {:#?}", s))
+        .expect(&format!("Parse error on input {s:#?}"))
 }
 
 #[test]
diff --git a/juniper/src/parser/utils.rs b/juniper/src/parser/utils.rs
index fdad1679..645c3014 100644
--- a/juniper/src/parser/utils.rs
+++ b/juniper/src/parser/utils.rs
@@ -81,7 +81,7 @@ impl<T> Spanning<T> {
         }
     }
 
-    /// Modify the contents of the spanned item
+    /// Modify the contents of the spanned item.
     pub fn map<O, F: Fn(T) -> O>(self, f: F) -> Spanning<O> {
         Spanning {
             item: f(self.item),
@@ -89,6 +89,13 @@ impl<T> Spanning<T> {
             end: self.end,
         }
     }
+
+    /// Modifies the contents of the spanned item in case `f` returns [`Some`],
+    /// or returns [`None`] otherwise.
+    pub fn and_then<O, F: Fn(T) -> Option<O>>(self, f: F) -> Option<Spanning<O>> {
+        let (start, end) = (self.start, self.end);
+        f(self.item).map(|item| Spanning { item, start, end })
+    }
 }
 
 impl<T: fmt::Display> fmt::Display for Spanning<T> {
diff --git a/juniper/src/parser/value.rs b/juniper/src/parser/value.rs
index 3ff6d5ef..f94f65c2 100644
--- a/juniper/src/parser/value.rs
+++ b/juniper/src/parser/value.rs
@@ -9,12 +9,12 @@ use crate::{
     value::ScalarValue,
 };
 
-pub fn parse_value_literal<'a, 'b, S>(
-    parser: &mut Parser<'a>,
+pub fn parse_value_literal<'b, S>(
+    parser: &mut Parser<'_>,
     is_const: bool,
     schema: &'b SchemaType<'b, S>,
     tpe: Option<&MetaType<'b, S>>,
-) -> ParseResult<'a, InputValue<S>>
+) -> ParseResult<InputValue<S>>
 where
     S: ScalarValue,
 {
@@ -113,16 +113,16 @@ where
             },
             _,
         ) => Ok(parser.next_token()?.map(|_| InputValue::enum_value(name))),
-        _ => Err(parser.next_token()?.map(ParseError::UnexpectedToken)),
+        _ => Err(parser.next_token()?.map(ParseError::unexpected_token)),
     }
 }
 
-fn parse_list_literal<'a, 'b, S>(
-    parser: &mut Parser<'a>,
+fn parse_list_literal<'b, S>(
+    parser: &mut Parser<'_>,
     is_const: bool,
     schema: &'b SchemaType<'b, S>,
     tpe: Option<&MetaType<'b, S>>,
-) -> ParseResult<'a, InputValue<S>>
+) -> ParseResult<InputValue<S>>
 where
     S: ScalarValue,
 {
@@ -135,12 +135,12 @@ where
         .map(InputValue::parsed_list))
 }
 
-fn parse_object_literal<'a, 'b, S>(
-    parser: &mut Parser<'a>,
+fn parse_object_literal<'b, S>(
+    parser: &mut Parser<'_>,
     is_const: bool,
     schema: &'b SchemaType<'b, S>,
     object_tpe: Option<&InputObjectMeta<'b, S>>,
-) -> ParseResult<'a, InputValue<S>>
+) -> ParseResult<InputValue<S>>
 where
     S: ScalarValue,
 {
@@ -153,12 +153,12 @@ where
         .map(|items| InputValue::parsed_object(items.into_iter().map(|s| s.item).collect())))
 }
 
-fn parse_object_field<'a, 'b, S>(
-    parser: &mut Parser<'a>,
+fn parse_object_field<'b, S>(
+    parser: &mut Parser<'_>,
     is_const: bool,
     schema: &'b SchemaType<'b, S>,
     object_meta: Option<&InputObjectMeta<'b, S>>,
-) -> ParseResult<'a, (Spanning<String>, Spanning<InputValue<S>>)>
+) -> ParseResult<(Spanning<String>, Spanning<InputValue<S>>)>
 where
     S: ScalarValue,
 {
@@ -179,7 +179,7 @@ where
     ))
 }
 
-fn parse_variable_literal<'a, S>(parser: &mut Parser<'a>) -> ParseResult<'a, InputValue<S>>
+fn parse_variable_literal<S>(parser: &mut Parser<'_>) -> ParseResult<InputValue<S>>
 where
     S: ScalarValue,
 {
@@ -199,12 +199,12 @@ where
     ))
 }
 
-fn parse_scalar_literal_by_infered_type<'a, 'b, S>(
-    token: ScalarToken<'a>,
+fn parse_scalar_literal_by_infered_type<'b, S>(
+    token: ScalarToken<'_>,
     start: &SourcePosition,
     end: &SourcePosition,
     schema: &'b SchemaType<'b, S>,
-) -> ParseResult<'a, InputValue<S>>
+) -> ParseResult<InputValue<S>>
 where
     S: ScalarValue,
 {
diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs
index 353095fd..7c7e5c19 100644
--- a/juniper/src/resolve/mod.rs
+++ b/juniper/src/resolve/mod.rs
@@ -200,5 +200,5 @@ pub trait InputValueAsRef<ScalarValue, Behavior: ?Sized = behavior::Standard> {
 }
 
 pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> {
-    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError<'_>>;
+    fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError>;
 }
diff --git a/juniper/src/schema/meta.rs b/juniper/src/schema/meta.rs
index ce5b0874..717a2383 100644
--- a/juniper/src/schema/meta.rs
+++ b/juniper/src/schema/meta.rs
@@ -72,7 +72,7 @@ impl<'a, S> Clone for ScalarMeta<'a, S> {
 pub type InputValueParseFn<S> = for<'b> fn(&'b InputValue<S>) -> Result<(), FieldError<S>>;
 
 /// Shortcut for a [`ScalarToken`] parsing function.
-pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError<'b>>;
+pub type ScalarTokenParseFn<S> = for<'b> fn(ScalarToken<'b>) -> Result<S, ParseError>;
 
 /// List type metadata
 #[derive(Clone, Debug)]
@@ -433,7 +433,7 @@ impl<'a, S> MetaType<'a, S> {
             // "used exclusively by GraphQL’s introspection system"
             {
                 name.starts_with("__") ||
-            // <https://facebook.github.io/graphql/draft/#sec-Scalars>
+            // https://spec.graphql.org/October2021#sec-Scalars
             name == "Boolean" || name == "String" || name == "Int" || name == "Float" || name == "ID" ||
             // Our custom empty markers
             name == "_EmptyMutation" || name == "_EmptySubscription"
@@ -543,7 +543,7 @@ impl<'a, S> ScalarMeta<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -613,7 +613,7 @@ impl<'a, S> ObjectMeta<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -624,7 +624,7 @@ impl<'a, S> ObjectMeta<'a, S> {
     pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> Self {
         self.interface_names = interfaces
             .iter()
-            .map(|t| t.innermost_name().to_owned())
+            .map(|t| t.innermost_name().into())
             .collect();
         self
     }
@@ -674,7 +674,7 @@ impl<'a, S> EnumMeta<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -704,7 +704,7 @@ impl<'a, S> InterfaceMeta<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -715,7 +715,7 @@ impl<'a, S> InterfaceMeta<'a, S> {
     pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> Self {
         self.interface_names = interfaces
             .iter()
-            .map(|t| t.innermost_name().to_owned())
+            .map(|t| t.innermost_name().into())
             .collect();
         self
     }
@@ -733,10 +733,7 @@ impl<'a> UnionMeta<'a> {
         Self {
             name,
             description: None,
-            of_type_names: of_types
-                .iter()
-                .map(|t| t.innermost_name().to_owned())
-                .collect(),
+            of_type_names: of_types.iter().map(|t| t.innermost_name().into()).collect(),
         }
     }
 
@@ -745,7 +742,7 @@ impl<'a> UnionMeta<'a> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -777,7 +774,7 @@ impl<'a, S> InputObjectMeta<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -793,7 +790,7 @@ impl<'a, S> Field<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -818,7 +815,7 @@ impl<'a, S> Field<'a, S> {
     /// Overwrites any previously set deprecation reason.
     #[must_use]
     pub fn deprecated(mut self, reason: Option<&str>) -> Self {
-        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(ToOwned::to_owned));
+        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
         self
     }
 }
@@ -827,7 +824,7 @@ impl<'a, S> Argument<'a, S> {
     /// Builds a new [`Argument`] of the given [`Type`] with the given `name`.
     pub fn new(name: &str, arg_type: Type<'a>) -> Self {
         Self {
-            name: name.to_owned(),
+            name: name.into(),
             description: None,
             arg_type,
             default_value: None,
@@ -839,7 +836,7 @@ impl<'a, S> Argument<'a, S> {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -857,7 +854,7 @@ impl EnumValue {
     /// Constructs a new [`EnumValue`] with the provided `name`.
     pub fn new(name: &str) -> Self {
         Self {
-            name: name.to_owned(),
+            name: name.into(),
             description: None,
             deprecation_status: DeprecationStatus::Current,
         }
@@ -868,7 +865,7 @@ impl EnumValue {
     /// Overwrites any previously set description.
     #[must_use]
     pub fn description(mut self, description: &str) -> Self {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 
@@ -877,7 +874,7 @@ impl EnumValue {
     /// Overwrites any previously set deprecation reason.
     #[must_use]
     pub fn deprecated(mut self, reason: Option<&str>) -> Self {
-        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(ToOwned::to_owned));
+        self.deprecation_status = DeprecationStatus::Deprecated(reason.map(Into::into));
         self
     }
 }
diff --git a/juniper/src/schema/model.rs b/juniper/src/schema/model.rs
index 5544fbbd..e7cba411 100644
--- a/juniper/src/schema/model.rs
+++ b/juniper/src/schema/model.rs
@@ -167,8 +167,7 @@ where
     /// [GraphQL Schema Language](https://graphql.org/learn/schema/#type-language)
     /// format.
     pub fn as_schema_language(&self) -> String {
-        let doc = self.as_parser_document();
-        format!("{}", doc)
+        self.as_parser_document().to_string()
     }
 
     #[cfg(feature = "graphql-parser")]
@@ -210,17 +209,14 @@ impl<'a, S> SchemaType<'a, S> {
 
         registry.get_type::<SchemaType<S>>(&());
 
-        directives.insert("skip".to_owned(), DirectiveType::new_skip(&mut registry));
+        directives.insert("skip".into(), DirectiveType::new_skip(&mut registry));
+        directives.insert("include".into(), DirectiveType::new_include(&mut registry));
         directives.insert(
-            "include".to_owned(),
-            DirectiveType::new_include(&mut registry),
-        );
-        directives.insert(
-            "deprecated".to_owned(),
+            "deprecated".into(),
             DirectiveType::new_deprecated(&mut registry),
         );
         directives.insert(
-            "specifiedBy".to_owned(),
+            "specifiedBy".into(),
             DirectiveType::new_specified_by(&mut registry),
         );
 
@@ -243,7 +239,7 @@ impl<'a, S> SchemaType<'a, S> {
 
         for meta_type in registry.types.values() {
             if let MetaType::Placeholder(PlaceholderMeta { ref of_type }) = *meta_type {
-                panic!("Type {:?} is still a placeholder type", of_type);
+                panic!("Type {of_type:?} is still a placeholder type");
             }
         }
         SchemaType {
@@ -508,9 +504,9 @@ where
         locations: &[DirectiveLocation],
         arguments: &[Argument<'a, S>],
         is_repeatable: bool,
-    ) -> DirectiveType<'a, S> {
-        DirectiveType {
-            name: name.to_owned(),
+    ) -> Self {
+        Self {
+            name: name.into(),
             description: None,
             locations: locations.to_vec(),
             arguments: arguments.to_vec(),
@@ -578,7 +574,7 @@ where
     }
 
     pub fn description(mut self, description: &str) -> DirectiveType<'a, S> {
-        self.description = Some(description.to_owned());
+        self.description = Some(description.into());
         self
     }
 }
@@ -605,8 +601,8 @@ impl<'a, S> fmt::Display for TypeType<'a, S> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Self::Concrete(t) => f.write_str(t.name().unwrap()),
-            Self::List(i, _) => write!(f, "[{}]", i),
-            Self::NonNull(i) => write!(f, "{}!", i),
+            Self::List(i, _) => write!(f, "[{i}]"),
+            Self::NonNull(i) => write!(f, "{i}!"),
         }
     }
 }
@@ -644,10 +640,7 @@ mod test {
             "#,
             )
             .unwrap();
-            assert_eq!(
-                format!("{}", ast),
-                format!("{}", schema.as_parser_document()),
-            );
+            assert_eq!(ast.to_string(), schema.as_parser_document().to_string());
         }
     }
 
@@ -691,10 +684,10 @@ mod test {
                 }
                 /// This is whatever's description.
                 fn whatever() -> String {
-                    "foo".to_string()
+                    "foo".into()
                 }
                 fn arr(stuff: Vec<Coordinate>) -> Option<&'static str> {
-                    (!stuff.is_empty()).then(|| "stuff")
+                    (!stuff.is_empty()).then_some("stuff")
                 }
                 fn fruit() -> Fruit {
                     Fruit::Apple
@@ -754,7 +747,7 @@ mod test {
             "#,
             )
             .unwrap();
-            assert_eq!(format!("{}", ast), schema.as_schema_language());
+            assert_eq!(ast.to_string(), schema.as_schema_language());
         }
     }
 }
diff --git a/juniper/src/schema/schema.rs b/juniper/src/schema/schema.rs
index 825bb43a..bf48ea37 100644
--- a/juniper/src/schema/schema.rs
+++ b/juniper/src/schema/schema.rs
@@ -211,13 +211,19 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> {
         }
     }
 
-    fn fields(&self, #[graphql(default)] include_deprecated: bool) -> Option<Vec<&Field<S>>> {
+    fn fields(
+        &self,
+        #[graphql(default = false)] include_deprecated: Option<bool>,
+    ) -> Option<Vec<&Field<S>>> {
         match self {
             TypeType::Concrete(&MetaType::Interface(InterfaceMeta { ref fields, .. }))
             | TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) => Some(
                 fields
                     .iter()
-                    .filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
+                    .filter(|f| {
+                        include_deprecated.unwrap_or_default()
+                            || !f.deprecation_status.is_deprecated()
+                    })
                     .filter(|f| !f.name.starts_with("__"))
                     .collect(),
             ),
@@ -282,16 +288,16 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> {
                     .iter()
                     .filter_map(|&ct| {
                         if let MetaType::Object(ObjectMeta {
-                            ref name,
-                            ref interface_names,
+                            name,
+                            interface_names,
                             ..
-                        }) = *ct
+                        }) = ct
                         {
-                            if interface_names.contains(&iface_name.to_string()) {
-                                context.type_by_name(name)
-                            } else {
-                                None
-                            }
+                            interface_names
+                                .iter()
+                                .any(|name| name == iface_name)
+                                .then(|| context.type_by_name(name))
+                                .flatten()
                         } else {
                             None
                         }
@@ -302,12 +308,18 @@ impl<'a, S: ScalarValue + 'a> TypeType<'a, S> {
         }
     }
 
-    fn enum_values(&self, #[graphql(default)] include_deprecated: bool) -> Option<Vec<&EnumValue>> {
+    fn enum_values(
+        &self,
+        #[graphql(default = false)] include_deprecated: Option<bool>,
+    ) -> Option<Vec<&EnumValue>> {
         match self {
             TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) => Some(
                 values
                     .iter()
-                    .filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
+                    .filter(|f| {
+                        include_deprecated.unwrap_or_default()
+                            || !f.deprecation_status.is_deprecated()
+                    })
                     .collect(),
             ),
             _ => None,
diff --git a/juniper/src/schema/translate/graphql_parser.rs b/juniper/src/schema/translate/graphql_parser.rs
index c3864561..6051965b 100644
--- a/juniper/src/schema/translate/graphql_parser.rs
+++ b/juniper/src/schema/translate/graphql_parser.rs
@@ -285,22 +285,18 @@ where
         DeprecationStatus::Current => None,
         DeprecationStatus::Deprecated(reason) => Some(ExternalDirective {
             position: Pos::default(),
-            name: From::from("deprecated"),
-            arguments: if let Some(reason) = reason {
-                vec![(
-                    From::from("reason"),
-                    ExternalValue::String(reason.to_string()),
-                )]
-            } else {
-                vec![]
-            },
+            name: "deprecated".into(),
+            arguments: reason
+                .as_ref()
+                .map(|rsn| vec![(From::from("reason"), ExternalValue::String(rsn.into()))])
+                .unwrap_or_default(),
         }),
     }
 }
 
-// Right now the only directive supported is `@deprecated`. `@skip` and `@include`
-// are dealt with elsewhere.
-// <https://facebook.github.io/graphql/draft/#sec-Type-System.Directives>
+// Right now the only directive supported is `@deprecated`.
+// `@skip` and `@include` are dealt with elsewhere.
+// https://spec.graphql.org/October2021#sec-Type-System.Directives.Built-in-Directives
 fn generate_directives<'a, T>(status: &DeprecationStatus) -> Vec<ExternalDirective<'a, T>>
 where
     T: Text<'a>,
diff --git a/juniper/src/tests/fixtures/starwars/schema.rs b/juniper/src/tests/fixtures/starwars/schema.rs
index d9c795de..d89af6bc 100644
--- a/juniper/src/tests/fixtures/starwars/schema.rs
+++ b/juniper/src/tests/fixtures/starwars/schema.rs
@@ -93,12 +93,12 @@ impl Human {
         home_planet: Option<&str>,
     ) -> Self {
         Self {
-            id: id.to_owned(),
-            name: name.to_owned(),
-            friend_ids: friend_ids.iter().copied().map(ToOwned::to_owned).collect(),
+            id: id.into(),
+            name: name.into(),
+            friend_ids: friend_ids.iter().copied().map(Into::into).collect(),
             appears_in: appears_in.to_vec(),
-            secret_backstory: secret_backstory.map(ToOwned::to_owned),
-            home_planet: home_planet.map(|p| p.to_owned()),
+            secret_backstory: secret_backstory.map(Into::into),
+            home_planet: home_planet.map(Into::into),
         }
     }
 }
@@ -153,12 +153,12 @@ impl Droid {
         primary_function: Option<&str>,
     ) -> Self {
         Self {
-            id: id.to_owned(),
-            name: name.to_owned(),
-            friend_ids: friend_ids.iter().copied().map(ToOwned::to_owned).collect(),
+            id: id.into(),
+            name: name.into(),
+            friend_ids: friend_ids.iter().copied().map(Into::into).collect(),
             appears_in: appears_in.to_vec(),
-            secret_backstory: secret_backstory.map(ToOwned::to_owned),
-            primary_function: primary_function.map(ToOwned::to_owned),
+            secret_backstory: secret_backstory.map(Into::into),
+            primary_function: primary_function.map(Into::into),
         }
     }
 }
@@ -192,7 +192,7 @@ impl Droid {
     }
 }
 
-#[derive(Default, Clone)]
+#[derive(Clone, Default)]
 pub struct Database {
     humans: HashMap<String, Human>,
     droids: HashMap<String, Droid>,
@@ -206,7 +206,7 @@ impl Database {
         let mut droids = HashMap::new();
 
         humans.insert(
-            "1000".to_owned(),
+            "1000".into(),
             Human::new(
                 "1000",
                 "Luke Skywalker",
@@ -218,7 +218,7 @@ impl Database {
         );
 
         humans.insert(
-            "1001".to_owned(),
+            "1001".into(),
             Human::new(
                 "1001",
                 "Darth Vader",
@@ -230,7 +230,7 @@ impl Database {
         );
 
         humans.insert(
-            "1002".to_owned(),
+            "1002".into(),
             Human::new(
                 "1002",
                 "Han Solo",
@@ -242,7 +242,7 @@ impl Database {
         );
 
         humans.insert(
-            "1003".to_owned(),
+            "1003".into(),
             Human::new(
                 "1003",
                 "Leia Organa",
@@ -254,7 +254,7 @@ impl Database {
         );
 
         humans.insert(
-            "1004".to_owned(),
+            "1004".into(),
             Human::new(
                 "1004",
                 "Wilhuff Tarkin",
@@ -266,7 +266,7 @@ impl Database {
         );
 
         droids.insert(
-            "2000".to_owned(),
+            "2000".into(),
             Droid::new(
                 "2000",
                 "C-3PO",
@@ -278,7 +278,7 @@ impl Database {
         );
 
         droids.insert(
-            "2001".to_owned(),
+            "2001".into(),
             Droid::new(
                 "2001",
                 "R2-D2",
diff --git a/juniper/src/tests/subscriptions.rs b/juniper/src/tests/subscriptions.rs
index 6ba01a76..8c73486b 100644
--- a/juniper/src/tests/subscriptions.rs
+++ b/juniper/src/tests/subscriptions.rs
@@ -1,4 +1,4 @@
-use std::{iter, iter::FromIterator as _, pin::Pin};
+use std::{iter, pin::Pin};
 
 use futures::{stream, StreamExt as _};
 
@@ -48,9 +48,9 @@ impl MySubscription {
     async fn async_human() -> HumanStream {
         Box::pin(stream::once(async {
             Human {
-                id: "stream id".to_string(),
-                name: "stream name".to_string(),
-                home_planet: "stream home planet".to_string(),
+                id: "stream id".into(),
+                name: "stream name".into(),
+                home_planet: "stream home planet".into(),
             }
         }))
     }
@@ -78,7 +78,7 @@ impl MySubscription {
             Human {
                 id,
                 name,
-                home_planet: "default home planet".to_string(),
+                home_planet: "default home planet".into(),
             }
         }))
     }
@@ -154,10 +154,10 @@ fn returns_requested_object() {
             id
             name
         }
-    }"#
-    .to_string();
+    }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(
@@ -182,10 +182,9 @@ fn returns_error() {
             id
             name
         }
-    }"#
-    .to_string();
+    }"#;
 
-    let response = create_and_execute(query);
+    let response = create_and_execute(query.into());
 
     assert!(response.is_err());
 
@@ -206,10 +205,10 @@ fn can_access_context() {
             humanWithContext {
                 id
               }
-        }"#
-    .to_string();
+        }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(iter::from_fn(
@@ -234,10 +233,10 @@ fn resolves_typed_inline_fragments() {
                   id
                 }
              }
-           }"#
-    .to_string();
+           }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(iter::from_fn(
@@ -262,10 +261,10 @@ fn resolves_nontyped_inline_fragments() {
                   id
                 }
              }
-           }"#
-    .to_string();
+           }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(iter::from_fn(
@@ -289,10 +288,10 @@ fn can_access_arguments() {
                 id
                 name
               }
-        }"#
-    .to_string();
+        }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(iter::from_fn(
@@ -317,10 +316,10 @@ fn type_alias() {
             id
             name
         }
-    }"#
-    .to_string();
+    }"#;
 
-    let (names, collected_values) = create_and_execute(query).expect("Got error from stream");
+    let (names, collected_values) =
+        create_and_execute(query.into()).expect("Got error from stream");
 
     let mut iterator_count = 0;
     let expected_values = vec![vec![Ok(Value::Object(Object::from_iter(iter::from_fn(
diff --git a/juniper/src/tests/type_info_tests.rs b/juniper/src/tests/type_info_tests.rs
index 61e7662b..6b43a7ef 100644
--- a/juniper/src/tests/type_info_tests.rs
+++ b/juniper/src/tests/type_info_tests.rs
@@ -75,15 +75,15 @@ fn test_node() {
             baz
         }"#;
     let node_info = NodeTypeInfo {
-        name: "MyNode".to_string(),
-        attribute_names: vec!["foo".to_string(), "bar".to_string(), "baz".to_string()],
+        name: "MyNode".into(),
+        attribute_names: vec!["foo".into(), "bar".into(), "baz".into()],
     };
     let mut node = Node {
         attributes: IndexMap::new(),
     };
-    node.attributes.insert("foo".to_string(), "1".to_string());
-    node.attributes.insert("bar".to_string(), "2".to_string());
-    node.attributes.insert("baz".to_string(), "3".to_string());
+    node.attributes.insert("foo".into(), "1".into());
+    node.attributes.insert("bar".into(), "2".into());
+    node.attributes.insert("baz".into(), "3".into());
     let schema: RootNode<_, _, _> = RootNode::new_with_info(
         node,
         EmptyMutation::new(),
diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs
index c49d9a45..f8dffd7a 100644
--- a/juniper/src/types/arc.rs
+++ b/juniper/src/types/arc.rs
@@ -200,7 +200,7 @@ where
     T: resolve::ScalarToken<SV, BH> + ?Sized,
     BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs
index 3565294e..a05a1fde 100644
--- a/juniper/src/types/array.rs
+++ b/juniper/src/types/array.rs
@@ -289,12 +289,11 @@ where
     fn into_field_error(self) -> FieldError<SV> {
         const ERROR_PREFIX: &str = "Failed to convert into exact-size array";
         match self {
-            Self::IsNull => format!("{}: Value cannot be `null`", ERROR_PREFIX).into(),
-            Self::WrongCount { actual, expected } => format!(
-                "{}: wrong elements count: {} instead of {}",
-                ERROR_PREFIX, actual, expected,
-            )
-            .into(),
+            Self::IsNull => format!("{ERROR_PREFIX}: Value cannot be `null`").into(),
+            Self::WrongCount { actual, expected } => {
+                format!("{ERROR_PREFIX}: wrong elements count: {actual} instead of {expected}",)
+                    .into()
+            }
             Self::Item(s) => s.into_field_error(),
         }
     }
diff --git a/juniper/src/types/async_await.rs b/juniper/src/types/async_await.rs
index e3273275..562bff7c 100644
--- a/juniper/src/types/async_await.rs
+++ b/juniper/src/types/async_await.rs
@@ -30,7 +30,7 @@ where
     ///
     /// The default implementation panics.
     ///
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve_field_async<'a>(
         &'a self,
         _info: &'a Self::TypeInfo,
@@ -54,9 +54,9 @@ where
     ///
     /// The default implementation panics.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    /// [2]: https://spec.graphql.org/June2018/#sec-Unions
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Unions
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve_into_type_async<'a>(
         &'a self,
         info: &'a Self::TypeInfo,
@@ -91,8 +91,8 @@ where
     ///
     /// The default implementation panics, if `selection_set` is [`None`].
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-Errors-and-Non-Nullability
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [0]: https://spec.graphql.org/October2021#sec-Handling-Field-Errors
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve_async<'a>(
         &'a self,
         info: &'a Self::TypeInfo,
@@ -226,7 +226,7 @@ where
                     panic!(
                         "Field {} not found on type {:?}",
                         f.name.item,
-                        meta_type.name()
+                        meta_type.name(),
                     )
                 });
 
@@ -242,7 +242,9 @@ where
                     f.arguments.as_ref().map(|m| {
                         m.item
                             .iter()
-                            .map(|&(ref k, ref v)| (k.item, v.item.clone().into_const(exec_vars)))
+                            .filter_map(|&(ref k, ref v)| {
+                                v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
+                            })
                             .collect()
                     }),
                     &meta_field.arguments,
diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs
index d5c9e394..9d54fee0 100644
--- a/juniper/src/types/base.rs
+++ b/juniper/src/types/base.rs
@@ -49,7 +49,6 @@ pub enum TypeKind {
     /// ## Input objects
     ///
     /// Represents complex values provided in queries _into_ the system.
-    #[graphql(name = "INPUT_OBJECT")]
     InputObject,
 
     /// ## List types
@@ -63,7 +62,6 @@ pub enum TypeKind {
     ///
     /// In GraphQL, nullable types are the default. By putting a `!` after a\
     /// type, it becomes non-nullable.
-    #[graphql(name = "NON_NULL")]
     NonNull,
 }
 
@@ -89,7 +87,7 @@ impl<'a, S> Arguments<'a, S> {
         if let (Some(args), Some(meta_args)) = (&mut args, meta_args) {
             for arg in meta_args {
                 let arg_name = arg.name.as_str();
-                if args.get(arg_name).map_or(true, InputValue::is_null) {
+                if args.get(arg_name).is_none() {
                     if let Some(val) = arg.default_value.as_ref() {
                         args.insert(arg_name, val.clone());
                     }
@@ -150,14 +148,14 @@ impl<'a, S> Arguments<'a, S> {
 /// This trait is intended to be used in a conjunction with a [`GraphQLType`] trait. See the example
 /// in the documentation of a [`GraphQLType`] trait.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-/// [2]: https://spec.graphql.org/June2018/#sec-Unions
-/// [3]: https://spec.graphql.org/June2018/#sec-Objects
-/// [4]: https://spec.graphql.org/June2018/#sec-Scalars
-/// [5]: https://spec.graphql.org/June2018/#sec-Enums
-/// [6]: https://spec.graphql.org/June2018/#sec-Type-System.List
-/// [7]: https://spec.graphql.org/June2018/#sec-Type-System.Non-Null
-/// [8]: https://spec.graphql.org/June2018/#sec-Input-Objects
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+/// [2]: https://spec.graphql.org/October2021#sec-Unions
+/// [3]: https://spec.graphql.org/October2021#sec-Objects
+/// [4]: https://spec.graphql.org/October2021#sec-Scalars
+/// [5]: https://spec.graphql.org/October2021#sec-Enums
+/// [6]: https://spec.graphql.org/October2021#sec-List
+/// [7]: https://spec.graphql.org/October2021#sec-Non-Null
+/// [8]: https://spec.graphql.org/October2021#sec-Input-Objects
 /// [11]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
 /// [12]: https://doc.rust-lang.org/reference/types/trait-object.html
 pub trait GraphQLValue<S = DefaultScalarValue>
@@ -196,7 +194,7 @@ where
     ///
     /// The default implementation panics.
     ///
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve_field(
         &self,
         _info: &Self::TypeInfo,
@@ -217,9 +215,9 @@ where
     ///
     /// The default implementation panics.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    /// [2]: https://spec.graphql.org/June2018/#sec-Unions
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Unions
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve_into_type(
         &self,
         info: &Self::TypeInfo,
@@ -243,9 +241,9 @@ where
     ///
     /// The default implementation panics.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    /// [2]: https://spec.graphql.org/June2018/#sec-Unions
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Unions
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     #[allow(unused_variables)]
     fn concrete_type_name(&self, context: &Self::Context, info: &Self::TypeInfo) -> String {
         panic!(
@@ -271,8 +269,8 @@ where
     ///
     /// The default implementation panics, if `selection_set` is [`None`].
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-Errors-and-Non-Nullability
-    /// [3]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [0]: https://spec.graphql.org/October2021#sec-Errors-and-Non-Nullability
+    /// [3]: https://spec.graphql.org/October2021#sec-Objects
     fn resolve(
         &self,
         info: &Self::TypeInfo,
@@ -379,13 +377,13 @@ where
 ///             // schema in `meta()` above, or a validation failed because of a this library bug.
 ///             //
 ///             // In either of those two cases, the only reasonable way out is to panic the thread.
-///             _ => panic!("Field {} not found on type User", field_name),
+///             _ => panic!("Field {field_name} not found on type User"),
 ///         }
 ///     }
 /// }
 /// ```
 ///
-/// [3]: https://spec.graphql.org/June2018/#sec-Objects
+/// [3]: https://spec.graphql.org/October2021#sec-Objects
 pub trait GraphQLType<S = DefaultScalarValue>: GraphQLValue<S>
 where
     S: ScalarValue,
@@ -454,7 +452,7 @@ where
                     panic!(
                         "Field {} not found on type {:?}",
                         f.name.item,
-                        meta_type.name()
+                        meta_type.name(),
                     )
                 });
 
@@ -474,8 +472,8 @@ where
                         f.arguments.as_ref().map(|m| {
                             m.item
                                 .iter()
-                                .map(|&(ref k, ref v)| {
-                                    (k.item, v.item.clone().into_const(exec_vars))
+                                .filter_map(|&(ref k, ref v)| {
+                                    v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
                                 })
                                 .collect()
                         }),
@@ -608,7 +606,7 @@ where
                 .arguments
                 .iter()
                 .flat_map(|m| m.item.get("if"))
-                .flat_map(|v| v.item.clone().into_const(vars).convert())
+                .filter_map(|v| v.item.clone().into_const(vars)?.convert().ok())
                 .next()
                 .unwrap();
 
diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs
index 9724d307..848e6363 100644
--- a/juniper/src/types/box.rs
+++ b/juniper/src/types/box.rs
@@ -198,7 +198,7 @@ where
     T: resolve::ScalarToken<SV, BH> + ?Sized,
     BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/containers.rs b/juniper/src/types/containers.rs
index bda6d4db..379cbae2 100644
--- a/juniper/src/types/containers.rs
+++ b/juniper/src/types/containers.rs
@@ -522,12 +522,11 @@ where
     fn into_field_error(self) -> FieldError<S> {
         const ERROR_PREFIX: &str = "Failed to convert into exact-size array";
         match self {
-            Self::Null => format!("{}: Value cannot be `null`", ERROR_PREFIX).into(),
-            Self::WrongCount { actual, expected } => format!(
-                "{}: wrong elements count: {} instead of {}",
-                ERROR_PREFIX, actual, expected
-            )
-            .into(),
+            Self::Null => format!("{ERROR_PREFIX}: Value cannot be `null`").into(),
+            Self::WrongCount { actual, expected } => {
+                format!("{ERROR_PREFIX}: wrong elements count: {actual} instead of {expected}",)
+                    .into()
+            }
             Self::Item(s) => s.into_field_error(),
         }
     }
diff --git a/juniper/src/types/cow.rs b/juniper/src/types/cow.rs
index 9626a870..0a6fbfce 100644
--- a/juniper/src/types/cow.rs
+++ b/juniper/src/types/cow.rs
@@ -215,7 +215,7 @@ where
     BH: ?Sized,
     Self: Deref<Target = T>,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/marker.rs b/juniper/src/types/marker.rs
index 2dd22789..c4cc18f5 100644
--- a/juniper/src/types/marker.rs
+++ b/juniper/src/types/marker.rs
@@ -17,23 +17,23 @@ use crate::{GraphQLType, ScalarValue};
 /// [GraphQL objects][1]. Other types ([scalars][2], [enums][3], [interfaces][4], [input objects][5]
 /// and [unions][6]) are not allowed.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Objects
-/// [2]: https://spec.graphql.org/June2018/#sec-Scalars
-/// [3]: https://spec.graphql.org/June2018/#sec-Enums
-/// [4]: https://spec.graphql.org/June2018/#sec-Interfaces
-/// [5]: https://spec.graphql.org/June2018/#sec-Input-Objects
-/// [6]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
+/// [2]: https://spec.graphql.org/October2021#sec-Scalars
+/// [3]: https://spec.graphql.org/October2021#sec-Enums
+/// [4]: https://spec.graphql.org/October2021#sec-Interfaces
+/// [5]: https://spec.graphql.org/October2021#sec-Input-Objects
+/// [6]: https://spec.graphql.org/October2021#sec-Unions
 pub trait GraphQLObject<S: ScalarValue>: GraphQLType<S> {
     /// An arbitrary function without meaning.
     ///
     /// May contain compile timed check logic which ensures that types are used correctly according
     /// to the [GraphQL specification][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/
+    /// [1]: https://spec.graphql.org/October2021
     fn mark() {}
 }
 
-impl<'a, S, T> GraphQLObject<S> for &T
+impl<S, T> GraphQLObject<S> for &T
 where
     T: GraphQLObject<S> + ?Sized,
     S: ScalarValue,
@@ -74,23 +74,23 @@ where
 /// [GraphQL interfaces][1]. Other types ([scalars][2], [enums][3], [objects][4], [input objects][5]
 /// and [unions][6]) are not allowed.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-/// [2]: https://spec.graphql.org/June2018/#sec-Scalars
-/// [3]: https://spec.graphql.org/June2018/#sec-Enums
-/// [4]: https://spec.graphql.org/June2018/#sec-Objects
-/// [5]: https://spec.graphql.org/June2018/#sec-Input-Objects
-/// [6]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+/// [2]: https://spec.graphql.org/October2021#sec-Scalars
+/// [3]: https://spec.graphql.org/October2021#sec-Enums
+/// [4]: https://spec.graphql.org/October2021#sec-Objects
+/// [5]: https://spec.graphql.org/October2021#sec-Input-Objects
+/// [6]: https://spec.graphql.org/October2021#sec-Unions
 pub trait GraphQLInterface<S: ScalarValue>: GraphQLType<S> {
     /// An arbitrary function without meaning.
     ///
     /// May contain compile timed check logic which ensures that types are used correctly according
     /// to the [GraphQL specification][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/
+    /// [1]: https://spec.graphql.org/October2021
     fn mark() {}
 }
 
-impl<'a, S, T> GraphQLInterface<S> for &T
+impl<S, T> GraphQLInterface<S> for &T
 where
     T: GraphQLInterface<S> + ?Sized,
     S: ScalarValue,
@@ -131,23 +131,23 @@ where
 /// [GraphQL unions][1]. Other types ([scalars][2], [enums][3], [objects][4], [input objects][5] and
 /// [interfaces][6]) are not allowed.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
-/// [2]: https://spec.graphql.org/June2018/#sec-Scalars
-/// [3]: https://spec.graphql.org/June2018/#sec-Enums
-/// [4]: https://spec.graphql.org/June2018/#sec-Objects
-/// [5]: https://spec.graphql.org/June2018/#sec-Input-Objects
-/// [6]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
+/// [2]: https://spec.graphql.org/October2021#sec-Scalars
+/// [3]: https://spec.graphql.org/October2021#sec-Enums
+/// [4]: https://spec.graphql.org/October2021#sec-Objects
+/// [5]: https://spec.graphql.org/October2021#sec-Input-Objects
+/// [6]: https://spec.graphql.org/October2021#sec-Interfaces
 pub trait GraphQLUnion<S: ScalarValue>: GraphQLType<S> {
     /// An arbitrary function without meaning.
     ///
     /// May contain compile timed check logic which ensures that types are used correctly according
     /// to the [GraphQL specification][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/
+    /// [1]: https://spec.graphql.org/October2021
     fn mark() {}
 }
 
-impl<'a, S, T> GraphQLUnion<S> for &T
+impl<S, T> GraphQLUnion<S> for &T
 where
     T: GraphQLUnion<S> + ?Sized,
     S: ScalarValue,
@@ -194,7 +194,7 @@ pub trait IsOutputType<S: ScalarValue>: GraphQLType<S> {
     fn mark() {}
 }
 
-impl<'a, S, T> IsOutputType<S> for &T
+impl<S, T> IsOutputType<S> for &T
 where
     T: IsOutputType<S> + ?Sized,
     S: ScalarValue,
@@ -271,7 +271,7 @@ where
     }
 }
 
-impl<'a, S> IsOutputType<S> for str where S: ScalarValue {}
+impl<S> IsOutputType<S> for str where S: ScalarValue {}
 
 /// Marker trait for types which can be used as input types.
 ///
@@ -287,7 +287,7 @@ pub trait IsInputType<S: ScalarValue>: GraphQLType<S> {
     fn mark() {}
 }
 
-impl<'a, S, T> IsInputType<S> for &T
+impl<S, T> IsInputType<S> for &T
 where
     T: IsInputType<S> + ?Sized,
     S: ScalarValue,
@@ -364,4 +364,4 @@ where
     }
 }
 
-impl<'a, S> IsInputType<S> for str where S: ScalarValue {}
+impl<S> IsInputType<S> for str where S: ScalarValue {}
diff --git a/juniper/src/types/name.rs b/juniper/src/types/name.rs
index eae555d9..fbf5304d 100644
--- a/juniper/src/types/name.rs
+++ b/juniper/src/types/name.rs
@@ -50,11 +50,10 @@ impl FromStr for Name {
     type Err = NameParseError;
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         if Name::is_valid(s) {
-            Ok(Name(s.to_string()))
+            Ok(Name(s.into()))
         } else {
             Err(NameParseError(format!(
-                "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{}\" does not",
-                s
+                "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"{s}\" does not",
             )))
         }
     }
diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs
index ee4a861a..31d3f848 100644
--- a/juniper/src/types/nullable.rs
+++ b/juniper/src/types/nullable.rs
@@ -51,6 +51,8 @@ pub enum Nullable<T> {
     Some(T),
 }
 
+// Implemented manually to omit redundant `T: Default` trait bound, imposed by
+// `#[derive(Default)]`.
 impl<T> Default for Nullable<T> {
     fn default() -> Self {
         Self::ImplicitNull
diff --git a/juniper/src/types/pointers.rs b/juniper/src/types/pointers.rs
index 0726ef52..17e70679 100644
--- a/juniper/src/types/pointers.rs
+++ b/juniper/src/types/pointers.rs
@@ -265,7 +265,7 @@ where
     }
 }
 
-impl<'e, S, T> GraphQLValueAsync<S> for Arc<T>
+impl<S, T> GraphQLValueAsync<S> for Arc<T>
 where
     T: GraphQLValueAsync<S> + Send + ?Sized,
     T::TypeInfo: Sync,
diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs
index 8e00993d..9adf6db9 100644
--- a/juniper/src/types/rc.rs
+++ b/juniper/src/types/rc.rs
@@ -200,7 +200,7 @@ where
     T: resolve::ScalarToken<SV, BH> + ?Sized,
     BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs
index 805b1472..eaaf9441 100644
--- a/juniper/src/types/ref.rs
+++ b/juniper/src/types/ref.rs
@@ -202,7 +202,7 @@ where
     T: resolve::ScalarToken<SV, BH> + ?Sized,
     BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs
index c0c479c6..bf5334b2 100644
--- a/juniper/src/types/ref_mut.rs
+++ b/juniper/src/types/ref_mut.rs
@@ -166,7 +166,7 @@ where
     T: resolve::ScalarToken<SV, BH> + ?Sized,
     BH: ?Sized,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         T::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/scalars.rs b/juniper/src/types/scalars.rs
index 66e26e74..54efa392 100644
--- a/juniper/src/types/scalars.rs
+++ b/juniper/src/types/scalars.rs
@@ -37,7 +37,7 @@ impl ID {
             .map(str::to_owned)
             .or_else(|| v.as_int_value().as_ref().map(ToString::to_string))
             .map(Self)
-            .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
     }
 }
 
@@ -81,10 +81,10 @@ mod impl_string_scalar {
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<String, String> {
         v.as_string_value()
             .map(str::to_owned)
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
     }
 
-    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         if let ScalarToken::String(value) = value {
             let mut ret = String::with_capacity(value.len());
             let mut char_iter = value.chars();
@@ -120,7 +120,7 @@ mod impl_string_scalar {
                         }
                         Some(s) => {
                             return Err(ParseError::LexerError(LexerError::UnknownEscapeSequence(
-                                format!("\\{}", s),
+                                format!("\\{s}"),
                             )))
                         }
                         None => return Err(ParseError::LexerError(LexerError::UnterminatedString)),
@@ -132,12 +132,12 @@ mod impl_string_scalar {
             }
             Ok(ret.into())
         } else {
-            Err(ParseError::UnexpectedToken(Token::Scalar(value)))
+            Err(ParseError::unexpected_token(Token::Scalar(value)))
         }
     }
 }
 
-fn parse_unicode_codepoint<'a, I>(char_iter: &mut I) -> Result<char, ParseError<'a>>
+fn parse_unicode_codepoint<I>(char_iter: &mut I) -> Result<char, ParseError>
 where
     I: Iterator<Item = char>,
 {
@@ -149,19 +149,16 @@ where
         .and_then(|c1| {
             char_iter
                 .next()
-                .map(|c2| format!("{}{}", c1, c2))
+                .map(|c2| format!("{c1}{c2}"))
                 .ok_or_else(|| {
-                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{}", c1)))
+                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{c1}")))
                 })
         })
         .and_then(|mut s| {
             char_iter
                 .next()
                 .ok_or_else(|| {
-                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
-                        "\\u{}",
-                        s.clone()
-                    )))
+                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
                 })
                 .map(|c2| {
                     s.push(c2);
@@ -172,10 +169,7 @@ where
             char_iter
                 .next()
                 .ok_or_else(|| {
-                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
-                        "\\u{}",
-                        s.clone()
-                    )))
+                    ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
                 })
                 .map(|c2| {
                     s.push(c2);
@@ -184,14 +178,12 @@ where
         })?;
     let code_point = u32::from_str_radix(&escaped_code_point, 16).map_err(|_| {
         ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
-            "\\u{}",
-            escaped_code_point
+            "\\u{escaped_code_point}",
         )))
     })?;
     char::from_u32(code_point).ok_or_else(|| {
         ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
-            "\\u{}",
-            escaped_code_point
+            "\\u{escaped_code_point}",
         )))
     })
 }
@@ -282,12 +274,12 @@ mod impl_boolean_scalar {
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Boolean, String> {
         v.as_scalar_value()
             .and_then(ScalarValue::as_bool)
-            .ok_or_else(|| format!("Expected `Boolean`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Boolean`, found: {v}"))
     }
 
-    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         // `Boolean`s are parsed separately, they shouldn't reach this code path.
-        Err(ParseError::UnexpectedToken(Token::Scalar(value)))
+        Err(ParseError::unexpected_token(Token::Scalar(value)))
     }
 }
 
@@ -303,16 +295,16 @@ mod impl_int_scalar {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Int, String> {
         v.as_int_value()
-            .ok_or_else(|| format!("Expected `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Int`, found: {v}"))
     }
 
-    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         if let ScalarToken::Int(v) = value {
             v.parse()
-                .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
+                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
                 .map(|s: i32| s.into())
         } else {
-            Err(ParseError::UnexpectedToken(Token::Scalar(value)))
+            Err(ParseError::unexpected_token(Token::Scalar(value)))
         }
     }
 }
@@ -329,20 +321,20 @@ mod impl_float_scalar {
 
     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Float, String> {
         v.as_float_value()
-            .ok_or_else(|| format!("Expected `Float`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Float`, found: {v}"))
     }
 
-    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         match value {
             ScalarToken::Int(v) => v
                 .parse()
-                .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
+                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
                 .map(|s: i32| f64::from(s).into()),
             ScalarToken::Float(v) => v
                 .parse()
-                .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
+                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
                 .map(|s: f64| s.into()),
-            ScalarToken::String(_) => Err(ParseError::UnexpectedToken(Token::Scalar(value))),
+            ScalarToken::String(_) => Err(ParseError::unexpected_token(Token::Scalar(value))),
         }
     }
 }
@@ -401,8 +393,9 @@ where
 {
 }
 
+// Implemented manually to omit redundant `T: Default` trait bound, imposed by
+// `#[derive(Default)]`.
 impl<T> Default for EmptyMutation<T> {
-    #[inline]
     fn default() -> Self {
         Self::new()
     }
@@ -461,8 +454,9 @@ where
 {
 }
 
+// Implemented manually to omit redundant `T: Default` trait bound, imposed by
+// `#[derive(Default)]`.
 impl<T> Default for EmptySubscription<T> {
-    #[inline]
     fn default() -> Self {
         Self::new()
     }
@@ -499,8 +493,8 @@ mod tests {
 
     #[test]
     fn test_id_display() {
-        let id = ID(String::from("foo"));
-        assert_eq!(format!("{}", id), "foo");
+        let id = ID("foo".into());
+        assert_eq!(id.to_string(), "foo");
     }
 
     #[test]
@@ -508,7 +502,7 @@ mod tests {
         fn parse_string(s: &str, expected: &str) {
             let s =
                 <String as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::String(s));
-            assert!(s.is_ok(), "A parsing error occurred: {:?}", s);
+            assert!(s.is_ok(), "A parsing error occurred: {s:?}");
             let s: Option<String> = s.unwrap().into();
             assert!(s.is_some(), "No string returned");
             assert_eq!(s.unwrap(), expected);
@@ -527,7 +521,7 @@ mod tests {
 
     #[test]
     fn parse_f64_from_int() {
-        for (v, expected) in &[
+        for (v, expected) in [
             ("0", 0),
             ("128", 128),
             ("1601942400", 1601942400),
@@ -538,14 +532,14 @@ mod tests {
             assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
 
             let n: Option<f64> = n.unwrap().into();
-            assert!(n.is_some(), "No f64 returned");
-            assert_eq!(n.unwrap(), f64::from(*expected));
+            assert!(n.is_some(), "No `f64` returned");
+            assert_eq!(n.unwrap(), f64::from(expected));
         }
     }
 
     #[test]
     fn parse_f64_from_float() {
-        for (v, expected) in &[
+        for (v, expected) in [
             ("0.", 0.),
             ("1.2", 1.2),
             ("1601942400.", 1601942400.),
@@ -556,8 +550,8 @@ mod tests {
             assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
 
             let n: Option<f64> = n.unwrap().into();
-            assert!(n.is_some(), "No f64 returned");
-            assert_eq!(n.unwrap(), *expected);
+            assert!(n.is_some(), "No `f64` returned");
+            assert_eq!(n.unwrap(), expected);
         }
     }
 
diff --git a/juniper/src/types/str.rs b/juniper/src/types/str.rs
index 5b874073..ebcc6149 100644
--- a/juniper/src/types/str.rs
+++ b/juniper/src/types/str.rs
@@ -80,7 +80,7 @@ impl<SV: ScalarValue> resolve::InputValueAsRef<SV> for str {
 
     fn try_from_input_value(v: &graphql::InputValue<SV>) -> Result<&Self, Self::Error> {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
     }
 }
 
@@ -137,7 +137,7 @@ impl<SV> resolve::ScalarToken<SV> for str
 where
     String: resolve::ScalarToken<SV>,
 {
-    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError<'_>> {
+    fn parse_scalar_token(token: ScalarToken<'_>) -> Result<SV, ParseError> {
         <String as resolve::ScalarToken<SV>>::parse_scalar_token(token)
     }
 }
diff --git a/juniper/src/types/subscriptions.rs b/juniper/src/types/subscriptions.rs
index e99a5aaf..e1f42fdf 100644
--- a/juniper/src/types/subscriptions.rs
+++ b/juniper/src/types/subscriptions.rs
@@ -94,8 +94,8 @@ pub trait SubscriptionConnection<S>: futures::Stream<Item = ExecutionOutput<S>>
 ///
 /// See trait methods for more detailed explanation on how this trait works.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Subscription
-/// [2]: https://spec.graphql.org/June2018/#sec-Objects
+/// [1]: https://spec.graphql.org/October2021#sec-Subscription
+/// [2]: https://spec.graphql.org/October2021#sec-Objects
 pub trait GraphQLSubscriptionValue<S = DefaultScalarValue>: GraphQLValue<S> + Sync
 where
     Self::TypeInfo: Sync,
@@ -204,7 +204,7 @@ crate::sa::assert_obj_safe!(GraphQLSubscriptionValue<Context = (), TypeInfo = ()
 /// It's automatically implemented for [`GraphQLSubscriptionValue`] and [`GraphQLType`]
 /// implementers, so doesn't require manual or code-generated implementation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Subscription
+/// [1]: https://spec.graphql.org/October2021#sec-Subscription
 pub trait GraphQLSubscriptionType<S = DefaultScalarValue>:
     GraphQLSubscriptionValue<S> + GraphQLType<S>
 where
@@ -316,7 +316,9 @@ where
                     f.arguments.as_ref().map(|m| {
                         m.item
                             .iter()
-                            .map(|&(ref k, ref v)| (k.item, v.item.clone().into_const(exec_vars)))
+                            .filter_map(|&(ref k, ref v)| {
+                                v.item.clone().into_const(exec_vars).map(|v| (k.item, v))
+                            })
                             .collect()
                     }),
                     &meta_field.arguments,
diff --git a/juniper/src/types/utilities.rs b/juniper/src/types/utilities.rs
index 2ed03b1f..f1be0792 100644
--- a/juniper/src/types/utilities.rs
+++ b/juniper/src/types/utilities.rs
@@ -25,6 +25,7 @@ where
             }
         }
         TypeType::List(ref inner, expected_size) => match *arg_value {
+            InputValue::Null | InputValue::Variable(_) => true,
             InputValue::List(ref items) => {
                 if let Some(expected) = expected_size {
                     if items.len() != expected {
@@ -71,7 +72,7 @@ where
                         let mut remaining_required_fields = input_fields
                             .iter()
                             .filter_map(|f| {
-                                if f.arg_type.is_non_null() {
+                                if f.arg_type.is_non_null() && f.default_value.is_none() {
                                     Some(&f.name)
                                 } else {
                                     None
diff --git a/juniper/src/validation/context.rs b/juniper/src/validation/context.rs
index d90e7362..c96c0491 100644
--- a/juniper/src/validation/context.rs
+++ b/juniper/src/validation/context.rs
@@ -30,9 +30,9 @@ pub struct ValidatorContext<'a, S: Debug + 'a> {
 
 impl RuleError {
     #[doc(hidden)]
-    pub fn new(message: &str, locations: &[SourcePosition]) -> RuleError {
-        RuleError {
-            message: message.to_owned(),
+    pub fn new(message: &str, locations: &[SourcePosition]) -> Self {
+        Self {
+            message: message.into(),
             locations: locations.to_vec(),
         }
     }
@@ -53,14 +53,15 @@ impl RuleError {
 
 impl fmt::Display for RuleError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // this is fine since all `RuleError`s should have at least one source position
+        // This is fine since all `RuleError`s should have at least one source
+        // position.
         let locations = self
             .locations
             .iter()
-            .map(|location| format!("{}", location))
+            .map(ToString::to_string)
             .collect::<Vec<_>>()
             .join(", ");
-        write!(f, "{}. At {}", self.message, locations)
+        write!(f, "{}. At {locations}", self.message)
     }
 }
 
diff --git a/juniper/src/validation/input_value.rs b/juniper/src/validation/input_value.rs
index b6238172..780a0ab3 100644
--- a/juniper/src/validation/input_value.rs
+++ b/juniper/src/validation/input_value.rs
@@ -99,7 +99,7 @@ where
                     var_name,
                     var_pos,
                     &path,
-                    &format!(r#"Expected "{}", found null"#, meta_type),
+                    format!(r#"Expected "{meta_type}", found null"#),
                 ));
             } else {
                 errors.append(&mut unify_value(
@@ -121,10 +121,10 @@ where
                                 var_name,
                                 var_pos,
                                 &path,
-                                &format!(
-                                    "Expected list of {} elements, found {} elements",
-                                    expected,
-                                    l.len()
+                                format!(
+                                    "Expected list of {expected} elements, \
+                                     found {} elements",
+                                    l.len(),
                                 ),
                             ));
                         }
@@ -168,11 +168,11 @@ where
                                 var_name,
                                 var_pos,
                                 &path,
-                                &format!(
-                                    "Expected input of type `{}`. Got: `{}`. \
+                                format!(
+                                    "Expected input of type `{}`. \
+                                     Got: `{value}`. \
                                      Details: {}",
                                     iom.name,
-                                    value,
                                     e.message(),
                                 ),
                             ));
@@ -205,10 +205,9 @@ where
             var_name,
             var_pos,
             path,
-            &format!(
-                "Expected input scalar `{}`. Got: `{}`. Details: {}",
+            format!(
+                "Expected input scalar `{}`. Got: `{value}`. Details: {}",
                 meta.name,
-                value,
                 e.message(),
             ),
         )];
@@ -219,13 +218,13 @@ where
             var_name,
             var_pos,
             path,
-            &format!(r#"Expected "{}", found list"#, meta.name),
+            format!(r#"Expected "{}", found list"#, meta.name),
         )),
         InputValue::Object(_) => errors.push(unification_error(
             var_name,
             var_pos,
             path,
-            &format!(r#"Expected "{}", found object"#, meta.name),
+            format!(r#"Expected "{}", found object"#, meta.name),
         )),
         _ => (),
     }
@@ -244,27 +243,27 @@ where
 {
     let mut errors: Vec<RuleError> = vec![];
 
-    match *value {
+    match value {
         // TODO: avoid this bad duplicate as_str() call. (value system refactor)
-        InputValue::Scalar(ref scalar) if scalar.as_str().is_some() => {
+        InputValue::Scalar(scalar) if scalar.as_str().is_some() => {
             if let Some(name) = scalar.as_str() {
                 if !meta.values.iter().any(|ev| ev.name == *name) {
                     errors.push(unification_error(
                         var_name,
                         var_pos,
                         path,
-                        &format!(r#"Invalid value for enum "{}""#, meta.name),
+                        format!(r#"Invalid value for enum "{}""#, meta.name),
                     ))
                 }
             }
         }
-        InputValue::Enum(ref name) => {
+        InputValue::Enum(name) => {
             if !meta.values.iter().any(|ev| &ev.name == name) {
                 errors.push(unification_error(
                     var_name,
                     var_pos,
                     path,
-                    &format!(r#"Invalid value for enum "{}""#, meta.name),
+                    format!(r#"Invalid value for enum "{}""#, meta.name),
                 ))
             }
         }
@@ -272,7 +271,7 @@ where
             var_name,
             var_pos,
             path,
-            &format!(r#"Expected "{}", found not a string or enum"#, meta.name),
+            format!(r#"Expected "{}", found not a string or enum"#, meta.name),
         )),
     }
     errors
@@ -318,7 +317,7 @@ where
                     var_name,
                     var_pos,
                     &Path::ObjectField(&input_field.name, path),
-                    &format!(r#"Expected "{}", found null"#, input_field.arg_type),
+                    format!(r#"Expected "{}", found null"#, input_field.arg_type),
                 ));
             }
         }
@@ -336,7 +335,7 @@ where
             var_name,
             var_pos,
             path,
-            &format!(r#"Expected "{}", found not an object"#, meta.name),
+            format!(r#"Expected "{}", found not an object"#, meta.name),
         ));
     }
     errors
@@ -349,17 +348,14 @@ where
     v.map_or(true, InputValue::is_null)
 }
 
-fn unification_error<'a>(
-    var_name: &str,
+fn unification_error(
+    var_name: impl fmt::Display,
     var_pos: &SourcePosition,
-    path: &Path<'a>,
-    message: &str,
+    path: &Path<'_>,
+    message: impl fmt::Display,
 ) -> RuleError {
     RuleError::new(
-        &format!(
-            r#"Variable "${}" got invalid value. {}{}."#,
-            var_name, path, message,
-        ),
+        &format!(r#"Variable "${var_name}" got invalid value. {path}{message}."#),
         &[*var_pos],
     )
 }
@@ -368,8 +364,8 @@ impl<'a> fmt::Display for Path<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             Path::Root => write!(f, ""),
-            Path::ArrayElement(idx, prev) => write!(f, "{}In element #{}: ", prev, idx),
-            Path::ObjectField(name, prev) => write!(f, r#"{}In field "{}": "#, prev, name),
+            Path::ArrayElement(idx, prev) => write!(f, "{prev}In element #{idx}: "),
+            Path::ObjectField(name, prev) => write!(f, r#"{prev}In field "{name}": "#),
         }
     }
 }
diff --git a/juniper/src/validation/rules/arguments_of_correct_type.rs b/juniper/src/validation/rules/arguments_of_correct_type.rs
index 495ca4f7..2c7aadbe 100644
--- a/juniper/src/validation/rules/arguments_of_correct_type.rs
+++ b/juniper/src/validation/rules/arguments_of_correct_type.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use crate::{
     ast::{Directive, Field, InputValue},
     parser::Spanning,
@@ -6,13 +8,12 @@ use crate::{
     validation::{ValidatorContext, Visitor},
     value::ScalarValue,
 };
-use std::fmt::Debug;
 
-pub struct ArgumentsOfCorrectType<'a, S: Debug + 'a> {
+pub struct ArgumentsOfCorrectType<'a, S: fmt::Debug + 'a> {
     current_args: Option<&'a Vec<Argument<'a, S>>>,
 }
 
-pub fn factory<'a, S: Debug>() -> ArgumentsOfCorrectType<'a, S> {
+pub fn factory<'a, S: fmt::Debug>() -> ArgumentsOfCorrectType<'a, S> {
     ArgumentsOfCorrectType { current_args: None }
 }
 
@@ -59,7 +60,7 @@ where
 
             if !is_valid_literal_value(ctx.schema, &meta_type, &arg_value.item) {
                 ctx.report_error(
-                    &error_message(arg_name.item, &format!("{}", argument_meta.arg_type)),
+                    &error_message(arg_name.item, &argument_meta.arg_type),
                     &[arg_value.start],
                 );
             }
@@ -67,11 +68,8 @@ where
     }
 }
 
-fn error_message(arg_name: &str, type_name: &str) -> String {
-    format!(
-        "Invalid value for argument \"{}\", expected type \"{}\"",
-        arg_name, type_name
-    )
+fn error_message(arg_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
+    format!("Invalid value for argument \"{arg_name}\", expected type \"{type_name}\"",)
 }
 
 #[cfg(test)]
@@ -85,7 +83,7 @@ mod tests {
     };
 
     #[test]
-    fn good_null_value() {
+    fn null_into_nullable_int() {
         expect_passes_rule::<_, _, DefaultScalarValue>(
             factory,
             r#"
@@ -98,6 +96,20 @@ mod tests {
         );
     }
 
+    #[test]
+    fn null_into_nullable_list() {
+        expect_passes_rule::<_, _, DefaultScalarValue>(
+            factory,
+            r#"
+            {
+              complicatedArgs {
+                stringListArgField(stringListArg: null)
+              }
+            }
+        "#,
+        );
+    }
+
     #[test]
     fn null_into_int() {
         expect_fails_rule::<_, _, DefaultScalarValue>(
@@ -116,6 +128,24 @@ mod tests {
         );
     }
 
+    #[test]
+    fn null_into_list() {
+        expect_fails_rule::<_, _, DefaultScalarValue>(
+            factory,
+            r#"
+            {
+              complicatedArgs {
+                nonNullStringListArgField(nonNullStringListArg: null)
+              }
+            }
+        "#,
+            &[RuleError::new(
+                &error_message("nonNullStringListArg", "[String!]!"),
+                &[SourcePosition::new(111, 3, 64)],
+            )],
+        );
+    }
+
     #[test]
     fn good_int_value() {
         expect_passes_rule::<_, _, DefaultScalarValue>(
diff --git a/juniper/src/validation/rules/default_values_of_correct_type.rs b/juniper/src/validation/rules/default_values_of_correct_type.rs
index 8ef4f98b..2d15f854 100644
--- a/juniper/src/validation/rules/default_values_of_correct_type.rs
+++ b/juniper/src/validation/rules/default_values_of_correct_type.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use crate::{
     ast::VariableDefinition,
     parser::Spanning,
@@ -29,7 +31,7 @@ where
         {
             if var_def.var_type.item.is_non_null() {
                 ctx.report_error(
-                    &non_null_error_message(var_name.item, &format!("{}", var_def.var_type.item)),
+                    &non_null_error_message(var_name.item, &var_def.var_type.item),
                     &[*start],
                 )
             } else {
@@ -37,7 +39,7 @@ where
 
                 if !is_valid_literal_value(ctx.schema, &meta_type, var_value) {
                     ctx.report_error(
-                        &type_error_message(var_name.item, &format!("{}", var_def.var_type.item)),
+                        &type_error_message(var_name.item, &var_def.var_type.item),
                         &[*start],
                     );
                 }
@@ -46,17 +48,14 @@ where
     }
 }
 
-fn type_error_message(arg_name: &str, type_name: &str) -> String {
-    format!(
-        "Invalid default value for argument \"{}\", expected type \"{}\"",
-        arg_name, type_name
-    )
+fn type_error_message(arg_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
+    format!("Invalid default value for argument \"{arg_name}\", expected type \"{type_name}\"")
 }
 
-fn non_null_error_message(arg_name: &str, type_name: &str) -> String {
+fn non_null_error_message(arg_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
     format!(
-        "Argument \"{}\" has type \"{}\" and is not nullable, so it can't have a default value",
-        arg_name, type_name
+        "Argument \"{arg_name}\" has type \"{type_name}\" and is not nullable, \
+         so it can't have a default value",
     )
 }
 
diff --git a/juniper/src/validation/rules/fields_on_correct_type.rs b/juniper/src/validation/rules/fields_on_correct_type.rs
index ad90cb25..b195df45 100644
--- a/juniper/src/validation/rules/fields_on_correct_type.rs
+++ b/juniper/src/validation/rules/fields_on_correct_type.rs
@@ -69,7 +69,7 @@ where
 }
 
 fn error_message(field: &str, type_name: &str) -> String {
-    format!(r#"Unknown field "{}" on type "{}""#, field, type_name)
+    format!(r#"Unknown field "{field}" on type "{type_name}""#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/fragments_on_composite_types.rs b/juniper/src/validation/rules/fragments_on_composite_types.rs
index 1d2ca75b..927f46de 100644
--- a/juniper/src/validation/rules/fragments_on_composite_types.rs
+++ b/juniper/src/validation/rules/fragments_on_composite_types.rs
@@ -59,15 +59,9 @@ where
 
 fn error_message(fragment_name: Option<&str>, on_type: &str) -> String {
     if let Some(name) = fragment_name {
-        format!(
-            r#"Fragment "{}" cannot condition non composite type "{}"#,
-            name, on_type
-        )
+        format!(r#"Fragment "{name}" cannot condition non composite type "{on_type}"#)
     } else {
-        format!(
-            r#"Fragment cannot condition on non composite type "{}""#,
-            on_type
-        )
+        format!(r#"Fragment cannot condition on non composite type "{on_type}""#)
     }
 }
 
diff --git a/juniper/src/validation/rules/known_argument_names.rs b/juniper/src/validation/rules/known_argument_names.rs
index 6e579977..d652caf3 100644
--- a/juniper/src/validation/rules/known_argument_names.rs
+++ b/juniper/src/validation/rules/known_argument_names.rs
@@ -91,17 +91,11 @@ where
 }
 
 fn field_error_message(arg_name: &str, field_name: &str, type_name: &str) -> String {
-    format!(
-        r#"Unknown argument "{}" on field "{}" of type "{}""#,
-        arg_name, field_name, type_name
-    )
+    format!(r#"Unknown argument "{arg_name}" on field "{field_name}" of type "{type_name}""#)
 }
 
 fn directive_error_message(arg_name: &str, directive_name: &str) -> String {
-    format!(
-        r#"Unknown argument "{}" on directive "{}""#,
-        arg_name, directive_name
-    )
+    format!(r#"Unknown argument "{arg_name}" on directive "{directive_name}""#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/known_directives.rs b/juniper/src/validation/rules/known_directives.rs
index 291e17db..9a2b9f5b 100644
--- a/juniper/src/validation/rules/known_directives.rs
+++ b/juniper/src/validation/rules/known_directives.rs
@@ -154,14 +154,11 @@ where
 }
 
 fn unknown_error_message(directive_name: &str) -> String {
-    format!(r#"Unknown directive "{}""#, directive_name)
+    format!(r#"Unknown directive "{directive_name}""#)
 }
 
 fn misplaced_error_message(directive_name: &str, location: &DirectiveLocation) -> String {
-    format!(
-        r#"Directive "{}" may not be used on {}"#,
-        directive_name, location
-    )
+    format!(r#"Directive "{directive_name}" may not be used on {location}"#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/known_fragment_names.rs b/juniper/src/validation/rules/known_fragment_names.rs
index 8795de4a..ac4b7b19 100644
--- a/juniper/src/validation/rules/known_fragment_names.rs
+++ b/juniper/src/validation/rules/known_fragment_names.rs
@@ -28,7 +28,7 @@ where
 }
 
 fn error_message(frag_name: &str) -> String {
-    format!(r#"Unknown fragment: "{}""#, frag_name)
+    format!(r#"Unknown fragment: "{frag_name}""#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/known_type_names.rs b/juniper/src/validation/rules/known_type_names.rs
index b5b2c936..4f2dffc2 100644
--- a/juniper/src/validation/rules/known_type_names.rs
+++ b/juniper/src/validation/rules/known_type_names.rs
@@ -56,7 +56,7 @@ fn validate_type<'a, S: Debug>(
 }
 
 fn error_message(type_name: &str) -> String {
-    format!(r#"Unknown type "{}""#, type_name)
+    format!(r#"Unknown type "{type_name}""#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/no_fragment_cycles.rs b/juniper/src/validation/rules/no_fragment_cycles.rs
index c5489e08..0845f820 100644
--- a/juniper/src/validation/rules/no_fragment_cycles.rs
+++ b/juniper/src/validation/rules/no_fragment_cycles.rs
@@ -7,19 +7,6 @@ use crate::{
     value::ScalarValue,
 };
 
-pub struct NoFragmentCycles<'a> {
-    current_fragment: Option<&'a str>,
-    spreads: HashMap<&'a str, Vec<Spanning<&'a str>>>,
-    fragment_order: Vec<&'a str>,
-}
-
-struct CycleDetector<'a> {
-    visited: HashSet<&'a str>,
-    spreads: &'a HashMap<&'a str, Vec<Spanning<&'a str>>>,
-    path_indices: HashMap<&'a str, usize>,
-    errors: Vec<RuleError>,
-}
-
 pub fn factory<'a>() -> NoFragmentCycles<'a> {
     NoFragmentCycles {
         current_fragment: None,
@@ -28,6 +15,12 @@ pub fn factory<'a>() -> NoFragmentCycles<'a> {
     }
 }
 
+pub struct NoFragmentCycles<'a> {
+    current_fragment: Option<&'a str>,
+    spreads: HashMap<&'a str, Vec<Spanning<&'a str>>>,
+    fragment_order: Vec<&'a str>,
+}
+
 impl<'a, S> Visitor<'a, S> for NoFragmentCycles<'a>
 where
     S: ScalarValue,
@@ -38,14 +31,12 @@ where
         let mut detector = CycleDetector {
             visited: HashSet::new(),
             spreads: &self.spreads,
-            path_indices: HashMap::new(),
             errors: Vec::new(),
         };
 
         for frag in &self.fragment_order {
             if !detector.visited.contains(frag) {
-                let mut path = Vec::new();
-                detector.detect_from(frag, &mut path);
+                detector.detect_from(frag);
             }
         }
 
@@ -91,19 +82,46 @@ where
     }
 }
 
+type CycleDetectorState<'a> = (&'a str, Vec<&'a Spanning<&'a str>>, HashMap<&'a str, usize>);
+
+struct CycleDetector<'a> {
+    visited: HashSet<&'a str>,
+    spreads: &'a HashMap<&'a str, Vec<Spanning<&'a str>>>,
+    errors: Vec<RuleError>,
+}
+
 impl<'a> CycleDetector<'a> {
-    fn detect_from(&mut self, from: &'a str, path: &mut Vec<&'a Spanning<&'a str>>) {
+    fn detect_from(&mut self, from: &'a str) {
+        let mut to_visit = Vec::new();
+        to_visit.push((from, Vec::new(), HashMap::new()));
+
+        while let Some((from, path, path_indices)) = to_visit.pop() {
+            to_visit.extend(self.detect_from_inner(from, path, path_indices));
+        }
+    }
+
+    /// This function should be called only inside [`Self::detect_from()`], as
+    /// it's a recursive function using heap instead of a stack. So, instead of
+    /// the recursive call, we return a [`Vec`] that is visited inside
+    /// [`Self::detect_from()`].
+    fn detect_from_inner(
+        &mut self,
+        from: &'a str,
+        path: Vec<&'a Spanning<&'a str>>,
+        mut path_indices: HashMap<&'a str, usize>,
+    ) -> Vec<CycleDetectorState<'a>> {
         self.visited.insert(from);
 
         if !self.spreads.contains_key(from) {
-            return;
+            return Vec::new();
         }
 
-        self.path_indices.insert(from, path.len());
+        path_indices.insert(from, path.len());
 
+        let mut to_visit = Vec::new();
         for node in &self.spreads[from] {
-            let name = &node.item;
-            let index = self.path_indices.get(name).cloned();
+            let name = node.item;
+            let index = path_indices.get(name).cloned();
 
             if let Some(index) = index {
                 let err_pos = if index < path.len() {
@@ -114,19 +132,19 @@ impl<'a> CycleDetector<'a> {
 
                 self.errors
                     .push(RuleError::new(&error_message(name), &[err_pos.start]));
-            } else if !self.visited.contains(name) {
+            } else {
+                let mut path = path.clone();
                 path.push(node);
-                self.detect_from(name, path);
-                path.pop();
+                to_visit.push((name, path, path_indices.clone()));
             }
         }
 
-        self.path_indices.remove(from);
+        to_visit
     }
 }
 
 fn error_message(frag_name: &str) -> String {
-    format!(r#"Cannot spread fragment "{}""#, frag_name)
+    format!(r#"Cannot spread fragment "{frag_name}""#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/no_undefined_variables.rs b/juniper/src/validation/rules/no_undefined_variables.rs
index 8f13f191..6e382b23 100644
--- a/juniper/src/validation/rules/no_undefined_variables.rs
+++ b/juniper/src/validation/rules/no_undefined_variables.rs
@@ -12,13 +12,6 @@ pub enum Scope<'a> {
     Fragment(&'a str),
 }
 
-pub struct NoUndefinedVariables<'a> {
-    defined_variables: HashMap<Option<&'a str>, (SourcePosition, HashSet<&'a str>)>,
-    used_variables: HashMap<Scope<'a>, Vec<Spanning<&'a str>>>,
-    current_scope: Option<Scope<'a>>,
-    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
-}
-
 pub fn factory<'a>() -> NoUndefinedVariables<'a> {
     NoUndefinedVariables {
         defined_variables: HashMap::new(),
@@ -28,6 +21,13 @@ pub fn factory<'a>() -> NoUndefinedVariables<'a> {
     }
 }
 
+pub struct NoUndefinedVariables<'a> {
+    defined_variables: HashMap<Option<&'a str>, (SourcePosition, HashSet<&'a str>)>,
+    used_variables: HashMap<Scope<'a>, Vec<Spanning<&'a str>>>,
+    current_scope: Option<Scope<'a>>,
+    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
+}
+
 impl<'a> NoUndefinedVariables<'a> {
     fn find_undef_vars(
         &'a self,
@@ -36,8 +36,34 @@ impl<'a> NoUndefinedVariables<'a> {
         unused: &mut Vec<&'a Spanning<&'a str>>,
         visited: &mut HashSet<Scope<'a>>,
     ) {
+        let mut to_visit = Vec::new();
+        if let Some(spreads) = self.find_undef_vars_inner(scope, defined, unused, visited) {
+            to_visit.push(spreads);
+        }
+        while let Some(spreads) = to_visit.pop() {
+            for spread in spreads {
+                if let Some(spreads) =
+                    self.find_undef_vars_inner(&Scope::Fragment(spread), defined, unused, visited)
+                {
+                    to_visit.push(spreads);
+                }
+            }
+        }
+    }
+
+    /// This function should be called only inside [`Self::find_undef_vars()`],
+    /// as it's a recursive function using heap instead of a stack. So, instead
+    /// of the recursive call, we return a [`Vec`] that is visited inside
+    /// [`Self::find_undef_vars()`].
+    fn find_undef_vars_inner(
+        &'a self,
+        scope: &Scope<'a>,
+        defined: &HashSet<&'a str>,
+        unused: &mut Vec<&'a Spanning<&'a str>>,
+        visited: &mut HashSet<Scope<'a>>,
+    ) -> Option<&'a Vec<&'a str>> {
         if visited.contains(scope) {
-            return;
+            return None;
         }
 
         visited.insert(scope.clone());
@@ -50,11 +76,7 @@ impl<'a> NoUndefinedVariables<'a> {
             }
         }
 
-        if let Some(spreads) = self.spreads.get(scope) {
-            for spread in spreads {
-                self.find_undef_vars(&Scope::Fragment(spread), defined, unused, visited);
-            }
-        }
+        self.spreads.get(scope)
     }
 }
 
@@ -151,12 +173,9 @@ where
 
 fn error_message(var_name: &str, op_name: Option<&str>) -> String {
     if let Some(op_name) = op_name {
-        format!(
-            r#"Variable "${}" is not defined by operation "{}""#,
-            var_name, op_name
-        )
+        format!(r#"Variable "${var_name}" is not defined by operation "{op_name}""#)
     } else {
-        format!(r#"Variable "${}" is not defined"#, var_name)
+        format!(r#"Variable "${var_name}" is not defined"#)
     }
 }
 
diff --git a/juniper/src/validation/rules/no_unused_fragments.rs b/juniper/src/validation/rules/no_unused_fragments.rs
index 97b2bcf8..bb1e9fbb 100644
--- a/juniper/src/validation/rules/no_unused_fragments.rs
+++ b/juniper/src/validation/rules/no_unused_fragments.rs
@@ -7,18 +7,12 @@ use crate::{
     value::ScalarValue,
 };
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Scope<'a> {
     Operation(Option<&'a str>),
     Fragment(&'a str),
 }
 
-pub struct NoUnusedFragments<'a> {
-    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
-    defined_fragments: HashSet<Spanning<&'a str>>,
-    current_scope: Option<Scope<'a>>,
-}
-
 pub fn factory<'a>() -> NoUnusedFragments<'a> {
     NoUnusedFragments {
         spreads: HashMap::new(),
@@ -27,21 +21,42 @@ pub fn factory<'a>() -> NoUnusedFragments<'a> {
     }
 }
 
+pub struct NoUnusedFragments<'a> {
+    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
+    defined_fragments: HashSet<Spanning<&'a str>>,
+    current_scope: Option<Scope<'a>>,
+}
+
 impl<'a> NoUnusedFragments<'a> {
-    fn find_reachable_fragments(&self, from: &Scope<'a>, result: &mut HashSet<&'a str>) {
-        if let Scope::Fragment(name) = *from {
+    fn find_reachable_fragments(&'a self, from: Scope<'a>, result: &mut HashSet<&'a str>) {
+        let mut to_visit = Vec::new();
+        to_visit.push(from);
+
+        while let Some(from) = to_visit.pop() {
+            if let Some(next) = self.find_reachable_fragments_inner(from, result) {
+                to_visit.extend(next.iter().map(|s| Scope::Fragment(s)));
+            }
+        }
+    }
+
+    /// This function should be called only inside
+    /// [`Self::find_reachable_fragments()`], as it's a recursive function using
+    /// heap instead of a stack. So, instead of the recursive call, we return a
+    /// [`Vec`] that is visited inside [`Self::find_reachable_fragments()`].
+    fn find_reachable_fragments_inner(
+        &'a self,
+        from: Scope<'a>,
+        result: &mut HashSet<&'a str>,
+    ) -> Option<&'a Vec<&'a str>> {
+        if let Scope::Fragment(name) = from {
             if result.contains(name) {
-                return;
+                return None;
             } else {
                 result.insert(name);
             }
         }
 
-        if let Some(spreads) = self.spreads.get(from) {
-            for spread in spreads {
-                self.find_reachable_fragments(&Scope::Fragment(spread), result)
-            }
-        }
+        self.spreads.get(&from)
     }
 }
 
@@ -59,7 +74,7 @@ where
             }) = *def
             {
                 let op_name = name.as_ref().map(|s| s.item);
-                self.find_reachable_fragments(&Scope::Operation(op_name), &mut reachable);
+                self.find_reachable_fragments(Scope::Operation(op_name), &mut reachable);
             }
         }
 
@@ -96,7 +111,7 @@ where
     ) {
         if let Some(ref scope) = self.current_scope {
             self.spreads
-                .entry(scope.clone())
+                .entry(*scope)
                 .or_insert_with(Vec::new)
                 .push(spread.item.name.item);
         }
@@ -104,7 +119,7 @@ where
 }
 
 fn error_message(frag_name: &str) -> String {
-    format!(r#"Fragment "{}" is never used"#, frag_name)
+    format!(r#"Fragment "{frag_name}" is never used"#)
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/no_unused_variables.rs b/juniper/src/validation/rules/no_unused_variables.rs
index 35e5f933..81b7dfb3 100644
--- a/juniper/src/validation/rules/no_unused_variables.rs
+++ b/juniper/src/validation/rules/no_unused_variables.rs
@@ -12,13 +12,6 @@ pub enum Scope<'a> {
     Fragment(&'a str),
 }
 
-pub struct NoUnusedVariables<'a> {
-    defined_variables: HashMap<Option<&'a str>, HashSet<&'a Spanning<&'a str>>>,
-    used_variables: HashMap<Scope<'a>, Vec<&'a str>>,
-    current_scope: Option<Scope<'a>>,
-    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
-}
-
 pub fn factory<'a>() -> NoUnusedVariables<'a> {
     NoUnusedVariables {
         defined_variables: HashMap::new(),
@@ -28,16 +21,49 @@ pub fn factory<'a>() -> NoUnusedVariables<'a> {
     }
 }
 
+pub struct NoUnusedVariables<'a> {
+    defined_variables: HashMap<Option<&'a str>, HashSet<&'a Spanning<&'a str>>>,
+    used_variables: HashMap<Scope<'a>, Vec<&'a str>>,
+    current_scope: Option<Scope<'a>>,
+    spreads: HashMap<Scope<'a>, Vec<&'a str>>,
+}
+
 impl<'a> NoUnusedVariables<'a> {
     fn find_used_vars(
-        &self,
+        &'a self,
         from: &Scope<'a>,
         defined: &HashSet<&'a str>,
         used: &mut HashSet<&'a str>,
         visited: &mut HashSet<Scope<'a>>,
     ) {
+        let mut to_visit = Vec::new();
+        if let Some(spreads) = self.find_used_vars_inner(from, defined, used, visited) {
+            to_visit.push(spreads);
+        }
+        while let Some(spreads) = to_visit.pop() {
+            for spread in spreads {
+                if let Some(spreads) =
+                    self.find_used_vars_inner(&Scope::Fragment(spread), defined, used, visited)
+                {
+                    to_visit.push(spreads);
+                }
+            }
+        }
+    }
+
+    /// This function should be called only inside [`Self::find_used_vars()`],
+    /// as it's a recursive function using heap instead of a stack. So, instead
+    /// of the recursive call, we return a [`Vec`] that is visited inside
+    /// [`Self::find_used_vars()`].
+    fn find_used_vars_inner(
+        &'a self,
+        from: &Scope<'a>,
+        defined: &HashSet<&'a str>,
+        used: &mut HashSet<&'a str>,
+        visited: &mut HashSet<Scope<'a>>,
+    ) -> Option<&'a Vec<&'a str>> {
         if visited.contains(from) {
-            return;
+            return None;
         }
 
         visited.insert(from.clone());
@@ -50,11 +76,7 @@ impl<'a> NoUnusedVariables<'a> {
             }
         }
 
-        if let Some(spreads) = self.spreads.get(from) {
-            for spread in spreads {
-                self.find_used_vars(&Scope::Fragment(spread), defined, used, visited);
-            }
-        }
+        self.spreads.get(from)
     }
 }
 
@@ -142,12 +164,9 @@ where
 
 fn error_message(var_name: &str, op_name: Option<&str>) -> String {
     if let Some(op_name) = op_name {
-        format!(
-            r#"Variable "${}" is not used by operation "{}""#,
-            var_name, op_name
-        )
+        format!(r#"Variable "${var_name}" is not used by operation "{op_name}""#)
     } else {
-        format!(r#"Variable "${}" is not used"#, var_name)
+        format!(r#"Variable "${var_name}" is not used"#)
     }
 }
 
diff --git a/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs b/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs
index 1b13f393..efacd1ce 100644
--- a/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs
+++ b/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs
@@ -274,30 +274,61 @@ impl<'a, S: Debug> OverlappingFieldsCanBeMerged<'a, S> {
     ) where
         S: ScalarValue,
     {
-        let fragment = match self.named_fragments.get(fragment_name) {
-            Some(f) => f,
-            None => return,
-        };
+        let mut to_check = Vec::new();
+        if let Some(fragments) = self.collect_conflicts_between_fields_and_fragment_inner(
+            conflicts,
+            field_map,
+            fragment_name,
+            mutually_exclusive,
+            ctx,
+        ) {
+            to_check.push((fragment_name, fragments))
+        }
+
+        while let Some((fragment_name, fragment_names2)) = to_check.pop() {
+            for fragment_name2 in fragment_names2 {
+                // Early return on fragment recursion, as it makes no sense.
+                // Fragment recursions are prevented by `no_fragment_cycles` validator.
+                if fragment_name == fragment_name2 {
+                    return;
+                }
+                if let Some(fragments) = self.collect_conflicts_between_fields_and_fragment_inner(
+                    conflicts,
+                    field_map,
+                    fragment_name2,
+                    mutually_exclusive,
+                    ctx,
+                ) {
+                    to_check.push((fragment_name2, fragments));
+                };
+            }
+        }
+    }
+
+    /// This function should be called only inside
+    /// [`Self::collect_conflicts_between_fields_and_fragment()`], as it's a
+    /// recursive function using heap instead of a stack. So, instead of the
+    /// recursive call, we return a [`Vec`] that is visited inside
+    /// [`Self::collect_conflicts_between_fields_and_fragment()`].
+    fn collect_conflicts_between_fields_and_fragment_inner(
+        &self,
+        conflicts: &mut Vec<Conflict>,
+        field_map: &AstAndDefCollection<'a, S>,
+        fragment_name: &str,
+        mutually_exclusive: bool,
+        ctx: &ValidatorContext<'a, S>,
+    ) -> Option<Vec<&'a str>>
+    where
+        S: ScalarValue,
+    {
+        let fragment = self.named_fragments.get(fragment_name)?;
 
         let (field_map2, fragment_names2) =
             self.get_referenced_fields_and_fragment_names(fragment, ctx);
 
         self.collect_conflicts_between(conflicts, mutually_exclusive, field_map, &field_map2, ctx);
 
-        for fragment_name2 in fragment_names2 {
-            // Early return on fragment recursion, as it makes no sense.
-            // Fragment recursions are prevented by `no_fragment_cycles` validator.
-            if fragment_name == fragment_name2 {
-                return;
-            }
-            self.collect_conflicts_between_fields_and_fragment(
-                conflicts,
-                field_map,
-                fragment_name2,
-                mutually_exclusive,
-                ctx,
-            );
-        }
+        Some(fragment_names2)
     }
 
     fn collect_conflicts_between(
@@ -376,10 +407,9 @@ impl<'a, S: Debug> OverlappingFieldsCanBeMerged<'a, S> {
             if name1 != name2 {
                 return Some(Conflict(
                     ConflictReason(
-                        response_name.to_owned(),
+                        response_name.into(),
                         ConflictReasonMessage::Message(format!(
-                            "{} and {} are different fields",
-                            name1, name2
+                            "{name1} and {name2} are different fields",
                         )),
                     ),
                     vec![ast1.start],
@@ -390,8 +420,8 @@ impl<'a, S: Debug> OverlappingFieldsCanBeMerged<'a, S> {
             if !self.is_same_arguments(&ast1.item.arguments, &ast2.item.arguments) {
                 return Some(Conflict(
                     ConflictReason(
-                        response_name.to_owned(),
-                        ConflictReasonMessage::Message("they have differing arguments".to_owned()),
+                        response_name.into(),
+                        ConflictReasonMessage::Message("they have differing arguments".into()),
                     ),
                     vec![ast1.start],
                     vec![ast2.start],
@@ -406,10 +436,9 @@ impl<'a, S: Debug> OverlappingFieldsCanBeMerged<'a, S> {
             if self.is_type_conflict(ctx, t1, t2) {
                 return Some(Conflict(
                     ConflictReason(
-                        response_name.to_owned(),
+                        response_name.into(),
                         ConflictReasonMessage::Message(format!(
-                            "they return conflicting types {} and {}",
-                            t1, t2
+                            "they return conflicting types {t1} and {t2}",
                         )),
                     ),
                     vec![ast1.start],
@@ -513,7 +542,7 @@ impl<'a, S: Debug> OverlappingFieldsCanBeMerged<'a, S> {
 
         Some(Conflict(
             ConflictReason(
-                response_name.to_owned(),
+                response_name.into(),
                 ConflictReasonMessage::Nested(conflicts.iter().map(|c| c.0.clone()).collect()),
             ),
             vec![*pos1]
@@ -722,10 +751,8 @@ where
 fn error_message(reason_name: &str, reason: &ConflictReasonMessage) -> String {
     let suffix = "Use different aliases on the fields to fetch both if this was intentional";
     format!(
-        r#"Fields "{}" conflict because {}. {}"#,
-        reason_name,
+        r#"Fields "{reason_name}" conflict because {}. {suffix}"#,
         format_reason(reason),
-        suffix
     )
 }
 
@@ -736,9 +763,8 @@ fn format_reason(reason: &ConflictReasonMessage) -> String {
             .iter()
             .map(|&ConflictReason(ref name, ref subreason)| {
                 format!(
-                    r#"subfields "{}" conflict because {}"#,
-                    name,
-                    format_reason(subreason)
+                    r#"subfields "{name}" conflict because {}"#,
+                    format_reason(subreason),
                 )
             })
             .collect::<Vec<_>>()
@@ -872,7 +898,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "fido",
-                    &Message("name and nickname are different fields".to_owned()),
+                    &Message("name and nickname are different fields".into()),
                 ),
                 &[
                     SourcePosition::new(78, 2, 12),
@@ -912,7 +938,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "name",
-                    &Message("nickname and name are different fields".to_owned()),
+                    &Message("nickname and name are different fields".into()),
                 ),
                 &[
                     SourcePosition::new(71, 2, 12),
@@ -935,7 +961,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "doesKnowCommand",
-                    &Message("they have differing arguments".to_owned()),
+                    &Message("they have differing arguments".into()),
                 ),
                 &[
                     SourcePosition::new(57, 2, 12),
@@ -958,7 +984,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "doesKnowCommand",
-                    &Message("they have differing arguments".to_owned()),
+                    &Message("they have differing arguments".into()),
                 ),
                 &[
                     SourcePosition::new(57, 2, 12),
@@ -981,7 +1007,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "doesKnowCommand",
-                    &Message("they have differing arguments".to_owned()),
+                    &Message("they have differing arguments".into()),
                 ),
                 &[
                     SourcePosition::new(57, 2, 12),
@@ -1025,10 +1051,7 @@ mod tests {
           }
         "#,
             &[RuleError::new(
-                &error_message(
-                    "x",
-                    &Message("name and barks are different fields".to_owned()),
-                ),
+                &error_message("x", &Message("name and barks are different fields".into())),
                 &[
                     SourcePosition::new(101, 6, 12),
                     SourcePosition::new(163, 9, 12),
@@ -1066,10 +1089,7 @@ mod tests {
         "#,
             &[
                 RuleError::new(
-                    &error_message(
-                        "x",
-                        &Message("name and barks are different fields".to_owned()),
-                    ),
+                    &error_message("x", &Message("name and barks are different fields".into())),
                     &[
                         SourcePosition::new(235, 13, 14),
                         SourcePosition::new(311, 17, 12),
@@ -1078,7 +1098,7 @@ mod tests {
                 RuleError::new(
                     &error_message(
                         "x",
-                        &Message("name and nickname are different fields".to_owned()),
+                        &Message("name and nickname are different fields".into()),
                     ),
                     &[
                         SourcePosition::new(235, 13, 14),
@@ -1088,7 +1108,7 @@ mod tests {
                 RuleError::new(
                     &error_message(
                         "x",
-                        &Message("barks and nickname are different fields".to_owned()),
+                        &Message("barks and nickname are different fields".into()),
                     ),
                     &[
                         SourcePosition::new(311, 17, 12),
@@ -1117,8 +1137,8 @@ mod tests {
                 &error_message(
                     "dog",
                     &Nested(vec![ConflictReason(
-                        "x".to_owned(),
-                        Message("name and barks are different fields".to_owned()),
+                        "x".into(),
+                        Message("name and barks are different fields".into()),
                     )]),
                 ),
                 &[
@@ -1152,12 +1172,12 @@ mod tests {
                     "dog",
                     &Nested(vec![
                         ConflictReason(
-                            "x".to_owned(),
-                            Message("barks and nickname are different fields".to_owned()),
+                            "x".into(),
+                            Message("barks and nickname are different fields".into()),
                         ),
                         ConflictReason(
-                            "y".to_owned(),
-                            Message("name and barkVolume are different fields".to_owned()),
+                            "y".into(),
+                            Message("name and barkVolume are different fields".into()),
                         ),
                     ]),
                 ),
@@ -1195,10 +1215,10 @@ mod tests {
                 &error_message(
                     "human",
                     &Nested(vec![ConflictReason(
-                        "relatives".to_owned(),
+                        "relatives".into(),
                         Nested(vec![ConflictReason(
-                            "x".to_owned(),
-                            Message("name and iq are different fields".to_owned()),
+                            "x".into(),
+                            Message("name and iq are different fields".into()),
                         )]),
                     )]),
                 ),
@@ -1239,8 +1259,8 @@ mod tests {
                 &error_message(
                     "relatives",
                     &Nested(vec![ConflictReason(
-                        "x".to_owned(),
-                        Message("iq and name are different fields".to_owned()),
+                        "x".into(),
+                        Message("iq and name are different fields".into()),
                     )]),
                 ),
                 &[
@@ -1286,8 +1306,8 @@ mod tests {
                 &error_message(
                     "relatives",
                     &Nested(vec![ConflictReason(
-                        "x".to_owned(),
-                        Message("iq and name are different fields".to_owned()),
+                        "x".into(),
+                        Message("iq and name are different fields".into()),
                     )]),
                 ),
                 &[
@@ -1333,12 +1353,12 @@ mod tests {
                     "dog",
                     &Nested(vec![
                         ConflictReason(
-                            "x".to_owned(),
-                            Message("name and barks are different fields".to_owned()),
+                            "x".into(),
+                            Message("name and barks are different fields".into()),
                         ),
                         ConflictReason(
-                            "y".to_owned(),
-                            Message("barkVolume and nickname are different fields".to_owned()),
+                            "y".into(),
+                            Message("barkVolume and nickname are different fields".into()),
                         ),
                     ]),
                 ),
@@ -1794,7 +1814,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "scalar",
-                    &Message("they return conflicting types Int and String!".to_owned()),
+                    &Message("they return conflicting types Int and String!".into()),
                 ),
                 &[
                     SourcePosition::new(88, 4, 18),
@@ -1858,7 +1878,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "scalar",
-                    &Message("they return conflicting types Int and String".to_owned()),
+                    &Message("they return conflicting types Int and String".into()),
                 ),
                 &[
                     SourcePosition::new(89, 4, 18),
@@ -1922,8 +1942,8 @@ mod tests {
                 &error_message(
                     "other",
                     &Nested(vec![ConflictReason(
-                        "otherField".to_owned(),
-                        Message("otherField and unrelatedField are different fields".to_owned()),
+                        "otherField".into(),
+                        Message("otherField and unrelatedField are different fields".into()),
                     )]),
                 ),
                 &[
@@ -1957,7 +1977,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "scalar",
-                    &Message("they return conflicting types String! and String".to_owned()),
+                    &Message("they return conflicting types String! and String".into()),
                 ),
                 &[
                     SourcePosition::new(100, 4, 18),
@@ -1992,7 +2012,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "box",
-                    &Message("they return conflicting types [StringBox] and StringBox".to_owned()),
+                    &Message("they return conflicting types [StringBox] and StringBox".into()),
                 ),
                 &[
                     SourcePosition::new(89, 4, 18),
@@ -2024,7 +2044,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "box",
-                    &Message("they return conflicting types StringBox and [StringBox]".to_owned()),
+                    &Message("they return conflicting types StringBox and [StringBox]".into()),
                 ),
                 &[
                     SourcePosition::new(89, 4, 18),
@@ -2060,7 +2080,7 @@ mod tests {
             &[RuleError::new(
                 &error_message(
                     "val",
-                    &Message("scalar and unrelatedField are different fields".to_owned()),
+                    &Message("scalar and unrelatedField are different fields".into()),
                 ),
                 &[
                     SourcePosition::new(126, 5, 20),
@@ -2096,8 +2116,8 @@ mod tests {
                 &error_message(
                     "box",
                     &Nested(vec![ConflictReason(
-                        "scalar".to_owned(),
-                        Message("they return conflicting types String and Int".to_owned()),
+                        "scalar".into(),
+                        Message("they return conflicting types String and Int".into()),
                     )]),
                 ),
                 &[
@@ -2227,10 +2247,10 @@ mod tests {
                 &error_message(
                     "edges",
                     &Nested(vec![ConflictReason(
-                        "node".to_owned(),
+                        "node".into(),
                         Nested(vec![ConflictReason(
-                            "id".to_owned(),
-                            Message("name and id are different fields".to_owned()),
+                            "id".into(),
+                            Message("name and id are different fields".into()),
                         )]),
                     )]),
                 ),
@@ -2278,7 +2298,7 @@ mod tests {
     #[test]
     fn error_message_contains_hint_for_alias_conflict() {
         assert_eq!(
-            &error_message("x", &Message("a and b are different fields".to_owned())),
+            &error_message("x", &Message("a and b are different fields".into())),
             "Fields \"x\" conflict because a and b are different fields. Use \
              different aliases on the fields to fetch both if this \
              was intentional"
diff --git a/juniper/src/validation/rules/possible_fragment_spreads.rs b/juniper/src/validation/rules/possible_fragment_spreads.rs
index 53ef05a3..c9e11f6f 100644
--- a/juniper/src/validation/rules/possible_fragment_spreads.rs
+++ b/juniper/src/validation/rules/possible_fragment_spreads.rs
@@ -119,15 +119,13 @@ where
 fn error_message(frag_name: Option<&str>, parent_type_name: &str, frag_type: &str) -> String {
     if let Some(frag_name) = frag_name {
         format!(
-            "Fragment \"{}\" cannot be spread here as objects of type \
-             \"{}\" can never be of type \"{}\"",
-            frag_name, parent_type_name, frag_type
+            "Fragment \"{frag_name}\" cannot be spread here as objects of type \
+             \"{parent_type_name}\" can never be of type \"{frag_type}\"",
         )
     } else {
         format!(
-            "Fragment cannot be spread here as objects of type \"{}\" \
-             can never be of type \"{}\"",
-            parent_type_name, frag_type
+            "Fragment cannot be spread here as objects of type \
+             \"{parent_type_name}\" can never be of type \"{frag_type}\"",
         )
     }
 }
diff --git a/juniper/src/validation/rules/provided_non_null_arguments.rs b/juniper/src/validation/rules/provided_non_null_arguments.rs
index 7c2cb266..35672e18 100644
--- a/juniper/src/validation/rules/provided_non_null_arguments.rs
+++ b/juniper/src/validation/rules/provided_non_null_arguments.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use crate::{
     ast::{Directive, Field},
     parser::Spanning,
@@ -26,6 +28,7 @@ where
         {
             for meta_arg in meta_args {
                 if meta_arg.arg_type.is_non_null()
+                    && meta_arg.default_value.is_none()
                     && field
                         .item
                         .arguments
@@ -34,11 +37,7 @@ where
                         .is_none()
                 {
                     ctx.report_error(
-                        &field_error_message(
-                            field_name,
-                            &meta_arg.name,
-                            &format!("{}", meta_arg.arg_type),
-                        ),
+                        &field_error_message(field_name, &meta_arg.name, &meta_arg.arg_type),
                         &[field.start],
                     );
                 }
@@ -71,7 +70,7 @@ where
                         &directive_error_message(
                             directive_name,
                             &meta_arg.name,
-                            &format!("{}", meta_arg.arg_type),
+                            &meta_arg.arg_type,
                         ),
                         &[directive.start],
                     );
@@ -81,17 +80,23 @@ where
     }
 }
 
-fn field_error_message(field_name: &str, arg_name: &str, type_name: &str) -> String {
+fn field_error_message(
+    field_name: impl fmt::Display,
+    arg_name: impl fmt::Display,
+    type_name: impl fmt::Display,
+) -> String {
     format!(
-        r#"Field "{}" argument "{}" of type "{}" is required but not provided"#,
-        field_name, arg_name, type_name
+        r#"Field "{field_name}" argument "{arg_name}" of type "{type_name}" is required but not provided"#,
     )
 }
 
-fn directive_error_message(directive_name: &str, arg_name: &str, type_name: &str) -> String {
+fn directive_error_message(
+    directive_name: impl fmt::Display,
+    arg_name: impl fmt::Display,
+    type_name: impl fmt::Display,
+) -> String {
     format!(
-        r#"Directive "@{}" argument "{}" of type "{}" is required but not provided"#,
-        directive_name, arg_name, type_name
+        r#"Directive "@{directive_name}" argument "{arg_name}" of type "{type_name}" is required but not provided"#,
     )
 }
 
diff --git a/juniper/src/validation/rules/scalar_leafs.rs b/juniper/src/validation/rules/scalar_leafs.rs
index fe5ac777..00a92dad 100644
--- a/juniper/src/validation/rules/scalar_leafs.rs
+++ b/juniper/src/validation/rules/scalar_leafs.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use crate::{
     ast::Field,
     parser::Spanning,
@@ -23,11 +25,11 @@ where
         {
             match (field_type.is_leaf(), &field.item.selection_set) {
                 (true, &Some(_)) => Some(RuleError::new(
-                    &no_allowed_error_message(field_name, &format!("{}", field_type_literal)),
+                    &no_allowed_error_message(field_name, field_type_literal),
                     &[field.start],
                 )),
                 (false, &None) => Some(RuleError::new(
-                    &required_error_message(field_name, &format!("{}", field_type_literal)),
+                    &required_error_message(field_name, field_type_literal),
                     &[field.start],
                 )),
                 _ => None,
@@ -42,17 +44,15 @@ where
     }
 }
 
-fn no_allowed_error_message(field_name: &str, type_name: &str) -> String {
+fn no_allowed_error_message(field_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
     format!(
-        r#"Field "{}" must not have a selection since type {} has no subfields"#,
-        field_name, type_name
+        r#"Field "{field_name}" must not have a selection since type {type_name} has no subfields"#,
     )
 }
 
-fn required_error_message(field_name: &str, type_name: &str) -> String {
+fn required_error_message(field_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
     format!(
-        r#"Field "{}" of type "{}" must have a selection of subfields. Did you mean "{} {{ ... }}"?"#,
-        field_name, type_name, field_name
+        r#"Field "{field_name}" of type "{type_name}" must have a selection of subfields. Did you mean "{field_name} {{ ... }}"?"#,
     )
 }
 
diff --git a/juniper/src/validation/rules/unique_argument_names.rs b/juniper/src/validation/rules/unique_argument_names.rs
index 0b6ae6d6..697e0a27 100644
--- a/juniper/src/validation/rules/unique_argument_names.rs
+++ b/juniper/src/validation/rules/unique_argument_names.rs
@@ -46,7 +46,7 @@ where
 }
 
 fn error_message(arg_name: &str) -> String {
-    format!("There can only be one argument named \"{}\"", arg_name)
+    format!("There can only be one argument named \"{arg_name}\"")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/unique_fragment_names.rs b/juniper/src/validation/rules/unique_fragment_names.rs
index 2bcbb440..f54e46d1 100644
--- a/juniper/src/validation/rules/unique_fragment_names.rs
+++ b/juniper/src/validation/rules/unique_fragment_names.rs
@@ -41,7 +41,7 @@ where
 }
 
 fn duplicate_message(frag_name: &str) -> String {
-    format!("There can only be one fragment named {}", frag_name)
+    format!("There can only be one fragment named {frag_name}")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/unique_input_field_names.rs b/juniper/src/validation/rules/unique_input_field_names.rs
index db507502..7108c767 100644
--- a/juniper/src/validation/rules/unique_input_field_names.rs
+++ b/juniper/src/validation/rules/unique_input_field_names.rs
@@ -53,7 +53,7 @@ where
 type SpannedObject<'a, S> = Spanning<&'a Vec<(Spanning<String>, Spanning<InputValue<S>>)>>;
 
 fn error_message(field_name: &str) -> String {
-    format!("There can only be one input field named \"{}\"", field_name)
+    format!("There can only be one input field named \"{field_name}\"")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/unique_operation_names.rs b/juniper/src/validation/rules/unique_operation_names.rs
index 4d7e56f1..8f693696 100644
--- a/juniper/src/validation/rules/unique_operation_names.rs
+++ b/juniper/src/validation/rules/unique_operation_names.rs
@@ -40,7 +40,7 @@ where
 }
 
 fn error_message(op_name: &str) -> String {
-    format!("There can only be one operation named {}", op_name)
+    format!("There can only be one operation named {op_name}")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/unique_variable_names.rs b/juniper/src/validation/rules/unique_variable_names.rs
index 0c32706b..738e634b 100644
--- a/juniper/src/validation/rules/unique_variable_names.rs
+++ b/juniper/src/validation/rules/unique_variable_names.rs
@@ -46,7 +46,7 @@ where
 }
 
 fn error_message(var_name: &str) -> String {
-    format!("There can only be one variable named {}", var_name)
+    format!("There can only be one variable named {var_name}")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/variables_are_input_types.rs b/juniper/src/validation/rules/variables_are_input_types.rs
index 0336b618..168119d6 100644
--- a/juniper/src/validation/rules/variables_are_input_types.rs
+++ b/juniper/src/validation/rules/variables_are_input_types.rs
@@ -1,3 +1,5 @@
+use std::fmt;
+
 use crate::{
     ast::VariableDefinition,
     parser::Spanning,
@@ -26,7 +28,7 @@ where
         {
             if !var_type.is_input() {
                 ctx.report_error(
-                    &error_message(var_name.item, &format!("{}", var_def.var_type.item)),
+                    &error_message(var_name.item, &var_def.var_type.item),
                     &[var_def.var_type.start],
                 );
             }
@@ -34,11 +36,8 @@ where
     }
 }
 
-fn error_message(var_name: &str, type_name: &str) -> String {
-    format!(
-        "Variable \"{}\" cannot be of non-input type \"{}\"",
-        var_name, type_name
-    )
+fn error_message(var_name: impl fmt::Display, type_name: impl fmt::Display) -> String {
+    format!("Variable \"{var_name}\" cannot be of non-input type \"{type_name}\"")
 }
 
 #[cfg(test)]
diff --git a/juniper/src/validation/rules/variables_in_allowed_position.rs b/juniper/src/validation/rules/variables_in_allowed_position.rs
index 1f3dff59..776f12db 100644
--- a/juniper/src/validation/rules/variables_in_allowed_position.rs
+++ b/juniper/src/validation/rules/variables_in_allowed_position.rs
@@ -1,7 +1,7 @@
 use std::{
     borrow::Cow,
     collections::{HashMap, HashSet},
-    fmt::Debug,
+    fmt,
 };
 
 use crate::{
@@ -17,15 +17,7 @@ pub enum Scope<'a> {
     Fragment(&'a str),
 }
 
-pub struct VariableInAllowedPosition<'a, S: Debug + 'a> {
-    spreads: HashMap<Scope<'a>, HashSet<&'a str>>,
-    variable_usages: HashMap<Scope<'a>, Vec<(Spanning<&'a String>, Type<'a>)>>,
-    #[allow(clippy::type_complexity)]
-    variable_defs: HashMap<Scope<'a>, Vec<&'a (Spanning<&'a str>, VariableDefinition<'a, S>)>>,
-    current_scope: Option<Scope<'a>>,
-}
-
-pub fn factory<'a, S: Debug>() -> VariableInAllowedPosition<'a, S> {
+pub fn factory<'a, S: fmt::Debug>() -> VariableInAllowedPosition<'a, S> {
     VariableInAllowedPosition {
         spreads: HashMap::new(),
         variable_usages: HashMap::new(),
@@ -34,16 +26,54 @@ pub fn factory<'a, S: Debug>() -> VariableInAllowedPosition<'a, S> {
     }
 }
 
-impl<'a, S: Debug> VariableInAllowedPosition<'a, S> {
-    fn collect_incorrect_usages(
-        &self,
+pub struct VariableInAllowedPosition<'a, S: fmt::Debug + 'a> {
+    spreads: HashMap<Scope<'a>, HashSet<&'a str>>,
+    variable_usages: HashMap<Scope<'a>, Vec<(Spanning<&'a String>, Type<'a>)>>,
+    #[allow(clippy::type_complexity)]
+    variable_defs: HashMap<Scope<'a>, Vec<&'a (Spanning<&'a str>, VariableDefinition<'a, S>)>>,
+    current_scope: Option<Scope<'a>>,
+}
+
+impl<'a, S: fmt::Debug> VariableInAllowedPosition<'a, S> {
+    fn collect_incorrect_usages<'me>(
+        &'me self,
         from: &Scope<'a>,
         var_defs: &[&'a (Spanning<&'a str>, VariableDefinition<S>)],
         ctx: &mut ValidatorContext<'a, S>,
         visited: &mut HashSet<Scope<'a>>,
     ) {
+        let mut to_visit = Vec::new();
+        if let Some(spreads) = self.collect_incorrect_usages_inner(from, var_defs, ctx, visited) {
+            to_visit.push(spreads);
+        }
+
+        while let Some(spreads) = to_visit.pop() {
+            for spread in spreads {
+                if let Some(spreads) = self.collect_incorrect_usages_inner(
+                    &Scope::Fragment(spread),
+                    var_defs,
+                    ctx,
+                    visited,
+                ) {
+                    to_visit.push(spreads);
+                }
+            }
+        }
+    }
+
+    /// This function should be called only inside
+    /// [`Self::collect_incorrect_usages()`], as it's a recursive function using
+    /// heap instead of a stack. So, instead of the recursive call, we return a
+    /// [`Vec`] that is visited inside [`Self::collect_incorrect_usages()`].
+    fn collect_incorrect_usages_inner<'me>(
+        &'me self,
+        from: &Scope<'a>,
+        var_defs: &[&'a (Spanning<&'a str>, VariableDefinition<S>)],
+        ctx: &mut ValidatorContext<'a, S>,
+        visited: &mut HashSet<Scope<'a>>,
+    ) -> Option<&'me HashSet<&'a str>> {
         if visited.contains(from) {
-            return;
+            return None;
         }
 
         visited.insert(from.clone());
@@ -66,11 +96,7 @@ impl<'a, S: Debug> VariableInAllowedPosition<'a, S> {
 
                     if !ctx.schema.is_subtype(&expected_type, var_type) {
                         ctx.report_error(
-                            &error_message(
-                                var_name.item,
-                                &format!("{}", expected_type),
-                                &format!("{}", var_type),
-                            ),
+                            &error_message(var_name.item, expected_type, var_type),
                             &[var_def_name.start, var_name.start],
                         );
                     }
@@ -78,11 +104,7 @@ impl<'a, S: Debug> VariableInAllowedPosition<'a, S> {
             }
         }
 
-        if let Some(spreads) = self.spreads.get(from) {
-            for spread in spreads {
-                self.collect_incorrect_usages(&Scope::Fragment(spread), var_defs, ctx, visited);
-            }
-        }
+        self.spreads.get(from)
     }
 }
 
@@ -157,10 +179,13 @@ where
     }
 }
 
-fn error_message(var_name: &str, type_name: &str, expected_type_name: &str) -> String {
+fn error_message(
+    var_name: impl fmt::Display,
+    type_name: impl fmt::Display,
+    expected_type_name: impl fmt::Display,
+) -> String {
     format!(
-        "Variable \"{}\" of type \"{}\" used in position expecting type \"{}\"",
-        var_name, type_name, expected_type_name
+        "Variable \"{var_name}\" of type \"{type_name}\" used in position expecting type \"{expected_type_name}\"",
     )
 }
 
diff --git a/juniper/src/validation/test_harness.rs b/juniper/src/validation/test_harness.rs
index 1772b639..c2f5ddac 100644
--- a/juniper/src/validation/test_harness.rs
+++ b/juniper/src/validation/test_harness.rs
@@ -724,6 +724,9 @@ where
             registry
                 .field::<Option<String>>("stringListArgField", i)
                 .argument(registry.arg::<Option<Vec<Option<String>>>>("stringListArg", i)),
+            registry
+                .field::<Option<String>>("nonNullStringListArgField", i)
+                .argument(registry.arg::<Vec<String>>("nonNullStringListArg", i)),
             registry
                 .field::<Option<String>>("complexArgField", i)
                 .argument(registry.arg::<Option<ComplexInput>>("complexArg", i)),
@@ -920,7 +923,7 @@ where
     ));
 
     let doc =
-        parse_document_source(q, &root.schema).expect(&format!("Parse error on input {:#?}", q));
+        parse_document_source(q, &root.schema).expect(&format!("Parse error on input {q:#?}"));
     let mut ctx = ValidatorContext::new(unsafe { mem::transmute(&root.schema) }, &doc);
 
     visit_fn(&mut ctx, unsafe { mem::transmute(doc.as_slice()) });
diff --git a/juniper/src/value/mod.rs b/juniper/src/value/mod.rs
index 9d8ca2b3..b4798e90 100644
--- a/juniper/src/value/mod.rs
+++ b/juniper/src/value/mod.rs
@@ -218,15 +218,15 @@ impl<S: ScalarValue> fmt::Display for Value<S> {
             Self::Null => write!(f, "null"),
             Self::Scalar(s) => {
                 if let Some(string) = s.as_string() {
-                    write!(f, "\"{}\"", string)
+                    write!(f, "\"{string}\"")
                 } else {
-                    write!(f, "{}", s)
+                    write!(f, "{s}")
                 }
             }
             Self::List(list) => {
                 write!(f, "[")?;
                 for (idx, item) in list.iter().enumerate() {
-                    write!(f, "{}", item)?;
+                    write!(f, "{item}")?;
                     if idx < list.len() - 1 {
                         write!(f, ", ")?;
                     }
@@ -238,7 +238,7 @@ impl<S: ScalarValue> fmt::Display for Value<S> {
             Self::Object(obj) => {
                 write!(f, "{{")?;
                 for (idx, (key, value)) in obj.iter().enumerate() {
-                    write!(f, "\"{}\": {}", key, value)?;
+                    write!(f, "\"{key}\": {value}")?;
 
                     if idx < obj.field_count() - 1 {
                         write!(f, ", ")?;
@@ -309,52 +309,52 @@ mod tests {
     #[test]
     fn display_null() {
         let s: Value = graphql_value!(null);
-        assert_eq!("null", format!("{}", s));
+        assert_eq!(s.to_string(), "null");
     }
 
     #[test]
     fn display_int() {
         let s: Value = graphql_value!(123);
-        assert_eq!("123", format!("{}", s));
+        assert_eq!(s.to_string(), "123");
     }
 
     #[test]
     fn display_float() {
         let s: Value = graphql_value!(123.456);
-        assert_eq!("123.456", format!("{}", s));
+        assert_eq!(s.to_string(), "123.456");
     }
 
     #[test]
     fn display_string() {
         let s: Value = graphql_value!("foo");
-        assert_eq!("\"foo\"", format!("{}", s));
+        assert_eq!(s.to_string(), "\"foo\"");
     }
 
     #[test]
     fn display_bool() {
         let s: Value = graphql_value!(false);
-        assert_eq!("false", format!("{}", s));
+        assert_eq!(s.to_string(), "false");
 
         let s: Value = graphql_value!(true);
-        assert_eq!("true", format!("{}", s));
+        assert_eq!(s.to_string(), "true");
     }
 
     #[test]
     fn display_list() {
         let s: Value = graphql_value!([1, null, "foo"]);
-        assert_eq!("[1, null, \"foo\"]", format!("{}", s));
+        assert_eq!(s.to_string(), "[1, null, \"foo\"]");
     }
 
     #[test]
     fn display_list_one_element() {
         let s: Value = graphql_value!([1]);
-        assert_eq!("[1]", format!("{}", s));
+        assert_eq!(s.to_string(), "[1]");
     }
 
     #[test]
     fn display_list_empty() {
         let s: Value = graphql_value!([]);
-        assert_eq!("[]", format!("{}", s));
+        assert_eq!(s.to_string(), "[]");
     }
 
     #[test]
@@ -365,8 +365,8 @@ mod tests {
             "string": "foo",
         });
         assert_eq!(
+            s.to_string(),
             r#"{"int": 1, "null": null, "string": "foo"}"#,
-            format!("{}", s)
         );
     }
 
@@ -375,12 +375,12 @@ mod tests {
         let s: Value = graphql_value!({
             "int": 1,
         });
-        assert_eq!(r#"{"int": 1}"#, format!("{}", s));
+        assert_eq!(s.to_string(), r#"{"int": 1}"#);
     }
 
     #[test]
     fn display_object_empty() {
         let s: Value = graphql_value!({});
-        assert_eq!(r#"{}"#, format!("{}", s));
+        assert_eq!(s.to_string(), r#"{}"#);
     }
 }
diff --git a/juniper/src/value/object.rs b/juniper/src/value/object.rs
index 909abe3f..4e3deb41 100644
--- a/juniper/src/value/object.rs
+++ b/juniper/src/value/object.rs
@@ -1,4 +1,4 @@
-use std::{iter::FromIterator, mem};
+use std::mem;
 
 use super::Value;
 use indexmap::map::{IndexMap, IntoIter};
diff --git a/juniper/src/value/scalar.rs b/juniper/src/value/scalar.rs
index d14e8a6a..f93e7bbf 100644
--- a/juniper/src/value/scalar.rs
+++ b/juniper/src/value/scalar.rs
@@ -7,12 +7,12 @@ use crate::parser::{ParseError, ScalarToken};
 pub use juniper_codegen::ScalarValue;
 
 /// The result of converting a string into a scalar value
-pub type ParseScalarResult<'a, S = DefaultScalarValue> = Result<S, ParseError<'a>>;
+pub type ParseScalarResult<S = DefaultScalarValue> = Result<S, ParseError>;
 
 /// A trait used to convert a `ScalarToken` into a certain scalar value type
 pub trait ParseScalarValue<S = DefaultScalarValue> {
     /// See the trait documentation
-    fn from_str(value: ScalarToken<'_>) -> ParseScalarResult<'_, S>;
+    fn from_str(value: ScalarToken<'_>) -> ParseScalarResult<S>;
 }
 
 /// A trait marking a type that could be used as internal representation of
@@ -34,7 +34,7 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
 /// integers.
 ///
 /// ```rust
-/// # use std::{fmt, convert::TryInto as _};
+/// # use std::fmt;
 /// #
 /// # use serde::{de, Deserialize, Deserializer, Serialize};
 /// # use juniper::ScalarValue;
@@ -228,20 +228,20 @@ pub trait ScalarValue:
 ///
 /// These types closely follow the [GraphQL specification][0].
 ///
-/// [0]: https://spec.graphql.org/June2018
+/// [0]: https://spec.graphql.org/October2021
 #[derive(Clone, Debug, PartialEq, ScalarValue, Serialize)]
 #[serde(untagged)]
 pub enum DefaultScalarValue {
     /// [`Int` scalar][0] as a signed 32‐bit numeric non‐fractional value.
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-Int
+    /// [0]: https://spec.graphql.org/October2021#sec-Int
     #[value(as_float, as_int)]
     Int(i32),
 
     /// [`Float` scalar][0] as a signed double‐precision fractional values as
     /// specified by [IEEE 754].
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-Float
+    /// [0]: https://spec.graphql.org/October2021#sec-Float
     /// [IEEE 754]: https://en.wikipedia.org/wiki/IEEE_floating_point
     #[value(as_float)]
     Float(f64),
@@ -249,13 +249,13 @@ pub enum DefaultScalarValue {
     /// [`String` scalar][0] as a textual data, represented as UTF‐8 character
     /// sequences.
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-String
+    /// [0]: https://spec.graphql.org/October2021#sec-String
     #[value(as_str, as_string, into_string)]
     String(String),
 
     /// [`Boolean` scalar][0] as a `true` or `false` value.
     ///
-    /// [0]: https://spec.graphql.org/June2018/#sec-Boolean
+    /// [0]: https://spec.graphql.org/October2021#sec-Boolean
     #[value(as_bool)]
     Boolean(bool),
 }
diff --git a/juniper_actix/Cargo.toml b/juniper_actix/Cargo.toml
index f46a7498..bb60ff5f 100644
--- a/juniper_actix/Cargo.toml
+++ b/juniper_actix/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_actix"
 version = "0.5.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "`juniper` GraphQL integration with `actix-web`."
 license = "BSD-2-Clause"
 authors = ["Jordao Rosario <jordao.rosario01@gmail.com>"]
@@ -37,9 +38,9 @@ tokio = { version = "1.0", features = ["sync"], optional = true }
 
 [dev-dependencies]
 actix-cors = "0.6"
-actix-identity = "0.4"
+actix-identity = "0.5"
 actix-rt = "2.0"
-actix-test = "=0.1.0-beta.13"
+actix-test = "0.1"
 async-stream = "0.3"
 bytes = "1.0"
 env_logger = "0.9"
diff --git a/juniper_actix/examples/actix_server.rs b/juniper_actix/examples/actix_server.rs
index 5a13b79a..ab27373d 100644
--- a/juniper_actix/examples/actix_server.rs
+++ b/juniper_actix/examples/actix_server.rs
@@ -21,7 +21,7 @@ pub struct User {
     name: String,
 }
 
-#[derive(Default, Clone)]
+#[derive(Clone, Default)]
 pub struct Database {
     ///this could be a database connection
     users: HashMap<i32, User>,
@@ -33,28 +33,28 @@ impl Database {
             1,
             User {
                 id: 1,
-                name: "Aron".to_string(),
+                name: "Aron".into(),
             },
         );
         users.insert(
             2,
             User {
                 id: 2,
-                name: "Bea".to_string(),
+                name: "Bea".into(),
             },
         );
         users.insert(
             3,
             User {
                 id: 3,
-                name: "Carl".to_string(),
+                name: "Carl".into(),
             },
         );
         users.insert(
             4,
             User {
                 id: 4,
-                name: "Dora".to_string(),
+                name: "Dora".into(),
             },
         );
         Database { users }
diff --git a/juniper_actix/src/lib.rs b/juniper_actix/src/lib.rs
index c88c1b00..3c6192e6 100644
--- a/juniper_actix/src/lib.rs
+++ b/juniper_actix/src/lib.rs
@@ -368,7 +368,7 @@ pub mod subscriptions {
                 Err(e) => {
                     let reason = ws::CloseReason {
                         code: ws::CloseCode::Error,
-                        description: Some(format!("error serializing response: {}", e)),
+                        description: Some(format!("error serializing response: {e}")),
                     };
 
                     // TODO: trace
@@ -389,7 +389,7 @@ pub mod subscriptions {
     #[derive(Debug)]
     struct Message(ws::Message);
 
-    impl<S: ScalarValue> std::convert::TryFrom<Message> for ClientMessage<S> {
+    impl<S: ScalarValue> TryFrom<Message> for ClientMessage<S> {
         type Error = Error;
 
         fn try_from(msg: Message) -> Result<Self, Self::Error> {
@@ -416,7 +416,7 @@ pub mod subscriptions {
     impl fmt::Display for Error {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             match self {
-                Self::Serde(e) => write!(f, "serde error: {}", e),
+                Self::Serde(e) => write!(f, "serde error: {e}"),
                 Self::UnexpectedClientMessage => {
                     write!(f, "unexpected message received from client")
                 }
@@ -712,7 +712,7 @@ mod tests {
             self.make_request(
                 TestRequest::post()
                     .append_header(("content-type", "application/json"))
-                    .set_payload(body.to_string())
+                    .set_payload(body.to_owned())
                     .uri(url),
             )
         }
@@ -721,7 +721,7 @@ mod tests {
             self.make_request(
                 TestRequest::post()
                     .append_header(("content-type", "application/graphql"))
-                    .set_payload(body.to_string())
+                    .set_payload(body.to_owned())
                     .uri(url),
             )
         }
@@ -735,7 +735,7 @@ mod tests {
             .unwrap()
             .to_str()
             .unwrap()
-            .to_string();
+            .into();
         let body = take_response_body_string(resp).await;
         TestResponse {
             status_code: status_code as i32,
@@ -797,29 +797,28 @@ mod subscription_tests {
                         framed
                             .send(ws::Message::Text(body.to_owned().into()))
                             .await
-                            .map_err(|e| anyhow::anyhow!("WS error: {:?}", e))?;
+                            .map_err(|e| anyhow::anyhow!("WS error: {e:?}"))?;
                     }
                     WsIntegrationMessage::Expect(body, message_timeout) => {
                         let frame = timeout(Duration::from_millis(*message_timeout), framed.next())
                             .await
                             .map_err(|_| anyhow::anyhow!("Timed-out waiting for message"))?
                             .ok_or_else(|| anyhow::anyhow!("Empty message received"))?
-                            .map_err(|e| anyhow::anyhow!("WS error: {:?}", e))?;
+                            .map_err(|e| anyhow::anyhow!("WS error: {e:?}"))?;
 
                         match frame {
                             ws::Frame::Text(ref bytes) => {
                                 let expected_value =
                                     serde_json::from_str::<serde_json::Value>(body)
-                                        .map_err(|e| anyhow::anyhow!("Serde error: {:?}", e))?;
+                                        .map_err(|e| anyhow::anyhow!("Serde error: {e:?}"))?;
 
                                 let value: serde_json::Value = serde_json::from_slice(bytes)
-                                    .map_err(|e| anyhow::anyhow!("Serde error: {:?}", e))?;
+                                    .map_err(|e| anyhow::anyhow!("Serde error: {e:?}"))?;
 
                                 if value != expected_value {
                                     return Err(anyhow::anyhow!(
-                                        "Expected message: {}. Received message: {}",
-                                        expected_value,
-                                        value,
+                                        "Expected message: {expected_value}. \
+                                         Received message: {value}",
                                     ));
                                 }
                             }
diff --git a/juniper_codegen/CHANGELOG.md b/juniper_codegen/CHANGELOG.md
index 2ce86c70..aa93555e 100644
--- a/juniper_codegen/CHANGELOG.md
+++ b/juniper_codegen/CHANGELOG.md
@@ -16,10 +16,11 @@ All user visible changes to `juniper_codegen` crate will be documented in this f
     - Removed support for `dyn` attribute argument (interface values as trait objects).
     - Removed support for `downcast` attribute argument (custom resolution into implementer types).
     - Removed support for `async` trait methods (not required anymore).
-    - Removed necessity of writing `impl Trait for Type` blocks (interfaces are implemented just by matching their fields now).
+    - Removed necessity of writing `impl Trait for Type` blocks (interfaces are implemented just by matching their fields now). ([#113])
     - Forbade default implementations of non-ignored trait methods.
     - Supported coercion of additional `null`able arguments and return sub-typing on implementer.
     - Supported `rename_all = "<policy>"` 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`.
@@ -41,6 +42,7 @@ All user visible changes to `juniper_codegen` crate will be documented in this f
 
 - All procedural macros expansion inside `macro_rules!`. ([#1054], [#1051])
 
+[#113]: /../../issues/113
 [#971]: /../../pull/971
 [#985]: /../../pull/985
 [#987]: /../../pull/987
@@ -51,6 +53,7 @@ All user visible changes to `juniper_codegen` crate will be documented in this f
 [#1017]: /../../pull/1017
 [#1025]: /../../pull/1025
 [#1026]: /../../pull/1026
+[#1028]: /../../pull/1028
 [#1051]: /../../issues/1051
 [#1054]: /../../pull/1054
 
diff --git a/juniper_codegen/Cargo.toml b/juniper_codegen/Cargo.toml
index 79ba4d63..ef78a0a2 100644
--- a/juniper_codegen/Cargo.toml
+++ b/juniper_codegen/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_codegen"
 version = "0.16.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "Code generation for `juniper` crate."
 license = "BSD-2-Clause"
 authors = [
diff --git a/juniper_codegen/src/common/behavior.rs b/juniper_codegen/src/common/behavior.rs
index 5976c9d0..618ae5bc 100644
--- a/juniper_codegen/src/common/behavior.rs
+++ b/juniper_codegen/src/common/behavior.rs
@@ -10,16 +10,17 @@ use syn::{
     parse_quote,
 };
 
-use crate::util::span_container::SpanContainer;
+use crate::common::SpanContainer;
 
 /// [`Behaviour`] parametrization of the code generation.
 ///
 /// [`Behaviour`]: juniper::behavior
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
 pub(crate) enum Type {
     /// [`behavior::Standard`] should be used in the generated code.
     ///
     /// [`behavior::Standard`]: juniper::behavior::Standard
+    #[default]
     Standard,
 
     /// Concrete custom Rust type should be used as [`Behaviour`] in the
@@ -29,12 +30,6 @@ pub(crate) enum Type {
     Custom(syn::Type),
 }
 
-impl Default for Type {
-    fn default() -> Self {
-        Self::Standard
-    }
-}
-
 impl Parse for Type {
     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
         input.parse::<syn::Type>().map(Self::Custom)
diff --git a/juniper_codegen/src/common/default.rs b/juniper_codegen/src/common/default.rs
new file mode 100644
index 00000000..a2d00f45
--- /dev/null
+++ b/juniper_codegen/src/common/default.rs
@@ -0,0 +1,62 @@
+//! Common functions, definitions and extensions for parsing and code generation
+//! of [GraphQL default values][0]
+//!
+//! [0]: https://spec.graphql.org/October2021#DefaultValue
+
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{
+    parse::{Parse, ParseStream},
+    token,
+};
+
+use crate::common::parse::ParseBufferExt as _;
+
+/// Representation of a [GraphQL default value][0] for code generation.
+///
+/// [0]: https://spec.graphql.org/October2021#DefaultValue
+#[derive(Clone, Debug, Default)]
+pub(crate) enum Value {
+    /// [`Default`] implementation should be used.
+    #[default]
+    Default,
+
+    /// Explicit [`Expr`]ession to be used as the [default value][0].
+    ///
+    /// [`Expr`]: syn::Expr
+    /// [0]: https://spec.graphql.org/October2021#DefaultValue
+    Expr(Box<syn::Expr>),
+}
+
+impl From<Option<syn::Expr>> for Value {
+    fn from(opt: Option<syn::Expr>) -> Self {
+        match opt {
+            Some(expr) => Self::Expr(Box::new(expr)),
+            None => Self::Default,
+        }
+    }
+}
+
+impl Parse for Value {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        Ok(input
+            .try_parse::<token::Eq>()?
+            .map(|_| input.parse::<syn::Expr>())
+            .transpose()?
+            .into())
+    }
+}
+
+impl ToTokens for Value {
+    fn to_tokens(&self, into: &mut TokenStream) {
+        match self {
+            Self::Default => quote! {
+                ::std::default::Default::default()
+            },
+            Self::Expr(expr) => quote! {
+                (#expr).into()
+            },
+        }
+        .to_tokens(into)
+    }
+}
diff --git a/juniper_codegen/src/common/deprecation.rs b/juniper_codegen/src/common/deprecation.rs
new file mode 100644
index 00000000..9efd6ef0
--- /dev/null
+++ b/juniper_codegen/src/common/deprecation.rs
@@ -0,0 +1,114 @@
+//! Common functions, definitions and extensions for parsing and code generation
+//! of [GraphQL deprecation directive][0].
+//!
+//! [0]: https://spec.graphql.org/October2021#sec--deprecated
+
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{
+    parse::{Parse, ParseStream},
+    spanned::Spanned as _,
+    token,
+};
+
+use crate::common::{parse::ParseBufferExt as _, SpanContainer};
+
+/// [GraphQL deprecation directive][0] defined on a [GraphQL field][1] or a
+/// [GraphQL enum value][2] via `#[graphql(deprecated = ...)]` (or
+/// `#[deprecated(note = ...)]`) attribute.
+///
+/// [0]: https://spec.graphql.org/October2021#sec--deprecated
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+/// [2]: https://spec.graphql.org/October2021#sec-Enum-Value
+#[derive(Debug, Default)]
+pub(crate) struct Directive {
+    /// Optional [reason][1] attached to this [deprecation][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec--deprecated
+    /// [1]: https://spec.graphql.org/October2021#sel-GAHnBZDACEDDGAA_6L
+    pub(crate) reason: Option<syn::LitStr>,
+}
+
+impl Parse for Directive {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        Ok(Self {
+            reason: input
+                .try_parse::<token::Eq>()?
+                .map(|_| input.parse::<syn::LitStr>())
+                .transpose()?,
+        })
+    }
+}
+
+impl Directive {
+    /// Tries to parse a [`Directive`] from a `#[deprecated(note = ...)]`
+    /// attribute, by looking up for it in the provided [`syn::Attribute`]s.
+    ///
+    /// # Errors
+    ///
+    /// If failed to parse a [`Directive`] from a found
+    /// `#[deprecated(note = ...)]` attribute.
+    pub(crate) fn parse_from_deprecated_attr(
+        attrs: &[syn::Attribute],
+    ) -> syn::Result<Option<SpanContainer<Self>>> {
+        for attr in attrs {
+            return Ok(match attr.parse_meta() {
+                Ok(syn::Meta::List(ref list)) if list.path.is_ident("deprecated") => {
+                    let directive = Self::parse_from_deprecated_meta_list(list)?;
+                    Some(SpanContainer::new(
+                        list.path.span(),
+                        directive.reason.as_ref().map(|r| r.span()),
+                        directive,
+                    ))
+                }
+                Ok(syn::Meta::Path(ref path)) if path.is_ident("deprecated") => {
+                    Some(SpanContainer::new(path.span(), None, Self::default()))
+                }
+                _ => continue,
+            });
+        }
+        Ok(None)
+    }
+
+    /// Tries to parse a [`Directive`] from the [`syn::MetaList`] of a single
+    /// `#[deprecated(note = ...)]` attribute.
+    ///
+    /// # Errors
+    ///
+    /// If the `#[deprecated(note = ...)]` attribute has incorrect format.
+    fn parse_from_deprecated_meta_list(list: &syn::MetaList) -> syn::Result<Self> {
+        for meta in &list.nested {
+            if let syn::NestedMeta::Meta(syn::Meta::NameValue(nv)) = meta {
+                return if !nv.path.is_ident("note") {
+                    Err(syn::Error::new(
+                        nv.path.span(),
+                        "unrecognized setting on #[deprecated(..)] attribute",
+                    ))
+                } else if let syn::Lit::Str(strlit) = &nv.lit {
+                    Ok(Self {
+                        reason: Some(strlit.clone()),
+                    })
+                } else {
+                    Err(syn::Error::new(
+                        nv.lit.span(),
+                        "only strings are allowed for deprecation",
+                    ))
+                };
+            }
+        }
+        Ok(Self::default())
+    }
+}
+
+impl ToTokens for Directive {
+    fn to_tokens(&self, into: &mut TokenStream) {
+        let reason = self
+            .reason
+            .as_ref()
+            .map_or_else(|| quote! { None }, |text| quote! { Some(#text) });
+        quote! {
+            .deprecated(::std::option::Option::#reason)
+        }
+        .to_tokens(into);
+    }
+}
diff --git a/juniper_codegen/src/common/description.rs b/juniper_codegen/src/common/description.rs
new file mode 100644
index 00000000..cd8d739e
--- /dev/null
+++ b/juniper_codegen/src/common/description.rs
@@ -0,0 +1,200 @@
+//! Common functions, definitions and extensions for parsing and code generation
+//! of [GraphQL description][0].
+//!
+//! [0]: https://spec.graphql.org/October2021#sec-Descriptions
+
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::parse::{Parse, ParseStream};
+
+use crate::common::SpanContainer;
+
+/// [GraphQL description][0] defined on a GraphQL definition via
+/// `#[graphql(description = ...)]` (or `#[doc = ...]`) attribute.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Descriptions
+#[derive(Debug, Eq, PartialEq)]
+pub(crate) struct Description(syn::LitStr);
+
+impl Parse for Description {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        input.parse::<syn::LitStr>().map(Self)
+    }
+}
+
+impl Description {
+    /// Tries to parse a [`Description`] from a `#[doc = ...]` attribute (or
+    /// Rust doc comment), by looking up for it in the provided
+    /// [`syn::Attribute`]s.
+    ///
+    /// # Errors
+    ///
+    /// If failed to parse a [`Description`] from a found `#[doc = ...]`
+    /// attribute.
+    pub(crate) fn parse_from_doc_attrs(
+        attrs: &[syn::Attribute],
+    ) -> syn::Result<Option<SpanContainer<Self>>> {
+        let (mut first_span, mut descriptions) = (None, Vec::new());
+        for attr in attrs {
+            match attr.parse_meta() {
+                Ok(syn::Meta::NameValue(ref nv)) if nv.path.is_ident("doc") => {
+                    if let syn::Lit::Str(strlit) = &nv.lit {
+                        if first_span.is_none() {
+                            first_span = Some(strlit.span());
+                        }
+                        descriptions.push(strlit.value());
+                    } else {
+                        return Err(syn::Error::new(
+                            nv.lit.span(),
+                            "#[doc] attributes may only have a string literal",
+                        ));
+                    }
+                }
+                _ => continue,
+            }
+        }
+        Ok(first_span.map(|span| {
+            SpanContainer::new(
+                span,
+                None,
+                Self(syn::LitStr::new(&Self::concatenate(&descriptions), span)),
+            )
+        }))
+    }
+
+    /// Concatenates [`Description`] strings into a single one.
+    fn concatenate(descriptions: &[String]) -> String {
+        let last_index = descriptions.len() - 1;
+        descriptions
+            .iter()
+            .map(|s| s.as_str().trim_end())
+            .map(|s| {
+                // Trim leading space.
+                s.strip_prefix(' ').unwrap_or(s)
+            })
+            .enumerate()
+            .fold(String::new(), |mut buffer, (index, s)| {
+                // Add newline, except when string ends in a continuation
+                // backslash or is the last line.
+                if index == last_index {
+                    buffer.push_str(s);
+                } else if s.ends_with('\\') {
+                    buffer.push_str(s.trim_end_matches('\\'));
+                    buffer.push(' ');
+                } else {
+                    buffer.push_str(s);
+                    buffer.push('\n');
+                }
+                buffer
+            })
+    }
+}
+
+impl ToTokens for Description {
+    fn to_tokens(&self, into: &mut TokenStream) {
+        let desc = &self.0;
+
+        quote! {
+            .description(#desc)
+        }
+        .to_tokens(into);
+    }
+}
+
+#[cfg(test)]
+mod parse_from_doc_attrs_test {
+    use quote::quote;
+    use syn::parse_quote;
+
+    use super::Description;
+
+    #[test]
+    fn single() {
+        let desc = Description::parse_from_doc_attrs(&[parse_quote! { #[doc = "foo"] }])
+            .unwrap()
+            .unwrap()
+            .into_inner();
+        assert_eq!(
+            quote! { #desc }.to_string(),
+            quote! { .description("foo") }.to_string(),
+        );
+    }
+
+    #[test]
+    fn many() {
+        let desc = Description::parse_from_doc_attrs(&[
+            parse_quote! { #[doc = "foo"] },
+            parse_quote! { #[doc = "\n"] },
+            parse_quote! { #[doc = "bar"] },
+        ])
+        .unwrap()
+        .unwrap()
+        .into_inner();
+        assert_eq!(
+            quote! { #desc }.to_string(),
+            quote! { .description("foo\n\nbar") }.to_string(),
+        );
+    }
+
+    #[test]
+    fn not_doc() {
+        let desc = Description::parse_from_doc_attrs(&[parse_quote! { #[blah = "foo"] }]).unwrap();
+        assert_eq!(desc, None);
+    }
+}
+
+#[cfg(test)]
+mod concatenate_test {
+    use super::Description;
+
+    /// Forms a [`Vec`] of [`String`]s out of the provided [`str`]s
+    /// [`Iterator`].
+    fn to_strings<'i>(source: impl IntoIterator<Item = &'i str>) -> Vec<String> {
+        source.into_iter().map(Into::into).collect()
+    }
+
+    #[test]
+    fn single() {
+        assert_eq!(Description::concatenate(&to_strings(["foo"])), "foo");
+    }
+
+    #[test]
+    fn multiple() {
+        assert_eq!(
+            Description::concatenate(&to_strings(["foo", "bar"])),
+            "foo\nbar",
+        );
+    }
+
+    #[test]
+    fn trims_spaces() {
+        assert_eq!(
+            Description::concatenate(&to_strings([" foo ", "bar ", " baz"])),
+            "foo\nbar\nbaz",
+        );
+    }
+
+    #[test]
+    fn empty() {
+        assert_eq!(
+            Description::concatenate(&to_strings(["foo", "", "bar"])),
+            "foo\n\nbar",
+        );
+    }
+
+    #[test]
+    fn newline_spaces() {
+        assert_eq!(
+            Description::concatenate(&to_strings(["foo ", "", " bar"])),
+            "foo\n\nbar",
+        );
+    }
+
+    #[test]
+    fn continuation_backslash() {
+        assert_eq!(
+            Description::concatenate(&to_strings(["foo\\", "x\\", "y", "bar"])),
+            "foo x y\nbar",
+        );
+    }
+}
diff --git a/juniper_codegen/src/common/diagnostic.rs b/juniper_codegen/src/common/diagnostic.rs
new file mode 100644
index 00000000..d99bb504
--- /dev/null
+++ b/juniper_codegen/src/common/diagnostic.rs
@@ -0,0 +1,87 @@
+use std::fmt;
+
+use proc_macro2::Span;
+use proc_macro_error::{Diagnostic, Level};
+
+/// URL of the GraphQL specification (October 2021 Edition).
+pub(crate) const SPEC_URL: &str = "https://spec.graphql.org/October2021";
+
+pub(crate) enum Scope {
+    EnumDerive,
+    InputObjectDerive,
+    InterfaceAttr,
+    InterfaceDerive,
+    ObjectAttr,
+    ObjectDerive,
+    ScalarAttr,
+    ScalarDerive,
+    ScalarValueDerive,
+    UnionAttr,
+    UnionDerive,
+}
+
+impl Scope {
+    pub(crate) fn spec_section(&self) -> &str {
+        match self {
+            Self::EnumDerive => "#sec-Enums",
+            Self::InputObjectDerive => "#sec-Input-Objects",
+            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",
+        }
+    }
+}
+
+impl fmt::Display for Scope {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let name = match self {
+            Self::EnumDerive => "enum",
+            Self::InputObjectDerive => "input object",
+            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",
+        };
+        write!(f, "GraphQL {name}")
+    }
+}
+
+impl Scope {
+    fn spec_link(&self) -> String {
+        format!("{SPEC_URL}{}", self.spec_section())
+    }
+
+    pub(crate) fn custom<S: AsRef<str>>(&self, span: Span, msg: S) -> Diagnostic {
+        Diagnostic::spanned(span, Level::Error, format!("{self} {}", msg.as_ref()))
+            .note(self.spec_link())
+    }
+
+    pub(crate) fn error(&self, err: syn::Error) -> Diagnostic {
+        Diagnostic::spanned(err.span(), Level::Error, format!("{self} {err}"))
+            .note(self.spec_link())
+    }
+
+    pub(crate) fn emit_custom<S: AsRef<str>>(&self, span: Span, msg: S) {
+        self.custom(span, msg).emit()
+    }
+
+    pub(crate) fn custom_error<S: AsRef<str>>(&self, span: Span, msg: S) -> syn::Error {
+        syn::Error::new(span, format!("{self} {}", msg.as_ref()))
+    }
+
+    pub(crate) fn no_double_underscore(&self, field: Span) {
+        Diagnostic::spanned(
+            field,
+            Level::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."
+                .into(),
+        )
+        .note(format!("{SPEC_URL}#sec-Schema"))
+        .emit();
+    }
+}
diff --git a/juniper_codegen/src/common/field/arg.rs b/juniper_codegen/src/common/field/arg.rs
index 3bd1f9f3..dd0e1013 100644
--- a/juniper_codegen/src/common/field/arg.rs
+++ b/juniper_codegen/src/common/field/arg.rs
@@ -1,7 +1,7 @@
 //! Common functions, definitions and extensions for parsing and code generation
 //! of [GraphQL arguments][1]
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments.
+//! [1]: https://spec.graphql.org/October2021#sec-Language.Arguments.
 
 use std::mem;
 
@@ -14,23 +14,19 @@ use syn::{
     token,
 };
 
-use crate::{
-    common::{
-        behavior,
-        parse::{
-            attr::{err, OptionExt as _},
-            ParseBufferExt as _, TypeExt as _,
-        },
-        scalar,
+use crate::common::{
+    behavior, default, diagnostic, filter_attrs,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _, TypeExt as _,
     },
-    result::GraphQLScope,
-    util::{filter_attrs, path_eq_single, span_container::SpanContainer, RenameRule},
+    path_eq_single, rename, scalar, Description, SpanContainer,
 };
 
 /// Available metadata (arguments) behind `#[graphql]` attribute placed on a
 /// method argument, when generating code for [GraphQL argument][1].
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
 #[derive(Debug, Default)]
 pub(crate) struct Attr {
     /// Explicitly specified name of a [GraphQL argument][1] represented by this
@@ -38,29 +34,26 @@ pub(crate) struct Attr {
     ///
     /// If [`None`], then `camelCased` Rust argument name is used by default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     pub(crate) name: Option<SpanContainer<syn::LitStr>>,
 
     /// Explicitly specified [description][2] of this [GraphQL argument][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    pub(crate) description: Option<SpanContainer<syn::LitStr>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    pub(crate) description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified [default value][2] of this [GraphQL argument][1].
     ///
-    /// If the exact default expression is not specified, then the [`Default`]
-    /// value is used.
-    ///
     /// If [`None`], then this [GraphQL argument][1] is considered as
     /// [required][2].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
-    pub(crate) default: Option<SpanContainer<Option<syn::Expr>>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Required-Arguments
+    pub(crate) default: Option<SpanContainer<default::Value>>,
 
     /// Explicitly specified type of the custom [`Behavior`] this
-    /// [GraphQL argument][0] implementation is parametrized with, to [coerce]
+    /// [GraphQL argument][1] implementation is parametrized with, to [coerce]
     /// in the generated code from.
     ///
     /// If [`None`], then [`behavior::Standard`] will be used for the generated
@@ -68,7 +61,7 @@ pub(crate) struct Attr {
     ///
     /// [`Behavior`]: juniper::behavior
     /// [`behavior::Standard`]: juniper::behavior::Standard
-    /// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     /// [coerce]: juniper::behavior::Coerce
     pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
 
@@ -80,8 +73,8 @@ pub(crate) struct Attr {
     /// if it's named `context` or `ctx`.
     ///
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) context: Option<SpanContainer<syn::Ident>>,
 
     /// Explicitly specified marker indicating that this method argument doesn't
@@ -92,8 +85,8 @@ pub(crate) struct Attr {
     /// if it's named `executor`.
     ///
     /// [`Executor`]: juniper::Executor
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) executor: Option<SpanContainer<syn::Ident>>,
 }
 
@@ -112,27 +105,15 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
                         .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "default" => {
-                    let mut expr = None;
-                    if input.is_next::<token::Eq>() {
-                        input.parse::<token::Eq>()?;
-                        expr = Some(input.parse::<syn::Expr>()?);
-                    } else if input.is_next::<token::Paren>() {
-                        let inner;
-                        let _ = syn::parenthesized!(inner in input);
-                        expr = Some(inner.parse::<syn::Expr>()?);
-                    }
+                    let val = input.parse::<default::Value>()?;
                     out.default
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            expr.as_ref().map(|e| e.span()),
-                            expr,
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(val.span()), val))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "behave" | "behavior" => {
@@ -235,52 +216,46 @@ impl Attr {
     fn err_disallowed<S: Spanned>(span: &S, arg: &str) -> syn::Error {
         syn::Error::new(
             span.span(),
-            format!(
-                "attribute argument `#[graphql({} = ...)]` is not allowed here",
-                arg,
-            ),
+            format!("attribute argument `#[graphql({arg} = ...)]` is not allowed here",),
         )
     }
 }
 
 /// Representation of a [GraphQL field argument][1] for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
 #[derive(Debug)]
 pub(crate) struct OnField {
     /// Rust type that this [GraphQL field argument][1] is represented by.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     pub(crate) ty: syn::Type,
 
     /// Name of this [GraphQL field argument][2] in GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     pub(crate) name: String,
 
     /// [Description][2] of this [GraphQL field argument][1] to put into GraphQL
     /// schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    pub(crate) description: Option<String>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    pub(crate) description: Option<Description>,
 
     /// Default value of this [GraphQL field argument][1] in GraphQL schema.
     ///
-    /// If outer [`Option`] is [`None`], then this [argument][1] is a
-    /// [required][2] one.
+    /// If [`None`], then this [argument][1] is a [required][2] one.
     ///
-    /// If inner [`Option`] is [`None`], then the [`Default`] value is used.
-    ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
-    /// [2]: https://spec.graphql.org/June2018/#sec-Required-Arguments
-    pub(crate) default: Option<Option<syn::Expr>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [2]: https://spec.graphql.org/October2021#sec-Required-Arguments
+    pub(crate) default: Option<default::Value>,
 
-    /// [`Behavior`] parametrization of this [GraphQL argument][0]
+    /// [`Behavior`] parametrization of this [GraphQL field argument][1]
     /// implementation to [coerce] from in the generated code.
     ///
     /// [`Behavior`]: juniper::behavior
-    /// [0]: https://spec.graphql.org/October2021#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     /// [coerce]: juniper::behavior::Coerce
     pub(crate) behavior: behavior::Type,
 }
@@ -290,19 +265,19 @@ pub(crate) struct OnField {
 pub(crate) enum OnMethod {
     /// Regular [GraphQL field argument][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Arguments
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Arguments
     Regular(Box<OnField>),
 
     /// [`Context`] passed into a [GraphQL field][2] resolving method.
     ///
     /// [`Context`]: juniper::Context
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     Context(Box<syn::Type>),
 
     /// [`Executor`] passed into a [GraphQL field][2] resolving method.
     ///
     /// [`Executor`]: juniper::Executor
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     Executor,
 }
 
@@ -353,16 +328,9 @@ impl OnMethod {
 
         let (name, ty) = (&arg.name, &arg.ty);
 
-        let description = arg
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
+        let description = &arg.description;
 
         let method = if let Some(val) = &arg.default {
-            let val = val
-                .as_ref()
-                .map(|v| quote! { (#v).into() })
-                .unwrap_or_else(|| quote! { <#ty as Default>::default() });
             quote_spanned! { val.span() =>
                 .arg_with_default::<#ty>(#name, &#val, info)
             }
@@ -370,7 +338,7 @@ impl OnMethod {
             quote! { .arg::<#ty>(#name, info) }
         };
 
-        Some(quote! { .argument(registry#method#description) })
+        Some(quote! { .argument(registry #method #description) })
     }
 
     /// Returns generated code for the [`GraphQLValue::resolve_field`] method,
@@ -387,7 +355,7 @@ impl OnMethod {
         match self {
             Self::Regular(arg) => {
                 let (name, ty) = (&arg.name, &arg.ty);
-                let err_text = format!("Missing argument `{}`: {{}}", &name);
+                let err_text = format!("Missing argument `{name}`: {{}}");
 
                 let arg = quote! {
                     args.get::<#ty>(#name).and_then(|opt| opt.map_or_else(|| {
@@ -425,8 +393,8 @@ impl OnMethod {
     /// given `scope`.
     pub(crate) fn parse(
         argument: &mut syn::PatType,
-        renaming: &RenameRule,
-        scope: &GraphQLScope,
+        renaming: &rename::Policy,
+        scope: &diagnostic::Scope,
     ) -> Option<Self> {
         let orig_attrs = argument.attrs.clone();
 
@@ -492,8 +460,8 @@ impl OnMethod {
         Some(Self::Regular(Box::new(OnField {
             name,
             ty: argument.ty.as_ref().clone(),
-            description: attr.description.as_ref().map(|d| d.as_ref().value()),
-            default: attr.default.as_ref().map(|v| v.as_ref().clone()),
+            description: attr.description.map(SpanContainer::into_inner),
+            default: attr.default.map(SpanContainer::into_inner),
             behavior: attr.behavior.into(),
         })))
     }
diff --git a/juniper_codegen/src/common/field/mod.rs b/juniper_codegen/src/common/field/mod.rs
index 3ea86e40..24751fab 100644
--- a/juniper_codegen/src/common/field/mod.rs
+++ b/juniper_codegen/src/common/field/mod.rs
@@ -1,7 +1,7 @@
 //! Common functions, definitions and extensions for parsing and code generation
 //! of [GraphQL fields][1]
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Language.Fields.
+//! [1]: https://spec.graphql.org/October2021#sec-Language.Fields
 
 pub(crate) mod arg;
 
@@ -14,16 +14,13 @@ use syn::{
     token,
 };
 
-use crate::{
-    common::{
-        behavior,
-        parse::{
-            attr::{err, OptionExt as _},
-            ParseBufferExt as _,
-        },
-        scalar,
+use crate::common::{
+    behavior, deprecation, filter_attrs,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _,
     },
-    util::{filter_attrs, get_deprecated, get_doc_comment, span_container::SpanContainer},
+    scalar, Description, SpanContainer,
 };
 
 pub(crate) use self::arg::OnMethod as MethodArgument;
@@ -31,36 +28,36 @@ pub(crate) use self::arg::OnMethod as MethodArgument;
 /// Available metadata (arguments) behind `#[graphql]` attribute placed on a
 /// [GraphQL field][1] definition.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
 #[derive(Debug, Default)]
 pub(crate) struct Attr {
     /// Explicitly specified name of this [GraphQL field][1].
     ///
     /// If [`None`], then `camelCased` Rust method name is used by default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) name: Option<SpanContainer<syn::LitStr>>,
 
     /// Explicitly specified [description][2] of this [GraphQL field][1].
     ///
-    /// If [`None`], then Rust doc comment is used as the [description][2], if
-    /// any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    pub(crate) description: Option<SpanContainer<syn::LitStr>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    pub(crate) description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified [deprecation][2] of this [GraphQL field][1].
     ///
-    /// If [`None`], then Rust `#[deprecated]` attribute is used as the
+    /// If [`None`], then Rust `#[deprecated]` attribute will be used as the
     /// [deprecation][2], if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
-    /// [2]: https://spec.graphql.org/June2018/#sec-Deprecation
-    pub(crate) deprecated: Option<SpanContainer<Option<syn::LitStr>>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Deprecation
+    pub(crate) deprecated: Option<SpanContainer<deprecation::Directive>>,
 
     /// Explicitly specified type of the custom [`Behavior`] this
-    /// [GraphQL field][0] implementation is parametrized with, to [coerce] in
+    /// [GraphQL field][1] implementation is parametrized with, to [coerce] in
     /// the generated code from.
     ///
     /// If [`None`], then [`behavior::Standard`] will be used for the generated
@@ -68,7 +65,7 @@ pub(crate) struct Attr {
     ///
     /// [`Behavior`]: juniper::behavior
     /// [`behavior::Standard`]: juniper::behavior::Standard
-    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     /// [coerce]: juniper::behavior::Coerce
     pub(crate) behavior: Option<SpanContainer<behavior::Type>>,
 
@@ -76,7 +73,7 @@ pub(crate) struct Attr {
     /// field) should be omitted by code generation and not considered as the
     /// [GraphQL field][1] definition.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) ignore: Option<SpanContainer<syn::Ident>>,
 }
 
@@ -95,22 +92,18 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
                         .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "deprecated" => {
-                    let mut reason = None;
-                    if input.is_next::<token::Eq>() {
-                        input.parse::<token::Eq>()?;
-                        reason = Some(input.parse::<syn::LitStr>()?);
-                    }
+                    let directive = input.parse::<deprecation::Directive>()?;
                     out.deprecated
                         .replace(SpanContainer::new(
                             ident.span(),
-                            reason.as_ref().map(|r| r.span()),
-                            reason,
+                            directive.reason.as_ref().map(|r| r.span()),
+                            directive,
                         ))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
@@ -151,7 +144,7 @@ impl Attr {
     /// Parses [`Attr`] from the given multiple `name`d [`syn::Attribute`]s
     /// placed on a [GraphQL field][1] definition.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result<Self> {
         let mut attr = filter_attrs(name, attrs)
             .map(|attr| attr.parse_args())
@@ -167,17 +160,11 @@ impl Attr {
         }
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs).map(|sc| {
-                let span = sc.span_ident();
-                sc.map(|desc| syn::LitStr::new(&desc, span))
-            });
+            attr.description = Description::parse_from_doc_attrs(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)))
-            });
+            attr.deprecated = deprecation::Directive::parse_from_deprecated_attr(attrs)?;
         }
 
         Ok(attr)
@@ -186,46 +173,43 @@ impl Attr {
 
 /// Representation of a [GraphQL field][1] for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
 #[derive(Debug)]
 pub(crate) struct Definition {
     /// Rust type that this [GraphQL field][1] is represented by (method return
     /// type or struct field type).
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) ty: syn::Type,
 
     /// Name of this [GraphQL field][1] in GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) name: String,
 
     /// [Description][2] of this [GraphQL field][1] to put into GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    pub(crate) description: Option<String>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    pub(crate) description: Option<Description>,
 
     /// [Deprecation][2] of this [GraphQL field][1] to put into GraphQL schema.
     ///
-    /// If inner [`Option`] is [`None`], then deprecation has no message
-    /// attached.
-    ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
-    /// [2]: https://spec.graphql.org/June2018/#sec-Deprecation
-    pub(crate) deprecated: Option<Option<String>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Deprecation
+    pub(crate) deprecated: Option<deprecation::Directive>,
 
     /// Ident of the Rust method (or struct field) representing this
     /// [GraphQL field][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) ident: syn::Ident,
 
-    /// [`Behavior`] parametrization of this [GraphQL field][0] implementation
+    /// [`Behavior`] parametrization of this [GraphQL field][1] implementation
     /// to [coerce] from in the generated code.
     ///
     /// [`Behavior`]: juniper::behavior
-    /// [0]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     /// [coerce]: juniper::behavior::Coerce
     pub(crate) behavior: behavior::Type,
 
@@ -235,19 +219,19 @@ pub(crate) struct Definition {
     /// If [`None`] then this [GraphQL field][1] is represented by a struct
     /// field.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) arguments: Option<Vec<MethodArgument>>,
 
     /// Indicator whether the Rust method representing this [GraphQL field][1]
     /// has a [`syn::Receiver`].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) has_receiver: bool,
 
     /// Indicator whether this [GraphQL field][1] should be resolved
     /// asynchronously.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) is_async: bool,
 }
 
@@ -255,7 +239,7 @@ impl Definition {
     /// Indicates whether this [GraphQL field][1] is represented by a method,
     /// not a struct field.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     #[must_use]
     pub(crate) fn is_method(&self) -> bool {
         self.arguments.is_some()
@@ -265,14 +249,14 @@ impl Definition {
     /// tried to be resolved in the [`GraphQLValue::resolve_field`] method.
     ///
     /// [`GraphQLValue::resolve_field`]: juniper::GraphQLValue::resolve_field
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     #[must_use]
     pub(crate) fn method_resolve_field_err_no_field_tokens(
         scalar: &scalar::Type,
         ty_name: &str,
     ) -> TokenStream {
         quote! {
-            return Err(::juniper::FieldError::from(format!(
+            return Err(::juniper::FieldError::from(::std::format!(
                 "Field `{}` not found on type `{}`",
                 field,
                 <Self as ::juniper::GraphQLType<#scalar>>::name(info)
@@ -285,7 +269,7 @@ impl Definition {
     /// which performs static checks for this [GraphQL field][1].
     ///
     /// [`marker::IsOutputType::mark`]: juniper::marker::IsOutputType::mark
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     #[must_use]
     pub(crate) fn method_mark_tokens(
         &self,
@@ -321,7 +305,7 @@ impl Definition {
     ///
     /// [`GraphQLType::meta`]: juniper::GraphQLType::meta
     /// [`Registry`]: juniper::Registry
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
     #[must_use]
     pub(crate) fn method_meta_tokens(
         &self,
@@ -335,18 +319,8 @@ impl Definition {
             };
         }
 
-        let description = self
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
-
-        let deprecated = self.deprecated.as_ref().map(|reason| {
-            let reason = reason
-                .as_ref()
-                .map(|rsn| quote! { Some(#rsn) })
-                .unwrap_or_else(|| quote! { None });
-            quote! { .deprecated(#reason) }
-        });
+        let description = &self.description;
+        let deprecated = &self.deprecated;
 
         let args = self
             .arguments
@@ -366,8 +340,8 @@ impl Definition {
     /// resolves this [GraphQL field][1] as [subscription][2].
     ///
     /// [0]: juniper::GraphQLSubscriptionValue::resolve_field_into_stream
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
-    /// [2]: https://spec.graphql.org/June2018/#sec-Subscription
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+    /// [2]: https://spec.graphql.org/October2021#sec-Subscription
     #[must_use]
     pub(crate) fn method_resolve_field_into_stream_tokens(
         &self,
@@ -405,7 +379,7 @@ impl Definition {
                     let stream = ::juniper::futures::StreamExt::then(res, move |res| {
                         let executor = executor.clone();
                         let res2: ::juniper::FieldResult<_, #scalar> =
-                            ::juniper::IntoResolvable::into(res, executor.context());
+                            ::juniper::IntoResolvable::into_resolvable(res, executor.context());
                         async move {
                             let ex = executor.as_executor();
                             match res2 {
@@ -431,7 +405,7 @@ impl Definition {
 
 /// Checks whether all [GraphQL fields][1] fields have different names.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Language.Fields
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
 #[must_use]
 pub(crate) fn all_different(fields: &[Definition]) -> bool {
     let mut names: Vec<_> = fields.iter().map(|f| &f.name).collect();
diff --git a/juniper_codegen/src/common/gen.rs b/juniper_codegen/src/common/gen.rs
index dc5adc13..a0b5e731 100644
--- a/juniper_codegen/src/common/gen.rs
+++ b/juniper_codegen/src/common/gen.rs
@@ -8,10 +8,10 @@ use quote::quote;
 /// Value of a [GraphQL type][1] should be stored in a `res` binding in the generated code, before
 /// including this piece of code.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Types
+/// [1]: https://spec.graphql.org/October2021#sec-Types
 pub(crate) fn sync_resolving_code() -> TokenStream {
     quote! {
-        ::juniper::IntoResolvable::into(res, executor.context())
+        ::juniper::IntoResolvable::into_resolvable(res, executor.context())
             .and_then(|res| match res {
                 Some((ctx, r)) => executor.replaced_context(ctx).resolve_with_ctx(info, &r),
                 None => Ok(::juniper::Value::null()),
@@ -29,13 +29,13 @@ pub(crate) fn sync_resolving_code() -> TokenStream {
 ///
 /// [`Future`]: std::future::Future
 /// [`Future::Output`]: std::future::Future::Output
-/// [1]: https://spec.graphql.org/June2018/#sec-Types
+/// [1]: https://spec.graphql.org/October2021#sec-Types
 pub(crate) fn async_resolving_code(ty: Option<&syn::Type>) -> TokenStream {
     let ty = ty.map(|t| quote! { : #t });
 
     quote! {
         Box::pin(::juniper::futures::FutureExt::then(fut, move |res #ty| async move {
-            match ::juniper::IntoResolvable::into(res, executor.context())? {
+            match ::juniper::IntoResolvable::into_resolvable(res, executor.context())? {
                 Some((ctx, r)) => {
                     let subexec = executor.replaced_context(ctx);
                     subexec.resolve_with_ctx_async(info, &r).await
diff --git a/juniper_codegen/src/common/mod.rs b/juniper_codegen/src/common/mod.rs
index 638042dd..9c5f4a11 100644
--- a/juniper_codegen/src/common/mod.rs
+++ b/juniper_codegen/src/common/mod.rs
@@ -1,7 +1,32 @@
 //! Common functions, definitions and extensions for code generation, used by this crate.
 
 pub(crate) mod behavior;
+pub(crate) mod default;
+pub(crate) mod deprecation;
+mod description;
+pub(crate) mod diagnostic;
 pub(crate) mod field;
 pub(crate) mod gen;
 pub(crate) mod parse;
+pub(crate) mod rename;
 pub(crate) mod scalar;
+mod span_container;
+
+pub(crate) use self::{description::Description, span_container::SpanContainer};
+
+/// Checks whether the specified [`syn::Path`] equals to one-segment string
+/// `value`.
+pub(crate) fn path_eq_single(path: &syn::Path, value: &str) -> bool {
+    path.segments.len() == 1 && path.segments[0].ident == value
+}
+
+/// Filters the provided [`syn::Attribute`] to contain only ones with the
+/// specified `name`.
+pub(crate) fn filter_attrs<'a>(
+    name: &'a str,
+    attrs: &'a [syn::Attribute],
+) -> impl Iterator<Item = &'a syn::Attribute> + 'a {
+    attrs
+        .iter()
+        .filter(move |attr| path_eq_single(&attr.path, name))
+}
diff --git a/juniper_codegen/src/common/parse/attr.rs b/juniper_codegen/src/common/parse/attr.rs
index 9e42cc97..8b3eceec 100644
--- a/juniper_codegen/src/common/parse/attr.rs
+++ b/juniper_codegen/src/common/parse/attr.rs
@@ -4,7 +4,7 @@
 use proc_macro2::{Span, TokenStream};
 use syn::parse_quote;
 
-use crate::util::path_eq_single;
+use crate::common::path_eq_single;
 
 /// Prepends the given `attrs` collection with a new [`syn::Attribute`] generated from the given
 /// `attr_path` and `attr_args`.
@@ -49,7 +49,7 @@ pub(crate) mod err {
     pub(crate) fn unknown_arg<S: AsSpan>(span: S, name: &str) -> syn::Error {
         syn::Error::new(
             span.as_span(),
-            format!("unknown `{}` attribute argument", name),
+            format!("unknown `{name}` attribute argument"),
         )
     }
 
diff --git a/juniper_codegen/src/common/parse/downcaster.rs b/juniper_codegen/src/common/parse/downcaster.rs
index 89dd67cd..2a4e1369 100644
--- a/juniper_codegen/src/common/parse/downcaster.rs
+++ b/juniper_codegen/src/common/parse/downcaster.rs
@@ -1,8 +1,8 @@
 //! Common functions, definitions and extensions for parsing downcasting functions, used by GraphQL
 //! [interfaces][1] and [unions][2] definitions to downcast its type to a concrete implementer type.
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-//! [2]: https://spec.graphql.org/June2018/#sec-Unions
+//! [1]: https://spec.graphql.org/October2021#sec-Interfaces
+//! [2]: https://spec.graphql.org/October2021#sec-Unions
 
 use proc_macro2::Span;
 use syn::{ext::IdentExt as _, spanned::Spanned as _};
diff --git a/juniper_codegen/src/common/parse/mod.rs b/juniper_codegen/src/common/parse/mod.rs
index eaa946d9..53781675 100644
--- a/juniper_codegen/src/common/parse/mod.rs
+++ b/juniper_codegen/src/common/parse/mod.rs
@@ -4,11 +4,7 @@
 pub(crate) mod attr;
 pub(crate) mod downcaster;
 
-use std::{
-    any::TypeId,
-    iter::{self, FromIterator as _},
-    mem,
-};
+use std::{any::TypeId, iter, mem};
 
 use proc_macro2::Span;
 use quote::quote;
diff --git a/juniper_codegen/src/common/rename.rs b/juniper_codegen/src/common/rename.rs
new file mode 100644
index 00000000..d7c0cac9
--- /dev/null
+++ b/juniper_codegen/src/common/rename.rs
@@ -0,0 +1,164 @@
+//! Common functions, definitions and extensions for parsing and code generation
+//! of `#[graphql(rename_all = ...)]` attribute.
+
+use std::str::FromStr;
+
+use syn::parse::{Parse, ParseStream};
+
+/// Possible ways to rename all [GraphQL fields][1] or [GrqphQL enum values][2].
+///
+/// [1]: https://spec.graphql.org/October2021#sec-Language.Fields
+/// [2]: https://spec.graphql.org/October2021#sec-Enum-Value
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub(crate) enum Policy {
+    /// Do nothing, and use the default conventions renaming.
+    None,
+
+    /// Rename in `camelCase` style.
+    CamelCase,
+
+    /// Rename in `SCREAMING_SNAKE_CASE` style.
+    ScreamingSnakeCase,
+}
+
+impl Policy {
+    /// Applies this [`Policy`] to the given `name`.
+    pub(crate) fn apply(&self, name: &str) -> String {
+        match self {
+            Self::None => name.into(),
+            Self::CamelCase => to_camel_case(name),
+            Self::ScreamingSnakeCase => to_upper_snake_case(name),
+        }
+    }
+}
+
+impl FromStr for Policy {
+    type Err = ();
+
+    fn from_str(rule: &str) -> Result<Self, Self::Err> {
+        match rule {
+            "none" => Ok(Self::None),
+            "camelCase" => Ok(Self::CamelCase),
+            "SCREAMING_SNAKE_CASE" => Ok(Self::ScreamingSnakeCase),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryFrom<syn::LitStr> for Policy {
+    type Error = syn::Error;
+
+    fn try_from(lit: syn::LitStr) -> syn::Result<Self> {
+        Self::from_str(&lit.value())
+            .map_err(|_| syn::Error::new(lit.span(), "unknown renaming policy"))
+    }
+}
+
+impl Parse for Policy {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        Self::try_from(input.parse::<syn::LitStr>()?)
+    }
+}
+
+// NOTE: duplicated from juniper crate!
+fn to_camel_case(s: &str) -> String {
+    let mut dest = String::new();
+
+    // Handle `_` and `__` to be more friendly with the `_var` convention for
+    // unused variables, and GraphQL introspection identifiers.
+    let s_iter = if let Some(s) = s.strip_prefix("__") {
+        dest.push_str("__");
+        s
+    } else {
+        s.strip_prefix('_').unwrap_or(s)
+    }
+    .split('_')
+    .enumerate();
+
+    for (i, part) in s_iter {
+        if i > 0 && part.len() == 1 {
+            dest.push_str(&part.to_uppercase());
+        } else if i > 0 && part.len() > 1 {
+            let first = part
+                .chars()
+                .next()
+                .unwrap()
+                .to_uppercase()
+                .collect::<String>();
+            let second = &part[1..];
+
+            dest.push_str(&first);
+            dest.push_str(second);
+        } else if i == 0 {
+            dest.push_str(part);
+        }
+    }
+
+    dest
+}
+
+fn to_upper_snake_case(s: &str) -> String {
+    let mut last_lower = false;
+    let mut upper = String::new();
+    for c in s.chars() {
+        if c == '_' {
+            last_lower = false;
+        } else if c.is_lowercase() {
+            last_lower = true;
+        } else if c.is_uppercase() {
+            if last_lower {
+                upper.push('_');
+            }
+            last_lower = false;
+        }
+
+        for u in c.to_uppercase() {
+            upper.push(u);
+        }
+    }
+    upper
+}
+
+#[cfg(test)]
+mod to_camel_case_tests {
+    use super::to_camel_case;
+
+    #[test]
+    fn converts_correctly() {
+        for (input, expected) in [
+            ("test", "test"),
+            ("_test", "test"),
+            ("__test", "__test"),
+            ("first_second", "firstSecond"),
+            ("first_", "first"),
+            ("a_b_c", "aBC"),
+            ("a_bc", "aBc"),
+            ("a_b", "aB"),
+            ("a", "a"),
+            ("", ""),
+        ] {
+            assert_eq!(to_camel_case(input), expected);
+        }
+    }
+}
+
+#[cfg(test)]
+mod to_upper_snake_case_tests {
+    use super::to_upper_snake_case;
+
+    #[test]
+    fn converts_correctly() {
+        for (input, expected) in [
+            ("abc", "ABC"),
+            ("a_bc", "A_BC"),
+            ("ABC", "ABC"),
+            ("A_BC", "A_BC"),
+            ("SomeInput", "SOME_INPUT"),
+            ("someInput", "SOME_INPUT"),
+            ("someINpuT", "SOME_INPU_T"),
+            ("some_INpuT", "SOME_INPU_T"),
+        ] {
+            assert_eq!(to_upper_snake_case(input), expected);
+        }
+    }
+}
diff --git a/juniper_codegen/src/util/span_container.rs b/juniper_codegen/src/common/span_container.rs
similarity index 77%
rename from juniper_codegen/src/util/span_container.rs
rename to juniper_codegen/src/common/span_container.rs
index 8b4c6b58..bb27a03b 100644
--- a/juniper_codegen/src/util/span_container.rs
+++ b/juniper_codegen/src/common/span_container.rs
@@ -6,8 +6,8 @@ use std::{
 use proc_macro2::{Span, TokenStream};
 use quote::ToTokens;
 
-#[derive(Clone, Debug)]
-pub struct SpanContainer<T> {
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct SpanContainer<T> {
     expr: Option<Span>,
     ident: Span,
     val: T,
@@ -20,15 +20,15 @@ impl<T: ToTokens> ToTokens for SpanContainer<T> {
 }
 
 impl<T> SpanContainer<T> {
-    pub fn new(ident: Span, expr: Option<Span>, val: T) -> Self {
+    pub(crate) fn new(ident: Span, expr: Option<Span>, val: T) -> Self {
         Self { expr, ident, val }
     }
 
-    pub fn span_ident(&self) -> Span {
+    pub(crate) fn span_ident(&self) -> Span {
         self.ident
     }
 
-    pub fn span_joined(&self) -> Span {
+    pub(crate) fn span_joined(&self) -> Span {
         if let Some(s) = self.expr {
             // TODO: Use `Span::join` once stabilized and available on stable:
             //       https://github.com/rust-lang/rust/issues/54725
@@ -41,17 +41,9 @@ impl<T> SpanContainer<T> {
         }
     }
 
-    pub fn into_inner(self) -> T {
+    pub(crate) fn into_inner(self) -> T {
         self.val
     }
-
-    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> SpanContainer<U> {
-        SpanContainer {
-            expr: self.expr,
-            ident: self.ident,
-            val: f(self.val),
-        }
-    }
 }
 
 impl<T> AsRef<T> for SpanContainer<T> {
diff --git a/juniper_codegen/src/derive_input_object.rs b/juniper_codegen/src/derive_input_object.rs
deleted file mode 100644
index 48d63dbc..00000000
--- a/juniper_codegen/src/derive_input_object.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-#![allow(clippy::match_wild_err_arm)]
-use crate::{
-    result::{GraphQLScope, UnsupportedAttribute},
-    util::{self, span_container::SpanContainer, RenameRule},
-};
-use proc_macro2::TokenStream;
-use quote::{quote, ToTokens};
-use syn::{self, ext::IdentExt, spanned::Spanned, Data, Fields};
-
-pub fn impl_input_object(ast: syn::DeriveInput, error: GraphQLScope) -> syn::Result<TokenStream> {
-    let ast_span = ast.span();
-    let fields = match ast.data {
-        Data::Struct(data) => match data.fields {
-            Fields::Named(named) => named.named,
-            _ => {
-                return Err(
-                    error.custom_error(ast_span, "all fields must be named, e.g., `test: String`")
-                )
-            }
-        },
-        _ => return Err(error.custom_error(ast_span, "can only be used on structs with fields")),
-    };
-
-    // Parse attributes.
-    let attrs = util::ObjectAttributes::from_attrs(&ast.attrs)?;
-
-    // Parse attributes.
-    let ident = &ast.ident;
-    let name = attrs
-        .name
-        .clone()
-        .map(SpanContainer::into_inner)
-        .unwrap_or_else(|| ident.to_string());
-
-    let fields = fields
-        .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(e) => {
-                    proc_macro_error::emit_error!(e);
-                    return None;
-                }
-            };
-
-            let field_ident = field.ident.as_ref().unwrap();
-            let name = match field_attrs.name {
-                Some(ref name) => name.to_string(),
-                None => attrs
-                    .rename
-                    .unwrap_or(RenameRule::CamelCase)
-                    .apply(&field_ident.unraw().to_string()),
-            };
-
-            if let Some(span) = field_attrs.skip {
-                error.unsupported_attribute_within(span.span(), UnsupportedAttribute::Skip)
-            }
-
-            if let Some(span) = field_attrs.deprecation {
-                error.unsupported_attribute_within(
-                    span.span_ident(),
-                    UnsupportedAttribute::Deprecation,
-                )
-            }
-
-            if name.starts_with("__") {
-                error.no_double_underscore(if let Some(name) = field_attrs.name {
-                    name.span_ident()
-                } else {
-                    name.span()
-                });
-            }
-
-            let resolver_code = quote!(#field_ident);
-
-            let default = field_attrs
-                .default
-                .map(|default| match default.into_inner() {
-                    Some(expr) => expr.into_token_stream(),
-                    None => quote! { Default::default() },
-                });
-
-            Some(util::GraphQLTypeDefinitionField {
-                name,
-                _type: field.ty,
-                args: Vec::new(),
-                description: field_attrs.description.map(SpanContainer::into_inner),
-                deprecation: None,
-                resolver_code,
-                is_type_inferred: true,
-                is_async: false,
-                default,
-                span,
-            })
-        })
-        .collect::<Vec<_>>();
-
-    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(duplicates) =
-        crate::util::duplicate::Duplicate::find_by_key(&fields, |field| field.name.as_str())
-    {
-        error.duplicate(duplicates.iter());
-    }
-
-    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: attrs.scalar.map(SpanContainer::into_inner),
-        description: attrs.description.map(SpanContainer::into_inner),
-        fields,
-        generics: ast.generics,
-        interfaces: vec![],
-        include_type_generics: true,
-        generic_scalar: true,
-        no_async: attrs.no_async.is_some(),
-    };
-
-    Ok(definition.into_input_object_tokens())
-}
diff --git a/juniper_codegen/src/graphql_enum/derive.rs b/juniper_codegen/src/graphql_enum/derive.rs
index c386827b..05b727ca 100644
--- a/juniper_codegen/src/graphql_enum/derive.rs
+++ b/juniper_codegen/src/graphql_enum/derive.rs
@@ -1,20 +1,17 @@
 //! Code generation for `#[derive(GraphQLEnum)]` macro.
 
+use std::collections::HashSet;
+
 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 crate::common::{diagnostic, rename, scalar, SpanContainer};
 
 use super::{ContainerAttr, Definition, ValueDefinition, VariantAttr};
 
-/// [`GraphQLScope`] of errors for `#[derive(GraphQLEnum)]` macro.
-const ERR: GraphQLScope = GraphQLScope::EnumDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLEnum)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::EnumDerive;
 
 /// Expands `#[derive(GraphQLEnum)]` macro into generated code.
 pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
@@ -31,7 +28,7 @@ pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
     let renaming = attr
         .rename_values
         .map(SpanContainer::into_inner)
-        .unwrap_or(RenameRule::ScreamingSnakeCase);
+        .unwrap_or(rename::Policy::ScreamingSnakeCase);
     let values = data
         .variants
         .iter()
@@ -79,8 +76,6 @@ pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         .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();
@@ -89,7 +84,7 @@ pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         ident: ast.ident,
         generics: ast.generics,
         name,
-        description,
+        description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
         behavior: attr.behavior.into(),
@@ -103,7 +98,7 @@ pub(crate) fn expand(input: TokenStream) -> syn::Result<TokenStream> {
 /// 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<ValueDefinition> {
+fn parse_value(v: &syn::Variant, renaming: rename::Policy) -> Option<ValueDefinition> {
     let attr = VariantAttr::from_attrs("graphql", &v.attrs)
         .map_err(|e| proc_macro_error::emit_error!(e))
         .ok()?;
@@ -124,19 +119,11 @@ fn parse_value(v: &syn::Variant, renaming: RenameRule) -> Option<ValueDefinition
         )
         .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,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
     })
 }
 
diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs
index ae1b2322..85e22be0 100644
--- a/juniper_codegen/src/graphql_enum/mod.rs
+++ b/juniper_codegen/src/graphql_enum/mod.rs
@@ -4,8 +4,6 @@
 
 pub(crate) mod derive;
 
-use std::convert::TryInto as _;
-
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, ToTokens};
 use syn::{
@@ -16,22 +14,17 @@ use syn::{
     token,
 };
 
-use crate::{
-    common::{
-        behavior,
-        parse::{
-            attr::{err, OptionExt as _},
-            ParseBufferExt as _,
-        },
-        scalar,
-    },
-    util::{
-        filter_attrs, get_deprecated, get_doc_comment, span_container::SpanContainer, RenameRule,
+use crate::common::{
+    behavior, deprecation, filter_attrs,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _,
     },
+    rename, scalar, Description, SpanContainer,
 };
 
 /// Available arguments behind `#[graphql]` attribute placed on a Rust enum
-/// definition, when generating code for a [GraphQL enum][0] type.
+/// definition, when generating code for a [GraphQL enum][0].
 ///
 /// [0]: https://spec.graphql.org/October2021#sec-Enums
 #[derive(Debug, Default)]
@@ -45,12 +38,12 @@ struct ContainerAttr {
 
     /// Explicitly specified [description][2] of this [GraphQL enum][0].
     ///
-    /// If [`None`], then Rust doc comment will be used as [description][2], if
-    /// any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
-    description: Option<SpanContainer<String>>,
+    description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified type of [`Context`] to use for resolving this
     /// [GraphQL enum][0] type with.
@@ -83,15 +76,15 @@ struct ContainerAttr {
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     behavior: Option<SpanContainer<behavior::Type>>,
 
-    /// Explicitly specified [`RenameRule`] for all [values][1] of this
+    /// Explicitly specified [`rename::Policy`] for all [values][1] of this
     /// [GraphQL enum][0].
     ///
-    /// If [`None`], then the [`RenameRule::ScreamingSnakeCase`] rule will be
+    /// If [`None`], then the [`rename::Policy::ScreamingSnakeCase`] will be
     /// applied by default.
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     /// [1]: https://spec.graphql.org/October2021#EnumValuesDefinition
-    rename_values: Option<SpanContainer<RenameRule>>,
+    rename_values: Option<SpanContainer<rename::Policy>>,
 
     /// Indicator whether the generated code is intended to be used only inside
     /// the [`juniper`] library.
@@ -117,13 +110,9 @@ impl Parse for ContainerAttr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "ctx" | "context" | "Context" => {
@@ -194,7 +183,7 @@ impl ContainerAttr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs);
+            attr.description = Description::parse_from_doc_attrs(attrs)?;
         }
 
         Ok(attr)
@@ -210,30 +199,29 @@ impl ContainerAttr {
 struct VariantAttr {
     /// Explicitly specified name of this [GraphQL enum value][1].
     ///
-    /// If [`None`], then Rust enum variant's name is used by default.
+    /// If [`None`], then Rust enum variant's name will be used by default.
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value
     name: Option<SpanContainer<String>>,
 
     /// Explicitly specified [description][2] of this [GraphQL enum value][1].
     ///
-    /// If [`None`], then Rust doc comment is used as [description][2], if any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value
     /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
-    description: Option<SpanContainer<String>>,
+    description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified [deprecation][2] of this [GraphQL enum value][1].
     ///
-    /// If [`None`], then Rust `#[deprecated]` attribute is used as the
+    /// If [`None`], then Rust `#[deprecated]` attribute will be 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<SpanContainer<Option<syn::LitStr>>>,
+    deprecated: Option<SpanContainer<deprecation::Directive>>,
 
     /// Explicitly specified marker for the Rust enum variant to be ignored and
     /// not included into the code generated for a [GraphQL enum][0]
@@ -262,26 +250,18 @@ impl Parse for VariantAttr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "deprecated" => {
-                    let mut reason = None;
-                    if input.is_next::<token::Eq>() {
-                        input.parse::<token::Eq>()?;
-                        reason = Some(input.parse::<syn::LitStr>()?);
-                    }
+                    let directive = input.parse::<deprecation::Directive>()?;
                     out.deprecated
                         .replace(SpanContainer::new(
                             ident.span(),
-                            reason.as_ref().map(|r| r.span()),
-                            reason,
+                            directive.reason.as_ref().map(|r| r.span()),
+                            directive,
                         ))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
@@ -319,14 +299,11 @@ impl VariantAttr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs);
+            attr.description = Description::parse_from_doc_attrs(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)))
-            });
+            attr.deprecated = deprecation::Directive::parse_from_deprecated_attr(attrs)?;
         }
 
         Ok(attr)
@@ -354,18 +331,14 @@ struct ValueDefinition {
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Enum-Value
     /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
-    description: Option<Box<str>>,
+    description: Option<Description>,
 
     /// [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<Option<Box<str>>>,
+    deprecated: Option<deprecation::Directive>,
 }
 
 /// Representation of a [GraphQL enum][0] for code generation.
@@ -377,8 +350,9 @@ struct Definition {
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     ident: syn::Ident,
 
-    /// [`syn::Generics`] of the Rust enum behind this [GraphQL enum][0].
+    /// [`Generics`] of the Rust enum behind this [GraphQL enum][0].
     ///
+    /// [`Generics`]: syn::Generics
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     generics: syn::Generics,
 
@@ -391,7 +365,7 @@ struct Definition {
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Enums
     /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
-    description: Option<Box<str>>,
+    description: Option<Description>,
 
     /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
     /// for this [GraphQL enum][0].
@@ -468,13 +442,13 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::IsInputType<#scalar>
-                for #ident#ty_generics
+            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
+            impl #impl_generics ::juniper::marker::IsOutputType<#scalar>
+                for #ident #ty_generics
                 #where_clause {}
         }
     }
@@ -500,7 +474,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_input_type() {}
@@ -529,7 +503,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_output_type() {}
@@ -558,7 +532,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::Enum<#lt, #inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::Enum<#lt, #inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_enum() {}
@@ -580,44 +554,24 @@ impl Definition {
         let (_, ty_generics, _) = self.generics.split_for_impl();
 
         let name = &self.name;
-        let description = self
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
+        let description = &self.description;
 
         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))
-                        )
-                    }
-                }
-            };
+            let v_name = &v.name;
+            let v_description = &v.description;
+            let v_deprecation = &v.deprecated;
 
             quote! {
-                ::juniper::meta::EnumValue {
-                    name: String::from(#name),
-                    description: #description,
-                    deprecation_status: #deprecation_status,
-                }
+                ::juniper::meta::EnumValue::new(#v_name)
+                    #v_description
+                    #v_deprecation
             }
         });
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLType<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::GraphQLType<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 fn name(_ : &Self::TypeInfo) -> Option<&'static str> {
@@ -632,7 +586,7 @@ impl Definition {
                 {
                     let variants = [#( #variants_meta ),*];
 
-                    registry.build_enum_type::<#ident#ty_generics>(info, &variants)
+                    registry.build_enum_type::<#ident #ty_generics>(info, &variants)
                         #description
                         .into_meta()
                 }
@@ -659,24 +613,12 @@ impl Definition {
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let description = self
-            .description
-            .as_ref()
-            .map(|text| quote! { .description(#text) });
+        let description = &self.description;
 
         let values_meta = self.values.iter().map(|v| {
             let v_name = &v.name;
-            let v_description = v
-                .description
-                .as_ref()
-                .map(|text| quote! { .description(#text) });
-            let v_deprecation = v.deprecated.as_ref().map(|depr| {
-                let reason = depr.as_ref().map_or_else(
-                    || quote! { ::std::option::Option::None },
-                    |text| quote! { ::std::option::Option::Some(#text) },
-                );
-                quote! { .deprecated(#reason) }
-            });
+            let v_description = &v.description;
+            let v_deprecation = &v.deprecated;
 
             quote! {
                 ::juniper::meta::EnumValue::new(#v_name)
@@ -687,7 +629,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
                 #where_clause
             {
                 fn meta<'__r, '__ti: '__r>(
@@ -702,7 +644,7 @@ impl Definition {
                     registry.register_enum_with::<
                         ::juniper::behavior::Coerce<Self>, _, _,
                     >(&values, type_info, |meta| {
-                        meta#description
+                        meta #description
                     })
                 }
             }
@@ -722,7 +664,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
                 #where_clause
             {
                 fn type_name(_: &#inf) -> &'static str {
@@ -764,8 +706,8 @@ impl Definition {
         });
 
         quote! {
-            impl#impl_generics ::juniper::GraphQLValue<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::GraphQLValue<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 type Context = #context;
@@ -830,7 +772,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn resolve_value(
@@ -862,8 +804,8 @@ impl Definition {
         let (_, ty_generics, _) = self.generics.split_for_impl();
 
         quote! {
-            impl#impl_generics ::juniper::GraphQLValueAsync<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 fn resolve_async<'__a>(
@@ -901,7 +843,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn resolve_value_async<'__r>(
@@ -944,8 +886,8 @@ impl Definition {
         });
 
         quote! {
-            impl#impl_generics ::juniper::FromInputValue<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::FromInputValue<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 type Error = ::std::string::String;
@@ -987,8 +929,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh>
+                for #ty #where_clause
             {
                 type Error = ::std::string::String;
 
@@ -1040,8 +982,8 @@ impl Definition {
         });
 
         quote! {
-            impl#impl_generics ::juniper::ToInputValue<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::ToInputValue<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
@@ -1088,7 +1030,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
@@ -1118,23 +1060,23 @@ impl Definition {
         let (_, ty_generics, _) = self.generics.split_for_impl();
 
         quote! {
-            impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar>
-                for #ident#ty_generics
+            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
+            impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 const NAMES: ::juniper::macros::reflect::Types =
                     &[<Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME];
             }
 
-            impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
-                for #ident#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
+                for #ident #ty_generics
                 #where_clause
             {
                 const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
@@ -1159,14 +1101,14 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
@@ -1174,7 +1116,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -1215,14 +1157,14 @@ impl Definition {
                 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);
+                    lt.lifetime.ident = format_ident!("__fa__{ident}");
                 }
 
                 let lifetimes = generics.lifetimes().map(|lt| &lt.lifetime);
                 let ident = &self.ident;
                 let (_, ty_generics, _) = generics.split_for_impl();
 
-                quote! { for<#( #lifetimes ),*> #ident#ty_generics }
+                quote! { for<#( #lifetimes ),*> #ident #ty_generics }
             } else {
                 quote! { Self }
             };
@@ -1249,7 +1191,7 @@ impl Definition {
         let ty = {
             let ident = &self.ident;
             let (_, ty_gen, _) = generics.split_for_impl();
-            parse_quote! { #ident#ty_gen }
+            parse_quote! { #ident #ty_gen }
         };
         (ty, generics)
     }
diff --git a/juniper_codegen/src/graphql_input_object/derive.rs b/juniper_codegen/src/graphql_input_object/derive.rs
new file mode 100644
index 00000000..370fc200
--- /dev/null
+++ b/juniper_codegen/src/graphql_input_object/derive.rs
@@ -0,0 +1,129 @@
+//! Code generation for `#[derive(GraphQLInputObject)]` macro.
+
+use std::collections::HashSet;
+
+use proc_macro2::TokenStream;
+use quote::ToTokens as _;
+use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned};
+
+use crate::common::{diagnostic, rename, scalar, SpanContainer};
+
+use super::{ContainerAttr, Definition, FieldAttr, FieldDefinition};
+
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLInputObject)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::InputObjectDerive;
+
+/// Expands `#[derive(GraphQLInputObject)]` macro into generated code.
+pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
+    let ast = syn::parse2::<syn::DeriveInput>(input)?;
+    let attr = ContainerAttr::from_attrs("graphql", &ast.attrs)?;
+
+    let data = if let syn::Data::Struct(data) = &ast.data {
+        data
+    } else {
+        return Err(ERR.custom_error(ast.span(), "can only be derived on structs"));
+    };
+
+    let renaming = attr
+        .rename_fields
+        .map(SpanContainer::into_inner)
+        .unwrap_or(rename::Policy::CamelCase);
+
+    let is_internal = attr.is_internal;
+    let fields = data
+        .fields
+        .iter()
+        .filter_map(|f| parse_field(f, renaming, is_internal))
+        .collect::<Vec<_>>();
+
+    proc_macro_error::abort_if_dirty();
+
+    if !fields.iter().any(|f| !f.ignored) {
+        return Err(ERR.custom_error(data.fields.span(), "expected at least 1 non-ignored field"));
+    }
+
+    let unique_fields = fields.iter().map(|v| &v.name).collect::<HashSet<_>>();
+    if unique_fields.len() != fields.len() {
+        return Err(ERR.custom_error(
+            data.fields.span(),
+            "expected all fields 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 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: attr.description.map(SpanContainer::into_inner),
+        context,
+        scalar,
+        fields,
+    };
+
+    Ok(definition.into_token_stream())
+}
+
+/// Parses a [`FieldDefinition`] from the given struct field definition.
+///
+/// Returns [`None`] if the parsing fails.
+fn parse_field(
+    f: &syn::Field,
+    renaming: rename::Policy,
+    is_internal: bool,
+) -> Option<FieldDefinition> {
+    let field_attr = FieldAttr::from_attrs("graphql", &f.attrs)
+        .map_err(|e| proc_macro_error::emit_error!(e))
+        .ok()?;
+
+    let ident = f.ident.as_ref().or_else(|| err_unnamed_field(f))?;
+
+    let name = field_attr
+        .name
+        .map_or_else(
+            || renaming.apply(&ident.unraw().to_string()),
+            SpanContainer::into_inner,
+        )
+        .into_boxed_str();
+    if !is_internal && name.starts_with("__") {
+        ERR.no_double_underscore(f.span());
+    }
+
+    Some(FieldDefinition {
+        ident: ident.clone(),
+        ty: f.ty.clone(),
+        default: field_attr.default.map(SpanContainer::into_inner),
+        name,
+        description: field_attr.description.map(SpanContainer::into_inner),
+        ignored: field_attr.ignore.is_some(),
+    })
+}
+
+/// Emits "expected named struct field" [`syn::Error`] pointing to the given
+/// `span`.
+pub(crate) fn err_unnamed_field<T, S: Spanned>(span: &S) -> Option<T> {
+    ERR.emit_custom(span.span(), "expected named struct field");
+    None
+}
diff --git a/juniper_codegen/src/graphql_input_object/mod.rs b/juniper_codegen/src/graphql_input_object/mod.rs
new file mode 100644
index 00000000..93c21d6f
--- /dev/null
+++ b/juniper_codegen/src/graphql_input_object/mod.rs
@@ -0,0 +1,778 @@
+//! Code generation for [GraphQL input objects][0].
+//!
+//! [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+
+pub(crate) mod derive;
+
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens};
+use syn::{
+    ext::IdentExt as _,
+    parse::{Parse, ParseStream},
+    parse_quote,
+    spanned::Spanned,
+    token,
+};
+
+use crate::common::{
+    default, filter_attrs,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _,
+    },
+    rename, scalar, Description, SpanContainer,
+};
+
+/// Available arguments behind `#[graphql]` attribute placed on a Rust struct
+/// definition, when generating code for a [GraphQL input object][0].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+#[derive(Debug, Default)]
+struct ContainerAttr {
+    /// Explicitly specified name of this [GraphQL input object][0].
+    ///
+    /// If [`None`], then Rust struct name will be used by default.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    name: Option<SpanContainer<String>>,
+
+    /// Explicitly specified [description][2] of this [GraphQL input object][0].
+    ///
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<SpanContainer<Description>>,
+
+    /// Explicitly specified type of [`Context`] to use for resolving this
+    /// [GraphQL input object][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-Input-Objects
+    context: Option<SpanContainer<syn::Type>>,
+
+    /// Explicitly specified type (or type parameter with its bounds) of
+    /// [`ScalarValue`] to use for resolving this [GraphQL input object][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-Input-Objects
+    scalar: Option<SpanContainer<scalar::AttrValue>>,
+
+    /// Explicitly specified [`rename::Policy`] for all fields of this
+    /// [GraphQL input object][0].
+    ///
+    /// If [`None`], then the [`rename::Policy::CamelCase`] will be applied by
+    /// default.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    rename_fields: Option<SpanContainer<rename::Policy>>,
+
+    /// 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<Self> {
+        let mut out = Self::default();
+        while !input.is_empty() {
+            let ident = input.parse_any_ident()?;
+            match ident.to_string().as_str() {
+                "name" => {
+                    input.parse::<token::Eq>()?;
+                    let name = input.parse::<syn::LitStr>()?;
+                    out.name
+                        .replace(SpanContainer::new(
+                            ident.span(),
+                            Some(name.span()),
+                            name.value(),
+                        ))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "desc" | "description" => {
+                    input.parse::<token::Eq>()?;
+                    let desc = input.parse::<Description>()?;
+                    out.description
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "ctx" | "context" | "Context" => {
+                    input.parse::<token::Eq>()?;
+                    let ctx = input.parse::<syn::Type>()?;
+                    out.context
+                        .replace(SpanContainer::new(ident.span(), Some(ctx.span()), ctx))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "scalar" | "Scalar" | "ScalarValue" => {
+                    input.parse::<token::Eq>()?;
+                    let scl = input.parse::<scalar::AttrValue>()?;
+                    out.scalar
+                        .replace(SpanContainer::new(ident.span(), Some(scl.span()), scl))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "rename_all" => {
+                    input.parse::<token::Eq>()?;
+                    let val = input.parse::<syn::LitStr>()?;
+                    out.rename_fields
+                        .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::<token::Comma>()?;
+        }
+        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<Self> {
+        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_fields: try_merge_opt!(rename_fields: self, another),
+            is_internal: self.is_internal || another.is_internal,
+        })
+    }
+
+    /// Parses [`ContainerAttr`] from the given multiple `name`d
+    /// [`syn::Attribute`]s placed on a struct or impl block definition.
+    pub(crate) fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result<Self> {
+        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 = Description::parse_from_doc_attrs(attrs)?;
+        }
+
+        Ok(attr)
+    }
+}
+
+/// Available arguments behind `#[graphql]` attribute when generating code for
+/// [GraphQL input object][0]'s [field][1].
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+/// [1]: https://spec.graphql.org/October2021#InputFieldsDefinition
+#[derive(Debug, Default)]
+struct FieldAttr {
+    /// Explicitly specified name of this [GraphQL input object field][1].
+    ///
+    /// If [`None`], then Rust struct field name will be used by default.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    name: Option<SpanContainer<String>>,
+
+    /// Explicitly specified [default value][2] of this
+    /// [GraphQL input object field][1] to be used used in case a field value is
+    /// not provided.
+    ///
+    /// If [`None`], the this [field][1] will have no [default value][2].
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [2]: https://spec.graphql.org/October2021#DefaultValue
+    default: Option<SpanContainer<default::Value>>,
+
+    /// Explicitly specified [description][2] of this
+    /// [GraphQL input object field][1].
+    ///
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<SpanContainer<Description>>,
+
+    /// Explicitly specified marker for the Rust struct field to be ignored and
+    /// not included into the code generated for a [GraphQL input object][0]
+    /// implementation.
+    ///
+    /// Ignored Rust struct fields still consider the [`default`] attribute's
+    /// argument.
+    ///
+    /// [`default`]: Self::default
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    ignore: Option<SpanContainer<syn::Ident>>,
+}
+
+impl Parse for FieldAttr {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let mut out = Self::default();
+        while !input.is_empty() {
+            let ident = input.parse_any_ident()?;
+            match ident.to_string().as_str() {
+                "name" => {
+                    input.parse::<token::Eq>()?;
+                    let name = input.parse::<syn::LitStr>()?;
+                    out.name
+                        .replace(SpanContainer::new(
+                            ident.span(),
+                            Some(name.span()),
+                            name.value(),
+                        ))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "default" => {
+                    let val = input.parse::<default::Value>()?;
+                    out.default
+                        .replace(SpanContainer::new(ident.span(), Some(val.span()), val))
+                        .none_or_else(|_| err::dup_arg(&ident))?
+                }
+                "desc" | "description" => {
+                    input.parse::<token::Eq>()?;
+                    let desc = input.parse::<Description>()?;
+                    out.description
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
+                        .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::<token::Comma>()?;
+        }
+        Ok(out)
+    }
+}
+
+impl FieldAttr {
+    /// Tries to merge two [`FieldAttr`]s into a single one, reporting about
+    /// duplicates, if any.
+    fn try_merge(self, mut another: Self) -> syn::Result<Self> {
+        Ok(Self {
+            name: try_merge_opt!(name: self, another),
+            default: try_merge_opt!(default: self, another),
+            description: try_merge_opt!(description: self, another),
+            ignore: try_merge_opt!(ignore: self, another),
+        })
+    }
+
+    /// Parses [`FieldAttr`] from the given multiple `name`d [`syn::Attribute`]s
+    /// placed on a trait definition.
+    fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> syn::Result<Self> {
+        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 = Description::parse_from_doc_attrs(attrs)?;
+        }
+
+        Ok(attr)
+    }
+}
+
+/// Representation of a [GraphQL input object field][1] for code generation.
+///
+/// [1]: https://spec.graphql.org/October2021#InputFieldsDefinition
+#[derive(Debug)]
+struct FieldDefinition {
+    /// [`Ident`] of the Rust struct field behind this
+    /// [GraphQL input object field][1].
+    ///
+    /// [`Ident`]: syn::Ident
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    ident: syn::Ident,
+
+    /// Rust type that this [GraphQL input object field][1] is represented with.
+    ///
+    /// It should contain all its generics, if any.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    ty: syn::Type,
+
+    /// [Default value][2] of this [GraphQL input object field][1] to be used in
+    /// case a [field][1] value is not provided.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [2]: https://spec.graphql.org/October2021#DefaultValue
+    default: Option<default::Value>,
+
+    /// Name of this [GraphQL input object field][1] in GraphQL schema.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    name: Box<str>,
+
+    /// [Description][2] of this [GraphQL input object field][1] to put into
+    /// GraphQL schema.
+    ///
+    /// [1]: https://spec.graphql.org/October2021#InputValueDefinition
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<Description>,
+
+    /// Indicator whether the Rust struct field behinds this
+    /// [GraphQL input object field][1] is being ignored and should not be
+    /// included into the generated code.
+    ///
+    /// Ignored Rust struct fields still consider the [`default`] attribute's
+    /// argument.
+    ///
+    /// [`default`]: Self::default
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    ignored: bool,
+}
+
+/// Representation of [GraphQL input object][0] for code generation.
+///
+/// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+#[derive(Debug)]
+struct Definition {
+    /// [`Ident`] of the Rust struct behind this [GraphQL input object][0].
+    ///
+    /// [`Ident`]: syn::Ident
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    ident: syn::Ident,
+
+    /// [`Generics`] of the Rust enum behind this [GraphQL input object][0].
+    ///
+    /// [`Generics`]: syn::Generics
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    generics: syn::Generics,
+
+    /// Name of this [GraphQL input object][0] in GraphQL schema.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    name: Box<str>,
+
+    /// [Description][2] of this [GraphQL input object][0] to put into GraphQL
+    /// schema.
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<Description>,
+
+    /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
+    /// for this [GraphQL input object][0].
+    ///
+    /// [`GraphQLType`]: juniper::GraphQLType
+    /// [`Context`]: juniper::Context
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    context: syn::Type,
+
+    /// [`ScalarValue`] parametrization to generate [`GraphQLType`]
+    /// implementation with for this [GraphQL input object][0].
+    ///
+    /// [`GraphQLType`]: juniper::GraphQLType
+    /// [`ScalarValue`]: juniper::ScalarValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    scalar: scalar::Type,
+
+    /// [Fields][1] of this [GraphQL input object][0].
+    ///
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    /// [1]: https://spec.graphql.org/October2021#InputFieldsDefinition
+    fields: Vec<FieldDefinition>,
+}
+
+impl ToTokens for Definition {
+    fn to_tokens(&self, into: &mut TokenStream) {
+        self.impl_input_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::IsInputType`] trait for
+    /// this [GraphQL input object][0].
+    ///
+    /// [`marker::IsInputType`]: juniper::marker::IsInputType
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    fn impl_input_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 assert_fields_input_values = self.fields.iter().filter_map(|f| {
+            let ty = &f.ty;
+
+            (!f.ignored).then(|| {
+                quote! {
+                    <#ty as ::juniper::marker::IsInputType<#scalar>>::mark();
+                }
+            })
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_generics ::juniper::marker::IsInputType<#scalar>
+                for #ident #ty_generics
+                #where_clause
+            {
+                fn mark() {
+                    #( #assert_fields_input_values )*
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`GraphQLType`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`GraphQLType`]: juniper::GraphQLType
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    fn impl_graphql_type_tokens(&self) -> TokenStream {
+        let ident = &self.ident;
+        let scalar = &self.scalar;
+        let name = &self.name;
+
+        let generics = self.impl_generics(false);
+        let (impl_generics, _, where_clause) = generics.split_for_impl();
+        let (_, ty_generics, _) = self.generics.split_for_impl();
+
+        let description = &self.description;
+
+        let fields = self.fields.iter().filter_map(|f| {
+            let ty = &f.ty;
+            let name = &f.name;
+
+            (!f.ignored).then(|| {
+                let arg = if let Some(default) = &f.default {
+                    quote! { .arg_with_default::<#ty>(#name, &#default, info) }
+                } else {
+                    quote! { .arg::<#ty>(#name, info) }
+                };
+                let description = &f.description;
+
+                quote! { registry #arg #description }
+            })
+        });
+
+        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 fields = [#( #fields ),*];
+                    registry
+                        .build_input_object_type::<#ident #ty_generics>(info, &fields)
+                        #description
+                        .into_meta()
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`GraphQLValue`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`GraphQLValue`]: juniper::GraphQLValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    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();
+
+        quote! {
+            #[automatically_derived]
+            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> {
+                    <Self as ::juniper::GraphQLType<#scalar>>::name(info)
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`GraphQLValueAsync`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    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! {
+            #[allow(non_snake_case)]
+            #[automatically_derived]
+            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar>
+                for #ident #ty_generics
+                #where_clause {}
+        }
+    }
+
+    /// Returns generated code implementing [`FromInputValue`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`FromInputValue`]: juniper::FromInputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    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 fields = self.fields.iter().map(|f| {
+            let ident = &f.ident;
+
+            let construct = if f.ignored {
+                f.default.as_ref().map_or_else(
+                    || {
+                        let expr = default::Value::default();
+                        quote! { #expr }
+                    },
+                    |expr| quote! { #expr },
+                )
+            } else {
+                let name = &f.name;
+
+                let fallback = f.default.as_ref().map_or_else(
+                    || {
+                        quote! {
+                            ::juniper::FromInputValue::<#scalar>::from_implicit_null()
+                                .map_err(::juniper::IntoFieldError::into_field_error)?
+                        }
+                    },
+                    |expr| quote! { #expr },
+                );
+
+                quote! {
+                    match obj.get(#name) {
+                        Some(v) => {
+                            ::juniper::FromInputValue::<#scalar>::from_input_value(v)
+                                .map_err(::juniper::IntoFieldError::into_field_error)?
+                        }
+                        None => { #fallback }
+                    }
+                }
+            };
+
+            quote! { #ident: { #construct }, }
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_generics ::juniper::FromInputValue<#scalar>
+                for #ident #ty_generics
+                #where_clause
+            {
+                type Error = ::juniper::FieldError<#scalar>;
+
+                fn from_input_value(
+                    value: &::juniper::InputValue<#scalar>,
+                ) -> Result<Self, Self::Error> {
+                    let obj = value
+                        .to_object_value()
+                        .ok_or_else(|| ::juniper::FieldError::<#scalar>::from(
+                            ::std::format!("Expected input object, found: {}", value))
+                        )?;
+
+                    Ok(#ident {
+                        #( #fields )*
+                    })
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`ToInputValue`] trait for this
+    /// [GraphQL input object][0].
+    ///
+    /// [`ToInputValue`]: juniper::ToInputValue
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    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 fields = self.fields.iter().filter_map(|f| {
+            let ident = &f.ident;
+            let name = &f.name;
+
+            (!f.ignored).then(|| {
+                quote! {
+                    (#name, ::juniper::ToInputValue::to_input_value(&self.#ident))
+                }
+            })
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_generics ::juniper::ToInputValue<#scalar>
+                for #ident #ty_generics
+                #where_clause
+            {
+                fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
+                    ::juniper::InputValue::object(
+                        #[allow(deprecated)]
+                        ::std::array::IntoIter::new([#( #fields ),*])
+                            .collect()
+                    )
+                }
+            }
+        }
+    }
+
+    /// Returns generated code implementing [`BaseType`], [`BaseSubTypes`] and
+    /// [`WrappedType`] traits for this [GraphQL input object][0].
+    ///
+    /// [`BaseSubTypes`]: juniper::macros::reflect::BaseSubTypes
+    /// [`BaseType`]: juniper::macros::reflect::BaseType
+    /// [`WrappedType`]: juniper::macros::reflect::WrappedType
+    /// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+    #[must_use]
+    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! {
+            #[automatically_derived]
+            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 =
+                    &[<Self as ::juniper::macros::reflect::BaseType<#scalar>>::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 struct.
+    ///
+    /// If `for_async` is `true`, then additional predicates are added to suit
+    /// the [`GraphQLAsyncValue`] trait (and similar) requirements.
+    ///
+    /// [`GraphQLAsyncValue`]: juniper::GraphQLAsyncValue
+    /// [`GraphQLType`]: juniper::GraphQLType
+    #[must_use]
+    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| &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 6d546411..16bf2fbc 100644
--- a/juniper_codegen/src/graphql_interface/attr.rs
+++ b/juniper_codegen/src/graphql_interface/attr.rs
@@ -6,20 +6,16 @@ use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned};
 
-use crate::{
-    common::{
-        field,
-        parse::{self, TypeExt as _},
-        scalar,
-    },
-    result::GraphQLScope,
-    util::{path_eq_single, span_container::SpanContainer, RenameRule},
+use crate::common::{
+    diagnostic, field,
+    parse::{self, TypeExt as _},
+    path_eq_single, rename, scalar, SpanContainer,
 };
 
 use super::{enum_idents, Attr, Definition};
 
-/// [`GraphQLScope`] of errors for `#[graphql_interface]` macro.
-const ERR: GraphQLScope = GraphQLScope::InterfaceAttr;
+/// [`diagnostic::Scope`] of errors for `#[graphql_interface]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::InterfaceAttr;
 
 /// Expands `#[graphql_interface]` macro into generated code.
 pub fn expand(attr_args: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
@@ -74,7 +70,7 @@ fn expand_on_trait(
         .rename_fields
         .as_deref()
         .copied()
-        .unwrap_or(RenameRule::CamelCase);
+        .unwrap_or(rename::Policy::CamelCase);
 
     let fields = ast
         .items
@@ -121,7 +117,7 @@ fn expand_on_trait(
         enum_ident,
         enum_alias_ident,
         name,
-        description: attr.description.map(|d| d.into_inner().into_boxed_str()),
+        description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
         behavior: attr.behavior.into(),
@@ -137,7 +133,7 @@ fn expand_on_trait(
             .map(SpanContainer::into_inner)
             .collect(),
         suppress_dead_code: None,
-        src_intra_doc_link: format!("trait@{}", trait_ident).into_boxed_str(),
+        src_intra_doc_link: format!("trait@{trait_ident}").into_boxed_str(),
     };
 
     Ok(quote! {
@@ -152,7 +148,7 @@ fn expand_on_trait(
 #[must_use]
 fn parse_trait_method(
     method: &mut syn::TraitItemMethod,
-    renaming: &RenameRule,
+    renaming: &rename::Policy,
 ) -> Option<field::Definition> {
     let method_ident = &method.sig.ident;
     let method_attrs = method.attrs.clone();
@@ -206,17 +202,11 @@ fn parse_trait_method(
     };
     ty.lifetimes_anonymized();
 
-    let description = attr.description.as_ref().map(|d| d.as_ref().value());
-    let deprecated = attr
-        .deprecated
-        .as_deref()
-        .map(|d| d.as_ref().map(syn::LitStr::value));
-
     Some(field::Definition {
         name,
         ty,
-        description,
-        deprecated,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
         ident: method_ident.clone(),
         behavior: attr.behavior.into(),
         arguments: Some(arguments),
@@ -269,7 +259,7 @@ fn expand_on_derive_input(
         .rename_fields
         .as_deref()
         .copied()
-        .unwrap_or(RenameRule::CamelCase);
+        .unwrap_or(rename::Policy::CamelCase);
 
     let fields = data
         .fields
@@ -310,7 +300,7 @@ fn expand_on_derive_input(
         enum_ident,
         enum_alias_ident,
         name,
-        description: attr.description.map(|d| d.into_inner().into_boxed_str()),
+        description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
         behavior: attr.behavior.into(),
@@ -326,7 +316,7 @@ fn expand_on_derive_input(
             .map(SpanContainer::into_inner)
             .collect(),
         suppress_dead_code: None,
-        src_intra_doc_link: format!("struct@{}", struct_ident).into_boxed_str(),
+        src_intra_doc_link: format!("struct@{struct_ident}").into_boxed_str(),
     };
 
     Ok(quote! {
@@ -340,7 +330,10 @@ fn expand_on_derive_input(
 ///
 /// Returns [`None`] if the parsing fails, or the struct field is ignored.
 #[must_use]
-fn parse_struct_field(field: &mut syn::Field, renaming: &RenameRule) -> Option<field::Definition> {
+fn parse_struct_field(
+    field: &mut syn::Field,
+    renaming: &rename::Policy,
+) -> Option<field::Definition> {
     let field_ident = field.ident.as_ref().or_else(|| err_unnamed_field(&field))?;
     let field_attrs = field.attrs.clone();
 
@@ -376,17 +369,11 @@ fn parse_struct_field(field: &mut syn::Field, renaming: &RenameRule) -> Option<f
     let mut ty = field.ty.clone();
     ty.lifetimes_anonymized();
 
-    let description = attr.description.as_ref().map(|d| d.as_ref().value());
-    let deprecated = attr
-        .deprecated
-        .as_deref()
-        .map(|d| d.as_ref().map(syn::LitStr::value));
-
     Some(field::Definition {
         name,
         ty,
-        description,
-        deprecated,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
         ident: field_ident.clone(),
         behavior: attr.behavior.into(),
         arguments: None,
diff --git a/juniper_codegen/src/graphql_interface/derive.rs b/juniper_codegen/src/graphql_interface/derive.rs
index 54262408..52f88792 100644
--- a/juniper_codegen/src/graphql_interface/derive.rs
+++ b/juniper_codegen/src/graphql_interface/derive.rs
@@ -4,16 +4,12 @@ use proc_macro2::TokenStream;
 use quote::ToTokens as _;
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned};
 
-use crate::{
-    common::{field, parse::TypeExt as _, scalar},
-    result::GraphQLScope,
-    util::{span_container::SpanContainer, RenameRule},
-};
+use crate::common::{diagnostic, field, parse::TypeExt as _, rename, scalar, SpanContainer};
 
 use super::{attr::err_unnamed_field, enum_idents, Attr, Definition};
 
-/// [`GraphQLScope`] of errors for `#[derive(GraphQLInterface)]` macro.
-const ERR: GraphQLScope = GraphQLScope::InterfaceDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLInterface)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::InterfaceDerive;
 
 /// Expands `#[derive(GraphQLInterface)]` macro into generated code.
 pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
@@ -52,7 +48,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         .rename_fields
         .as_deref()
         .copied()
-        .unwrap_or(RenameRule::CamelCase);
+        .unwrap_or(rename::Policy::CamelCase);
 
     let fields = data
         .fields
@@ -94,7 +90,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         enum_ident,
         enum_alias_ident,
         name,
-        description: attr.description.map(|d| d.into_inner().into_boxed_str()),
+        description: attr.description.map(SpanContainer::into_inner),
         context,
         scalar,
         behavior: attr.behavior.into(),
@@ -110,7 +106,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
             .map(SpanContainer::into_inner)
             .collect(),
         suppress_dead_code: Some((ast.ident.clone(), data.fields.clone())),
-        src_intra_doc_link: format!("struct@{}", struct_ident).into_boxed_str(),
+        src_intra_doc_link: format!("struct@{struct_ident}").into_boxed_str(),
     }
     .into_token_stream())
 }
@@ -119,7 +115,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
 ///
 /// Returns [`None`] if the parsing fails, or the struct field is ignored.
 #[must_use]
-fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Definition> {
+fn parse_field(field: &syn::Field, renaming: &rename::Policy) -> Option<field::Definition> {
     let field_ident = field.ident.as_ref().or_else(|| err_unnamed_field(&field))?;
 
     let attr = field::Attr::from_attrs("graphql", &field.attrs)
@@ -148,17 +144,11 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
     let mut ty = field.ty.clone();
     ty.lifetimes_anonymized();
 
-    let description = attr.description.as_ref().map(|d| d.as_ref().value());
-    let deprecated = attr
-        .deprecated
-        .as_deref()
-        .map(|d| d.as_ref().map(syn::LitStr::value));
-
     Some(field::Definition {
         name,
         ty,
-        description,
-        deprecated,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
         ident: field_ident.clone(),
         behavior: attr.behavior.into(),
         arguments: None,
diff --git a/juniper_codegen/src/graphql_interface/mod.rs b/juniper_codegen/src/graphql_interface/mod.rs
index b8c642c8..832531c2 100644
--- a/juniper_codegen/src/graphql_interface/mod.rs
+++ b/juniper_codegen/src/graphql_interface/mod.rs
@@ -1,11 +1,11 @@
 //! Code generation for [GraphQL interface][1].
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+//! [1]: https://spec.graphql.org/October2021#sec-Interfaces
 
 pub mod attr;
 pub mod derive;
 
-use std::{collections::HashSet, convert::TryInto as _};
+use std::collections::HashSet;
 
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, quote_spanned, ToTokens};
@@ -19,33 +19,30 @@ use syn::{
     visit::Visit,
 };
 
-use crate::{
-    common::{
-        behavior, field, gen,
-        parse::{
-            attr::{err, OptionExt as _},
-            GenericsExt as _, ParseBufferExt as _,
-        },
-        scalar,
+use crate::common::{
+    behavior, field, filter_attrs, gen,
+    parse::{
+        attr::{err, OptionExt as _},
+        GenericsExt as _, ParseBufferExt as _,
     },
-    util::{filter_attrs, get_doc_comment, span_container::SpanContainer, RenameRule},
+    rename, scalar, Description, SpanContainer,
 };
 
 /// Returns [`syn::Ident`]s for a generic enum deriving [`Clone`] and [`Copy`]
 /// on it and enum alias which generic arguments are filled with
 /// [GraphQL interface][1] implementers.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
 fn enum_idents(
     trait_ident: &syn::Ident,
     alias_ident: Option<&syn::Ident>,
 ) -> (syn::Ident, syn::Ident) {
     let enum_alias_ident = alias_ident
         .cloned()
-        .unwrap_or_else(|| format_ident!("{}Value", trait_ident.to_string()));
+        .unwrap_or_else(|| format_ident!("{trait_ident}Value"));
     let enum_ident = alias_ident.map_or_else(
-        || format_ident!("{}ValueEnum", trait_ident.to_string()),
-        |c| format_ident!("{}Enum", c.to_string()),
+        || format_ident!("{trait_ident}ValueEnum"),
+        |c| format_ident!("{c}Enum"),
     );
     (enum_ident, enum_alias_ident)
 }
@@ -54,23 +51,24 @@ fn enum_idents(
 /// trait or struct definition, when generating code for [GraphQL interface][1]
 /// type.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
 #[derive(Debug, Default)]
 struct Attr {
     /// Explicitly specified name of [GraphQL interface][1] type.
     ///
     /// If [`None`], then Rust trait name is used by default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     name: Option<SpanContainer<String>>,
 
     /// Explicitly specified [description][2] of [GraphQL interface][1] type.
     ///
-    /// If [`None`], then Rust doc comment is used as [description][2], if any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    description: Option<SpanContainer<String>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified identifier of the type alias of Rust enum type
     /// behind the trait or struct, being an actual implementation of a
@@ -78,14 +76,14 @@ struct Attr {
     ///
     /// If [`None`], then `{trait_name}Value` identifier will be used.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     r#enum: Option<SpanContainer<syn::Ident>>,
 
     /// 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
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Objects
     implemented_for: HashSet<SpanContainer<syn::TypePath>>,
 
     /// Explicitly specified [GraphQL interfaces, implemented][1] by this
@@ -101,7 +99,7 @@ struct Attr {
     /// If [`None`], then unit type `()` is assumed as a type of [`Context`].
     ///
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     context: Option<SpanContainer<syn::Type>>,
 
     /// Explicitly specified type (or type parameter with its bounds) of
@@ -115,7 +113,7 @@ struct Attr {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
     /// Explicitly specified type of the custom [`Behavior`] to parametrize this
@@ -136,13 +134,14 @@ struct Attr {
     /// it contains async methods.
     asyncness: Option<SpanContainer<syn::Ident>>,
 
-    /// Explicitly specified [`RenameRule`] for all fields of this
+    /// Explicitly specified [`rename::Policy`] for all fields of this
     /// [GraphQL interface][1] type.
     ///
-    /// If [`None`] then the default rule will be [`RenameRule::CamelCase`].
+    /// If [`None`], then the [`rename::Policy::CamelCase`] will be applied by
+    /// default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    rename_fields: Option<SpanContainer<RenameRule>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    rename_fields: Option<SpanContainer<rename::Policy>>,
 
     /// Indicator whether the generated code is intended to be used only inside
     /// the [`juniper`] library.
@@ -168,13 +167,9 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "ctx" | "context" | "Context" => {
@@ -286,7 +281,7 @@ impl Attr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs);
+            attr.description = Description::parse_from_doc_attrs(attrs)?;
         }
 
         Ok(attr)
@@ -295,18 +290,18 @@ impl Attr {
 
 /// Definition of [GraphQL interface][1] for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
 struct Definition {
     /// [`syn::Generics`] of the trait or struct describing the
     /// [GraphQL interface][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     generics: syn::Generics,
 
     /// [`syn::Visibility`] of the trait or struct describing the
     /// [GraphQL interface][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     vis: syn::Visibility,
 
     /// Name of the generic enum describing all [`implementers`]. It's generic
@@ -330,14 +325,14 @@ struct Definition {
     /// Description of this [GraphQL interface][0] to put into GraphQL schema.
     ///
     /// [0]: https://spec.graphql.org/October2021#sec-Interfaces
-    description: Option<Box<str>>,
+    description: Option<Description>,
 
     /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
     /// for this [GraphQL interface][1].
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     context: syn::Type,
 
     /// [`ScalarValue`] parametrization to generate [`GraphQLType`]
@@ -345,7 +340,7 @@ struct Definition {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     scalar: scalar::Type,
 
     /// [`Behavior`] parametrization to generate code with for this
@@ -357,13 +352,13 @@ struct Definition {
 
     /// Defined [GraphQL fields][2] of this [GraphQL interface][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     fields: Vec<field::Definition>,
 
     /// Defined [`Implementer`]s of this [GraphQL interface][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     implemented_for: Vec<syn::TypePath>,
 
     /// [GraphQL interfaces implemented][1] by this [GraphQL interface][0].
@@ -377,7 +372,7 @@ struct Definition {
     /// [GraphQL interface][1]. We generate hacky `const` which doesn't actually
     /// use it, but suppresses this warning.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     suppress_dead_code: Option<(syn::Ident, syn::Fields)>,
 
     /// Intra-doc link to the [`syn::Item`] defining this
@@ -400,7 +395,7 @@ impl ToTokens for Definition {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        self.impl_reflect().to_tokens(into);
+        //self.impl_reflect().to_tokens(into);
     }
 }
 
@@ -415,7 +410,7 @@ impl Definition {
         let alias_ident = &self.enum_alias_ident;
 
         let variant_gens_pars = (0..self.implemented_for.len()).map::<syn::GenericParam, _>(|id| {
-            let par = format_ident!("__I{}", id);
+            let par = format_ident!("__I{id}");
             parse_quote! { #par }
         });
         let variants_idents = self
@@ -467,13 +462,13 @@ impl Definition {
             "Enum building an opaque value represented by [`{}`]({}) \
              [GraphQL interface][0].\
              \n\n\
-             [0]: https://spec.graphql.org/June2018/#sec-Interfaces",
+             [0]: https://spec.graphql.org/October2021#sec-Interfaces",
             self.name, self.src_intra_doc_link,
         );
         let enum_alias_doc = format!(
             "Opaque value represented by [`{}`]({}) [GraphQL interface][0].\
              \n\n\
-             [0]: https://spec.graphql.org/June2018/#sec-Interfaces",
+             [0]: https://spec.graphql.org/October2021#sec-Interfaces",
             self.name, self.src_intra_doc_link,
         );
 
@@ -507,8 +502,8 @@ impl Definition {
             .map(|(ty, ident)| {
                 quote! {
                     #[automatically_derived]
-                    impl#interface_impl_gens ::std::convert::From<#ty>
-                        for #alias_ident#interface_ty_gens
+                    impl #interface_impl_gens ::std::convert::From<#ty>
+                        for #alias_ident #interface_ty_gens
                         #interface_where_clause
                     {
                         fn from(v: #ty) -> Self {
@@ -522,14 +517,14 @@ impl Definition {
             #[automatically_derived]
             #[derive(Clone, Copy, Debug)]
             #[doc = #enum_doc]
-            #vis enum #enum_ident#enum_gens {
+            #vis enum #enum_ident #enum_gens {
                 #( #[doc(hidden)] #variants_idents(#variant_gens_pars), )*
                 #( #[doc(hidden)] #phantom_variant, )*
             }
 
             #[automatically_derived]
             #[doc = #enum_alias_doc]
-            #vis type #alias_ident#enum_alias_gens =
+            #vis type #alias_ident #enum_alias_gens =
                 #enum_ident<#( #enum_to_alias_gens ),*>;
 
             #( #from_impls )*
@@ -540,7 +535,7 @@ impl Definition {
     /// [GraphQL interface][1].
     ///
     /// [`GraphQLInterface`]: juniper::GraphQLInterface
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_graphql_interface_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -556,7 +551,7 @@ impl Definition {
 
             quote! {{
                 const SUPPRESS_DEAD_CODE: () = {
-                    let none = Option::<#ident#const_gens>::None;
+                    let none = Option::<#ident #const_gens>::None;
                     match none {
                         Some(unreachable) => {
                             #( let _ = unreachable.#fields; )*
@@ -613,8 +608,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::GraphQLInterface<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::marker::GraphQLInterface<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 fn mark() {
@@ -630,7 +625,7 @@ impl Definition {
     /// this [GraphQL interface][1].
     ///
     /// [`marker::IsOutputType`]: juniper::marker::IsOutputType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_output_type_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -670,7 +665,7 @@ impl Definition {
             quote_spanned! { const_impl_for.span() =>
                 ::juniper::assert_transitive_impls!(
                     #const_scalar,
-                    #ty#ty_const_generics,
+                    #ty #ty_const_generics,
                     #const_impl_for,
                     #( #const_implements ),*
                 );
@@ -679,8 +674,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::IsOutputType<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::marker::IsOutputType<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 fn mark() {
@@ -688,12 +683,12 @@ impl Definition {
                     #( #is_output )*
                     ::juniper::assert_interfaces_impls!(
                         #const_scalar,
-                        #ty#ty_const_generics,
+                        #ty #ty_const_generics,
                         #( #const_impl_for ),*
                     );
                     ::juniper::assert_implemented_for!(
                         #const_scalar,
-                        #ty#ty_const_generics,
+                        #ty #ty_const_generics,
                         #( #const_implements ),*
                     );
                     #( #transitive_checks )*
@@ -706,7 +701,7 @@ impl Definition {
     /// [GraphQL interface][1].
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_graphql_type_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -717,10 +712,7 @@ impl Definition {
         let (_, ty_generics, _) = self.generics.split_for_impl();
 
         let name = &self.name;
-        let description = self
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
+        let description = &self.description;
 
         // Sorting is required to preserve/guarantee the order of implementers registered in schema.
         let mut implemented_for = self.implemented_for.clone();
@@ -747,8 +739,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLType<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::GraphQLType<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 fn name(_ : &Self::TypeInfo) -> Option<&'static str> {
@@ -767,7 +759,7 @@ impl Definition {
                     let fields = [
                         #( #fields_meta, )*
                     ];
-                    registry.build_interface_type::<#ty#ty_generics>(info, &fields)
+                    registry.build_interface_type::<#ty #ty_generics>(info, &fields)
                         #description
                         #impl_interfaces
                         .into_meta()
@@ -780,7 +772,7 @@ impl Definition {
     /// [GraphQL interface][1].
     ///
     /// [`GraphQLValue`]: juniper::GraphQLValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_graphql_value_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -814,7 +806,7 @@ impl Definition {
         quote! {
             #[allow(deprecated)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty#ty_generics
+            impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty #ty_generics
                 #where_clause
             {
                 type Context = #context;
@@ -862,7 +854,7 @@ impl Definition {
     /// [GraphQL interface][1].
     ///
     /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_graphql_value_async_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -892,7 +884,7 @@ impl Definition {
         quote! {
             #[allow(deprecated, non_snake_case)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty#ty_generics
+            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #ty_generics
                 #where_clause
             {
                 fn resolve_field_async<'b>(
@@ -928,7 +920,7 @@ impl Definition {
     /// [`BaseType`]: juniper::macros::reflect::BaseType
     /// [`Fields`]: juniper::macros::reflect::Fields
     /// [`WrappedType`]: juniper::macros::reflect::WrappedType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     #[must_use]
     fn impl_reflection_traits_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
@@ -944,16 +936,16 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::BaseType<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 const NAME: ::juniper::macros::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 const NAMES: ::juniper::macros::reflect::Types = &[
@@ -963,8 +955,8 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::Implements<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::Implements<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 const NAMES: ::juniper::macros::reflect::Types =
@@ -972,16 +964,16 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::Fields<#scalar>
-                for #ty#ty_generics
+            impl #impl_generics ::juniper::macros::reflect::Fields<#scalar>
+                for #ty #ty_generics
                 #where_clause
             {
                 const NAMES: ::juniper::macros::reflect::Names = &[#(#fields),*];
@@ -1010,14 +1002,14 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[
@@ -1027,7 +1019,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::Implements<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::Implements<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[#(
@@ -1036,7 +1028,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -1044,7 +1036,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::Fields<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::Fields<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
@@ -1056,7 +1048,7 @@ impl Definition {
     /// [GraphQL interface][1].
     ///
     /// [`FieldMeta`]: juniper::macros::reflect::FieldMeta
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     fn impl_field_meta_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
         let context = &self.context;
@@ -1086,10 +1078,10 @@ impl Definition {
                 quote! {
                     #[allow(non_snake_case)]
                     #[automatically_derived]
-                    impl#impl_generics ::juniper::macros::reflect::FieldMeta<
+                    impl #impl_generics ::juniper::macros::reflect::FieldMeta<
                         #scalar,
                         { ::juniper::macros::reflect::fnv1a128(#field_name) }
-                    > for #ty#ty_generics #where_clause {
+                    > for #ty #ty_generics #where_clause {
                         type Context = #context;
                         type TypeInfo = ();
                         const TYPE: ::juniper::macros::reflect::Type =
@@ -1117,7 +1109,7 @@ impl Definition {
     /// this [GraphQL interface][1].
     ///
     /// [`Field`]: juniper::macros::reflect::Field
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     fn impl_field_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
         let scalar = &self.scalar;
@@ -1160,10 +1152,10 @@ impl Definition {
                 quote_spanned! { field.ident.span() =>
                     #[allow(non_snake_case)]
                     #[automatically_derived]
-                    impl#impl_generics ::juniper::macros::reflect::Field<
+                    impl #impl_generics ::juniper::macros::reflect::Field<
                         #scalar,
                         { ::juniper::macros::reflect::fnv1a128(#field_name) }
-                    > for #ty#ty_generics #where_clause {
+                    > for #ty #ty_generics #where_clause {
                         fn call(
                             &self,
                             info: &Self::TypeInfo,
@@ -1173,7 +1165,7 @@ impl Definition {
                             match self {
                                 #( #ty::#implemented_for_idents(v) => {
                                     ::juniper::assert_field!(
-                                        #ty#const_ty_generics,
+                                        #ty #const_ty_generics,
                                         #const_implemented_for,
                                         #const_scalar,
                                         #field_name,
@@ -1197,7 +1189,7 @@ impl Definition {
     /// of this [GraphQL interface][1].
     ///
     /// [`AsyncField`]: juniper::macros::reflect::AsyncField
-    /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Interfaces
     fn impl_async_field_tokens(&self) -> TokenStream {
         let ty = &self.enum_alias_ident;
         let scalar = &self.scalar;
@@ -1240,10 +1232,10 @@ impl Definition {
                 quote_spanned! { field.ident.span() =>
                     #[allow(non_snake_case)]
                     #[automatically_derived]
-                    impl#impl_generics ::juniper::macros::reflect::AsyncField<
+                    impl #impl_generics ::juniper::macros::reflect::AsyncField<
                         #scalar,
                         { ::juniper::macros::reflect::fnv1a128(#field_name) }
-                    > for #ty#ty_generics #where_clause {
+                    > for #ty #ty_generics #where_clause {
                         fn call<'b>(
                             &'b self,
                             info: &'b Self::TypeInfo,
@@ -1253,7 +1245,7 @@ impl Definition {
                             match self {
                                 #( #ty::#implemented_for_idents(v) => {
                                     ::juniper::assert_field!(
-                                        #ty#const_ty_generics,
+                                        #ty #const_ty_generics,
                                         #const_implemented_for,
                                         #const_scalar,
                                         #field_name,
@@ -1445,14 +1437,14 @@ impl Definition {
                 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);
+                    lt.lifetime.ident = format_ident!("__fa__{ident}");
                 }
 
                 let lifetimes = generics.lifetimes().map(|lt| &lt.lifetime);
                 let ty = &self.enum_alias_ident;
                 let (_, ty_generics, _) = generics.split_for_impl();
 
-                quote! { for<#( #lifetimes ),*> #ty#ty_generics }
+                quote! { for<#( #lifetimes ),*> #ty #ty_generics }
             } else {
                 quote! { Self }
             };
@@ -1480,7 +1472,7 @@ impl Definition {
         let ty = {
             let ident = &self.enum_alias_ident;
             let (_, ty_gen, _) = generics.split_for_impl();
-            parse_quote! { #ident#ty_gen }
+            parse_quote! { #ident #ty_gen }
         };
 
         (ty, generics)
diff --git a/juniper_codegen/src/graphql_object/attr.rs b/juniper_codegen/src/graphql_object/attr.rs
index c9854400..83c08484 100644
--- a/juniper_codegen/src/graphql_object/attr.rs
+++ b/juniper_codegen/src/graphql_object/attr.rs
@@ -6,20 +6,16 @@ use proc_macro2::{Span, TokenStream};
 use quote::{quote, ToTokens};
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned};
 
-use crate::{
-    common::{
-        field,
-        parse::{self, TypeExt as _},
-        scalar,
-    },
-    result::GraphQLScope,
-    util::{path_eq_single, span_container::SpanContainer, RenameRule},
+use crate::common::{
+    diagnostic, field,
+    parse::{self, TypeExt as _},
+    path_eq_single, rename, scalar, SpanContainer,
 };
 
 use super::{Attr, Definition, Query};
 
-/// [`GraphQLScope`] of errors for `#[graphql_object]` macro.
-const ERR: GraphQLScope = GraphQLScope::ObjectAttr;
+/// [`diagnostic::Scope`] of errors for `#[graphql_object]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::ObjectAttr;
 
 /// Expands `#[graphql_object]` macro into generated code.
 pub fn expand(attr_args: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
@@ -73,7 +69,7 @@ where
         .rename_fields
         .as_deref()
         .copied()
-        .unwrap_or(RenameRule::CamelCase);
+        .unwrap_or(rename::Policy::CamelCase);
 
     let async_only = TypeId::of::<Operation>() != TypeId::of::<Query>();
     let fields: Vec<_> = ast
@@ -144,7 +140,7 @@ where
 fn parse_field(
     method: &mut syn::ImplItemMethod,
     async_only: bool,
-    renaming: &RenameRule,
+    renaming: &rename::Policy,
 ) -> Option<field::Definition> {
     let method_attrs = method.attrs.clone();
 
@@ -193,7 +189,7 @@ fn parse_field(
                 }
                 syn::FnArg::Typed(arg) => {
                     if let syn::Pat::Ident(a) = &*arg.pat {
-                        if a.ident.to_string().as_str() == "self" {
+                        if a.ident == "self" {
                             return err_invalid_method_receiver(arg);
                         }
                     }
@@ -217,17 +213,11 @@ fn parse_field(
     };
     ty.lifetimes_anonymized();
 
-    let description = attr.description.as_ref().map(|d| d.as_ref().value());
-    let deprecated = attr
-        .deprecated
-        .as_deref()
-        .map(|d| d.as_ref().map(syn::LitStr::value));
-
     Some(field::Definition {
         name,
         ty,
-        description,
-        deprecated,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
         ident: method_ident.clone(),
         behavior: attr.behavior.into(),
         arguments: Some(arguments),
diff --git a/juniper_codegen/src/graphql_object/derive.rs b/juniper_codegen/src/graphql_object/derive.rs
index 283133d1..be1c939b 100644
--- a/juniper_codegen/src/graphql_object/derive.rs
+++ b/juniper_codegen/src/graphql_object/derive.rs
@@ -7,16 +7,12 @@ use proc_macro_error::ResultExt as _;
 use quote::ToTokens;
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _};
 
-use crate::{
-    common::{field, parse::TypeExt as _, scalar},
-    result::GraphQLScope,
-    util::{span_container::SpanContainer, RenameRule},
-};
+use crate::common::{diagnostic, field, parse::TypeExt as _, rename, scalar, SpanContainer};
 
 use super::{Attr, Definition, Query};
 
-/// [`GraphQLScope`] of errors for `#[derive(GraphQLObject)]` macro.
-const ERR: GraphQLScope = GraphQLScope::ObjectDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLObject)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::ObjectDerive;
 
 /// Expands `#[derive(GraphQLObject)]` macro into generated code.
 pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
@@ -38,7 +34,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition<Query>> {
     let struct_ident = ast.ident;
 
     let (_, struct_generics, _) = ast.generics.split_for_impl();
-    let ty = parse_quote! { #struct_ident#struct_generics };
+    let ty = parse_quote! { #struct_ident #struct_generics };
 
     let name = attr
         .name
@@ -62,7 +58,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition<Query>> {
         .rename_fields
         .as_deref()
         .copied()
-        .unwrap_or(RenameRule::CamelCase);
+        .unwrap_or(rename::Policy::CamelCase);
 
     let mut fields = vec![];
     if let syn::Data::Struct(data) = &ast.data {
@@ -113,7 +109,7 @@ fn expand_struct(ast: syn::DeriveInput) -> syn::Result<Definition<Query>> {
 ///
 /// Returns [`None`] if parsing fails, or the struct field is ignored.
 #[must_use]
-fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Definition> {
+fn parse_field(field: &syn::Field, renaming: &rename::Policy) -> Option<field::Definition> {
     let attr = field::Attr::from_attrs("graphql", &field.attrs)
         .map_err(|e| proc_macro_error::emit_error!(e))
         .ok()?;
@@ -142,17 +138,11 @@ fn parse_field(field: &syn::Field, renaming: &RenameRule) -> Option<field::Defin
     let mut ty = field.ty.unparenthesized().clone();
     ty.lifetimes_anonymized();
 
-    let description = attr.description.as_ref().map(|d| d.as_ref().value());
-    let deprecated = attr
-        .deprecated
-        .as_deref()
-        .map(|d| d.as_ref().map(syn::LitStr::value));
-
     Some(field::Definition {
         name,
         ty,
-        description,
-        deprecated,
+        description: attr.description.map(SpanContainer::into_inner),
+        deprecated: attr.deprecated.map(SpanContainer::into_inner),
         ident: field_ident.clone(),
         behavior: attr.behavior.into(),
         arguments: None,
diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs
index 7e724956..de132f89 100644
--- a/juniper_codegen/src/graphql_object/mod.rs
+++ b/juniper_codegen/src/graphql_object/mod.rs
@@ -1,54 +1,52 @@
 //! Code generation for [GraphQL object][1].
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Objects
+//! [1]: https://spec.graphql.org/October2021#sec-Objects
 
 pub mod attr;
 pub mod derive;
 
-use std::{any::TypeId, collections::HashSet, convert::TryInto as _, marker::PhantomData};
+use std::{any::TypeId, collections::HashSet, marker::PhantomData};
 
 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::{
-        behavior, field, gen,
-        parse::{
-            attr::{err, OptionExt as _},
-            GenericsExt as _, ParseBufferExt as _, TypeExt,
-        },
-        scalar,
+use crate::common::{
+    behavior, field, filter_attrs, gen,
+    parse::{
+        attr::{err, OptionExt as _},
+        GenericsExt as _, ParseBufferExt as _, TypeExt,
     },
-    util::{filter_attrs, get_doc_comment, span_container::SpanContainer, RenameRule},
+    rename, scalar, Description, SpanContainer,
 };
-use syn::ext::IdentExt;
 
 /// Available arguments behind `#[graphql]` (or `#[graphql_object]`) attribute
 /// when generating code for [GraphQL object][1] type.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Objects
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
 #[derive(Debug, Default)]
 pub(crate) struct Attr {
     /// Explicitly specified name of this [GraphQL object][1] type.
     ///
     /// If [`None`], then Rust type name is used by default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) name: Option<SpanContainer<String>>,
 
     /// Explicitly specified [description][2] of this [GraphQL object][1] type.
     ///
-    /// If [`None`], then Rust doc comment is used as [description][2], if any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    pub(crate) description: Option<SpanContainer<String>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    pub(crate) description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified type of [`Context`] to use for resolving this
     /// [GraphQL object][1] type with.
@@ -56,7 +54,7 @@ pub(crate) struct Attr {
     /// If [`None`], then unit type `()` is assumed as a type of [`Context`].
     ///
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) context: Option<SpanContainer<syn::Type>>,
 
     /// Explicitly specified type (or type parameter with its bounds) of
@@ -70,7 +68,7 @@ pub(crate) struct Attr {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) scalar: Option<SpanContainer<scalar::AttrValue>>,
 
     /// Explicitly specified type of the custom [`Behavior`] to parametrize this
@@ -87,17 +85,18 @@ pub(crate) struct Attr {
     /// Explicitly specified [GraphQL interfaces][2] this [GraphQL object][1]
     /// type implements.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    /// [2]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Interfaces
     pub(crate) interfaces: HashSet<SpanContainer<syn::Type>>,
 
-    /// Explicitly specified [`RenameRule`] for all fields of this
+    /// Explicitly specified [`rename::Policy`] for all fields of this
     /// [GraphQL object][1] type.
     ///
-    /// If [`None`] then the default rule will be [`RenameRule::CamelCase`].
+    /// If [`None`], then the [`rename::Policy::CamelCase`] will be applied by
+    /// default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    pub(crate) rename_fields: Option<SpanContainer<RenameRule>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    pub(crate) rename_fields: Option<SpanContainer<rename::Policy>>,
 
     /// Indicator whether the generated code is intended to be used only inside
     /// the [`juniper`] library.
@@ -123,13 +122,9 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "ctx" | "context" | "Context" => {
@@ -213,7 +208,7 @@ impl Attr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs);
+            attr.description = Description::parse_from_doc_attrs(attrs)?;
         }
 
         Ok(attr)
@@ -222,38 +217,38 @@ impl Attr {
 
 /// Definition of [GraphQL object][1] for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Objects
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
 #[derive(Debug)]
 pub(crate) struct Definition<Operation: ?Sized> {
     /// Name of this [GraphQL object][1] in GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) name: String,
 
     /// Rust type that this [GraphQL object][1] is represented with.
     ///
     /// It should contain all its generics, if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) ty: syn::Type,
 
     /// Generics of the Rust type that this [GraphQL object][1] is implemented
     /// for.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) generics: syn::Generics,
 
     /// Description of this [GraphQL object][1] to put into GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    pub(crate) description: Option<String>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    pub(crate) description: Option<Description>,
 
     /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
     /// for this [GraphQL object][1].
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) context: syn::Type,
 
     /// [`ScalarValue`] parametrization to generate [`GraphQLType`]
@@ -261,7 +256,7 @@ pub(crate) struct Definition<Operation: ?Sized> {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     pub(crate) scalar: scalar::Type,
 
     /// [`Behavior`] parametrization to generate code with for this
@@ -273,23 +268,23 @@ pub(crate) struct Definition<Operation: ?Sized> {
 
     /// Defined [GraphQL fields][2] of this [GraphQL object][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    /// [2]: https://spec.graphql.org/June2018/#sec-Language.Fields
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Language.Fields
     pub(crate) fields: Vec<field::Definition>,
 
     /// [GraphQL interfaces][2] implemented by this [GraphQL object][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
-    /// [2]: https://spec.graphql.org/June2018/#sec-Interfaces
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
+    /// [2]: https://spec.graphql.org/October2021#sec-Interfaces
     pub(crate) interfaces: HashSet<syn::Type>,
 
     /// [GraphQL operation][1] this [`Definition`] should generate code for.
     ///
     /// Either [GraphQL query][2] or [GraphQL subscription][3].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Language.Operations
-    /// [2]: https://spec.graphql.org/June2018/#sec-Query
-    /// [3]: https://spec.graphql.org/June2018/#sec-Subscription
+    /// [1]: https://spec.graphql.org/October2021#sec-Language.Operations
+    /// [2]: https://spec.graphql.org/October2021#sec-Query
+    /// [3]: https://spec.graphql.org/October2021#sec-Subscription
     pub(crate) _operation: PhantomData<Box<Operation>>,
 }
 
@@ -302,7 +297,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
     ///
     /// [`GraphQLAsyncValue`]: juniper::GraphQLAsyncValue
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     pub(crate) fn impl_generics(&self, for_async: bool) -> (TokenStream, Option<syn::WhereClause>) {
         let mut generics = self.generics.clone();
@@ -330,7 +325,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                 let mut ty = self.ty.clone();
                 ty.lifetimes_iter_mut(&mut |lt| {
                     let ident = lt.ident.unraw();
-                    lt.ident = format_ident!("__fa__{}", ident);
+                    lt.ident = format_ident!("__fa__{ident}");
                     lifetimes.push(lt.clone());
                 });
 
@@ -366,7 +361,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
     /// this [GraphQL object][1].
     ///
     /// [`marker::IsOutputType`]: juniper::marker::IsOutputType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     pub(crate) fn impl_output_type_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -384,7 +379,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::IsOutputType<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::marker::IsOutputType<#scalar> for #ty #where_clause
             {
                 fn mark() {
                     #( #fields_marks )*
@@ -401,7 +396,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
     /// [`BaseType`]: juniper::macros::reflect::BaseType
     /// [`Fields`]: juniper::macros::reflect::Fields
     /// [`WrappedType`]: juniper::macros::reflect::WrappedType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     pub(crate) fn impl_reflection_traits_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -413,7 +408,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::BaseType<#scalar>
                 for #ty
                 #where_clause
             {
@@ -421,7 +416,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
                 for #ty
                 #where_clause
             {
@@ -430,7 +425,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::Implements<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::Implements<#scalar>
                 for #ty
                 #where_clause
             {
@@ -439,7 +434,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
                 for #ty
                 #where_clause
             {
@@ -447,7 +442,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::Fields<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::Fields<#scalar>
                 for #ty
                 #where_clause
             {
@@ -479,14 +474,14 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
@@ -494,7 +489,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::Implements<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::Implements<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types = &[#(
@@ -503,7 +498,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -511,7 +506,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::Fields<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::Fields<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Names = &[#( #fields ),*];
@@ -557,7 +552,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
                 quote! {
                     #[allow(deprecated, non_snake_case)]
                     #[automatically_derived]
-                    impl#impl_gens ::juniper::reflect::Field<
+                    impl #impl_gens ::juniper::reflect::Field<
                         { ::juniper::reflect::fnv1a128(#f_name) }, #bh,
                     > for #ty #where_clause {
                         const TYPE: ::juniper::reflect::Type =
@@ -587,7 +582,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
     /// [GraphQL object][1].
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     pub(crate) fn impl_graphql_type_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -596,16 +591,13 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
         let ty = &self.ty;
 
         let name = &self.name;
-        let description = self
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
+        let description = &self.description;
 
         let extract_stream_type = TypeId::of::<Operation>() != TypeId::of::<Query>();
         let fields_meta = self
             .fields
             .iter()
-            .map(|f| f.method_meta_tokens(extract_stream_type.then(|| scalar)));
+            .map(|f| f.method_meta_tokens(extract_stream_type.then_some(scalar)));
 
         // Sorting is required to preserve/guarantee the order of interfaces registered in schema.
         let mut interface_tys: Vec<_> = self.interfaces.iter().collect();
@@ -623,7 +615,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLType<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::GraphQLType<#scalar> for #ty #where_clause
             {
                 fn name(_ : &Self::TypeInfo) -> Option<&'static str> {
                     Some(#name)
@@ -650,7 +642,7 @@ impl<Operation: ?Sized + 'static> Definition<Operation> {
 
 /// [GraphQL query operation][2] of the [`Definition`] to generate code for.
 ///
-/// [2]: https://spec.graphql.org/June2018/#sec-Query
+/// [2]: https://spec.graphql.org/October2021#sec-Query
 struct Query;
 
 impl ToTokens for Definition<Query> {
@@ -665,7 +657,7 @@ impl ToTokens for Definition<Query> {
         self.impl_field_tokens().to_tokens(into);
         self.impl_async_field_tokens().to_tokens(into);
         ////////////////////////////////////////////////////////////////////////
-        self.impl_reflect().to_tokens(into);
+        //self.impl_reflect().to_tokens(into);
         //self.impl_reflect_field().to_tokens(into);
         //self.impl_resolve_field_static().to_tokens(into);
     }
@@ -676,7 +668,7 @@ impl Definition<Query> {
     /// [GraphQL object][1].
     ///
     /// [`GraphQLObject`]: juniper::GraphQLObject
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_graphql_object_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -708,7 +700,7 @@ impl Definition<Query> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::GraphQLObject<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::marker::GraphQLObject<#scalar> for #ty #where_clause
             {
                 fn mark() {
                     #( <#interface_tys as ::juniper::marker::GraphQLInterface<#scalar>>::mark(); )*
@@ -724,7 +716,7 @@ impl Definition<Query> {
     /// of this [GraphQL object][1].
     ///
     /// [`FieldMeta`]: juniper::FieldMeta
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_field_meta_tokens(&self) -> TokenStream {
         let impl_ty = &self.ty;
@@ -785,7 +777,7 @@ impl Definition<Query> {
     /// this [GraphQL object][1].
     ///
     /// [`Field`]: juniper::Field
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_field_tokens(&self) -> TokenStream {
         let (impl_ty, scalar) = (&self.ty, &self.scalar);
@@ -858,7 +850,7 @@ impl Definition<Query> {
     /// of this [GraphQL object][1].
     ///
     /// [`AsyncField`]: juniper::AsyncField
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_async_field_tokens(&self) -> TokenStream {
         let (impl_ty, scalar) = (&self.ty, &self.scalar);
@@ -920,7 +912,7 @@ impl Definition<Query> {
     /// [GraphQL object][1].
     ///
     /// [`GraphQLValue`]: juniper::GraphQLValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_graphql_value_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -950,7 +942,7 @@ impl Definition<Query> {
         quote! {
             #[allow(deprecated)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty #where_clause
             {
                 type Context = #context;
                 type TypeInfo = ();
@@ -977,7 +969,7 @@ impl Definition<Query> {
                     _: &Self::Context,
                     _: &Self::TypeInfo,
                 ) -> String {
-                    #name.to_string()
+                    #name.into()
                 }
             }
         }
@@ -987,7 +979,7 @@ impl Definition<Query> {
     /// [GraphQL object][1].
     ///
     /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync
-    /// [1]: https://spec.graphql.org/June2018/#sec-Objects
+    /// [1]: https://spec.graphql.org/October2021#sec-Objects
     #[must_use]
     fn impl_graphql_value_async_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -1014,7 +1006,7 @@ impl Definition<Query> {
         quote! {
             #[allow(deprecated, non_snake_case)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #where_clause
             {
                 fn resolve_field_async<'b>(
                     &'b self,
diff --git a/juniper_codegen/src/graphql_scalar/attr.rs b/juniper_codegen/src/graphql_scalar/attr.rs
index 3139da74..a336712c 100644
--- a/juniper_codegen/src/graphql_scalar/attr.rs
+++ b/juniper_codegen/src/graphql_scalar/attr.rs
@@ -4,14 +4,12 @@ use proc_macro2::{Span, TokenStream};
 use quote::quote;
 use syn::{parse_quote, spanned::Spanned};
 
-use crate::{
-    common::{parse, scalar},
-    GraphQLScope,
-};
+use crate::common::{diagnostic, parse, scalar, SpanContainer};
 
 use super::{derive::parse_derived_methods, Attr, Definition, Methods, ParseToken};
 
-const ERR: GraphQLScope = GraphQLScope::ScalarAttr;
+/// [`diagnostic::Scope`] of errors for `#[graphql_scalar]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::ScalarAttr;
 
 /// Expands `#[graphql_scalar]` macro into generated code.
 pub(crate) fn expand(attr_args: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
@@ -57,11 +55,10 @@ fn expand_on_type_alias(
         methods,
         name: attr
             .name
-            .as_deref()
-            .cloned()
+            .map(SpanContainer::into_inner)
             .unwrap_or_else(|| ast.ident.to_string()),
-        description: attr.description.as_deref().cloned(),
-        specified_by_url: attr.specified_by_url.as_deref().cloned(),
+        description: attr.description.map(SpanContainer::into_inner),
+        specified_by_url: attr.specified_by_url.map(SpanContainer::into_inner),
         scalar,
         scalar_value: attr.scalar.as_deref().into(),
         behavior: attr.behavior.into(),
@@ -92,11 +89,10 @@ fn expand_on_derive_input(
         methods,
         name: attr
             .name
-            .as_deref()
-            .cloned()
+            .map(SpanContainer::into_inner)
             .unwrap_or_else(|| ast.ident.to_string()),
-        description: attr.description.as_deref().cloned(),
-        specified_by_url: attr.specified_by_url.as_deref().cloned(),
+        description: attr.description.map(SpanContainer::into_inner),
+        specified_by_url: attr.specified_by_url.map(SpanContainer::into_inner),
         scalar,
         scalar_value: attr.scalar.as_deref().into(),
         behavior: attr.behavior.into(),
diff --git a/juniper_codegen/src/graphql_scalar/derive.rs b/juniper_codegen/src/graphql_scalar/derive.rs
index 552c28ba..53a27ddb 100644
--- a/juniper_codegen/src/graphql_scalar/derive.rs
+++ b/juniper_codegen/src/graphql_scalar/derive.rs
@@ -1,17 +1,15 @@
 //! Code generation for `#[derive(GraphQLScalar)]` macro.
 
-use std::convert::TryFrom;
-
 use proc_macro2::TokenStream;
 use quote::ToTokens;
 use syn::{parse_quote, spanned::Spanned};
 
-use crate::{common::scalar, result::GraphQLScope};
+use crate::common::{diagnostic, scalar, SpanContainer};
 
 use super::{Attr, Definition, Field, Methods, ParseToken};
 
-/// [`GraphQLScope`] of errors for `#[derive(GraphQLScalar)]` macro.
-const ERR: GraphQLScope = GraphQLScope::ScalarDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLScalar)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::ScalarDerive;
 
 /// Expands `#[derive(GraphQLScalar)]` macro into generated code.
 pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
@@ -20,10 +18,10 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
 
     let methods = parse_derived_methods(&ast, &attr)?;
     let scalar = scalar::Type::parse(attr.scalar.as_deref(), &ast.generics);
+
     let name = attr
         .name
-        .as_deref()
-        .cloned()
+        .map(SpanContainer::into_inner)
         .unwrap_or_else(|| ast.ident.to_string());
 
     Ok(Definition {
@@ -34,8 +32,8 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
         generics: ast.generics,
         methods,
         name,
-        description: attr.description.as_deref().cloned(),
-        specified_by_url: attr.specified_by_url.as_deref().cloned(),
+        description: attr.description.map(SpanContainer::into_inner),
+        specified_by_url: attr.specified_by_url.map(SpanContainer::into_inner),
         scalar,
         scalar_value: attr.scalar.as_deref().into(),
         behavior: attr.behavior.into(),
diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs
index 21ad3b32..316d79ed 100644
--- a/juniper_codegen/src/graphql_scalar/mod.rs
+++ b/juniper_codegen/src/graphql_scalar/mod.rs
@@ -2,8 +2,6 @@
 //!
 //! [1]: https://spec.graphql.org/October2021#sec-Scalars
 
-use std::convert::TryFrom;
-
 use proc_macro2::{Literal, TokenStream};
 use quote::{format_ident, quote, ToTokens, TokenStreamExt};
 use syn::{
@@ -16,16 +14,13 @@ use syn::{
 };
 use url::Url;
 
-use crate::{
-    common::{
-        behavior,
-        parse::{
-            attr::{err, OptionExt as _},
-            ParseBufferExt as _,
-        },
-        scalar,
+use crate::common::{
+    behavior, filter_attrs,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _,
     },
-    util::{filter_attrs, get_doc_comment, span_container::SpanContainer},
+    scalar, Description, SpanContainer,
 };
 
 pub mod attr;
@@ -45,7 +40,7 @@ struct Attr {
     /// Description of this [GraphQL scalar][1] to put into GraphQL schema.
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
-    description: Option<SpanContainer<String>>,
+    description: Option<SpanContainer<Description>>,
 
     /// Spec [`Url`] of this [GraphQL scalar][1] to put into GraphQL schema.
     ///
@@ -126,20 +121,16 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "specified_by_url" => {
                     input.parse::<token::Eq>()?;
                     let lit = input.parse::<syn::LitStr>()?;
                     let url = lit.value().parse::<Url>().map_err(|err| {
-                        syn::Error::new(lit.span(), format!("Invalid URL: {}", err))
+                        syn::Error::new(lit.span(), format!("Invalid URL: {err}"))
                     })?;
                     out.specified_by_url
                         .replace(SpanContainer::new(ident.span(), Some(lit.span()), url))
@@ -277,7 +268,7 @@ impl Attr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if attr.description.is_none() {
-            attr.description = get_doc_comment(attrs);
+            attr.description = Description::parse_from_doc_attrs(attrs)?;
         }
 
         Ok(attr)
@@ -315,7 +306,7 @@ struct Definition {
     /// Description of this [GraphQL scalar][1] to put into GraphQL schema.
     ///
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
-    description: Option<String>,
+    description: Option<Description>,
 
     /// Spec [`Url`] of this [GraphQL scalar][1] to put into GraphQL schema.
     ///
@@ -386,11 +377,11 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::marker::IsInputType<#scalar> for #ty
+            impl #impl_gens ::juniper::marker::IsInputType<#scalar> for #ty
                 #where_clause { }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::marker::IsOutputType<#scalar> for #ty
+            impl #impl_gens ::juniper::marker::IsOutputType<#scalar> for #ty
                 #where_clause { }
         }
     }
@@ -416,7 +407,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::InputType<#lt, #inf, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_input_type() {}
@@ -445,7 +436,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::OutputType<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_output_type() {}
@@ -475,7 +466,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::graphql::Scalar<#lt, #inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::graphql::Scalar<#lt, #inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn assert_scalar() {}
@@ -490,12 +481,9 @@ impl Definition {
     /// [1]: https://spec.graphql.org/October2021#sec-Scalars
     fn impl_type_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
-        let name = &self.name;
 
-        let description = self
-            .description
-            .as_ref()
-            .map(|val| quote! { .description(#val) });
+        let name = &self.name;
+        let description = &self.description;
         let specified_by_url = self.specified_by_url.as_ref().map(|url| {
             let url_lit = url.as_str();
             quote! { .specified_by_url(#url_lit) }
@@ -506,7 +494,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::GraphQLType<#scalar> for #ty
+            impl #impl_gens ::juniper::GraphQLType<#scalar> for #ty
                 #where_clause
             {
                 fn name(_: &Self::TypeInfo) -> Option<&'static str> {
@@ -542,7 +530,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::TypeName<#inf, #bh> for #ty
                 #where_clause
             {
                 fn type_name(_: &#inf) -> &'static str {
@@ -572,11 +560,7 @@ impl Definition {
         });
         let (impl_gens, _, where_clause) = generics.split_for_impl();
 
-        let description = self
-            .description
-            .as_ref()
-            .map(|text| quote! { .description(#text) });
-
+        let description = &self.description;
         let specified_by_url = self.specified_by_url.as_ref().map(|url| {
             let url_lit = url.as_str();
             quote! { .specified_by_url(#url_lit) }
@@ -584,7 +568,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::Type<#inf, #sv, #bh> for #ty
                 #where_clause
             {
                 fn meta<'__r, '__ti: '__r>(
@@ -597,8 +581,7 @@ impl Definition {
                     registry.register_scalar_with::<
                         ::juniper::behavior::Coerce<Self>, _, _,
                     >(type_info, |meta| {
-                        meta#description
-                            #specified_by_url
+                        meta #description #specified_by_url
                     })
                 }
             }
@@ -620,7 +603,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::GraphQLValue<#scalar> for #ty
+            impl #impl_gens ::juniper::GraphQLValue<#scalar> for #ty
                 #where_clause
             {
                 type Context = ();
@@ -663,7 +646,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::resolve::Value<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn resolve_value(
@@ -691,7 +674,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::GraphQLValueAsync<#scalar> for #ty
+            impl #impl_gens ::juniper::GraphQLValueAsync<#scalar> for #ty
                 #where_clause
             {
                 fn resolve_async<'b>(
@@ -730,7 +713,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
+            impl #impl_gens ::juniper::resolve::ValueAsync<#inf, #cx, #sv, #bh>
                 for #ty #where_clause
             {
                 fn resolve_value_async<'__r>(
@@ -765,7 +748,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::ToInputValue<#scalar> for #ty
+            impl #impl_gens ::juniper::ToInputValue<#scalar> for #ty
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
@@ -794,7 +777,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::ToInputValue<#sv, #bh> for #ty
                 #where_clause
             {
                 fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
@@ -819,7 +802,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::FromInputValue<#scalar> for #ty
+            impl #impl_gens ::juniper::FromInputValue<#scalar> for #ty
                 #where_clause
             {
                 type Error = ::juniper::executor::FieldError<#scalar>;
@@ -853,8 +836,8 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh> for #ty
-                #where_clause
+            impl #impl_gens ::juniper::resolve::InputValue<#lt, #sv, #bh>
+                for #ty #where_clause
             {
                 type Error = #error_ty;
 
@@ -882,12 +865,12 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::ParseScalarValue<#scalar> for #ty
+            impl #impl_gens ::juniper::ParseScalarValue<#scalar> for #ty
                 #where_clause
             {
                 fn from_str(
                     token: ::juniper::parser::ScalarToken<'_>,
-                ) -> ::juniper::ParseScalarResult<'_, #scalar> {
+                ) -> ::juniper::ParseScalarResult<#scalar> {
                     #from_str
                 }
             }
@@ -913,15 +896,12 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::resolve::ScalarToken<#sv, #bh> for #ty
+            impl #impl_gens ::juniper::resolve::ScalarToken<#sv, #bh> for #ty
                 #where_clause
             {
                 fn parse_scalar_token(
                     token: ::juniper::parser::ScalarToken<'_>,
-                ) -> ::std::result::Result<
-                    #sv,
-                    ::juniper::parser::ParseError<'_>,
-                > {
+                ) -> ::std::result::Result<#sv, ::juniper::parser::ParseError> {
                     #body
                 }
             }
@@ -944,14 +924,14 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::BaseType<#scalar> for #ty
+            impl #impl_gens ::juniper::macros::reflect::BaseType<#scalar> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::macros::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::BaseSubTypes<#scalar> for #ty
+            impl #impl_gens ::juniper::macros::reflect::BaseSubTypes<#scalar> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::macros::reflect::Types =
@@ -959,7 +939,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::macros::reflect::WrappedType<#scalar> for #ty
+            impl #impl_gens ::juniper::macros::reflect::WrappedType<#scalar> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
@@ -984,14 +964,14 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseType<#bh> for #ty
                 #where_clause
             {
                 const NAME: ::juniper::reflect::Type = #name;
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::BaseSubTypes<#bh> for #ty
                 #where_clause
             {
                 const NAMES: ::juniper::reflect::Types =
@@ -999,7 +979,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
+            impl #impl_gens ::juniper::reflect::WrappedType<#bh> for #ty
                 #where_clause
             {
                 const VALUE: ::juniper::reflect::WrappedValue =
@@ -1023,7 +1003,7 @@ impl Definition {
         let ty = {
             let ident = &self.ident;
             let (_, ty_gen, _) = self.generics.split_for_impl();
-            quote! { #ident#ty_gen }
+            quote! { #ident #ty_gen }
         };
 
         if !self.where_clause.is_empty() {
@@ -1056,7 +1036,7 @@ impl Definition {
                 let ty = {
                     let ident = &self.ident;
                     let (_, ty_gen, _) = generics.split_for_impl();
-                    quote! { #ident#ty_gen }
+                    quote! { #ident #ty_gen }
                 };
 
                 quote! { for<#( #lifetimes ),*> #ty }
@@ -1087,7 +1067,7 @@ impl Definition {
         let ty = {
             let ident = &self.ident;
             let (_, ty_gen, _) = generics.split_for_impl();
-            parse_quote! { #ident#ty_gen }
+            parse_quote! { #ident #ty_gen }
         };
 
         if !self.where_clause.is_empty() {
@@ -1434,7 +1414,7 @@ impl Methods {
                     quote! { .map_scalar_value() }
                 });
                 quote! {
-                    #from_input(input#map_sv)
+                    #from_input(input #map_sv)
                         .map_err(
                             ::juniper::IntoFieldError::<#sv>::into_field_error,
                         )
diff --git a/juniper_codegen/src/graphql_subscription/mod.rs b/juniper_codegen/src/graphql_subscription/mod.rs
index 3c07c9ae..c8d2fb42 100644
--- a/juniper_codegen/src/graphql_subscription/mod.rs
+++ b/juniper_codegen/src/graphql_subscription/mod.rs
@@ -1,6 +1,6 @@
 //! Code generation for [GraphQL subscription][1].
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Subscription
+//! [1]: https://spec.graphql.org/October2021#sec-Subscription
 
 pub mod attr;
 
@@ -13,7 +13,7 @@ use crate::{common::field, graphql_object::Definition};
 /// [GraphQL subscription operation][2] of the [`Definition`] to generate code
 /// for.
 ///
-/// [2]: https://spec.graphql.org/June2018/#sec-Subscription
+/// [2]: https://spec.graphql.org/October2021#sec-Subscription
 struct Subscription;
 
 impl ToTokens for Definition<Subscription> {
@@ -31,7 +31,7 @@ impl Definition<Subscription> {
     /// [GraphQL subscription][1].
     ///
     /// [`GraphQLValue`]: juniper::GraphQLValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Subscription
+    /// [1]: https://spec.graphql.org/October2021#sec-Subscription
     #[must_use]
     fn impl_graphql_value_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -44,7 +44,7 @@ impl Definition<Subscription> {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty #where_clause
             {
                 type Context = #context;
                 type TypeInfo = ();
@@ -70,7 +70,7 @@ impl Definition<Subscription> {
                     _: &Self::Context,
                     _: &Self::TypeInfo,
                 ) -> String {
-                    #name.to_string()
+                    #name.into()
                 }
             }
         }
@@ -80,7 +80,7 @@ impl Definition<Subscription> {
     /// for this [GraphQL subscription][1].
     ///
     /// [`GraphQLSubscriptionValue`]: juniper::GraphQLSubscriptionValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Subscription
+    /// [1]: https://spec.graphql.org/October2021#sec-Subscription
     #[must_use]
     fn impl_graphql_subscription_value_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -109,7 +109,7 @@ impl Definition<Subscription> {
         quote! {
             #[allow(deprecated)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLSubscriptionValue<#scalar> for #ty #where_clause
+            impl #impl_generics ::juniper::GraphQLSubscriptionValue<#scalar> for #ty #where_clause
             {
                 fn resolve_field_into_stream<
                     's, 'i, 'fi, 'args, 'e, 'ref_e, 'res, 'f,
diff --git a/juniper_codegen/src/graphql_union/attr.rs b/juniper_codegen/src/graphql_union/attr.rs
index ae2be4db..006ad226 100644
--- a/juniper_codegen/src/graphql_union/attr.rs
+++ b/juniper_codegen/src/graphql_union/attr.rs
@@ -6,19 +6,15 @@ use proc_macro2::{Span, TokenStream};
 use quote::{quote, ToTokens as _};
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _};
 
-use crate::{
-    common::{parse, scalar},
-    result::GraphQLScope,
-    util::{path_eq_single, span_container::SpanContainer},
-};
+use crate::common::{diagnostic, parse, path_eq_single, scalar, SpanContainer};
 
 use super::{
     all_variants_different, emerge_union_variants_from_attr, Attr, Definition, VariantAttr,
     VariantDefinition,
 };
 
-/// [`GraphQLScope`] of errors for `#[graphql_union]` macro.
-const ERR: GraphQLScope = GraphQLScope::UnionAttr;
+/// [`diagnostic::Scope`] of errors for `#[graphql_union]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::UnionAttr;
 
 /// Expands `#[graphql_union]` macro into generated code.
 pub fn expand(attr_args: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
@@ -112,7 +108,7 @@ fn expand_on_trait(
 /// On failure returns [`None`] and internally fills up [`proc_macro_error`]
 /// with the corresponding errors.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 fn parse_variant_from_trait_method(
     method: &mut syn::TraitItemMethod,
     trait_ident: &syn::Ident,
@@ -177,10 +173,9 @@ fn parse_variant_from_trait_method(
             ERR.custom(
                 method_span,
                 format!(
-                    "trait method `{}` conflicts with the external resolver \
-                     function `{}` declared on the trait to resolve the \
-                     variant type `{}`",
-                    method_ident,
+                    "trait method `{method_ident}` conflicts with the external \
+                     resolver function `{}` declared on the trait to resolve \
+                     the variant type `{}`",
                     other.to_token_stream(),
                     ty.to_token_stream(),
                 ),
diff --git a/juniper_codegen/src/graphql_union/derive.rs b/juniper_codegen/src/graphql_union/derive.rs
index 1c1bc5c1..a10be60c 100644
--- a/juniper_codegen/src/graphql_union/derive.rs
+++ b/juniper_codegen/src/graphql_union/derive.rs
@@ -5,19 +5,15 @@ use proc_macro_error::ResultExt as _;
 use quote::{quote, ToTokens};
 use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _, Data, Fields};
 
-use crate::{
-    common::{parse::TypeExt as _, scalar},
-    result::GraphQLScope,
-    util::span_container::SpanContainer,
-};
+use crate::common::{diagnostic, parse::TypeExt as _, scalar, SpanContainer};
 
 use super::{
     all_variants_different, emerge_union_variants_from_attr, Attr, Definition, VariantAttr,
     VariantDefinition,
 };
 
-/// [`GraphQLScope`] of errors for `#[derive(GraphQLUnion)]` macro.
-const ERR: GraphQLScope = GraphQLScope::UnionDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(GraphQLUnion)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::UnionDerive;
 
 /// Expands `#[derive(GraphQLUnion)]` macro into generated code.
 pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
@@ -98,7 +94,7 @@ fn expand_enum(ast: syn::DeriveInput) -> syn::Result<Definition> {
 /// On failure returns [`None`] and internally fills up [`proc_macro_error`]
 /// with the corresponding errors.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 fn parse_variant_from_enum_variant(
     var: syn::Variant,
     enum_ident: &syn::Ident,
diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs
index 21fb9cb4..fa585b00 100644
--- a/juniper_codegen/src/graphql_union/mod.rs
+++ b/juniper_codegen/src/graphql_union/mod.rs
@@ -1,6 +1,6 @@
 //! Code generation for [GraphQL union][1].
 //!
-//! [1]: https://spec.graphql.org/June2018/#sec-Unions
+//! [1]: https://spec.graphql.org/October2021#sec-Unions
 
 pub mod attr;
 pub mod derive;
@@ -17,16 +17,13 @@ use syn::{
     token,
 };
 
-use crate::{
-    common::{
-        gen,
-        parse::{
-            attr::{err, OptionExt as _},
-            ParseBufferExt as _,
-        },
-        scalar,
+use crate::common::{
+    filter_attrs, gen,
+    parse::{
+        attr::{err, OptionExt as _},
+        ParseBufferExt as _,
     },
-    util::{filter_attrs, get_doc_comment, span_container::SpanContainer},
+    scalar, Description, SpanContainer,
 };
 
 /// Helper alias for the type of [`Attr::external_resolvers`] field.
@@ -35,23 +32,24 @@ type AttrResolvers = HashMap<syn::Type, SpanContainer<syn::ExprPath>>;
 /// Available arguments behind `#[graphql]` (or `#[graphql_union]`) attribute
 /// when generating code for [GraphQL union][1] type.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 #[derive(Debug, Default)]
 struct Attr {
     /// Explicitly specified name of [GraphQL union][1] type.
     ///
     /// If [`None`], then Rust type name is used by default.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     name: Option<SpanContainer<String>>,
 
     /// Explicitly specified [description][2] of [GraphQL union][1] type.
     ///
-    /// If [`None`], then Rust doc comment is used as [description][2], if any.
+    /// If [`None`], then Rust doc comment will be used as the [description][2],
+    /// if any.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
-    /// [2]: https://spec.graphql.org/June2018/#sec-Descriptions
-    description: Option<SpanContainer<String>>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
+    /// [2]: https://spec.graphql.org/October2021#sec-Descriptions
+    description: Option<SpanContainer<Description>>,
 
     /// Explicitly specified type of [`Context`] to use for resolving this
     /// [GraphQL union][1] type with.
@@ -59,7 +57,7 @@ struct Attr {
     /// If [`None`], then unit type `()` is assumed as a type of [`Context`].
     ///
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     context: Option<SpanContainer<syn::Type>>,
 
     /// Explicitly specified type of [`ScalarValue`] to use for resolving this
@@ -73,7 +71,7 @@ struct Attr {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     scalar: Option<SpanContainer<scalar::AttrValue>>,
 
     /// Explicitly specified external resolver functions for [GraphQL union][1]
@@ -84,7 +82,7 @@ struct Attr {
     /// external resolver function has sense, when some custom [union][1]
     /// variant resolving logic is involved, or variants cannot be inferred.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     external_resolvers: AttrResolvers,
 
     /// Indicator whether the generated code is intended to be used only inside
@@ -111,13 +109,9 @@ impl Parse for Attr {
                 }
                 "desc" | "description" => {
                     input.parse::<token::Eq>()?;
-                    let desc = input.parse::<syn::LitStr>()?;
+                    let desc = input.parse::<Description>()?;
                     out.description
-                        .replace(SpanContainer::new(
-                            ident.span(),
-                            Some(desc.span()),
-                            desc.value(),
-                        ))
+                        .replace(SpanContainer::new(ident.span(), Some(desc.span()), desc))
                         .none_or_else(|_| err::dup_arg(&ident))?
                 }
                 "ctx" | "context" | "Context" => {
@@ -181,7 +175,7 @@ impl Attr {
             .try_fold(Self::default(), |prev, curr| prev.try_merge(curr?))?;
 
         if meta.description.is_none() {
-            meta.description = get_doc_comment(attrs);
+            meta.description = Description::parse_from_doc_attrs(attrs)?;
         }
 
         Ok(meta)
@@ -191,13 +185,13 @@ impl Attr {
 /// Available arguments behind `#[graphql]` attribute when generating code for
 /// [GraphQL union][1]'s variant.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 #[derive(Debug, Default)]
 struct VariantAttr {
     /// Explicitly specified marker for the variant/field being ignored and not
     /// included into [GraphQL union][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     ignore: Option<SpanContainer<syn::Ident>>,
 
     /// Explicitly specified external resolver function for this [GraphQL union][1] variant.
@@ -206,7 +200,7 @@ struct VariantAttr {
     /// Usually, specifying an external resolver function has sense, when some custom resolving
     /// logic is involved.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     external_resolver: Option<SpanContainer<syn::ExprPath>>,
 }
 
@@ -258,22 +252,22 @@ impl VariantAttr {
 
 /// Definition of [GraphQL union][1] for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 struct Definition {
     /// Name of this [GraphQL union][1] in GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     name: String,
 
     /// Rust type that this [GraphQL union][1] is represented with.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     ty: syn::Type,
 
     /// Generics of the Rust type that this [GraphQL union][1] is implemented
     /// for.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     generics: syn::Generics,
 
     /// Indicator whether code should be generated for a trait object, rather
@@ -282,15 +276,15 @@ struct Definition {
 
     /// Description of this [GraphQL union][1] to put into GraphQL schema.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
-    description: Option<String>,
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
+    description: Option<Description>,
 
     /// Rust type of [`Context`] to generate [`GraphQLType`] implementation with
     /// for this [GraphQL union][1].
     ///
     /// [`Context`]: juniper::Context
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     context: syn::Type,
 
     /// Rust type of [`ScalarValue`] to generate [`GraphQLType`] implementation
@@ -304,12 +298,12 @@ struct Definition {
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
     /// [`ScalarValue`]: juniper::ScalarValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     scalar: scalar::Type,
 
     /// Variants definitions of this [GraphQL union][1].
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     variants: Vec<VariantDefinition>,
 }
 
@@ -333,7 +327,7 @@ impl Definition {
     ///
     /// [`GraphQLAsyncValue`]: juniper::GraphQLAsyncValue
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_generics(
         &self,
@@ -342,7 +336,7 @@ impl Definition {
         let (_, ty_generics, _) = self.generics.split_for_impl();
         let ty = &self.ty;
 
-        let mut ty_full = quote! { #ty#ty_generics };
+        let mut ty_full = quote! { #ty #ty_generics };
         if self.is_trait_object {
             ty_full = quote! { dyn #ty_full + '__obj + Send + Sync };
         }
@@ -374,14 +368,14 @@ impl Definition {
                 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);
+                    lt.lifetime.ident = format_ident!("__fa__{ident}");
                 }
 
                 let lifetimes = generics.lifetimes().map(|lt| &lt.lifetime);
                 let ty = &self.ty;
                 let (_, ty_generics, _) = generics.split_for_impl();
 
-                quote! { for<#( #lifetimes ),*> #ty#ty_generics }
+                quote! { for<#( #lifetimes ),*> #ty #ty_generics }
             } else {
                 quote! { Self }
             };
@@ -410,7 +404,7 @@ impl Definition {
     /// [GraphQL union][1].
     ///
     /// [`GraphQLUnion`]: juniper::GraphQLUnion
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_graphql_union_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -424,7 +418,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::GraphQLUnion<#scalar> for #ty_full #where_clause
+            impl #impl_generics ::juniper::marker::GraphQLUnion<#scalar> for #ty_full #where_clause
             {
                 fn mark() {
                     #all_variants_unique
@@ -438,7 +432,7 @@ impl Definition {
     /// this [GraphQL union][1].
     ///
     /// [`marker::IsOutputType`]: juniper::marker::IsOutputType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_output_type_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -449,7 +443,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::marker::IsOutputType<#scalar> for #ty_full #where_clause
+            impl #impl_generics ::juniper::marker::IsOutputType<#scalar> for #ty_full #where_clause
             {
                 fn mark() {
                     #( <#variant_tys as ::juniper::marker::IsOutputType<#scalar>>::mark(); )*
@@ -462,7 +456,7 @@ impl Definition {
     /// [GraphQL union][1].
     ///
     /// [`GraphQLType`]: juniper::GraphQLType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_graphql_type_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -470,16 +464,13 @@ impl Definition {
         let (impl_generics, ty_full, where_clause) = self.impl_generics(false);
 
         let name = &self.name;
-        let description = self
-            .description
-            .as_ref()
-            .map(|desc| quote! { .description(#desc) });
+        let description = &self.description;
 
         let variant_tys = self.variants.iter().map(|var| &var.ty);
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLType<#scalar> for #ty_full #where_clause
+            impl #impl_generics ::juniper::GraphQLType<#scalar> for #ty_full #where_clause
             {
                 fn name(_ : &Self::TypeInfo) -> Option<&'static str> {
                     Some(#name)
@@ -506,7 +497,7 @@ impl Definition {
     /// [GraphQL union][1].
     ///
     /// [`GraphQLValue`]: juniper::GraphQLValue
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_graphql_value_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -528,7 +519,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty_full #where_clause
+            impl #impl_generics ::juniper::GraphQLValue<#scalar> for #ty_full #where_clause
             {
                 type Context = #context;
                 type TypeInfo = ();
@@ -543,7 +534,7 @@ impl Definition {
                     info: &Self::TypeInfo,
                 ) -> String {
                     #( #match_variant_names )*
-                    panic!(
+                    ::std::panic!(
                         "GraphQL union `{}` cannot be resolved into any of its \
                          variants in its current state",
                         #name,
@@ -559,7 +550,7 @@ impl Definition {
                 ) -> ::juniper::ExecutionResult<#scalar> {
                     let context = executor.context();
                     #( #variant_resolvers )*
-                    return Err(::juniper::FieldError::from(format!(
+                    return Err(::juniper::FieldError::from(::std::format!(
                         "Concrete type `{}` is not handled by instance \
                          resolvers on GraphQL union `{}`",
                         type_name, #name,
@@ -573,7 +564,7 @@ impl Definition {
     /// [GraphQL union][1].
     ///
     /// [`GraphQLValueAsync`]: juniper::GraphQLValueAsync
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     fn impl_graphql_value_async_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -590,7 +581,7 @@ impl Definition {
         quote! {
             #[allow(non_snake_case)]
             #[automatically_derived]
-            impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty_full #where_clause
+            impl #impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty_full #where_clause
             {
                 fn resolve_into_type_async<'b>(
                     &'b self,
@@ -601,7 +592,7 @@ impl Definition {
                 ) -> ::juniper::BoxFuture<'b, ::juniper::ExecutionResult<#scalar>> {
                     let context = executor.context();
                     #( #variant_async_resolvers )*
-                    return ::juniper::macros::helper::err_fut(format!(
+                    return ::juniper::macros::helper::err_fut(::std::format!(
                         "Concrete type `{}` is not handled by instance \
                          resolvers on GraphQL union `{}`",
                         type_name, #name,
@@ -617,7 +608,7 @@ impl Definition {
     /// [`BaseSubTypes`]: juniper::macros::reflect::BaseSubTypes
     /// [`BaseType`]: juniper::macros::reflect::BaseType
     /// [`WrappedType`]: juniper::macros::reflect::WrappedType
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     #[must_use]
     pub(crate) fn impl_reflection_traits_tokens(&self) -> TokenStream {
         let scalar = &self.scalar;
@@ -627,7 +618,7 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::BaseType<#scalar>
                 for #ty
                 #where_clause
             {
@@ -635,7 +626,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
                 for #ty
                 #where_clause
             {
@@ -646,7 +637,7 @@ impl Definition {
             }
 
             #[automatically_derived]
-            impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
+            impl #impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
                 for #ty
                 #where_clause
             {
@@ -658,22 +649,22 @@ impl Definition {
 
 /// Definition of [GraphQL union][1] variant for code generation.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 struct VariantDefinition {
     /// Rust type that this [GraphQL union][1] variant resolves into.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     ty: syn::Type,
 
     /// Rust code for value resolution of this [GraphQL union][1] variant.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     resolver_code: syn::Expr,
 
     /// Rust code for checking whether [GraphQL union][1] should be resolved
     /// into this variant.
     ///
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     resolver_check: syn::Expr,
 
     /// Rust type of [`Context`] that this [GraphQL union][1] variant requires
@@ -683,7 +674,7 @@ struct VariantDefinition {
     /// trait method contains context argument.
     ///
     /// [`Context`]: juniper::Context
-    /// [1]: https://spec.graphql.org/June2018/#sec-Unions
+    /// [1]: https://spec.graphql.org/October2021#sec-Unions
     context: Option<syn::Type>,
 }
 
@@ -762,7 +753,7 @@ impl VariantDefinition {
 /// If duplication happens, then resolving code is overwritten with the one from
 /// `external_resolvers`.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 fn emerge_union_variants_from_attr(
     variants: &mut Vec<VariantDefinition>,
     external_resolvers: AttrResolvers,
@@ -809,7 +800,7 @@ fn emerge_union_variants_from_attr(
 /// used to enforce this requirement in the generated code. However, due to the
 /// bad error message this implementation should stay and provide guidance.
 ///
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 /// [2]: juniper::sa::assert_type_ne_all
 fn all_variants_different(variants: &[VariantDefinition]) -> bool {
     let mut types: Vec<_> = variants.iter().map(|var| &var.ty).collect();
diff --git a/juniper_codegen/src/lib.rs b/juniper_codegen/src/lib.rs
index 70c346ee..d88488c3 100644
--- a/juniper_codegen/src/lib.rs
+++ b/juniper_codegen/src/lib.rs
@@ -1,9 +1,6 @@
 #![doc = include_str!("../README.md")]
 #![recursion_limit = "1024"]
 
-mod result;
-mod util;
-
 // NOTICE: Unfortunately this macro MUST be defined here, in the crate's root module, because Rust
 //         doesn't allow to export `macro_rules!` macros from a `proc-macro` crate type currently,
 //         and so we cannot move the definition into a sub-module and use the `#[macro_export]`
@@ -16,8 +13,8 @@ mod util;
 /// By default, [`SpanContainer::span_ident`] is used.
 ///
 /// [`Span`]: proc_macro2::Span
-/// [`SpanContainer`]: crate::util::span_container::SpanContainer
-/// [`SpanContainer::span_ident`]: crate::util::span_container::SpanContainer::span_ident
+/// [`SpanContainer`]: crate::common::SpanContainer
+/// [`SpanContainer::span_ident`]: crate::common::SpanContainer::span_ident
 macro_rules! try_merge_opt {
     ($field:ident: $self:ident, $another:ident => $span:ident) => {{
         if let Some(v) = $self.$field {
@@ -47,8 +44,8 @@ macro_rules! try_merge_opt {
 ///
 /// [`HashMap`]: std::collections::HashMap
 /// [`Span`]: proc_macro2::Span
-/// [`SpanContainer`]: crate::util::span_container::SpanContainer
-/// [`SpanContainer::span_ident`]: crate::util::span_container::SpanContainer::span_ident
+/// [`SpanContainer`]: crate::common::SpanContainer
+/// [`SpanContainer::span_ident`]: crate::common::SpanContainer::span_ident
 macro_rules! try_merge_hashmap {
     ($field:ident: $self:ident, $another:ident => $span:ident) => {{
         if !$self.$field.is_empty() {
@@ -80,8 +77,8 @@ macro_rules! try_merge_hashmap {
 ///
 /// [`HashSet`]: std::collections::HashSet
 /// [`Span`]: proc_macro2::Span
-/// [`SpanContainer`]: crate::util::span_container::SpanContainer
-/// [`SpanContainer::span_ident`]: crate::util::span_container::SpanContainer::span_ident
+/// [`SpanContainer`]: crate::common::SpanContainer
+/// [`SpanContainer::span_ident`]: crate::common::SpanContainer::span_ident
 macro_rules! try_merge_hashset {
     ($field:ident: $self:ident, $another:ident => $span:ident) => {{
         if !$self.$field.is_empty() {
@@ -100,10 +97,9 @@ macro_rules! try_merge_hashset {
     };
 }
 
-mod derive_input_object;
-
 mod common;
 mod graphql_enum;
+mod graphql_input_object;
 mod graphql_interface;
 mod graphql_object;
 mod graphql_scalar;
@@ -113,17 +109,116 @@ mod scalar_value;
 
 use proc_macro::TokenStream;
 use proc_macro_error::{proc_macro_error, ResultExt as _};
-use result::GraphQLScope;
 
+/// `#[derive(GraphQLInputObject)]` macro for deriving a
+/// [GraphQL input object][0] implementation for a Rust struct. Each
+/// non-ignored field type must itself be [GraphQL input object][0] or a
+/// [GraphQL scalar][2].
+///
+/// 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::GraphQLInputObject;
+///
+/// #[derive(GraphQLInputObject)]
+/// struct Point2D {
+///     x: f64,
+///     y: f64,
+/// }
+/// ```
+///
+/// # Custom name and description
+///
+/// The name of a [GraphQL input object][0] or its [fields][1] may be overridden
+/// with the `name` attribute's argument. By default, a type name or a struct
+/// field name is used in a `camelCase`.
+///
+/// The description of a [GraphQL input object][0] or its [fields][1] may be
+/// specified either with the `description`/`desc` attribute's argument, or with
+/// a regular Rust doc comment.
+///
+/// ```rust
+/// # use juniper::GraphQLInputObject;
+/// #
+/// #[derive(GraphQLInputObject)]
+/// #[graphql(
+///     // Rename the type for GraphQL by specifying the name here.
+///     name = "Point",
+///     // You may also specify a description here.
+///     // If present, doc comments will be ignored.
+///     desc = "A point is the simplest two-dimensional primitive.",
+/// )]
+/// struct Point2D {
+///     /// Abscissa value.
+///     x: f64,
+///
+///     #[graphql(name = "y", desc = "Ordinate value")]
+///     y_coord: f64,
+/// }
+/// ```
+///
+/// # Renaming policy
+///
+/// By default, all [GraphQL input object fields][1] are renamed in a
+/// `camelCase` manner (so a `y_coord` Rust struct field becomes a
+/// `yCoord` [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::GraphQLInputObject;
+/// #
+/// #[derive(GraphQLInputObject)]
+/// #[graphql(rename_all = "none")] // disables renaming
+/// struct Point2D {
+///     x: f64,
+///     y_coord: f64, // will be `y_coord` instead of `yCoord` in GraphQL schema
+/// }
+/// ```
+///
+/// # Ignoring fields
+///
+/// To omit exposing a Rust field in a GraphQL schema, use the `ignore`
+/// attribute's argument directly on that field. Ignored fields must implement
+/// [`Default`] or have the `default = <expression>` attribute's argument.
+///
+/// ```rust
+/// # use juniper::GraphQLInputObject;
+/// #
+/// enum System {
+///     Cartesian,
+/// }
+///
+/// #[derive(GraphQLInputObject)]
+/// struct Point2D {
+///     x: f64,
+///     y: f64,
+///     #[graphql(ignore)]
+///     shift: f64, // `Default::default()` impl is used.
+///     #[graphql(skip, default = System::Cartesian)]
+///     //              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+///     // This attribute is required, as we need to be to construct `Point2D`
+///     // from `{ x: 0.0, y: 0.0 }` GraphQL input.
+///     system: System,
+/// }
+/// ```
+///
+/// [`ScalarValue`]: juniper::ScalarValue
+/// [0]: https://spec.graphql.org/October2021#sec-Input-Objects
+/// [1]: https://spec.graphql.org/October2021#InputFieldsDefinition
+/// [2]: https://spec.graphql.org/October2021#sec-Scalars
 #[proc_macro_error]
 #[proc_macro_derive(GraphQLInputObject, attributes(graphql))]
 pub fn derive_input_object(input: TokenStream) -> TokenStream {
-    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
-    let gen = derive_input_object::impl_input_object(ast, GraphQLScope::DeriveInputObject);
-    match gen {
-        Ok(gen) => gen.into(),
-        Err(err) => proc_macro_error::abort!(err),
-    }
+    graphql_input_object::derive::expand(input.into())
+        .unwrap_or_abort()
+        .into()
 }
 
 /// `#[derive(GraphQLEnum)]` macro for deriving a [GraphQL enum][0]
@@ -158,6 +253,8 @@ pub fn derive_input_object(input: TokenStream) -> TokenStream {
 /// attribute's argument, or with regular a Rust `#[deprecated]` attribute.
 ///
 /// ```rust
+/// # #![allow(deprecated)]
+/// #
 /// # use juniper::GraphQLEnum;
 /// #
 /// #[derive(GraphQLEnum)]
@@ -343,18 +440,17 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///     ) -> Result<Self, String> {
 ///         //            ^^^^^^ must implement `IntoFieldError`
 ///         input.as_string_value()
-///             .ok_or_else(|| format!("Expected `String`, found: {}", input))
+///             .ok_or_else(|| format!("Expected `String`, found: {input}"))
 ///             .and_then(|str| {
 ///                 str.strip_prefix("id: ")
 ///                     .ok_or_else(|| {
 ///                         format!(
 ///                             "Expected `UserId` to begin with `id: `, \
-///                              found: {}",
-///                             input,
+///                              found: {input}",
 ///                         )
 ///                     })
 ///             })
-///             .map(|id| Self(id.to_owned()))
+///             .map(|id| Self(id.into()))
 ///     }
 /// }
 /// ```
@@ -386,19 +482,19 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///
 /// fn to_output<S: ScalarValue>(v: &StringOrInt) -> Value<S> {
 ///     match v {
-///         StringOrInt::String(str) => Value::scalar(str.to_owned()),
+///         StringOrInt::String(s) => Value::scalar(s.to_owned()),
 ///         StringOrInt::Int(i) => Value::scalar(*i),
 ///     }
 /// }
 ///
 /// fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<StringOrInt, String> {
 ///     v.as_string_value()
-///         .map(|s| StringOrInt::String(s.to_owned()))
+///         .map(|s| StringOrInt::String(s.into()))
 ///         .or_else(|| v.as_int_value().map(StringOrInt::Int))
-///         .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+///         .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
 /// }
 ///
-/// fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+/// fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
 ///     <String as ParseScalarValue<S>>::from_str(value)
 ///         .or_else(|_| <i32 as ParseScalarValue<S>>::from_str(value))
 /// }
@@ -429,19 +525,19 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///
 ///     pub(super) fn to_output<S: ScalarValue>(v: &StringOrInt) -> Value<S> {
 ///         match v {
-///             StringOrInt::String(str) => Value::scalar(str.to_owned()),
+///             StringOrInt::String(s) => Value::scalar(s.to_owned()),
 ///             StringOrInt::Int(i) => Value::scalar(*i),
 ///         }
 ///     }
 ///
 ///     pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<StringOrInt, String> {
 ///         v.as_string_value()
-///             .map(|s| StringOrInt::String(s.to_owned()))
+///             .map(|s| StringOrInt::String(s.into()))
 ///             .or_else(|| v.as_int_value().map(StringOrInt::Int))
-///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
 ///     }
 ///
-///     pub(super) fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+///     pub(super) fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<S> {
 ///         <String as ParseScalarValue<S>>::from_str(t)
 ///             .or_else(|_| <i32 as ParseScalarValue<S>>::from_str(t))
 ///     }
@@ -467,7 +563,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 /// impl StringOrInt {
 ///     fn to_output<S: ScalarValue>(&self) -> Value<S> {
 ///         match self {
-///             Self::String(str) => Value::scalar(str.to_owned()),
+///             Self::String(s) => Value::scalar(s.to_owned()),
 ///             Self::Int(i) => Value::scalar(*i),
 ///         }
 ///     }
@@ -477,12 +573,12 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///         S: ScalarValue
 ///     {
 ///         v.as_string_value()
-///             .map(|s| Self::String(s.to_owned()))
+///             .map(|s| Self::String(s.into()))
 ///             .or_else(|| v.as_int_value().map(Self::Int))
-///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
 ///     }
 ///
-///     fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S>
+///     fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<S>
 ///     where
 ///         S: ScalarValue
 ///     {
@@ -519,7 +615,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///         S: ScalarValue,
 ///     {
 ///         match v {
-///             StringOrInt::String(str) => Value::scalar(str.to_owned()),
+///             StringOrInt::String(s) => Value::scalar(s.to_owned()),
 ///             StringOrInt::Int(i) => Value::scalar(*i),
 ///         }
 ///     }
@@ -529,9 +625,9 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
 ///         S: ScalarValue,
 ///     {
 ///         v.as_string_value()
-///             .map(|s| StringOrInt::String(s.to_owned()))
+///             .map(|s| StringOrInt::String(s.into()))
 ///             .or_else(|| v.as_int_value().map(StringOrInt::Int))
-///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+///             .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
 ///     }
 ///
 ///     // No need in `parse_token()` function.
@@ -639,8 +735,8 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
 ///
 ///     pub(super) fn from_input(v: &InputValue<CustomScalarValue>) -> Result<Date, String> {
 ///       v.as_string_value()
-///           .ok_or_else(|| format!("Expected `String`, found: {}", v))
-///           .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {}", e)))
+///           .ok_or_else(|| format!("Expected `String`, found: {v}"))
+///           .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {e}")))
 ///     }
 /// }
 /// #
@@ -669,7 +765,7 @@ pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream {
 /// methods).
 ///
 /// ```rust
-/// # use std::{fmt, convert::TryInto as _};
+/// # use std::fmt;
 /// #
 /// # use serde::{de, Deserialize, Deserializer, Serialize};
 /// # use juniper::ScalarValue;
@@ -1032,7 +1128,7 @@ pub fn derive_scalar_value(input: TokenStream) -> TokenStream {
 ///     // You can return `&str` even if trait definition returns `String`.
 ///     fn detailed_info(&self, info_kind: String) -> &str {
 ///         (info_kind == "planet")
-///             .then(|| &self.home_planet)
+///             .then_some(&self.home_planet)
 ///             .unwrap_or(&self.id)
 ///     }
 /// }
@@ -1188,8 +1284,8 @@ pub fn derive_scalar_value(input: TokenStream) -> TokenStream {
 /// [`Context`]: juniper::Context
 /// [`Executor`]: juniper::Executor
 /// [`ScalarValue`]: juniper::ScalarValue
-/// [0]: https://spec.graphql.org/June2018
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [0]: https://spec.graphql.org/October2021
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
 /// [2]: https://doc.rust-lang.org/stable/reference/items/traits.html#object-safety
 /// [3]: https://doc.rust-lang.org/stable/reference/types/trait-object.html
 /// [4]: https://doc.rust-lang.org/stable/std/primitive.unit.html
@@ -1229,7 +1325,7 @@ pub fn graphql_interface(attr: TokenStream, body: TokenStream) -> TokenStream {
 /// For more info and possibilities see [`#[graphql_interface]`] macro.
 ///
 /// [`#[graphql_interface]`]: crate::graphql_interface
-/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
+/// [1]: https://spec.graphql.org/October2021#sec-Interfaces
 #[proc_macro_error]
 #[proc_macro_derive(GraphQLInterface, attributes(graphql))]
 pub fn derive_interface(body: TokenStream) -> TokenStream {
@@ -1366,7 +1462,7 @@ pub fn derive_interface(body: TokenStream) -> TokenStream {
 /// ```
 ///
 /// [`ScalarValue`]: juniper::ScalarValue
-/// [1]: https://spec.graphql.org/June2018/#sec-Objects
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
 #[proc_macro_error]
 #[proc_macro_derive(GraphQLObject, attributes(graphql))]
 pub fn derive_object(body: TokenStream) -> TokenStream {
@@ -1690,8 +1786,8 @@ pub fn derive_object(body: TokenStream) -> TokenStream {
 /// [`GraphQLType`]: juniper::GraphQLType
 /// [`GraphQLValue`]: juniper::GraphQLValue
 /// [`ScalarValue`]: juniper::ScalarValue
-/// [0]: https://spec.graphql.org/June2018
-/// [1]: https://spec.graphql.org/June2018/#sec-Objects
+/// [0]: https://spec.graphql.org/October2021
+/// [1]: https://spec.graphql.org/October2021#sec-Objects
 #[proc_macro_error]
 #[proc_macro_attribute]
 pub fn graphql_object(attr: TokenStream, body: TokenStream) -> TokenStream {
@@ -1744,7 +1840,7 @@ pub fn graphql_object(attr: TokenStream, body: TokenStream) -> TokenStream {
 /// [`GraphQLType`]: juniper::GraphQLType
 /// [`GraphQLSubscriptionValue`]: juniper::GraphQLSubscriptionValue
 /// [`Stream`]: futures::Stream
-/// [1]: https://spec.graphql.org/June2018/#sec-Subscription
+/// [1]: https://spec.graphql.org/October2021#sec-Subscription
 #[proc_macro_error]
 #[proc_macro_attribute]
 pub fn graphql_subscription(attr: TokenStream, body: TokenStream) -> TokenStream {
@@ -2051,7 +2147,7 @@ pub fn graphql_subscription(attr: TokenStream, body: TokenStream) -> TokenStream
 ///
 /// [`Context`]: juniper::Context
 /// [`ScalarValue`]: juniper::ScalarValue
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 /// [4]: https://doc.rust-lang.org/stable/std/primitive.unit.html
 #[proc_macro_error]
 #[proc_macro_derive(GraphQLUnion, attributes(graphql))]
@@ -2341,7 +2437,7 @@ pub fn derive_union(body: TokenStream) -> TokenStream {
 ///
 /// [`Context`]: juniper::Context
 /// [`ScalarValue`]: juniper::ScalarValue
-/// [1]: https://spec.graphql.org/June2018/#sec-Unions
+/// [1]: https://spec.graphql.org/October2021#sec-Unions
 /// [2]: https://doc.rust-lang.org/stable/reference/items/traits.html#object-safety
 /// [3]: https://doc.rust-lang.org/stable/reference/types/trait-object.html
 /// [4]: https://doc.rust-lang.org/stable/std/primitive.unit.html
diff --git a/juniper_codegen/src/result.rs b/juniper_codegen/src/result.rs
deleted file mode 100644
index 5c979d69..00000000
--- a/juniper_codegen/src/result.rs
+++ /dev/null
@@ -1,152 +0,0 @@
-//!
-
-use crate::util::duplicate::Duplicate;
-use proc_macro2::Span;
-use proc_macro_error::{Diagnostic, Level};
-use std::fmt;
-
-/// URL of the GraphQL specification (June 2018 Edition).
-pub const SPEC_URL: &str = "https://spec.graphql.org/June2018/";
-
-pub enum GraphQLScope {
-    EnumDerive,
-    InterfaceAttr,
-    InterfaceDerive,
-    ObjectAttr,
-    ObjectDerive,
-    ScalarAttr,
-    ScalarDerive,
-    ScalarValueDerive,
-    UnionAttr,
-    UnionDerive,
-    DeriveInputObject,
-}
-
-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",
-        }
-    }
-}
-
-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",
-        };
-        write!(f, "GraphQL {}", name)
-    }
-}
-
-#[allow(unused_variables)]
-#[derive(Debug)]
-pub enum UnsupportedAttribute {
-    Skip,
-    Interface,
-    Deprecation,
-}
-
-impl GraphQLScope {
-    fn spec_link(&self) -> String {
-        format!("{}{}", SPEC_URL, self.spec_section())
-    }
-
-    pub fn custom<S: AsRef<str>>(&self, span: Span, msg: S) -> Diagnostic {
-        Diagnostic::spanned(span, Level::Error, format!("{} {}", self, msg.as_ref()))
-            .note(self.spec_link())
-    }
-
-    pub fn error(&self, err: syn::Error) -> Diagnostic {
-        Diagnostic::spanned(err.span(), Level::Error, format!("{} {}", self, err))
-            .note(self.spec_link())
-    }
-
-    pub fn emit_custom<S: AsRef<str>>(&self, span: Span, msg: S) {
-        self.custom(span, msg).emit()
-    }
-
-    pub fn custom_error<S: AsRef<str>>(&self, span: Span, msg: S) -> syn::Error {
-        syn::Error::new(span, format!("{} {}", self, msg.as_ref()))
-    }
-
-    pub fn unsupported_attribute(&self, attribute: Span, kind: UnsupportedAttribute) {
-        Diagnostic::spanned(
-            attribute,
-            Level::Error,
-            format!("attribute `{:?}` can not be used at the top level of {}", kind, self),
-        )
-        .note("The macro is known to Juniper. However, not all valid #[graphql] attributes are available for each macro".to_string())
-        .emit();
-    }
-
-    pub fn unsupported_attribute_within(&self, attribute: Span, kind: UnsupportedAttribute) {
-        Diagnostic::spanned(
-            attribute,
-            Level::Error,
-            format!("attribute `{:?}` can not be used inside of {}", kind, self),
-        )
-        .note("The macro is known to Juniper. However, not all valid #[graphql] attributes are available for each macro".to_string())
-        .emit();
-    }
-
-    pub fn not_empty(&self, container: Span) {
-        Diagnostic::spanned(
-            container,
-            Level::Error,
-            format!("{} expects at least one field", self),
-        )
-        .note(self.spec_link())
-        .emit();
-    }
-
-    pub fn duplicate<'a, T: syn::spanned::Spanned + 'a>(
-        &self,
-        duplicates: impl IntoIterator<Item = &'a Duplicate<T>>,
-    ) {
-        duplicates
-            .into_iter()
-            .for_each(|dup| {
-                dup.spanned[1..]
-                    .iter()
-                    .for_each(|spanned| {
-                        Diagnostic::spanned(
-                            spanned.span(),
-                            Level::Error,
-                            format!(
-                                "{} does not allow fields with the same name",
-                                self
-                            ),
-                        )
-                            .help(format!("There is at least one other field with the same name `{}`, possibly renamed via the #[graphql] attribute", dup.name))
-                            .note(self.spec_link())
-                            .emit();
-                    });
-            })
-    }
-
-    pub fn no_double_underscore(&self, field: Span) {
-        Diagnostic::spanned(
-            field,
-            Level::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."
-                .into(),
-        )
-        .note(format!("{}#sec-Schema", SPEC_URL))
-        .emit();
-    }
-}
diff --git a/juniper_codegen/src/scalar_value/mod.rs b/juniper_codegen/src/scalar_value/mod.rs
index 023ba148..e0a0d78b 100644
--- a/juniper_codegen/src/scalar_value/mod.rs
+++ b/juniper_codegen/src/scalar_value/mod.rs
@@ -1,6 +1,6 @@
 //! Code generation for `#[derive(ScalarValue)]` macro.
 
-use std::{collections::HashMap, convert::TryFrom};
+use std::collections::HashMap;
 
 use proc_macro2::{Literal, TokenStream};
 use quote::{quote, ToTokens, TokenStreamExt as _};
@@ -12,14 +12,14 @@ use syn::{
     visit::Visit,
 };
 
-use crate::{
-    common::parse::{attr::err, ParseBufferExt as _},
-    util::{filter_attrs, span_container::SpanContainer},
-    GraphQLScope,
+use crate::common::{
+    diagnostic, filter_attrs,
+    parse::{attr::err, ParseBufferExt as _},
+    SpanContainer,
 };
 
-/// [`GraphQLScope`] of errors for `#[derive(ScalarValue)]` macro.
-const ERR: GraphQLScope = GraphQLScope::ScalarValueDerive;
+/// [`diagnostic::Scope`] of errors for `#[derive(ScalarValue)]` macro.
+const ERR: diagnostic::Scope = diagnostic::Scope::ScalarValueDerive;
 
 /// Expands `#[derive(ScalarValue)]` macro into generated code.
 pub fn expand_derive(input: TokenStream) -> syn::Result<TokenStream> {
@@ -55,11 +55,11 @@ pub fn expand_derive(input: TokenStream) -> syn::Result<TokenStream> {
         (Method::AsBool, "as_bool"),
     ]
     .iter()
-    .filter_map(|(method, err)| (!methods.contains_key(method)).then(|| err))
+    .filter_map(|(method, err)| (!methods.contains_key(method)).then_some(err))
     .fold(None, |acc, &method| {
         Some(
-            acc.map(|acc| format!("{}, {}", acc, method))
-                .unwrap_or_else(|| method.to_owned()),
+            acc.map(|acc| format!("{acc}, {method}"))
+                .unwrap_or_else(|| method.into()),
         )
     })
     .filter(|_| !attr.allow_missing_attrs);
@@ -67,10 +67,9 @@ pub fn expand_derive(input: TokenStream) -> syn::Result<TokenStream> {
         return Err(ERR.custom_error(
             span,
             format!(
-                "missing `#[value({})]` attributes. In case you are sure \
-                 that it's ok, use `#[value(allow_missing_attributes)]` to \
-                 suppress this error.",
-                missing_methods,
+                "missing `#[value({missing_methods})]` attributes. In case you \
+                 are sure that it's ok, use `#[value(allow_missing_attributes)]` \
+                 to suppress this error.",
             ),
         ));
     }
@@ -298,10 +297,10 @@ impl Definition {
 
         quote! {
             #[automatically_derived]
-            impl#impl_gens ::juniper::ScalarValue for #ident#ty_gens
+            impl #impl_gens ::juniper::ScalarValue for #ident #ty_gens
                 #where_clause
             {
-                #(#methods)*
+                #( #methods )*
             }
         }
     }
@@ -333,20 +332,20 @@ impl Definition {
 
                 quote! {
                     #[automatically_derived]
-                    impl#impl_gen ::std::convert::From<#var_ty> for #ty_ident#ty_gen
+                    impl #impl_gen ::std::convert::From<#var_ty> for #ty_ident #ty_gen
                         #where_clause
                     {
                         fn from(v: #var_ty) -> Self {
-                            Self::#var_ident#var_field
+                            Self::#var_ident #var_field
                         }
                     }
 
                     #[automatically_derived]
-                    impl#impl_gen ::std::convert::From<#ty_ident#ty_gen> for Option<#var_ty>
+                    impl #impl_gen ::std::convert::From<#ty_ident #ty_gen> for Option<#var_ty>
                         #where_clause
                     {
-                        fn from(ty: #ty_ident#ty_gen) -> Self {
-                            if let #ty_ident::#var_ident#var_field = ty {
+                        fn from(ty: #ty_ident #ty_gen) -> Self {
+                            if let #ty_ident::#var_ident #var_field = ty {
                                 Some(v)
                             } else {
                                 None
@@ -355,12 +354,12 @@ impl Definition {
                     }
 
                     #[automatically_derived]
-                    impl#lf_impl_gen ::std::convert::From<&'___a #ty_ident#ty_gen> for
+                    impl #lf_impl_gen ::std::convert::From<&'___a #ty_ident #ty_gen> for
                         Option<&'___a #var_ty>
                         #where_clause
                     {
-                        fn from(ty: &'___a #ty_ident#ty_gen) -> Self {
-                            if let #ty_ident::#var_ident#var_field = ty {
+                        fn from(ty: &'___a #ty_ident #ty_gen) -> Self {
+                            if let #ty_ident::#var_ident #var_field = ty {
                                 Some(v)
                             } else {
                                 None
@@ -404,17 +403,17 @@ impl Definition {
                 .as_ref()
                 .map_or_else(|| quote! { (v) }, |i| quote! { { #i: v } });
 
-            quote! { Self::#var_ident#var_field => ::std::fmt::Display::fmt(v, f), }
+            quote! { Self::#var_ident #var_field => ::std::fmt::Display::fmt(v, f), }
         });
 
         quote! {
             #[automatically_derived]
-            impl#impl_gen ::std::fmt::Display for #ident#ty_gen
+            impl #impl_gen ::std::fmt::Display for #ident #ty_gen
                 #where_clause
             {
                 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
                     match self {
-                        #(#arms)*
+                        #( #arms )*
                     }
                 }
             }
@@ -440,7 +439,7 @@ impl Variant {
     fn match_arm(&self) -> TokenStream {
         let (ident, field) = (&self.ident, &self.field.match_arg());
         quote! {
-            Self::#ident#field
+            Self::#ident #field
         }
     }
 }
diff --git a/juniper_codegen/src/util/duplicate.rs b/juniper_codegen/src/util/duplicate.rs
deleted file mode 100644
index b056eb71..00000000
--- a/juniper_codegen/src/util/duplicate.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-//!
-
-use std::collections::HashMap;
-
-pub struct Duplicate<T> {
-    pub name: String,
-    pub spanned: Vec<T>,
-}
-
-impl<T> Duplicate<T> {
-    pub fn find_by_key<'a, F>(items: &'a [T], name: F) -> Option<Vec<Duplicate<&'a T>>>
-    where
-        T: 'a,
-        F: Fn(&'a T) -> &'a str,
-    {
-        let mut mapping: HashMap<&str, Vec<&T>> = HashMap::with_capacity(items.len());
-
-        for item in items {
-            if let Some(vals) = mapping.get_mut(name(item)) {
-                vals.push(item);
-            } else {
-                mapping.insert(name(item), vec![item]);
-            }
-        }
-
-        let duplicates = mapping
-            .into_iter()
-            .filter_map(|(k, v)| {
-                if v.len() != 1 {
-                    Some(Duplicate {
-                        name: k.to_string(),
-                        spanned: v,
-                    })
-                } else {
-                    None
-                }
-            })
-            .collect::<Vec<_>>();
-
-        if !duplicates.is_empty() {
-            Some(duplicates)
-        } else {
-            None
-        }
-    }
-}
diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs
deleted file mode 100644
index 19b70a0a..00000000
--- a/juniper_codegen/src/util/mod.rs
+++ /dev/null
@@ -1,1107 +0,0 @@
-#![allow(clippy::single_match)]
-
-pub mod duplicate;
-pub mod span_container;
-
-use std::{collections::HashMap, convert::TryFrom, str::FromStr};
-
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::abort;
-use quote::{quote, quote_spanned};
-use span_container::SpanContainer;
-use syn::{
-    ext::IdentExt as _,
-    parse::{Parse, ParseStream},
-    parse_quote,
-    punctuated::Punctuated,
-    spanned::Spanned,
-    token, Attribute, Ident, Lit, Meta, MetaList, MetaNameValue, NestedMeta,
-};
-
-use crate::common::parse::ParseBufferExt as _;
-
-/// Compares a path to a one-segment string value,
-/// return true if equal.
-pub fn path_eq_single(path: &syn::Path, value: &str) -> bool {
-    path.segments.len() == 1 && path.segments[0].ident == value
-}
-
-#[derive(Debug)]
-pub struct DeprecationAttr {
-    pub reason: Option<String>,
-}
-
-pub fn find_graphql_attr(attrs: &[Attribute]) -> Option<&Attribute> {
-    attrs
-        .iter()
-        .find(|attr| path_eq_single(&attr.path, "graphql"))
-}
-
-/// Filters given `attrs` to contain attributes only with the given `name`.
-pub fn filter_attrs<'a>(
-    name: &'a str,
-    attrs: &'a [Attribute],
-) -> impl Iterator<Item = &'a Attribute> + 'a {
-    attrs
-        .iter()
-        .filter(move |attr| path_eq_single(&attr.path, name))
-}
-
-pub fn get_deprecated(attrs: &[Attribute]) -> Option<SpanContainer<DeprecationAttr>> {
-    attrs
-        .iter()
-        .filter_map(|attr| match attr.parse_meta() {
-            Ok(Meta::List(ref list)) if list.path.is_ident("deprecated") => {
-                let val = get_deprecated_meta_list(list);
-                Some(SpanContainer::new(list.path.span(), None, val))
-            }
-            Ok(Meta::Path(ref path)) if path.is_ident("deprecated") => Some(SpanContainer::new(
-                path.span(),
-                None,
-                DeprecationAttr { reason: None },
-            )),
-            _ => None,
-        })
-        .next()
-}
-
-fn get_deprecated_meta_list(list: &MetaList) -> DeprecationAttr {
-    for meta in &list.nested {
-        if let NestedMeta::Meta(Meta::NameValue(ref nv)) = *meta {
-            if nv.path.is_ident("note") {
-                match nv.lit {
-                    Lit::Str(ref strlit) => {
-                        return DeprecationAttr {
-                            reason: Some(strlit.value()),
-                        };
-                    }
-                    _ => abort!(syn::Error::new(
-                        nv.lit.span(),
-                        "only strings are allowed for deprecation",
-                    )),
-                }
-            } else {
-                abort!(syn::Error::new(
-                    nv.path.span(),
-                    "unrecognized setting on #[deprecated(..)] attribute",
-                ));
-            }
-        }
-    }
-    DeprecationAttr { reason: None }
-}
-
-// Gets doc comment.
-pub fn get_doc_comment(attrs: &[Attribute]) -> Option<SpanContainer<String>> {
-    if let Some(items) = get_doc_attr(attrs) {
-        if let Some(doc_strings) = get_doc_strings(&items) {
-            return Some(doc_strings.map(|strings| join_doc_strings(&strings)));
-        }
-    }
-    None
-}
-
-// Concatenates doc strings into one string.
-fn join_doc_strings(docs: &[String]) -> String {
-    // Note: this is guaranteed since this function is only called
-    // from get_doc_strings().
-    debug_assert!(!docs.is_empty());
-
-    let last_index = docs.len() - 1;
-    docs.iter()
-        .map(|s| s.as_str().trim_end())
-        // Trim leading space.
-        .map(|s| s.strip_prefix(' ').unwrap_or(s))
-        // Add newline, exept when string ends in a continuation backslash or is the last line.
-        .enumerate()
-        .fold(String::new(), |mut buffer, (index, s)| {
-            if index == last_index {
-                buffer.push_str(s);
-            } else if s.ends_with('\\') {
-                buffer.push_str(s.trim_end_matches('\\'));
-                buffer.push(' ');
-            } else {
-                buffer.push_str(s);
-                buffer.push('\n');
-            }
-            buffer
-        })
-}
-
-// Gets doc strings from doc comment attributes.
-fn get_doc_strings(items: &[MetaNameValue]) -> Option<SpanContainer<Vec<String>>> {
-    let mut span = None;
-    let comments = items
-        .iter()
-        .filter_map(|item| {
-            if item.path.is_ident("doc") {
-                match item.lit {
-                    Lit::Str(ref strlit) => {
-                        if span.is_none() {
-                            span = Some(strlit.span());
-                        }
-                        Some(strlit.value())
-                    }
-                    _ => abort!(syn::Error::new(
-                        item.lit.span(),
-                        "doc attributes only have string literal"
-                    )),
-                }
-            } else {
-                None
-            }
-        })
-        .collect::<Vec<_>>();
-    span.map(|span| SpanContainer::new(span, None, comments))
-}
-
-// Gets doc comment attributes.
-fn get_doc_attr(attrs: &[Attribute]) -> Option<Vec<MetaNameValue>> {
-    let mut docs = Vec::new();
-    for attr in attrs {
-        match attr.parse_meta() {
-            Ok(Meta::NameValue(ref nv)) if nv.path.is_ident("doc") => docs.push(nv.clone()),
-            _ => {}
-        }
-    }
-    if !docs.is_empty() {
-        return Some(docs);
-    }
-    None
-}
-
-// Note: duplicated from juniper crate!
-#[doc(hidden)]
-pub fn to_camel_case(s: &str) -> String {
-    let mut dest = String::new();
-
-    // Handle `_` and `__` to be more friendly with the `_var` convention for unused variables, and
-    // GraphQL introspection identifiers.
-    let s_iter = if let Some(s) = s.strip_prefix("__") {
-        dest.push_str("__");
-        s
-    } else {
-        s.strip_prefix('_').unwrap_or(s)
-    }
-    .split('_')
-    .enumerate();
-
-    for (i, part) in s_iter {
-        if i > 0 && part.len() == 1 {
-            dest.push_str(&part.to_uppercase());
-        } else if i > 0 && part.len() > 1 {
-            let first = part
-                .chars()
-                .next()
-                .unwrap()
-                .to_uppercase()
-                .collect::<String>();
-            let second = &part[1..];
-
-            dest.push_str(&first);
-            dest.push_str(second);
-        } else if i == 0 {
-            dest.push_str(part);
-        }
-    }
-
-    dest
-}
-
-pub(crate) fn to_upper_snake_case(s: &str) -> String {
-    let mut last_lower = false;
-    let mut upper = String::new();
-    for c in s.chars() {
-        if c == '_' {
-            last_lower = false;
-        } else if c.is_lowercase() {
-            last_lower = true;
-        } else if c.is_uppercase() {
-            if last_lower {
-                upper.push('_');
-            }
-            last_lower = false;
-        }
-
-        for u in c.to_uppercase() {
-            upper.push(u);
-        }
-    }
-    upper
-}
-
-#[doc(hidden)]
-pub fn is_valid_name(field_name: &str) -> bool {
-    let mut chars = field_name.chars();
-
-    match chars.next() {
-        // first char can't be a digit
-        Some(c) if c.is_ascii_alphabetic() || c == '_' => (),
-        // can't be an empty string or any other character
-        _ => return false,
-    };
-
-    chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
-}
-
-/// The different possible ways to change case of fields in a struct, or variants in an enum.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum RenameRule {
-    /// Don't apply a default rename rule.
-    None,
-    /// Rename to "camelCase" style.
-    CamelCase,
-    /// Rename to "SCREAMING_SNAKE_CASE" style
-    ScreamingSnakeCase,
-}
-
-impl RenameRule {
-    pub fn apply(&self, field: &str) -> String {
-        match self {
-            Self::None => field.to_owned(),
-            Self::CamelCase => to_camel_case(field),
-            Self::ScreamingSnakeCase => to_upper_snake_case(field),
-        }
-    }
-}
-
-impl FromStr for RenameRule {
-    type Err = ();
-
-    fn from_str(rule: &str) -> Result<Self, Self::Err> {
-        match rule {
-            "none" => Ok(Self::None),
-            "camelCase" => Ok(Self::CamelCase),
-            "SCREAMING_SNAKE_CASE" => Ok(Self::ScreamingSnakeCase),
-            _ => Err(()),
-        }
-    }
-}
-
-impl TryFrom<syn::LitStr> for RenameRule {
-    type Error = syn::Error;
-
-    fn try_from(lit: syn::LitStr) -> syn::Result<Self> {
-        Self::from_str(&lit.value()).map_err(|_| syn::Error::new(lit.span(), "unknown rename rule"))
-    }
-}
-
-impl Parse for RenameRule {
-    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
-        Self::try_from(input.parse::<syn::LitStr>()?)
-    }
-}
-
-#[derive(Default, Debug)]
-pub struct ObjectAttributes {
-    pub name: Option<SpanContainer<String>>,
-    pub description: Option<SpanContainer<String>>,
-    pub context: Option<SpanContainer<syn::Type>>,
-    pub scalar: Option<SpanContainer<syn::Type>>,
-    pub interfaces: Vec<SpanContainer<syn::Type>>,
-    pub no_async: Option<SpanContainer<()>>,
-    pub is_internal: bool,
-    pub rename: Option<RenameRule>,
-}
-
-impl Parse for ObjectAttributes {
-    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
-        let mut output = Self::default();
-
-        while !input.is_empty() {
-            let ident = input.parse_any_ident()?;
-            match ident.to_string().as_str() {
-                "name" => {
-                    input.parse::<token::Eq>()?;
-                    let val = input.parse::<syn::LitStr>()?;
-                    output.name = Some(SpanContainer::new(
-                        ident.span(),
-                        Some(val.span()),
-                        val.value(),
-                    ));
-                }
-                "description" => {
-                    input.parse::<token::Eq>()?;
-                    let val = input.parse::<syn::LitStr>()?;
-                    output.description = Some(SpanContainer::new(
-                        ident.span(),
-                        Some(val.span()),
-                        val.value(),
-                    ));
-                }
-                "context" | "Context" => {
-                    input.parse::<token::Eq>()?;
-                    // TODO: remove legacy support for string based Context.
-                    let ctx = if let Ok(val) = input.parse::<syn::LitStr>() {
-                        eprintln!("DEPRECATION WARNING: using a string literal for the Context is deprecated");
-                        eprintln!("Use a normal type instead - example: 'Context = MyContextType'");
-                        syn::parse_str::<syn::Type>(&val.value())?
-                    } else {
-                        input.parse::<syn::Type>()?
-                    };
-                    output.context = Some(SpanContainer::new(ident.span(), Some(ctx.span()), ctx));
-                }
-                "scalar" | "Scalar" => {
-                    input.parse::<token::Eq>()?;
-                    let val = input.parse::<syn::Type>()?;
-                    output.scalar = Some(SpanContainer::new(ident.span(), Some(val.span()), val));
-                }
-                "impl" | "implements" | "interfaces" => {
-                    input.parse::<token::Eq>()?;
-                    output.interfaces = input.parse_maybe_wrapped_and_punctuated::<
-                        syn::Type, token::Bracket, token::Comma,
-                    >()?.into_iter()
-                        .map(|interface| {
-                            SpanContainer::new(ident.span(), Some(interface.span()), interface)
-                        })
-                        .collect();
-                }
-                // FIXME: make this unneccessary.
-                "noasync" => {
-                    output.no_async = Some(SpanContainer::new(ident.span(), None, ()));
-                }
-                "internal" => {
-                    output.is_internal = true;
-                }
-                "rename" => {
-                    input.parse::<token::Eq>()?;
-                    output.rename = Some(input.parse::<RenameRule>()?);
-                }
-                _ => {
-                    return Err(syn::Error::new(ident.span(), "unknown attribute"));
-                }
-            }
-            input.try_parse::<token::Comma>()?;
-        }
-
-        Ok(output)
-    }
-}
-
-impl ObjectAttributes {
-    pub fn from_attrs(attrs: &[syn::Attribute]) -> syn::Result<Self> {
-        let attr_opt = find_graphql_attr(attrs);
-        if let Some(attr) = attr_opt {
-            // Need to unwrap  outer (), which are not present for proc macro attributes,
-            // but are present for regular ones.
-
-            let mut a: Self = attr.parse_args()?;
-            if a.description.is_none() {
-                a.description = get_doc_comment(attrs);
-            }
-            Ok(a)
-        } else {
-            Ok(Self {
-                description: get_doc_comment(attrs),
-                ..Self::default()
-            })
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct FieldAttributeArgument {
-    pub name: syn::Ident,
-    pub rename: Option<SpanContainer<syn::LitStr>>,
-    pub default: Option<syn::Expr>,
-    pub description: Option<syn::LitStr>,
-}
-
-impl Parse for FieldAttributeArgument {
-    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
-        let name = input.parse::<Ident>()?.unraw();
-
-        let mut arg = Self {
-            name,
-            rename: None,
-            default: None,
-            description: None,
-        };
-
-        let content;
-        syn::parenthesized!(content in input);
-        while !content.is_empty() {
-            let name = content.parse::<syn::Ident>()?;
-            content.parse::<token::Eq>()?;
-
-            match name.to_string().as_str() {
-                "name" => {
-                    let val: syn::LitStr = content.parse()?;
-                    arg.rename = Some(SpanContainer::new(name.span(), Some(val.span()), val));
-                }
-                "description" => {
-                    arg.description = Some(content.parse()?);
-                }
-                "default" => {
-                    arg.default = Some(content.parse()?);
-                }
-                _ => return Err(syn::Error::new(name.span(), "unknown attribute")),
-            }
-
-            // Discard trailing comma.
-            content.parse::<token::Comma>().ok();
-        }
-
-        Ok(arg)
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub enum FieldAttributeParseMode {
-    Object,
-}
-
-enum FieldAttribute {
-    Name(SpanContainer<syn::LitStr>),
-    Description(SpanContainer<syn::LitStr>),
-    Deprecation(SpanContainer<DeprecationAttr>),
-    Skip(SpanContainer<syn::Ident>),
-    Arguments(HashMap<String, FieldAttributeArgument>),
-    Default(Box<SpanContainer<Option<syn::Expr>>>),
-}
-
-impl Parse for FieldAttribute {
-    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
-        let ident = input.parse::<syn::Ident>()?;
-
-        match ident.to_string().as_str() {
-            "name" => {
-                input.parse::<token::Eq>()?;
-                let lit = input.parse::<syn::LitStr>()?;
-                let raw = lit.value();
-                if !is_valid_name(&raw) {
-                    Err(syn::Error::new(lit.span(), "name consists of not allowed characters. (must match /^[_a-zA-Z][_a-zA-Z0-9]*$/)"))
-                } else {
-                    Ok(FieldAttribute::Name(SpanContainer::new(
-                        ident.span(),
-                        Some(lit.span()),
-                        lit,
-                    )))
-                }
-            }
-            "description" => {
-                input.parse::<token::Eq>()?;
-                let lit = input.parse::<syn::LitStr>()?;
-                Ok(FieldAttribute::Description(SpanContainer::new(
-                    ident.span(),
-                    Some(lit.span()),
-                    lit,
-                )))
-            }
-            "deprecated" | "deprecation" => {
-                let reason = if input.peek(token::Eq) {
-                    input.parse::<token::Eq>()?;
-                    Some(input.parse::<syn::LitStr>()?)
-                } else {
-                    None
-                };
-                Ok(FieldAttribute::Deprecation(SpanContainer::new(
-                    ident.span(),
-                    reason.as_ref().map(|val| val.span()),
-                    DeprecationAttr {
-                        reason: reason.map(|val| val.value()),
-                    },
-                )))
-            }
-            "skip" => Ok(FieldAttribute::Skip(SpanContainer::new(
-                ident.span(),
-                None,
-                ident,
-            ))),
-            "arguments" => {
-                let arg_content;
-                syn::parenthesized!(arg_content in input);
-                let args = Punctuated::<FieldAttributeArgument, token::Comma>::parse_terminated(
-                    &arg_content,
-                )?;
-                let map = args
-                    .into_iter()
-                    .map(|arg| (arg.name.to_string(), arg))
-                    .collect();
-                Ok(FieldAttribute::Arguments(map))
-            }
-            "default" => {
-                let default_expr = if input.peek(token::Eq) {
-                    input.parse::<token::Eq>()?;
-                    let lit = input.parse::<syn::LitStr>()?;
-                    let default_expr = lit.parse::<syn::Expr>()?;
-                    SpanContainer::new(ident.span(), Some(lit.span()), Some(default_expr))
-                } else {
-                    SpanContainer::new(ident.span(), None, None)
-                };
-
-                Ok(FieldAttribute::Default(Box::new(default_expr)))
-            }
-            _ => Err(syn::Error::new(ident.span(), "unknown attribute")),
-        }
-    }
-}
-
-#[derive(Default)]
-pub struct FieldAttributes {
-    pub name: Option<SpanContainer<String>>,
-    pub description: Option<SpanContainer<String>>,
-    pub deprecation: Option<SpanContainer<DeprecationAttr>>,
-    /// Only relevant for GraphQLObject derive.
-    pub skip: Option<SpanContainer<syn::Ident>>,
-    /// Only relevant for object macro.
-    pub arguments: HashMap<String, FieldAttributeArgument>,
-    /// Only relevant for object input objects.
-    pub default: Option<SpanContainer<Option<syn::Expr>>>,
-}
-
-impl Parse for FieldAttributes {
-    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
-        let items = Punctuated::<FieldAttribute, token::Comma>::parse_terminated(input)?;
-
-        let mut output = Self::default();
-
-        for item in items {
-            match item {
-                FieldAttribute::Name(name) => {
-                    output.name = Some(name.map(|val| val.value()));
-                }
-                FieldAttribute::Description(name) => {
-                    output.description = Some(name.map(|val| val.value()));
-                }
-                FieldAttribute::Deprecation(attr) => {
-                    output.deprecation = Some(attr);
-                }
-                FieldAttribute::Skip(ident) => {
-                    output.skip = Some(ident);
-                }
-                FieldAttribute::Arguments(args) => {
-                    output.arguments = args;
-                }
-                FieldAttribute::Default(expr) => {
-                    output.default = Some(*expr);
-                }
-            }
-        }
-
-        if !input.is_empty() {
-            Err(input.error("Unexpected input"))
-        } else {
-            Ok(output)
-        }
-    }
-}
-
-impl FieldAttributes {
-    pub fn from_attrs(
-        attrs: &[syn::Attribute],
-        _mode: FieldAttributeParseMode,
-    ) -> syn::Result<Self> {
-        let doc_comment = get_doc_comment(attrs);
-        let deprecation = get_deprecated(attrs);
-
-        let attr_opt = attrs.iter().find(|attr| attr.path.is_ident("graphql"));
-
-        let mut output = match attr_opt {
-            Some(attr) => attr.parse_args()?,
-            None => Self::default(),
-        };
-
-        // Check for regular doc comment.
-        if output.description.is_none() {
-            output.description = doc_comment;
-        }
-        if output.deprecation.is_none() {
-            output.deprecation = deprecation;
-        }
-
-        Ok(output)
-    }
-}
-
-#[derive(Debug)]
-pub struct GraphQLTypeDefinitionFieldArg {
-    pub name: String,
-    pub description: Option<String>,
-    pub default: Option<syn::Expr>,
-    pub _type: Box<syn::Type>,
-}
-
-#[derive(Debug)]
-pub struct GraphQLTypeDefinitionField {
-    pub name: String,
-    pub _type: syn::Type,
-    pub description: Option<String>,
-    pub deprecation: Option<DeprecationAttr>,
-    pub args: Vec<GraphQLTypeDefinitionFieldArg>,
-    pub resolver_code: TokenStream,
-    pub is_type_inferred: bool,
-    pub is_async: bool,
-    pub default: Option<TokenStream>,
-    pub span: Span,
-}
-
-impl syn::spanned::Spanned for GraphQLTypeDefinitionField {
-    fn span(&self) -> Span {
-        self.span
-    }
-}
-
-impl<'a> syn::spanned::Spanned for &'a GraphQLTypeDefinitionField {
-    fn span(&self) -> Span {
-        self.span
-    }
-}
-
-/// Definition of a graphql type based on information extracted
-/// by various macros.
-/// The definition can be rendered to Rust code.
-#[derive(Debug)]
-pub struct GraphQLTypeDefiniton {
-    pub name: String,
-    pub _type: syn::Type,
-    pub context: Option<syn::Type>,
-    pub scalar: Option<syn::Type>,
-    pub description: Option<String>,
-    pub fields: Vec<GraphQLTypeDefinitionField>,
-    pub generics: syn::Generics,
-    pub interfaces: Vec<syn::Type>,
-    // Due to syn parsing differences,
-    // when parsing an impl the type generics are included in the type
-    // directly, but in syn::DeriveInput, the type generics are
-    // in the generics field.
-    // This flag signifies if the type generics need to be
-    // included manually.
-    pub include_type_generics: bool,
-    // This flag indicates if the generated code should always be
-    // generic over the ScalarValue.
-    // If false, the scalar is only generic if a generic parameter
-    // is specified manually.
-    pub generic_scalar: bool,
-    // FIXME: make this redundant.
-    pub no_async: bool,
-}
-
-impl GraphQLTypeDefiniton {
-    #[allow(unused)]
-    fn has_async_field(&self) -> bool {
-        self.fields.iter().any(|field| field.is_async)
-    }
-
-    pub fn into_input_object_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 meta_fields = self
-            .fields
-            .iter()
-            .map(|field| {
-                // HACK: use a different interface for the GraphQLField?
-                let field_ty = &field._type;
-                let field_name = &field.name;
-
-                let description = match field.description.as_ref() {
-                    Some(description) => quote!( .description(#description) ),
-                    None => quote!(),
-                };
-
-                let deprecation = match field.deprecation.as_ref() {
-                    Some(deprecation) => {
-                        if let Some(reason) = deprecation.reason.as_ref() {
-                            quote!( .deprecated(Some(#reason)) )
-                        } else {
-                            quote!( .deprecated(None) )
-                        }
-                    }
-                    None => quote!(),
-                };
-
-                let create_meta_field = match field.default {
-                    Some(ref def) => {
-                        quote! {
-                            registry.arg_with_default::<#field_ty>( #field_name, &#def, &())
-                        }
-                    }
-                    None => {
-                        quote! {
-                            registry.arg::<#field_ty>(#field_name, &())
-                        }
-                    }
-                };
-
-                quote!(
-                    {
-                        #create_meta_field
-                        #description
-                        #deprecation
-                    },
-                )
-            })
-            .collect::<Vec<_>>();
-
-        let from_inputs = self
-            .fields
-            .iter()
-            .map(|field| {
-                let field_ident = &field.resolver_code;
-                let field_name = &field.name;
-
-                // Build from_input clause.
-                let from_input_default = match field.default {
-                    Some(ref def) => {
-                        quote! {
-                            Some(&&::juniper::InputValue::Null) | None if true => #def,
-                        }
-                    }
-                    None => quote! {},
-                };
-
-                quote!(
-                    #field_ident: {
-                        match obj.get(#field_name) {
-                            #from_input_default
-                            Some(ref v) => {
-                                ::juniper::FromInputValue::<#scalar>::from_input_value(v)
-                                    .map_err(::juniper::IntoFieldError::into_field_error)?
-                            },
-                            None => {
-                                ::juniper::FromInputValue::<#scalar>::from_implicit_null()
-                                    .map_err(::juniper::IntoFieldError::into_field_error)?
-                            },
-                        }
-                    },
-                )
-            })
-            .collect::<Vec<_>>();
-
-        let to_inputs = self
-            .fields
-            .iter()
-            .map(|field| {
-                let field_name = &field.name;
-                let field_ident = &field.resolver_code;
-                // Build to_input clause.
-                quote!(
-                    (#field_name, self.#field_ident.to_input_value()),
-                )
-            })
-            .collect::<Vec<_>>();
-
-        let description = self
-            .description
-            .as_ref()
-            .map(|description| quote!( .description(#description) ));
-
-        // Preserve the original type_generics before modification,
-        // since alteration makes them invalid if self.generic_scalar
-        // is specified.
-        let (_, type_generics, _) = self.generics.split_for_impl();
-
-        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 type_generics_tokens = if self.include_type_generics {
-            Some(type_generics)
-        } else {
-            None
-        };
-
-        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_type = quote!(
-            impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ty #type_generics_tokens
-                #where_async
-            {}
-        );
-
-        let marks = self.fields.iter().map(|field| {
-            let field_ty = &field._type;
-            quote_spanned! { field_ty.span() =>
-                <#field_ty as ::juniper::marker::IsInputType<#scalar>>::mark();
-            }
-        });
-
-        let mut body = quote!(
-            impl#impl_generics ::juniper::marker::IsInputType<#scalar> for #ty #type_generics_tokens
-                #where_clause {
-                    fn mark() {
-                        #( #marks )*
-                    }
-                }
-
-            impl#impl_generics ::juniper::GraphQLType<#scalar> for #ty #type_generics_tokens
-                #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
-                {
-                    let fields = &[
-                        #( #meta_fields )*
-                    ];
-                    registry.build_input_object_type::<#ty>(&(), fields)
-                    #description
-                    .into_meta()
-                }
-            }
-
-            impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ty #type_generics_tokens
-                #where_clause
-            {
-                type Context = #context;
-                type TypeInfo = ();
-
-                fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> {
-                    <Self as ::juniper::GraphQLType<#scalar>>::name(info)
-                }
-            }
-
-            impl#impl_generics ::juniper::FromInputValue<#scalar> for #ty #type_generics_tokens
-                #where_clause
-            {
-                type Error = ::juniper::FieldError<#scalar>;
-
-                fn from_input_value(
-                    value: &::juniper::InputValue<#scalar>
-                ) -> Result<Self, Self::Error> {
-                    let obj = value
-                        .to_object_value()
-                        .ok_or_else(|| ::juniper::FieldError::<#scalar>::from(
-                            format!("Expected input object, found: {}", value))
-                        )?;
-                    Ok(#ty {
-                        #( #from_inputs )*
-                    })
-                }
-            }
-
-            impl#impl_generics ::juniper::ToInputValue<#scalar> for #ty #type_generics_tokens
-                #where_clause
-            {
-                fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
-                    ::juniper::InputValue::object([
-                        #( #to_inputs )*
-                    ])
-                }
-            }
-
-            impl#impl_generics ::juniper::macros::reflect::BaseType<#scalar>
-                for #ty #type_generics_tokens
-                #where_clause
-            {
-                const NAME: ::juniper::macros::reflect::Type = #name;
-            }
-
-            impl#impl_generics ::juniper::macros::reflect::BaseSubTypes<#scalar>
-                for #ty #type_generics_tokens
-                #where_clause
-            {
-                const NAMES: ::juniper::macros::reflect::Types =
-                    &[<Self as ::juniper::macros::reflect::BaseType<#scalar>>::NAME];
-            }
-
-            impl#impl_generics ::juniper::macros::reflect::WrappedType<#scalar>
-                for #ty #type_generics_tokens
-                #where_clause
-            {
-                const VALUE: ::juniper::macros::reflect::WrappedValue = 1;
-            }
-        );
-
-        if !self.no_async {
-            body.extend(async_type);
-        }
-
-        body
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use syn::{Ident, LitStr};
-
-    fn strs_to_strings(source: Vec<&str>) -> Vec<String> {
-        source
-            .iter()
-            .map(|x| (*x).to_string())
-            .collect::<Vec<String>>()
-    }
-
-    fn litstr(s: &str) -> Lit {
-        Lit::Str(LitStr::new(s, Span::call_site()))
-    }
-
-    fn ident(s: &str) -> Ident {
-        quote::format_ident!("{}", s)
-    }
-
-    mod test_get_doc_strings {
-        use super::*;
-
-        #[test]
-        fn test_single() {
-            let result = get_doc_strings(&[MetaNameValue {
-                path: ident("doc").into(),
-                eq_token: Default::default(),
-                lit: litstr("foo"),
-            }]);
-            assert_eq!(
-                &result.unwrap(),
-                Some(&strs_to_strings(vec!["foo"])).unwrap()
-            );
-        }
-
-        #[test]
-        fn test_many() {
-            let result = get_doc_strings(&[
-                MetaNameValue {
-                    path: ident("doc").into(),
-                    eq_token: Default::default(),
-                    lit: litstr("foo"),
-                },
-                MetaNameValue {
-                    path: ident("doc").into(),
-                    eq_token: Default::default(),
-                    lit: litstr("\n"),
-                },
-                MetaNameValue {
-                    path: ident("doc").into(),
-                    eq_token: Default::default(),
-                    lit: litstr("bar"),
-                },
-            ]);
-            assert_eq!(
-                &result.unwrap(),
-                Some(&strs_to_strings(vec!["foo", "\n", "bar"])).unwrap()
-            );
-        }
-
-        #[test]
-        fn test_not_doc() {
-            let result = get_doc_strings(&[MetaNameValue {
-                path: ident("blah").into(),
-                eq_token: Default::default(),
-                lit: litstr("foo"),
-            }]);
-            assert_eq!(&result, &None);
-        }
-    }
-
-    mod test_join_doc_strings {
-        use super::*;
-
-        #[test]
-        fn test_single() {
-            let result = join_doc_strings(&strs_to_strings(vec!["foo"]));
-            assert_eq!(&result, "foo");
-        }
-        #[test]
-        fn test_multiple() {
-            let result = join_doc_strings(&strs_to_strings(vec!["foo", "bar"]));
-            assert_eq!(&result, "foo\nbar");
-        }
-
-        #[test]
-        fn test_trims_spaces() {
-            let result = join_doc_strings(&strs_to_strings(vec![" foo ", "bar ", " baz"]));
-            assert_eq!(&result, "foo\nbar\nbaz");
-        }
-
-        #[test]
-        fn test_empty() {
-            let result = join_doc_strings(&strs_to_strings(vec!["foo", "", "bar"]));
-            assert_eq!(&result, "foo\n\nbar");
-        }
-
-        #[test]
-        fn test_newline_spaces() {
-            let result = join_doc_strings(&strs_to_strings(vec!["foo ", "", " bar"]));
-            assert_eq!(&result, "foo\n\nbar");
-        }
-
-        #[test]
-        fn test_continuation_backslash() {
-            let result = join_doc_strings(&strs_to_strings(vec!["foo\\", "x\\", "y", "bar"]));
-            assert_eq!(&result, "foo x y\nbar");
-        }
-    }
-
-    #[test]
-    fn test_to_camel_case() {
-        assert_eq!(&to_camel_case("test")[..], "test");
-        assert_eq!(&to_camel_case("_test")[..], "test");
-        assert_eq!(&to_camel_case("__test")[..], "__test");
-        assert_eq!(&to_camel_case("first_second")[..], "firstSecond");
-        assert_eq!(&to_camel_case("first_")[..], "first");
-        assert_eq!(&to_camel_case("a_b_c")[..], "aBC");
-        assert_eq!(&to_camel_case("a_bc")[..], "aBc");
-        assert_eq!(&to_camel_case("a_b")[..], "aB");
-        assert_eq!(&to_camel_case("a")[..], "a");
-        assert_eq!(&to_camel_case("")[..], "");
-    }
-
-    #[test]
-    fn test_to_upper_snake_case() {
-        assert_eq!(to_upper_snake_case("abc"), "ABC");
-        assert_eq!(to_upper_snake_case("a_bc"), "A_BC");
-        assert_eq!(to_upper_snake_case("ABC"), "ABC");
-        assert_eq!(to_upper_snake_case("A_BC"), "A_BC");
-        assert_eq!(to_upper_snake_case("SomeInput"), "SOME_INPUT");
-        assert_eq!(to_upper_snake_case("someInput"), "SOME_INPUT");
-        assert_eq!(to_upper_snake_case("someINpuT"), "SOME_INPU_T");
-        assert_eq!(to_upper_snake_case("some_INpuT"), "SOME_INPU_T");
-    }
-
-    #[test]
-    fn test_is_valid_name() {
-        assert_eq!(is_valid_name("yesItIs"), true);
-        assert_eq!(is_valid_name("NoitIsnt"), true);
-        assert_eq!(is_valid_name("iso6301"), true);
-        assert_eq!(is_valid_name("thisIsATest"), true);
-        assert_eq!(is_valid_name("i6Op"), true);
-        assert_eq!(is_valid_name("i!"), false);
-        assert_eq!(is_valid_name(""), false);
-        assert_eq!(is_valid_name("aTest"), true);
-        assert_eq!(is_valid_name("__Atest90"), true);
-    }
-}
diff --git a/juniper_graphql_ws/Cargo.toml b/juniper_graphql_ws/Cargo.toml
index 3b74f4bb..c8b68806 100644
--- a/juniper_graphql_ws/Cargo.toml
+++ b/juniper_graphql_ws/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_graphql_ws"
 version = "0.4.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "GraphQL over WebSocket Protocol implementation for `juniper` crate."
 license = "BSD-2-Clause"
 authors = ["Christopher Brown <ccbrown112@gmail.com>"]
diff --git a/juniper_graphql_ws/src/client_message.rs b/juniper_graphql_ws/src/client_message.rs
index c893f6da..767f6969 100644
--- a/juniper_graphql_ws/src/client_message.rs
+++ b/juniper_graphql_ws/src/client_message.rs
@@ -78,11 +78,11 @@ mod test {
 
         assert_eq!(
             ClientMessage::Start {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: StartPayload {
-                    query: "query MyQuery { __typename }".to_string(),
+                    query: "query MyQuery { __typename }".into(),
                     variables: graphql_vars! {"foo": "bar"},
-                    operation_name: Some("MyQuery".to_string()),
+                    operation_name: Some("MyQuery".into()),
                 },
             },
             serde_json::from_str(
@@ -99,9 +99,9 @@ mod test {
 
         assert_eq!(
             ClientMessage::Start {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: StartPayload {
-                    query: "query MyQuery { __typename }".to_string(),
+                    query: "query MyQuery { __typename }".into(),
                     variables: graphql_vars! {},
                     operation_name: None,
                 },
@@ -115,9 +115,7 @@ mod test {
         );
 
         assert_eq!(
-            ClientMessage::Stop {
-                id: "foo".to_string()
-            },
+            ClientMessage::Stop { id: "foo".into() },
             serde_json::from_str(r##"{"type": "stop", "id": "foo"}"##).unwrap(),
         );
 
diff --git a/juniper_graphql_ws/src/lib.rs b/juniper_graphql_ws/src/lib.rs
index cfb8b967..d1621a61 100644
--- a/juniper_graphql_ws/src/lib.rs
+++ b/juniper_graphql_ws/src/lib.rs
@@ -14,13 +14,8 @@ pub use schema::*;
 mod utils;
 
 use std::{
-    collections::HashMap,
-    convert::{Infallible, TryInto},
-    error::Error,
-    marker::PhantomPinned,
-    pin::Pin,
-    sync::Arc,
-    time::Duration,
+    collections::HashMap, convert::Infallible, error::Error, marker::PhantomPinned, pin::Pin,
+    sync::Arc, time::Duration,
 };
 
 use juniper::{
@@ -292,9 +287,10 @@ impl<S: Schema, I: Init<S::ScalarValue, S::Context>> ConnectionState<S, I> {
     }
 
     async fn start(id: String, params: ExecutionParams<S>) -> BoxStream<'static, Reaction<S>> {
-        // TODO: This could be made more efficient if juniper exposed functionality to allow us to
-        // parse and validate the query, determine whether it's a subscription, and then execute
-        // it. For now, the query gets parsed and validated twice.
+        // TODO: This could be made more efficient if `juniper` exposed
+        //       functionality to allow us to parse and validate the query,
+        //       determine whether it's a subscription, and then execute it.
+        //       For now, the query gets parsed and validated twice.
 
         let params = Arc::new(params);
 
@@ -358,10 +354,7 @@ enum SubscriptionStartState<S: Schema> {
         id: String,
         future: BoxFuture<
             'static,
-            Result<
-                juniper_subscriptions::Connection<'static, S::ScalarValue>,
-                GraphQLError<'static>,
-            >,
+            Result<juniper_subscriptions::Connection<'static, S::ScalarValue>, GraphQLError>,
         >,
     },
     /// Streaming is the state after we've successfully obtained the event stream for the
@@ -629,7 +622,7 @@ mod test {
     use juniper::{
         futures::sink::SinkExt,
         graphql_input_value, graphql_object, graphql_subscription, graphql_value, graphql_vars,
-        parser::{ParseError, Spanning, Token},
+        parser::{ParseError, Spanning},
         DefaultScalarValue, EmptyMutation, FieldError, FieldResult, RootNode,
     };
 
@@ -710,9 +703,9 @@ mod test {
         assert_eq!(ServerMessage::ConnectionAck, conn.next().await.unwrap());
 
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "{context}".to_string(),
+                query: "{context}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -722,7 +715,7 @@ mod test {
 
         assert_eq!(
             ServerMessage::Data {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: DataPayload {
                     data: graphql_value!({"context": 1}),
                     errors: vec![],
@@ -732,9 +725,7 @@ mod test {
         );
 
         assert_eq!(
-            ServerMessage::Complete {
-                id: "foo".to_string(),
-            },
+            ServerMessage::Complete { id: "foo".into() },
             conn.next().await.unwrap()
         );
     }
@@ -755,9 +746,9 @@ mod test {
         assert_eq!(ServerMessage::ConnectionAck, conn.next().await.unwrap());
 
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "subscription Foo {context}".to_string(),
+                query: "subscription Foo {context}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -767,7 +758,7 @@ mod test {
 
         assert_eq!(
             ServerMessage::Data {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: DataPayload {
                     data: graphql_value!({"context": 1}),
                     errors: vec![],
@@ -777,9 +768,9 @@ mod test {
         );
 
         conn.send(ClientMessage::Start {
-            id: "bar".to_string(),
+            id: "bar".into(),
             payload: StartPayload {
-                query: "subscription Bar {context}".to_string(),
+                query: "subscription Bar {context}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -789,7 +780,7 @@ mod test {
 
         assert_eq!(
             ServerMessage::Data {
-                id: "bar".to_string(),
+                id: "bar".into(),
                 payload: DataPayload {
                     data: graphql_value!({"context": 1}),
                     errors: vec![],
@@ -798,16 +789,12 @@ mod test {
             conn.next().await.unwrap()
         );
 
-        conn.send(ClientMessage::Stop {
-            id: "foo".to_string(),
-        })
-        .await
-        .unwrap();
+        conn.send(ClientMessage::Stop { id: "foo".into() })
+            .await
+            .unwrap();
 
         assert_eq!(
-            ServerMessage::Complete {
-                id: "foo".to_string(),
-            },
+            ServerMessage::Complete { id: "foo".into() },
             conn.next().await.unwrap()
         );
     }
@@ -844,7 +831,7 @@ mod test {
         assert_eq!(
             ServerMessage::ConnectionError {
                 payload: ConnectionErrorPayload {
-                    message: "init error".to_string(),
+                    message: "init error".into(),
                 },
             },
             conn.next().await.unwrap()
@@ -869,9 +856,9 @@ mod test {
         assert_eq!(ServerMessage::ConnectionAck, conn.next().await.unwrap());
 
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "subscription Foo {never}".to_string(),
+                query: "subscription Foo {never}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -880,9 +867,9 @@ mod test {
         .unwrap();
 
         conn.send(ClientMessage::Start {
-            id: "bar".to_string(),
+            id: "bar".into(),
             payload: StartPayload {
-                query: "subscription Bar {never}".to_string(),
+                query: "subscription Bar {never}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -894,7 +881,7 @@ mod test {
             ServerMessage::Error { id, .. } => {
                 assert_eq!(id, "bar");
             }
-            msg @ _ => panic!("expected error, got: {:?}", msg),
+            msg @ _ => panic!("expected error, got: {msg:?}"),
         }
     }
 
@@ -914,9 +901,9 @@ mod test {
         assert_eq!(ServerMessage::ConnectionAck, conn.next().await.unwrap());
 
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "asd".to_string(),
+                query: "asd".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -929,13 +916,13 @@ mod test {
                 assert_eq!(id, "foo");
                 match payload.graphql_error() {
                     GraphQLError::ParseError(Spanning {
-                        item: ParseError::UnexpectedToken(Token::Name("asd")),
+                        item: ParseError::UnexpectedToken(token),
                         ..
-                    }) => {}
-                    p @ _ => panic!("expected graphql parse error, got: {:?}", p),
+                    }) => assert_eq!(token, "asd"),
+                    p @ _ => panic!("expected graphql parse error, got: {p:?}"),
                 }
             }
-            msg @ _ => panic!("expected error, got: {:?}", msg),
+            msg @ _ => panic!("expected error, got: {msg:?}"),
         }
     }
 
@@ -977,9 +964,9 @@ mod test {
 
         // If we send the start message before the init is handled, we should still get results.
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "{context}".to_string(),
+                query: "{context}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -991,7 +978,7 @@ mod test {
 
         assert_eq!(
             ServerMessage::Data {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: DataPayload {
                     data: graphql_value!({"context": 1}),
                     errors: vec![],
@@ -1017,9 +1004,9 @@ mod test {
         assert_eq!(ServerMessage::ConnectionAck, conn.next().await.unwrap());
 
         conn.send(ClientMessage::Start {
-            id: "foo".to_string(),
+            id: "foo".into(),
             payload: StartPayload {
-                query: "subscription Foo {error}".to_string(),
+                query: "subscription Foo {error}".into(),
                 variables: graphql_vars! {},
                 operation_name: None,
             },
@@ -1036,7 +1023,7 @@ mod test {
                 assert_eq!(data, graphql_value!({ "error": null }));
                 assert_eq!(errors.len(), 1);
             }
-            msg @ _ => panic!("expected data, got: {:?}", msg),
+            msg @ _ => panic!("expected data, got: {msg:?}"),
         }
     }
 }
diff --git a/juniper_graphql_ws/src/server_message.rs b/juniper_graphql_ws/src/server_message.rs
index f52c1244..232ef038 100644
--- a/juniper_graphql_ws/src/server_message.rs
+++ b/juniper_graphql_ws/src/server_message.rs
@@ -32,7 +32,7 @@ pub struct DataPayload<S> {
 // _execution_params).
 pub struct ErrorPayload {
     _execution_params: Option<Box<dyn Any + Send>>,
-    error: GraphQLError<'static>,
+    error: GraphQLError,
     _marker: PhantomPinned,
 }
 
@@ -41,7 +41,7 @@ impl ErrorPayload {
     /// execution_params and that execution_params has not been modified or moved.
     pub(crate) unsafe fn new_unchecked(
         execution_params: Box<dyn Any + Send>,
-        error: GraphQLError<'_>,
+        error: GraphQLError,
     ) -> Self {
         Self {
             _execution_params: Some(execution_params),
@@ -51,7 +51,7 @@ impl ErrorPayload {
     }
 
     /// Returns the contained GraphQLError.
-    pub fn graphql_error<'a>(&'a self) -> &GraphQLError<'a> {
+    pub fn graphql_error(&self) -> &GraphQLError {
         &self.error
     }
 }
@@ -77,8 +77,8 @@ impl Serialize for ErrorPayload {
     }
 }
 
-impl From<GraphQLError<'static>> for ErrorPayload {
-    fn from(error: GraphQLError<'static>) -> Self {
+impl From<GraphQLError> for ErrorPayload {
+    fn from(error: GraphQLError) -> Self {
         Self {
             _execution_params: None,
             error,
@@ -143,7 +143,7 @@ mod test {
         assert_eq!(
             serde_json::to_string(&ServerMessage::ConnectionError {
                 payload: ConnectionErrorPayload {
-                    message: "foo".to_string(),
+                    message: "foo".into(),
                 },
             })
             .unwrap(),
@@ -157,7 +157,7 @@ mod test {
 
         assert_eq!(
             serde_json::to_string(&ServerMessage::Data {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: DataPayload {
                     data: graphql_value!(null),
                     errors: vec![],
@@ -169,7 +169,7 @@ mod test {
 
         assert_eq!(
             serde_json::to_string(&ServerMessage::Error {
-                id: "foo".to_string(),
+                id: "foo".into(),
                 payload: GraphQLError::UnknownOperationName.into(),
             })
             .unwrap(),
@@ -177,10 +177,7 @@ mod test {
         );
 
         assert_eq!(
-            serde_json::to_string(&ServerMessage::Complete {
-                id: "foo".to_string(),
-            })
-            .unwrap(),
+            serde_json::to_string(&ServerMessage::Complete { id: "foo".into() }).unwrap(),
             r##"{"type":"complete","id":"foo"}"##,
         );
 
diff --git a/juniper_hyper/Cargo.toml b/juniper_hyper/Cargo.toml
index 72ab1f4f..0f2f6bb2 100644
--- a/juniper_hyper/Cargo.toml
+++ b/juniper_hyper/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_hyper"
 version = "0.9.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "`juniper` GraphQL integration with `hyper`."
 license = "BSD-2-Clause"
 authors = ["Damir Vandic <info@dvic.io>"]
diff --git a/juniper_hyper/examples/hyper_server.rs b/juniper_hyper/examples/hyper_server.rs
index 3187451e..afa1d4e0 100644
--- a/juniper_hyper/examples/hyper_server.rs
+++ b/juniper_hyper/examples/hyper_server.rs
@@ -49,9 +49,9 @@ async fn main() {
     });
 
     let server = Server::bind(&addr).serve(new_service);
-    println!("Listening on http://{}", addr);
+    println!("Listening on http://{addr}");
 
     if let Err(e) = server.await {
-        eprintln!("server error: {}", e)
+        eprintln!("server error: {e}")
     }
 }
diff --git a/juniper_hyper/src/lib.rs b/juniper_hyper/src/lib.rs
index ce9204eb..eb8dafe3 100644
--- a/juniper_hyper/src/lib.rs
+++ b/juniper_hyper/src/lib.rs
@@ -84,7 +84,7 @@ fn parse_get_req<S: ScalarValue>(
         .map(|q| gql_request_from_get(q).map(GraphQLBatchRequest::Single))
         .unwrap_or_else(|| {
             Err(GraphQLRequestError::Invalid(
-                "'query' parameter is missing".to_string(),
+                "'query' parameter is missing".into(),
             ))
         })
 }
@@ -144,7 +144,7 @@ pub async fn playground(
 }
 
 fn render_error(err: GraphQLRequestError) -> Response<Body> {
-    let message = format!("{}", err);
+    let message = err.to_string();
     let mut resp = new_response(StatusCode::BAD_REQUEST);
     *resp.body_mut() = Body::from(message);
     resp
@@ -249,15 +249,14 @@ where
     match query {
         Some(query) => Ok(JuniperGraphQLRequest::new(query, operation_name, variables)),
         None => Err(GraphQLRequestError::Invalid(
-            "'query' parameter is missing".to_string(),
+            "'query' parameter is missing".into(),
         )),
     }
 }
 
 fn invalid_err(parameter_name: &str) -> GraphQLRequestError {
     GraphQLRequestError::Invalid(format!(
-        "'{}' parameter is specified multiple times",
-        parameter_name
+        "`{parameter_name}` parameter is specified multiple times",
     ))
 }
 
@@ -330,31 +329,31 @@ mod tests {
 
     impl http_tests::HttpIntegration for TestHyperIntegration {
         fn get(&self, url: &str) -> http_tests::TestResponse {
-            let url = format!("http://127.0.0.1:{}/graphql{}", self.port, url);
-            make_test_response(reqwest::blocking::get(&url).expect(&format!("failed GET {}", url)))
+            let url = format!("http://127.0.0.1:{}/graphql{url}", self.port);
+            make_test_response(reqwest::blocking::get(&url).expect(&format!("failed GET {url}")))
         }
 
         fn post_json(&self, url: &str, body: &str) -> http_tests::TestResponse {
-            let url = format!("http://127.0.0.1:{}/graphql{}", self.port, url);
+            let url = format!("http://127.0.0.1:{}/graphql{url}", self.port);
             let client = reqwest::blocking::Client::new();
             let res = client
                 .post(&url)
                 .header(reqwest::header::CONTENT_TYPE, "application/json")
-                .body(body.to_string())
+                .body(body.to_owned())
                 .send()
-                .expect(&format!("failed POST {}", url));
+                .expect(&format!("failed POST {url}"));
             make_test_response(res)
         }
 
         fn post_graphql(&self, url: &str, body: &str) -> http_tests::TestResponse {
-            let url = format!("http://127.0.0.1:{}/graphql{}", self.port, url);
+            let url = format!("http://127.0.0.1:{}/graphql{url}", self.port);
             let client = reqwest::blocking::Client::new();
             let res = client
                 .post(&url)
                 .header(reqwest::header::CONTENT_TYPE, "application/graphql")
-                .body(body.to_string())
+                .body(body.to_owned())
                 .send()
-                .expect(&format!("failed POST {}", url));
+                .expect(&format!("failed POST {url}"));
             make_test_response(res)
         }
     }
@@ -362,11 +361,9 @@ mod tests {
     fn make_test_response(response: ReqwestResponse) -> http_tests::TestResponse {
         let status_code = response.status().as_u16() as i32;
         let content_type_header = response.headers().get(reqwest::header::CONTENT_TYPE);
-        let content_type = if let Some(ct) = content_type_header {
-            format!("{}", ct.to_str().unwrap())
-        } else {
-            String::default()
-        };
+        let content_type = content_type_header
+            .map(|ct| ct.to_str().unwrap().into())
+            .unwrap_or_default();
         let body = response.text().unwrap();
 
         http_tests::TestResponse {
@@ -439,7 +436,7 @@ mod tests {
         });
 
         if let Err(e) = server.await {
-            eprintln!("server error: {}", e);
+            eprintln!("server error: {e}");
         }
     }
 
diff --git a/juniper_iron/Cargo.toml b/juniper_iron/Cargo.toml
index d4b4b759..82c18f9c 100644
--- a/juniper_iron/Cargo.toml
+++ b/juniper_iron/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_iron"
 version = "0.8.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "`juniper` GraphQL integration with `iron`."
 license = "BSD-2-Clause"
 authors = [
diff --git a/juniper_iron/examples/iron_server.rs b/juniper_iron/examples/iron_server.rs
index d243b221..218af60b 100644
--- a/juniper_iron/examples/iron_server.rs
+++ b/juniper_iron/examples/iron_server.rs
@@ -33,7 +33,7 @@ fn main() {
     chain.link_before(logger_before);
     chain.link_after(logger_after);
 
-    let host = env::var("LISTEN").unwrap_or_else(|_| "0.0.0.0:8080".to_owned());
-    println!("GraphQL server started on {}", host);
+    let host = env::var("LISTEN").unwrap_or_else(|_| "0.0.0.0:8080".into());
+    println!("GraphQL server started on {host}");
     Iron::new(chain).http(host.as_str()).unwrap();
 }
diff --git a/juniper_iron/src/lib.rs b/juniper_iron/src/lib.rs
index 6e104ea0..b8829614 100644
--- a/juniper_iron/src/lib.rs
+++ b/juniper_iron/src/lib.rs
@@ -175,8 +175,8 @@ impl GraphiQLHandler {
     /// relative, so a common value could be `"/graphql"`.
     pub fn new(graphql_url: &str, subscription_url: Option<&str>) -> GraphiQLHandler {
         GraphiQLHandler {
-            graphql_url: graphql_url.to_owned(),
-            subscription_url: subscription_url.map(|s| s.to_owned()),
+            graphql_url: graphql_url.into(),
+            subscription_url: subscription_url.map(Into::into),
         }
     }
 }
@@ -188,14 +188,14 @@ impl PlaygroundHandler {
     /// relative, so a common value could be `"/graphql"`.
     pub fn new(graphql_url: &str, subscription_url: Option<&str>) -> PlaygroundHandler {
         PlaygroundHandler {
-            graphql_url: graphql_url.to_owned(),
-            subscription_url: subscription_url.map(|s| s.to_owned()),
+            graphql_url: graphql_url.into(),
+            subscription_url: subscription_url.map(Into::into),
         }
     }
 }
 
-impl<'a, CtxFactory, Query, Mutation, Subscription, CtxT, S> Handler
-    for GraphQLHandler<'a, CtxFactory, Query, Mutation, Subscription, CtxT, S>
+impl<CtxFactory, Query, Mutation, Subscription, CtxT, S> Handler
+    for GraphQLHandler<'static, CtxFactory, Query, Mutation, Subscription, CtxT, S>
 where
     S: ScalarValue + Sync + Send + 'static,
     CtxFactory: Fn(&mut Request) -> IronResult<CtxT> + Send + Sync + 'static,
@@ -203,7 +203,6 @@ where
     Query: GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
     Mutation: GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
     Subscription: GraphQLType<S, Context = CtxT, TypeInfo = ()> + Send + Sync + 'static,
-    'a: 'static,
 {
     fn handle(&self, req: &mut Request) -> IronResult<Response> {
         let context = (self.context_factory)(req)?;
@@ -284,7 +283,7 @@ impl Error for GraphQLIronError {
 
 impl From<GraphQLIronError> for IronError {
     fn from(err: GraphQLIronError) -> IronError {
-        let message = format!("{}", err);
+        let message = err.to_string();
         IronError::new(err, (status::BadRequest, message))
     }
 }
@@ -314,17 +313,16 @@ mod tests {
     // This is ugly but it works. `iron_test` just dumps the path/url in headers
     // and newer `hyper` doesn't allow unescaped "{" or "}".
     fn fixup_url(url: &str) -> String {
-        let url = Url::parse(&format!("http://localhost:3000{}", url)).expect("url to parse");
+        let url = Url::parse(&format!("http://localhost:3000{url}")).expect("url to parse");
         let path: String = url
             .path()
             .iter()
-            .map(|x| (*x).to_string())
+            .map(|x| x.to_string())
             .collect::<Vec<_>>()
             .join("/");
         format!(
-            "http://localhost:3000{}?{}",
-            path,
-            utf8_percent_encode(url.query().unwrap_or(""), QUERY_ENCODE_SET)
+            "http://localhost:3000{path}?{}",
+            utf8_percent_encode(url.query().unwrap_or(""), QUERY_ENCODE_SET),
         )
     }
 
@@ -375,7 +373,7 @@ mod tests {
         http_tests::TestResponse {
             status_code: 400,
             body: None,
-            content_type: "application/json".to_string(),
+            content_type: "application/json".into(),
         }
     }
 
diff --git a/juniper_rocket/Cargo.toml b/juniper_rocket/Cargo.toml
index e3ff1bec..dc275ee3 100644
--- a/juniper_rocket/Cargo.toml
+++ b/juniper_rocket/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_rocket"
 version = "0.9.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "`juniper` GraphQL integration with `rocket`."
 license = "BSD-2-Clause"
 authors = [
diff --git a/juniper_rocket/src/lib.rs b/juniper_rocket/src/lib.rs
index e6e60bee..fea4e27e 100644
--- a/juniper_rocket/src/lib.rs
+++ b/juniper_rocket/src/lib.rs
@@ -242,9 +242,9 @@ where
 
     fn push_value(ctx: &mut Self::Context, field: ValueField<'f>) {
         match field.name.key().map(|key| key.as_str()) {
-            Some("query") => ctx.query(field.value.to_owned()),
-            Some("operation_name") => ctx.operation_name(field.value.to_owned()),
-            Some("variables") => ctx.variables(field.value.to_owned()),
+            Some("query") => ctx.query(field.value.into()),
+            Some("operation_name") => ctx.operation_name(field.value.into()),
+            Some("variables") => ctx.variables(field.value.into()),
             Some(key) => {
                 if ctx.opts.strict {
                     let error = Error::from(ErrorKind::Unknown).with_name(key);
@@ -318,13 +318,13 @@ where
             let mut reader = data.open(limit);
             let mut body = String::new();
             if let Err(e) = reader.read_to_string(&mut body).await {
-                return Failure((Status::InternalServerError, format!("{:?}", e)));
+                return Failure((Status::InternalServerError, format!("{e:?}")));
             }
 
             Success(GraphQLRequest(if is_json {
                 match serde_json::from_str(&body) {
                     Ok(req) => req,
-                    Err(e) => return Failure((Status::BadRequest, format!("{}", e))),
+                    Err(e) => return Failure((Status::BadRequest, e.to_string())),
                 }
             } else {
                 GraphQLBatchRequest::Single(http::GraphQLRequest::new(body, None, None))
@@ -437,7 +437,7 @@ mod fromform_tests {
         check_error(
             "query=test&variables=NOT_JSON",
             vec![Error::from(ErrorKind::Validation(Cow::Owned(
-                "expected value at line 1 column 1".to_owned(),
+                "expected value at line 1 column 1".into(),
             )))
             .with_name("variables")],
             false,
@@ -451,7 +451,7 @@ mod fromform_tests {
         assert!(result.is_ok());
         let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"bar"}"#).unwrap();
         let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
-            "test".to_string(),
+            "test".into(),
             None,
             Some(variables),
         )));
@@ -465,7 +465,7 @@ mod fromform_tests {
         ));
         let variables = ::serde_json::from_str::<InputValue>(r#"{"foo":"x y&? z"}"#).unwrap();
         let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
-            "test".to_string(),
+            "test".into(),
             None,
             Some(variables),
         )));
@@ -479,8 +479,8 @@ mod fromform_tests {
         ));
         assert!(result.is_ok());
         let expected = GraphQLRequest(GraphQLBatchRequest::Single(http::GraphQLRequest::new(
-            "%foo bar baz&?".to_string(),
-            Some("test".to_string()),
+            "%foo bar baz&?".into(),
+            Some("test".into()),
             None,
         )));
         assert_eq!(result.unwrap(), expected);
diff --git a/juniper_rocket/tests/custom_response_tests.rs b/juniper_rocket/tests/custom_response_tests.rs
index 050be566..72893703 100644
--- a/juniper_rocket/tests/custom_response_tests.rs
+++ b/juniper_rocket/tests/custom_response_tests.rs
@@ -3,5 +3,5 @@ use rocket::http::Status;
 
 #[test]
 fn test_graphql_response_is_public() {
-    let _ = GraphQLResponse(Status::Unauthorized, "Unauthorized".to_string());
+    let _ = GraphQLResponse(Status::Unauthorized, "Unauthorized".into());
 }
diff --git a/juniper_subscriptions/Cargo.toml b/juniper_subscriptions/Cargo.toml
index ddea6d98..8ccf40e5 100644
--- a/juniper_subscriptions/Cargo.toml
+++ b/juniper_subscriptions/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_subscriptions"
 version = "0.17.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "Juniper `SubscriptionCoordinator` and `SubscriptionConnection` implementations."
 license = "BSD-2-Clause"
 authors = ["nWacky <gosha.evtushenko@gmail.com>"]
diff --git a/juniper_subscriptions/src/lib.rs b/juniper_subscriptions/src/lib.rs
index df6c5fe7..3d5d77bb 100644
--- a/juniper_subscriptions/src/lib.rs
+++ b/juniper_subscriptions/src/lib.rs
@@ -3,7 +3,6 @@
 #![deny(warnings)]
 
 use std::{
-    iter::FromIterator,
     pin::Pin,
     task::{self, Poll},
 };
@@ -63,8 +62,7 @@ where
     S: ScalarValue + Send + Sync + 'a,
 {
     type Connection = Connection<'a, S>;
-
-    type Error = GraphQLError<'a>;
+    type Error = GraphQLError;
 
     fn subscribe(
         &'a self,
diff --git a/juniper_warp/Cargo.toml b/juniper_warp/Cargo.toml
index b49e379d..bb704a20 100644
--- a/juniper_warp/Cargo.toml
+++ b/juniper_warp/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "juniper_warp"
 version = "0.8.0-dev"
-edition = "2018"
+edition = "2021"
+rust-version = "1.62"
 description = "`juniper` GraphQL integration with `warp`."
 license = "BSD-2-Clause"
 authors = ["Tom Houlé <tom@tomhoule.com>"]
diff --git a/juniper_warp/src/lib.rs b/juniper_warp/src/lib.rs
index e7686b8d..b30b007b 100644
--- a/juniper_warp/src/lib.rs
+++ b/juniper_warp/src/lib.rs
@@ -44,7 +44,7 @@ use warp::{body, filters::BoxedFilter, http, hyper::body::Bytes, query, Filter};
 ///         format!(
 ///             "good morning {}, the app state is {:?}",
 ///             context.1,
-///             context.0
+///             context.0,
 ///         )
 ///     }
 /// }
@@ -108,7 +108,7 @@ where
         let schema = post_graphql_schema.clone();
         async move {
             let query = str::from_utf8(body.as_ref())
-                .map_err(|e| anyhow!("Request body query is not a valid UTF-8 string: {}", e))?;
+                .map_err(|e| anyhow!("Request body query is not a valid UTF-8 string: {e}"))?;
             let req = GraphQLRequest::new(query.into(), None, None);
 
             let resp = req.execute(&schema, &context).await;
@@ -192,7 +192,7 @@ where
         async move {
             let res = task::spawn_blocking(move || {
                 let query = str::from_utf8(body.as_ref())
-                    .map_err(|e| anyhow!("Request body is not a valid UTF-8 string: {}", e))?;
+                    .map_err(|e| anyhow!("Request body is not a valid UTF-8 string: {e}"))?;
                 let req = GraphQLRequest::new(query.into(), None, None);
 
                 let resp = req.execute_sync(&schema, &context);
@@ -359,7 +359,7 @@ pub mod subscriptions {
 
     struct Message(warp::ws::Message);
 
-    impl<S: ScalarValue> std::convert::TryFrom<Message> for ClientMessage<S> {
+    impl<S: ScalarValue> TryFrom<Message> for ClientMessage<S> {
         type Error = serde_json::Error;
 
         fn try_from(msg: Message) -> serde_json::Result<Self> {
@@ -381,8 +381,8 @@ pub mod subscriptions {
     impl fmt::Display for Error {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             match self {
-                Self::Warp(e) => write!(f, "warp error: {}", e),
-                Self::Serde(e) => write!(f, "serde error: {}", e),
+                Self::Warp(e) => write!(f, "warp error: {e}"),
+                Self::Serde(e) => write!(f, "serde error: {e}"),
             }
         }
     }
@@ -711,7 +711,7 @@ mod tests_http_harness {
             const QUERY_ENCODE_SET: &AsciiSet =
                 &CONTROLS.add(b' ').add(b'"').add(b'#').add(b'<').add(b'>');
 
-            let url = Url::parse(&format!("http://localhost:3000{}", url)).expect("url to parse");
+            let url = Url::parse(&format!("http://localhost:3000{url}")).expect("url to parse");
 
             let url: String = utf8_percent_encode(url.query().unwrap_or(""), QUERY_ENCODE_SET)
                 .into_iter()
@@ -721,7 +721,7 @@ mod tests_http_harness {
             self.make_request(
                 warp::test::request()
                     .method("GET")
-                    .path(&format!("/?{}", url)),
+                    .path(&format!("/?{url}")),
             )
         }
 
@@ -756,7 +756,7 @@ mod tests_http_harness {
                 .expect("missing content-type header in warp response")
                 .to_str()
                 .expect("invalid content-type string")
-                .to_owned(),
+                .into(),
         }
     }
 
diff --git a/tests/codegen/Cargo.toml b/tests/codegen/Cargo.toml
index f08b1f1a..3efcfaef 100644
--- a/tests/codegen/Cargo.toml
+++ b/tests/codegen/Cargo.toml
@@ -1,14 +1,15 @@
 [package]
 name = "juniper_codegen_tests"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 publish = false
 
 [dependencies]
-futures = "0.3.1"
-juniper = { path = "../../juniper" }
+rustversion = "1.0"
 
 [dev-dependencies]
+futures = "0.3.1"
+juniper = { path = "../../juniper" }
 serde_json = "1.0"
 tokio = { version = "1.0", features = ["rt", "time", "macros"] }
-trybuild = "1.0.25"
+trybuild = "1.0.63"
diff --git a/tests/codegen/fail/enum/derive_name_double_underscored.stderr b/tests/codegen/fail/enum/derive_name_double_underscored.stderr
index 6b00b6bd..36955ef3 100644
--- a/tests/codegen/fail/enum/derive_name_double_underscored.stderr
+++ b/tests/codegen/fail/enum/derive_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | enum __Test {
   |      ^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/enum/derive_variant_with_field.stderr b/tests/codegen/fail/enum/derive_variant_with_field.stderr
index 96cae1a7..be3bc256 100644
--- a/tests/codegen/fail/enum/derive_variant_with_field.stderr
+++ b/tests/codegen/fail/enum/derive_variant_with_field.stderr
@@ -4,4 +4,4 @@ error: GraphQL enum no fields allowed for non-ignored variants
 5 |     Variant(i32),
   |            ^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Enums
+  = note: https://spec.graphql.org/October2021#sec-Enums
diff --git a/tests/codegen/fail/input-object/derive_incompatible_field_type.rs b/tests/codegen/fail/input-object/derive_incompatible_field_type.rs
new file mode 100644
index 00000000..b3e26444
--- /dev/null
+++ b/tests/codegen/fail/input-object/derive_incompatible_field_type.rs
@@ -0,0 +1,13 @@
+use juniper::{GraphQLInputObject, GraphQLObject};
+
+#[derive(GraphQLObject)]
+struct ObjectA {
+    test: String,
+}
+
+#[derive(GraphQLInputObject)]
+struct Object {
+    field: ObjectA,
+}
+
+fn main() {}
diff --git a/tests/codegen/fail/input-object/derive_incompatible_object.stderr b/tests/codegen/fail/input-object/derive_incompatible_field_type.stderr
similarity index 50%
rename from tests/codegen/fail/input-object/derive_incompatible_object.stderr
rename to tests/codegen/fail/input-object/derive_incompatible_field_type.stderr
index 6767eead..5ddabb55 100644
--- a/tests/codegen/fail/input-object/derive_incompatible_object.stderr
+++ b/tests/codegen/fail/input-object/derive_incompatible_field_type.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `ObjectA: IsInputType<__S>` is not satisfied
- --> fail/input-object/derive_incompatible_object.rs:8:12
+ --> fail/input-object/derive_incompatible_field_type.rs:8:10
   |
-8 |     field: ObjectA,
-  |            ^^^^^^^ the trait `IsInputType<__S>` is not implemented for `ObjectA`
+8 | #[derive(GraphQLInputObject)]
+  |          ^^^^^^^^^^^^^^^^^^ the trait `IsInputType<__S>` is not implemented for `ObjectA`
   |
   = help: the following other types implement trait `IsInputType<S>`:
             <&T as IsInputType<S>>
@@ -14,12 +14,13 @@ error[E0277]: the trait bound `ObjectA: IsInputType<__S>` is not satisfied
             <Vec<T> as IsInputType<S>>
             <[T; N] as IsInputType<S>>
           and 13 others
+  = note: this error originates in the derive macro `GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `ObjectA: FromInputValue<__S>` is not satisfied
-    --> fail/input-object/derive_incompatible_object.rs:6:10
+    --> fail/input-object/derive_incompatible_field_type.rs:8:10
      |
-6    | #[derive(juniper::GraphQLInputObject)]
-     |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjectA`
+8    | #[derive(GraphQLInputObject)]
+     |          ^^^^^^^^^^^^^^^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjectA`
      |
      = help: the following other types implement trait `FromInputValue<S>`:
                <Arc<T> as FromInputValue<S>>
@@ -36,13 +37,13 @@ note: required by a bound in `Registry::<'r, S>::arg`
      |
      |         T: GraphQLType<S> + FromInputValue<S>,
      |                             ^^^^^^^^^^^^^^^^^ required by this bound in `Registry::<'r, S>::arg`
-     = note: this error originates in the derive macro `juniper::GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
+     = note: this error originates in the derive macro `GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `ObjectA: FromInputValue<__S>` is not satisfied
- --> fail/input-object/derive_incompatible_object.rs:6:10
+ --> fail/input-object/derive_incompatible_field_type.rs:8:10
   |
-6 | #[derive(juniper::GraphQLInputObject)]
-  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjectA`
+8 | #[derive(GraphQLInputObject)]
+  |          ^^^^^^^^^^^^^^^^^^ the trait `FromInputValue<__S>` is not implemented for `ObjectA`
   |
   = help: the following other types implement trait `FromInputValue<S>`:
             <Arc<T> as FromInputValue<S>>
@@ -54,18 +55,22 @@ error[E0277]: the trait bound `ObjectA: FromInputValue<__S>` is not satisfied
             <[T; N] as FromInputValue<S>>
             <bool as FromInputValue<__S>>
           and 10 others
-  = note: this error originates in the derive macro `juniper::GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the derive macro `GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0599]: no method named `to_input_value` found for struct `ObjectA` in the current scope
- --> fail/input-object/derive_incompatible_object.rs:6:10
+error[E0277]: the trait bound `ObjectA: ToInputValue<_>` is not satisfied
+ --> fail/input-object/derive_incompatible_field_type.rs:8:10
   |
-2 | struct ObjectA {
-  |        ------- method `to_input_value` not found for this struct
-...
-6 | #[derive(juniper::GraphQLInputObject)]
-  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `ObjectA`
+8 | #[derive(GraphQLInputObject)]
+  |          ^^^^^^^^^^^^^^^^^^ the trait `ToInputValue<_>` is not implemented for `ObjectA`
   |
-  = help: items from traits can only be used if the trait is implemented and in scope
-  = note: the following trait defines an item `to_input_value`, perhaps you need to implement it:
-          candidate #1: `ToInputValue`
-  = note: this error originates in the derive macro `juniper::GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = help: the following other types implement trait `ToInputValue<S>`:
+            <&'a T as ToInputValue<S>>
+            <&'a [T] as ToInputValue<S>>
+            <&'a str as ToInputValue<S>>
+            <Arc<T> as ToInputValue<S>>
+            <Box<T> as ToInputValue<S>>
+            <ID as ToInputValue<__S>>
+            <Object as ToInputValue<__S>>
+            <TypeKind as ToInputValue<__S>>
+          and 14 others
+  = note: this error originates in the derive macro `GraphQLInputObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/input-object/derive_incompatible_object.rs b/tests/codegen/fail/input-object/derive_incompatible_object.rs
deleted file mode 100644
index 98cdb65b..00000000
--- a/tests/codegen/fail/input-object/derive_incompatible_object.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#[derive(juniper::GraphQLObject)]
-struct ObjectA {
-    test: String,
-}
-
-#[derive(juniper::GraphQLInputObject)]
-struct Object {
-    field: ObjectA,
-}
-
-fn main() {}
diff --git a/tests/codegen/fail/input-object/derive_no_fields.rs b/tests/codegen/fail/input-object/derive_no_fields.rs
index eedbe26e..2861298f 100644
--- a/tests/codegen/fail/input-object/derive_no_fields.rs
+++ b/tests/codegen/fail/input-object/derive_no_fields.rs
@@ -1,4 +1,6 @@
-#[derive(juniper::GraphQLInputObject)]
+use juniper::GraphQLInputObject;
+
+#[derive(GraphQLInputObject)]
 struct Object {}
 
 fn main() {}
diff --git a/tests/codegen/fail/input-object/derive_no_fields.stderr b/tests/codegen/fail/input-object/derive_no_fields.stderr
index 9362b428..4ab046c5 100644
--- a/tests/codegen/fail/input-object/derive_no_fields.stderr
+++ b/tests/codegen/fail/input-object/derive_no_fields.stderr
@@ -1,7 +1,5 @@
-error: GraphQL input object expects at least one field
- --> fail/input-object/derive_no_fields.rs:2:1
+error: GraphQL input object expected at least 1 non-ignored field
+ --> fail/input-object/derive_no_fields.rs:4:15
   |
-2 | struct Object {}
-  | ^^^^^^^^^^^^^^^^
-  |
-  = note: https://spec.graphql.org/June2018/#sec-Input-Objects
+4 | struct Object {}
+  |               ^^
diff --git a/tests/codegen/fail/input-object/derive_no_underscore.rs b/tests/codegen/fail/input-object/derive_no_underscore.rs
index 71ab5b9d..46b86a3c 100644
--- a/tests/codegen/fail/input-object/derive_no_underscore.rs
+++ b/tests/codegen/fail/input-object/derive_no_underscore.rs
@@ -1,4 +1,6 @@
-#[derive(juniper::GraphQLInputObject)]
+use juniper::GraphQLInputObject;
+
+#[derive(GraphQLInputObject)]
 struct Object {
     #[graphql(name = "__test")]
     test: String,
diff --git a/tests/codegen/fail/input-object/derive_no_underscore.stderr b/tests/codegen/fail/input-object/derive_no_underscore.stderr
index 86a6a9b2..98deeaa1 100644
--- a/tests/codegen/fail/input-object/derive_no_underscore.stderr
+++ b/tests/codegen/fail/input-object/derive_no_underscore.stderr
@@ -1,7 +1,8 @@
 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/input-object/derive_no_underscore.rs:3:15
+ --> fail/input-object/derive_no_underscore.rs:5:5
   |
-3 |     #[graphql(name = "__test")]
-  |               ^^^^
+5 | /     #[graphql(name = "__test")]
+6 | |     test: String,
+  | |________________^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/input-object/derive_unique_name.rs b/tests/codegen/fail/input-object/derive_unique_name.rs
index ecaa8631..a0d9a5b2 100644
--- a/tests/codegen/fail/input-object/derive_unique_name.rs
+++ b/tests/codegen/fail/input-object/derive_unique_name.rs
@@ -1,4 +1,6 @@
-#[derive(juniper::GraphQLInputObject)]
+use juniper::GraphQLInputObject;
+
+#[derive(GraphQLInputObject)]
 struct Object {
     test: String,
     #[graphql(name = "test")]
diff --git a/tests/codegen/fail/input-object/derive_unique_name.stderr b/tests/codegen/fail/input-object/derive_unique_name.stderr
index 066fdbe6..20a72cfa 100644
--- a/tests/codegen/fail/input-object/derive_unique_name.stderr
+++ b/tests/codegen/fail/input-object/derive_unique_name.stderr
@@ -1,9 +1,10 @@
-error: GraphQL input object does not allow fields with the same name
- --> fail/input-object/derive_unique_name.rs:4:5
+error: GraphQL input object expected all fields to have unique names
+ --> fail/input-object/derive_unique_name.rs:4:15
   |
-4 | /     #[graphql(name = "test")]
-5 | |     test2: String,
-  | |_________________^
-  |
-  = help: There is at least one other field with the same name `test`, possibly renamed via the #[graphql] attribute
-  = note: https://spec.graphql.org/June2018/#sec-Input-Objects
+4 |   struct Object {
+  |  _______________^
+5 | |     test: String,
+6 | |     #[graphql(name = "test")]
+7 | |     test2: String,
+8 | | }
+  | |_^
diff --git a/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.rs b/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.rs
index dfe2d7b5..e2ed37ea 100644
--- a/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.rs
+++ b/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.rs
@@ -7,7 +7,7 @@ pub struct ObjA {
 #[graphql_object(impl = CharacterValue)]
 impl ObjA {
     fn id(&self, is_present: bool) -> &str {
-        is_present.then(|| self.id.as_str()).unwrap_or("missing")
+        is_present.then_some(&*self.id).unwrap_or("missing")
     }
 }
 
diff --git a/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.stderr b/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.stderr
index a1b8ce2f..5d03e44c 100644
--- a/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.stderr
+++ b/tests/codegen/fail/interface/struct/attr_additional_non_nullable_argument.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 16 |     id: String,
    |     ^^ 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.', $DIR/fail/interface/struct/attr_additional_non_nullable_argument.rs:16:5
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/struct/attr_additional_non_nullable_argument.rs:16:5
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 16 |     id: String,
    |     ^^ 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.', $DIR/fail/interface/struct/attr_additional_non_nullable_argument.rs:16:5
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_field_double_underscored.stderr b/tests/codegen/fail/interface/struct/attr_field_double_underscored.stderr
index 31648f4e..85e57564 100644
--- a/tests/codegen/fail/interface/struct/attr_field_double_underscored.stderr
+++ b/tests/codegen/fail/interface/struct/attr_field_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 |     __id: String,
   |     ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr b/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr
index b6a25f24..109f2b7c 100644
--- a/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr
+++ b/tests/codegen/fail/interface/struct/attr_fields_duplicate.stderr
@@ -9,4 +9,4 @@ error: GraphQL interface must have a different name for each field
 9 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
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 a9f9fe37..ce5a6101 100644
--- a/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr
+++ b/tests/codegen/fail/interface/struct/attr_implementers_duplicate_pretty.stderr
@@ -16,7 +16,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -32,4 +32,4 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_implementers_duplicate_ugly.stderr b/tests/codegen/fail/interface/struct/attr_implementers_duplicate_ugly.stderr
index da24362c..210ab346 100644
--- a/tests/codegen/fail/interface/struct/attr_implementers_duplicate_ugly.stderr
+++ b/tests/codegen/fail/interface/struct/attr_implementers_duplicate_ugly.stderr
@@ -18,4 +18,4 @@ error[E0119]: conflicting implementations of trait `<CharacterValueEnum<ObjA, Ob
    | first implementation here
    | conflicting implementation for `ObjA`
    |
-   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the attribute macro `graphql_interface` (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 37afdb39..be1cb7fd 100644
--- a/tests/codegen/fail/interface/struct/attr_missing_field.stderr
+++ b/tests/codegen/fail/interface/struct/attr_missing_field.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -12,7 +12,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -20,7 +20,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -28,7 +28,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -36,7 +36,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -45,13 +45,13 @@ error: any use of this value will cause an error
    |     ^^
    |     |
    |     referenced constant has errors
-   |     inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
-   |     inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59
+   |     inside `<CharacterValueEnum<ObjA> as reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
+   |     inside `<CharacterValueEnum<ObjA> as 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -61,7 +61,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -71,7 +71,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -81,7 +81,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -89,7 +89,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -97,7 +97,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -107,7 +107,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -117,7 +117,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -125,7 +125,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -133,7 +133,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -143,7 +143,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -153,7 +153,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -161,7 +161,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -171,7 +171,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -179,7 +179,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -187,7 +187,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -197,7 +197,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -205,7 +205,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -215,7 +215,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -223,7 +223,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -231,7 +231,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -241,7 +241,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -251,7 +251,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -259,7 +259,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -269,7 +269,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -277,7 +277,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -285,7 +285,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -295,7 +295,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -303,7 +303,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -313,7 +313,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -321,7 +321,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -329,7 +329,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -337,7 +337,7 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -347,7 +347,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -357,7 +357,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -365,7 +365,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -375,15 +383,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -393,7 +393,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -403,7 +419,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -411,7 +427,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -421,7 +437,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -429,7 +445,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -437,23 +453,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -463,7 +463,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -473,7 +473,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -481,7 +481,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -489,7 +489,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -497,7 +497,7 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -505,7 +505,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -513,7 +513,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -521,7 +521,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -529,7 +529,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -543,7 +543,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -553,7 +553,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -563,7 +563,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -573,7 +573,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -581,7 +581,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -589,7 +589,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -599,7 +599,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -609,7 +609,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -617,7 +617,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -625,7 +625,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -635,7 +635,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -645,7 +645,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -653,7 +653,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -663,7 +663,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -671,7 +671,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -679,7 +679,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -689,7 +689,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -697,7 +697,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -707,7 +707,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -715,7 +715,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -723,7 +723,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -733,7 +733,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -743,7 +743,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -751,7 +751,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -761,7 +761,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -769,7 +769,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -777,7 +777,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -787,7 +787,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -795,7 +795,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -805,7 +805,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -813,7 +813,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -821,7 +821,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -829,7 +829,7 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -839,7 +839,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -849,7 +849,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -857,7 +857,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -867,15 +875,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -885,7 +885,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -895,7 +911,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -903,7 +919,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -913,7 +929,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -921,7 +937,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -929,23 +945,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -955,7 +955,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -965,7 +965,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -973,7 +973,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -981,4 +981,4 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_missing_for_attr.stderr b/tests/codegen/fail/interface/struct/attr_missing_for_attr.stderr
index b7008d17..eddbb9b3 100644
--- a/tests/codegen/fail/interface/struct/attr_missing_for_attr.stderr
+++ b/tests/codegen/fail/interface/struct/attr_missing_for_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 3 | #[derive(GraphQLObject)]
   |          ^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing implementer reference in interface's `for` attribute.', $DIR/fail/interface/struct/attr_missing_for_attr.rs:3:10
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_missing_impl_attr.stderr b/tests/codegen/fail/interface/struct/attr_missing_impl_attr.stderr
index f03491d3..cfccb3cb 100644
--- a/tests/codegen/fail/interface/struct/attr_missing_impl_attr.stderr
+++ b/tests/codegen/fail/interface/struct/attr_missing_impl_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 8 | #[graphql_interface(for = ObjA)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing interface reference in implementer's `impl` attribute.', $DIR/fail/interface/struct/attr_missing_impl_attr.rs:8:1
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the attribute macro `graphql_interface` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr
index 389334dc..0eb3178c 100644
--- a/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr
+++ b/tests/codegen/fail/interface/struct/attr_missing_transitive_impl.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_transitive_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_name_double_underscored.stderr b/tests/codegen/fail/interface/struct/attr_name_double_underscored.stderr
index 15db17f6..df34c85e 100644
--- a/tests/codegen/fail/interface/struct/attr_name_double_underscored.stderr
+++ b/tests/codegen/fail/interface/struct/attr_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | struct __Character {
   |        ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/struct/attr_no_fields.stderr b/tests/codegen/fail/interface/struct/attr_no_fields.stderr
index 6920674e..f8fc279a 100644
--- a/tests/codegen/fail/interface/struct/attr_no_fields.stderr
+++ b/tests/codegen/fail/interface/struct/attr_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL interface must have at least one field
 4 | struct Character {}
   | ^^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/struct/attr_non_subtype_return.stderr b/tests/codegen/fail/interface/struct/attr_non_subtype_return.stderr
index c5d9903c..480c7b1e 100644
--- a/tests/codegen/fail/interface/struct/attr_non_subtype_return.stderr
+++ b/tests/codegen/fail/interface/struct/attr_non_subtype_return.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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!`.', $DIR/fail/interface/struct/attr_non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/struct/attr_non_subtype_return.rs:11:5
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 11 |     id: String,
    |     ^^ 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!`.', $DIR/fail/interface/struct/attr_non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/attr_unnamed_field.stderr b/tests/codegen/fail/interface/struct/attr_unnamed_field.stderr
index 6fa918e2..6ad84969 100644
--- a/tests/codegen/fail/interface/struct/attr_unnamed_field.stderr
+++ b/tests/codegen/fail/interface/struct/attr_unnamed_field.stderr
@@ -4,4 +4,4 @@ error: GraphQL interface expected named struct field
 4 | struct Character(i32);
   |                  ^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.rs b/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.rs
index 5636cc17..3a7d192c 100644
--- a/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.rs
+++ b/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.rs
@@ -7,7 +7,7 @@ pub struct ObjA {
 #[graphql_object(impl = CharacterValue)]
 impl ObjA {
     fn id(&self, is_present: bool) -> &str {
-        is_present.then(|| self.id.as_str()).unwrap_or("missing")
+        is_present.then_some(&*self.id).unwrap_or("missing")
     }
 }
 
diff --git a/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.stderr b/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.stderr
index aa1fd8ee..f6e828fc 100644
--- a/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.stderr
+++ b/tests/codegen/fail/interface/struct/derive_additional_non_nullable_argument.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 17 |     id: String,
    |     ^^ 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.', $DIR/fail/interface/struct/derive_additional_non_nullable_argument.rs:17:5
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/struct/derive_additional_non_nullable_argument.rs:17:5
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 17 |     id: String,
    |     ^^ 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.', $DIR/fail/interface/struct/derive_additional_non_nullable_argument.rs:17:5
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_field_double_underscored.stderr b/tests/codegen/fail/interface/struct/derive_field_double_underscored.stderr
index 37b88b68..f8330549 100644
--- a/tests/codegen/fail/interface/struct/derive_field_double_underscored.stderr
+++ b/tests/codegen/fail/interface/struct/derive_field_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 |     __id: String,
   |     ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/struct/derive_fields_duplicate.stderr b/tests/codegen/fail/interface/struct/derive_fields_duplicate.stderr
index a0078989..63d03bc9 100644
--- a/tests/codegen/fail/interface/struct/derive_fields_duplicate.stderr
+++ b/tests/codegen/fail/interface/struct/derive_fields_duplicate.stderr
@@ -9,4 +9,4 @@ error: GraphQL interface must have a different name for each field
 9 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
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 234878de..926c96b1 100644
--- a/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr
+++ b/tests/codegen/fail/interface/struct/derive_implementers_duplicate_pretty.stderr
@@ -16,7 +16,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -32,4 +32,4 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_implementers_duplicate_ugly.stderr b/tests/codegen/fail/interface/struct/derive_implementers_duplicate_ugly.stderr
index fde533c1..de35d399 100644
--- a/tests/codegen/fail/interface/struct/derive_implementers_duplicate_ugly.stderr
+++ b/tests/codegen/fail/interface/struct/derive_implementers_duplicate_ugly.stderr
@@ -18,4 +18,4 @@ error[E0119]: conflicting implementations of trait `<CharacterValueEnum<ObjA, Ob
    |          first implementation here
    |          conflicting implementation for `ObjA`
    |
-   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the derive macro `GraphQLInterface` (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 a9a91ec7..11f1490e 100644
--- a/tests/codegen/fail/interface/struct/derive_missing_field.stderr
+++ b/tests/codegen/fail/interface/struct/derive_missing_field.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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,7 +12,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -20,7 +20,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -28,7 +28,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -36,7 +36,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -45,13 +45,13 @@ error: any use of this value will cause an error
    |     ^^
    |     |
    |     referenced constant has errors
-   |     inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
-   |     inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59
+   |     inside `<CharacterValueEnum<ObjA> as reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
+   |     inside `<CharacterValueEnum<ObjA> as 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -61,7 +61,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -71,7 +71,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -81,7 +81,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -89,7 +89,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -97,7 +97,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -107,7 +107,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -117,7 +117,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -125,7 +125,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -133,7 +133,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -143,7 +143,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -153,7 +153,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -161,7 +161,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -171,7 +171,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -179,7 +179,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -187,7 +187,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -197,7 +197,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -205,7 +205,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -215,7 +215,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -223,7 +223,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -231,7 +231,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -241,7 +241,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -251,7 +251,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -259,7 +259,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -269,7 +269,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -277,7 +277,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -285,7 +285,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -295,7 +295,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -303,7 +303,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -313,7 +313,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -321,7 +321,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -329,7 +329,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -337,7 +337,7 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -347,7 +347,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -357,7 +357,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -365,7 +365,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -375,15 +383,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -393,7 +393,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -403,7 +419,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -411,7 +427,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -421,7 +437,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -429,7 +445,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -437,23 +453,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -463,7 +463,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -473,7 +473,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -481,7 +481,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -489,7 +489,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -497,7 +497,7 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -505,7 +505,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -513,7 +513,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -521,7 +521,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -529,7 +529,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -543,7 +543,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -553,7 +553,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -563,7 +563,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -573,7 +573,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -581,7 +581,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -589,7 +589,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -599,7 +599,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -609,7 +609,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -617,7 +617,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -625,7 +625,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -635,7 +635,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -645,7 +645,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -653,7 +653,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -663,7 +663,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -671,7 +671,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -679,7 +679,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -689,7 +689,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -697,7 +697,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -707,7 +707,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -715,7 +715,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -723,7 +723,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -733,7 +733,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -743,7 +743,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -751,7 +751,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -761,7 +761,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -769,7 +769,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -777,7 +777,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -787,7 +787,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -795,7 +795,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -805,7 +805,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -813,7 +813,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -821,7 +821,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -829,7 +829,7 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -839,7 +839,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -849,7 +849,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -857,7 +857,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -867,15 +875,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -885,7 +885,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -895,7 +911,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -903,7 +919,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -913,7 +929,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -921,7 +937,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -929,23 +945,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -955,7 +955,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -965,7 +965,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -973,7 +973,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -981,4 +981,4 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_missing_for_attr.stderr b/tests/codegen/fail/interface/struct/derive_missing_for_attr.stderr
index 9f394b97..89c02448 100644
--- a/tests/codegen/fail/interface/struct/derive_missing_for_attr.stderr
+++ b/tests/codegen/fail/interface/struct/derive_missing_for_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 3 | #[derive(GraphQLObject)]
   |          ^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing implementer reference in interface's `for` attribute.', $DIR/fail/interface/struct/derive_missing_for_attr.rs:3:10
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_missing_impl_attr.stderr b/tests/codegen/fail/interface/struct/derive_missing_impl_attr.stderr
index e092494a..7a7a1018 100644
--- a/tests/codegen/fail/interface/struct/derive_missing_impl_attr.stderr
+++ b/tests/codegen/fail/interface/struct/derive_missing_impl_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 8 | #[derive(GraphQLInterface)]
   |          ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing interface reference in implementer's `impl` attribute.', $DIR/fail/interface/struct/derive_missing_impl_attr.rs:8:10
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the derive macro `GraphQLInterface` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr
index 278b725f..8ed89a93 100644
--- a/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr
+++ b/tests/codegen/fail/interface/struct/derive_missing_transitive_impl.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_transitive_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_name_double_underscored.stderr b/tests/codegen/fail/interface/struct/derive_name_double_underscored.stderr
index 0996adac..9b41f141 100644
--- a/tests/codegen/fail/interface/struct/derive_name_double_underscored.stderr
+++ b/tests/codegen/fail/interface/struct/derive_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | struct __Character {
   |        ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/struct/derive_no_fields.stderr b/tests/codegen/fail/interface/struct/derive_no_fields.stderr
index d0718a6d..742c337a 100644
--- a/tests/codegen/fail/interface/struct/derive_no_fields.stderr
+++ b/tests/codegen/fail/interface/struct/derive_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL interface must have at least one field
 4 | struct Character {}
   | ^^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/struct/derive_non_subtype_return.stderr b/tests/codegen/fail/interface/struct/derive_non_subtype_return.stderr
index b62b6b0f..87095cf3 100644
--- a/tests/codegen/fail/interface/struct/derive_non_subtype_return.stderr
+++ b/tests/codegen/fail/interface/struct/derive_non_subtype_return.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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!`.', $DIR/fail/interface/struct/derive_non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/struct/derive_non_subtype_return.rs:12:5
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 12 |     id: String,
    |     ^^ 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!`.', $DIR/fail/interface/struct/derive_non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/struct/derive_unnamed_field.stderr b/tests/codegen/fail/interface/struct/derive_unnamed_field.stderr
index 8a826c10..9783cb53 100644
--- a/tests/codegen/fail/interface/struct/derive_unnamed_field.stderr
+++ b/tests/codegen/fail/interface/struct/derive_unnamed_field.stderr
@@ -4,4 +4,4 @@ error: GraphQL interface expected named struct field
 4 | struct Character(i32);
   |                  ^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/trait/additional_non_nullable_argument.rs b/tests/codegen/fail/interface/trait/additional_non_nullable_argument.rs
index c69f0f66..d8c4060c 100644
--- a/tests/codegen/fail/interface/trait/additional_non_nullable_argument.rs
+++ b/tests/codegen/fail/interface/trait/additional_non_nullable_argument.rs
@@ -7,7 +7,7 @@ pub struct ObjA {
 #[graphql_object(impl = CharacterValue)]
 impl ObjA {
     fn id(&self, is_present: bool) -> &str {
-        is_present.then(|| self.id.as_str()).unwrap_or("missing")
+        is_present.then_some(&*self.id).unwrap_or("missing")
     }
 }
 
diff --git a/tests/codegen/fail/interface/trait/additional_non_nullable_argument.stderr b/tests/codegen/fail/interface/trait/additional_non_nullable_argument.stderr
index 4817ef41..29e48523 100644
--- a/tests/codegen/fail/interface/trait/additional_non_nullable_argument.stderr
+++ b/tests/codegen/fail/interface/trait/additional_non_nullable_argument.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 16 |     fn id(&self) -> &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.', $DIR/fail/interface/trait/additional_non_nullable_argument.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/trait/additional_non_nullable_argument.rs:16:8
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 16 |     fn id(&self) -> &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.', $DIR/fail/interface/trait/additional_non_nullable_argument.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/argument_double_underscored.stderr b/tests/codegen/fail/interface/trait/argument_double_underscored.stderr
index 81723140..4cf82f0a 100644
--- a/tests/codegen/fail/interface/trait/argument_double_underscored.stderr
+++ b/tests/codegen/fail/interface/trait/argument_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 |     fn id(&self, __num: i32) -> &str;
   |                  ^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/trait/field_double_underscored.stderr b/tests/codegen/fail/interface/trait/field_double_underscored.stderr
index 979daae6..3069e574 100644
--- a/tests/codegen/fail/interface/trait/field_double_underscored.stderr
+++ b/tests/codegen/fail/interface/trait/field_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 |     fn __id(&self) -> &str;
   |        ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/trait/fields_duplicate.stderr b/tests/codegen/fail/interface/trait/fields_duplicate.stderr
index e7fc5080..4750e958 100644
--- a/tests/codegen/fail/interface/trait/fields_duplicate.stderr
+++ b/tests/codegen/fail/interface/trait/fields_duplicate.stderr
@@ -9,4 +9,4 @@ error: GraphQL interface must have a different name for each field
 9 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr b/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr
index 13696d8d..0dc684f7 100644
--- a/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr
+++ b/tests/codegen/fail/interface/trait/implementers_duplicate_pretty.stderr
@@ -16,7 +16,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (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
@@ -32,4 +32,4 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/implementers_duplicate_ugly.stderr b/tests/codegen/fail/interface/trait/implementers_duplicate_ugly.stderr
index 74b695d8..052d6585 100644
--- a/tests/codegen/fail/interface/trait/implementers_duplicate_ugly.stderr
+++ b/tests/codegen/fail/interface/trait/implementers_duplicate_ugly.stderr
@@ -18,4 +18,4 @@ error[E0119]: conflicting implementations of trait `<CharacterValueEnum<ObjA, Ob
    | first implementation here
    | conflicting implementation for `ObjA`
    |
-   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the attribute macro `graphql_interface` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/method_default_impl.stderr b/tests/codegen/fail/interface/trait/method_default_impl.stderr
index b95687d4..0e95cc3d 100644
--- a/tests/codegen/fail/interface/trait/method_default_impl.stderr
+++ b/tests/codegen/fail/interface/trait/method_default_impl.stderr
@@ -7,4 +7,4 @@ error: GraphQL interface trait method can't have default implementation
 7 | |     }
   | |_____^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/trait/missing_field.stderr b/tests/codegen/fail/interface/trait/missing_field.stderr
index 45913e16..71babfcf 100644
--- a/tests/codegen/fail/interface/trait/missing_field.stderr
+++ b/tests/codegen/fail/interface/trait/missing_field.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -12,7 +12,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -20,7 +20,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -28,7 +28,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -36,7 +36,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -45,13 +45,13 @@ error: any use of this value will cause an error
    |        ^^
    |        |
    |        referenced constant has errors
-   |        inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
-   |        inside `<CharacterValueEnum<ObjA> as juniper::macros::reflect::Field<__S, id>>::call::_::RES` at $WORKSPACE/juniper/src/macros/reflect.rs:814:59
+   |        inside `<CharacterValueEnum<ObjA> as reflect::Field<__S, id>>::call::_::check` at $WORKSPACE/juniper/src/macros/reflect.rs:751:36
+   |        inside `<CharacterValueEnum<ObjA> as 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -61,7 +61,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -71,7 +71,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -81,7 +81,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -89,7 +89,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -97,7 +97,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -107,7 +107,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -117,7 +117,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -125,7 +125,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -133,7 +133,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -143,7 +143,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -153,7 +153,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -161,7 +161,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -171,7 +171,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -179,7 +179,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -187,7 +187,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -197,7 +197,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -205,7 +205,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -215,7 +215,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -223,7 +223,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -231,7 +231,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -241,7 +241,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -251,7 +251,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -259,7 +259,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -269,7 +269,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -277,7 +277,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -285,7 +285,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -295,7 +295,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -303,7 +303,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -313,7 +313,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -321,7 +321,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -329,7 +329,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -337,7 +337,7 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -347,7 +347,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -357,7 +357,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -365,7 +365,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -375,15 +383,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -393,7 +393,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -403,7 +419,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -411,7 +427,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -421,7 +437,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -429,7 +445,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -437,23 +453,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -463,7 +463,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -473,7 +473,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -481,7 +481,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -489,7 +489,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -497,7 +497,7 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -505,7 +505,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -513,7 +513,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -521,7 +521,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
   --> fail/interface/trait/missing_field.rs:11:8
@@ -529,7 +529,7 @@ error[E0080]: erroneous constant used
 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)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -543,7 +543,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -553,7 +553,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -563,7 +563,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -573,7 +573,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -581,7 +581,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -589,7 +589,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -599,7 +599,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -609,7 +609,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -617,7 +617,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -625,7 +625,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -635,7 +635,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -645,7 +645,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -653,7 +653,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -663,7 +663,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -671,7 +671,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -679,7 +679,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -689,7 +689,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -697,7 +697,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -707,7 +707,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -715,7 +715,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -723,7 +723,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -733,7 +733,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -743,7 +743,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -751,7 +751,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -761,7 +761,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -769,7 +769,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -777,7 +777,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -787,7 +787,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -795,7 +795,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -805,7 +805,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_field_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_field_args` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -813,7 +813,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -821,7 +821,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -829,7 +829,7 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -839,7 +839,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -849,7 +849,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -857,7 +857,15 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -867,15 +875,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/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)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -885,7 +885,23 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -895,7 +911,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -903,7 +919,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -913,7 +929,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -921,7 +937,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -929,23 +945,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::const_concat` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -955,7 +955,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::assert_subtype` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::assert_subtype` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -965,7 +965,7 @@ error: any use of this value will cause an error
    |
    = 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 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this error originates in the macro `$crate::format_type` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -973,7 +973,7 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (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
@@ -981,4 +981,4 @@ error[E0080]: evaluation of constant value failed
 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)
+   = note: this error originates in the macro `$crate::format_type` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/missing_field_argument.stderr b/tests/codegen/fail/interface/trait/missing_field_argument.stderr
index 276222f7..d292529c 100644
--- a/tests/codegen/fail/interface/trait/missing_field_argument.stderr
+++ b/tests/codegen/fail/interface/trait/missing_field_argument.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 16 |     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!` was expected, but not found.', $DIR/fail/interface/trait/missing_field_argument.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/trait/missing_field_argument.rs:16:8
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 16 |     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!` was expected, but not found.', $DIR/fail/interface/trait/missing_field_argument.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/missing_for_attr.stderr b/tests/codegen/fail/interface/trait/missing_for_attr.stderr
index da011ad9..a71e07c3 100644
--- a/tests/codegen/fail/interface/trait/missing_for_attr.stderr
+++ b/tests/codegen/fail/interface/trait/missing_for_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 3 | #[derive(GraphQLObject)]
   |          ^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing implementer reference in interface's `for` attribute.', $DIR/fail/interface/trait/missing_for_attr.rs:3:10
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the derive macro `GraphQLObject` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/missing_impl_attr.stderr b/tests/codegen/fail/interface/trait/missing_impl_attr.stderr
index a82878d6..d502fd0e 100644
--- a/tests/codegen/fail/interface/trait/missing_impl_attr.stderr
+++ b/tests/codegen/fail/interface/trait/missing_impl_attr.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 8 | #[graphql_interface(for = ObjA)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: missing interface reference in implementer's `impl` attribute.', $DIR/fail/interface/trait/missing_impl_attr.rs:8:1
   |
-  = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the attribute macro `graphql_interface` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr b/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr
index f120ac36..16767ee9 100644
--- a/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr
+++ b/tests/codegen/fail/interface/trait/missing_transitive_impl.stderr
@@ -4,4 +4,4 @@ error[E0080]: evaluation of constant value failed
 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)
+  = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_transitive_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/name_double_underscored.stderr b/tests/codegen/fail/interface/trait/name_double_underscored.stderr
index 1fa999a4..35640240 100644
--- a/tests/codegen/fail/interface/trait/name_double_underscored.stderr
+++ b/tests/codegen/fail/interface/trait/name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | trait __Character {
   |       ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/interface/trait/no_fields.stderr b/tests/codegen/fail/interface/trait/no_fields.stderr
index 63c7d296..2638dc9d 100644
--- a/tests/codegen/fail/interface/trait/no_fields.stderr
+++ b/tests/codegen/fail/interface/trait/no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL interface must have at least one field
 4 | trait Character {}
   | ^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Interfaces
+  = note: https://spec.graphql.org/October2021#sec-Interfaces
diff --git a/tests/codegen/fail/interface/trait/non_subtype_return.stderr b/tests/codegen/fail/interface/trait/non_subtype_return.stderr
index 92e123f2..3c9d1bdb 100644
--- a/tests/codegen/fail/interface/trait/non_subtype_return.stderr
+++ b/tests/codegen/fail/interface/trait/non_subtype_return.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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!`.', $DIR/fail/interface/trait/non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/trait/non_subtype_return.rs:11:8
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 11 |     fn id(&self) -> &str;
    |        ^^ 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!`.', $DIR/fail/interface/trait/non_subtype_return.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)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/interface/trait/wrong_argument_type.stderr b/tests/codegen/fail/interface/trait/wrong_argument_type.stderr
index 3a47b725..36c24e4f 100644
--- a/tests/codegen/fail/interface/trait/wrong_argument_type.stderr
+++ b/tests/codegen/fail/interface/trait/wrong_argument_type.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 16 |     fn id(&self, is_present: bool) -> &str;
    |        ^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: Field `id`: Argument `isPresent`: expected type `Boolean!`, found: `Int!`.', $DIR/fail/interface/trait/wrong_argument_type.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> fail/interface/trait/wrong_argument_type.rs:16:8
@@ -12,4 +12,4 @@ error[E0080]: evaluation of constant value failed
 16 |     fn id(&self, is_present: bool) -> &str;
    |        ^^ the evaluated program panicked at 'Failed to implement interface `Character` on `ObjA`: Field `id`: Argument `isPresent`: expected type `Boolean!`, found: `Int!`.', $DIR/fail/interface/trait/wrong_argument_type.rs:16:8
    |
-   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `::juniper::assert_field` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/object/argument_double_underscored.stderr b/tests/codegen/fail/object/argument_double_underscored.stderr
index 6ee3a756..ae33cf32 100644
--- a/tests/codegen/fail/object/argument_double_underscored.stderr
+++ b/tests/codegen/fail/object/argument_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 7 |     fn id(&self, __num: i32) -> &str {
   |                  ^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/object/attr_fields_duplicate.stderr b/tests/codegen/fail/object/attr_fields_duplicate.stderr
index 3c6968b2..04304a3a 100644
--- a/tests/codegen/fail/object/attr_fields_duplicate.stderr
+++ b/tests/codegen/fail/object/attr_fields_duplicate.stderr
@@ -4,4 +4,4 @@ error: GraphQL object must have a different name for each field
 6 | impl ObjA {
   |      ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Objects
+  = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/object/attr_name_double_underscored.stderr b/tests/codegen/fail/object/attr_name_double_underscored.stderr
index 031654a2..a46fbda4 100644
--- a/tests/codegen/fail/object/attr_name_double_underscored.stderr
+++ b/tests/codegen/fail/object/attr_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 6 | impl __Obj {
   |      ^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/object/attr_no_fields.stderr b/tests/codegen/fail/object/attr_no_fields.stderr
index 9ba0098b..bd3a050b 100644
--- a/tests/codegen/fail/object/attr_no_fields.stderr
+++ b/tests/codegen/fail/object/attr_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL object must have at least one field
 6 | impl Obj {}
   |      ^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Objects
+  = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/object/derive_field_double_underscored.stderr b/tests/codegen/fail/object/derive_field_double_underscored.stderr
index 6a6e6403..16b38b89 100644
--- a/tests/codegen/fail/object/derive_field_double_underscored.stderr
+++ b/tests/codegen/fail/object/derive_field_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 |     __test: String,
   |     ^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/object/derive_fields_duplicate.stderr b/tests/codegen/fail/object/derive_fields_duplicate.stderr
index 18c08423..e7e01291 100644
--- a/tests/codegen/fail/object/derive_fields_duplicate.stderr
+++ b/tests/codegen/fail/object/derive_fields_duplicate.stderr
@@ -8,4 +8,4 @@ error: GraphQL object must have a different name for each field
 8 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Objects
+  = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/object/derive_name_double_underscored.stderr b/tests/codegen/fail/object/derive_name_double_underscored.stderr
index 809f7297..08793621 100644
--- a/tests/codegen/fail/object/derive_name_double_underscored.stderr
+++ b/tests/codegen/fail/object/derive_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | struct __Obj {
   |        ^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/object/derive_no_fields.stderr b/tests/codegen/fail/object/derive_no_fields.stderr
index ef198b79..31f6812d 100644
--- a/tests/codegen/fail/object/derive_no_fields.stderr
+++ b/tests/codegen/fail/object/derive_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL object must have at least one field
 4 | struct Obj {}
   | ^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Objects
+  = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/subscription/argument_double_underscored.stderr b/tests/codegen/fail/subscription/argument_double_underscored.stderr
index fd373703..dd83ba63 100644
--- a/tests/codegen/fail/subscription/argument_double_underscored.stderr
+++ b/tests/codegen/fail/subscription/argument_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 11 |     async fn id(&self, __num: i32) -> Stream<'static, &'static str> {
    |                        ^^^^^
    |
-   = note: https://spec.graphql.org/June2018/#sec-Schema
+   = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/subscription/field_not_async.stderr b/tests/codegen/fail/subscription/field_not_async.stderr
index c2061179..93fa942b 100644
--- a/tests/codegen/fail/subscription/field_not_async.stderr
+++ b/tests/codegen/fail/subscription/field_not_async.stderr
@@ -4,5 +4,5 @@ error: GraphQL object synchronous resolvers are not supported
 11 |     fn id(&self) -> Stream<'static, bool> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: https://spec.graphql.org/June2018/#sec-Objects
+   = note: https://spec.graphql.org/October2021#sec-Objects
    = note: Specify that this function is async: `async fn foo()`
diff --git a/tests/codegen/fail/subscription/fields_duplicate.stderr b/tests/codegen/fail/subscription/fields_duplicate.stderr
index 34773a15..28281e51 100644
--- a/tests/codegen/fail/subscription/fields_duplicate.stderr
+++ b/tests/codegen/fail/subscription/fields_duplicate.stderr
@@ -4,4 +4,4 @@ error: GraphQL object must have a different name for each field
 10 | impl ObjA {
    |      ^^^^
    |
-   = note: https://spec.graphql.org/June2018/#sec-Objects
+   = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/subscription/name_double_underscored.stderr b/tests/codegen/fail/subscription/name_double_underscored.stderr
index 4752ecb0..d9fffd1b 100644
--- a/tests/codegen/fail/subscription/name_double_underscored.stderr
+++ b/tests/codegen/fail/subscription/name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 10 | impl __Obj {
    |      ^^^^^
    |
-   = note: https://spec.graphql.org/June2018/#sec-Schema
+   = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/subscription/no_fields.stderr b/tests/codegen/fail/subscription/no_fields.stderr
index 90d4eb11..6faaed2f 100644
--- a/tests/codegen/fail/subscription/no_fields.stderr
+++ b/tests/codegen/fail/subscription/no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL object must have at least one field
 6 | impl Obj {}
   |      ^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Objects
+  = note: https://spec.graphql.org/October2021#sec-Objects
diff --git a/tests/codegen/fail/union/enum_external_resolver_fn_conflicts_with_variant_external_resolver_fn.stderr b/tests/codegen/fail/union/enum_external_resolver_fn_conflicts_with_variant_external_resolver_fn.stderr
index 9d913d22..17b5ec8d 100644
--- a/tests/codegen/fail/union/enum_external_resolver_fn_conflicts_with_variant_external_resolver_fn.stderr
+++ b/tests/codegen/fail/union/enum_external_resolver_fn_conflicts_with_variant_external_resolver_fn.stderr
@@ -4,4 +4,4 @@ error: GraphQL union variant `Human` already has external resolver function `res
 6 |     #[graphql(with = resolve_fn2)]
   |               ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/enum_name_double_underscored.stderr b/tests/codegen/fail/union/enum_name_double_underscored.stderr
index be6d0e29..623186d8 100644
--- a/tests/codegen/fail/union/enum_name_double_underscored.stderr
+++ b/tests/codegen/fail/union/enum_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | enum __Character {
   |      ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/union/enum_no_fields.stderr b/tests/codegen/fail/union/enum_no_fields.stderr
index 9ab9c400..7e036c6a 100644
--- a/tests/codegen/fail/union/enum_no_fields.stderr
+++ b/tests/codegen/fail/union/enum_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL union expects at least one union variant
 4 | enum Character {}
   | ^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/enum_same_type_pretty.stderr b/tests/codegen/fail/union/enum_same_type_pretty.stderr
index 8c432f3e..7b03ac3a 100644
--- a/tests/codegen/fail/union/enum_same_type_pretty.stderr
+++ b/tests/codegen/fail/union/enum_same_type_pretty.stderr
@@ -7,4 +7,4 @@ error: GraphQL union must have a different type for each union variant
 7 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/enum_same_type_ugly.stderr b/tests/codegen/fail/union/enum_same_type_ugly.stderr
index fbb313ad..37c11674 100644
--- a/tests/codegen/fail/union/enum_same_type_ugly.stderr
+++ b/tests/codegen/fail/union/enum_same_type_ugly.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `<Character as juniper::GraphQLUnion<__S>>::mark::_::{closure#0}::MutuallyExclusive` for type `std::string::String`
- --> $DIR/enum_same_type_ugly.rs:3:10
+ --> fail/union/enum_same_type_ugly.rs:3:10
   |
 3 | #[derive(GraphQLUnion)]
   |          ^^^^^^^^^^^^
@@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `<Character as juniper::Graph
   |          first implementation here
   |          conflicting implementation for `std::string::String`
   |
-  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the derive macro `GraphQLUnion` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/union/enum_wrong_variant_field.stderr b/tests/codegen/fail/union/enum_wrong_variant_field.stderr
index f9d00963..6ad79275 100644
--- a/tests/codegen/fail/union/enum_wrong_variant_field.stderr
+++ b/tests/codegen/fail/union/enum_wrong_variant_field.stderr
@@ -4,7 +4,7 @@ error: GraphQL union enum allows only unnamed variants with a single field, e.g.
 5 |     A { human: Human },
   |     ^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
 
 error: GraphQL union enum allows only unnamed variants with a single field, e.g. `Some(T)`
   --> fail/union/enum_wrong_variant_field.rs:10:6
@@ -12,4 +12,4 @@ error: GraphQL union enum allows only unnamed variants with a single field, e.g.
 10 |     A(Human, u8),
    |      ^^^^^^^^^^^
    |
-   = note: https://spec.graphql.org/June2018/#sec-Unions
+   = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/struct_name_double_underscored.stderr b/tests/codegen/fail/union/struct_name_double_underscored.stderr
index 5c4d04e4..84b3e3a9 100644
--- a/tests/codegen/fail/union/struct_name_double_underscored.stderr
+++ b/tests/codegen/fail/union/struct_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 5 | struct __Character;
   |        ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/union/struct_no_fields.stderr b/tests/codegen/fail/union/struct_no_fields.stderr
index c26a9da1..e5e79101 100644
--- a/tests/codegen/fail/union/struct_no_fields.stderr
+++ b/tests/codegen/fail/union/struct_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL union expects at least one union variant
 4 | struct Character;
   | ^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/struct_same_type_ugly.stderr b/tests/codegen/fail/union/struct_same_type_ugly.stderr
index 48a91be2..583006f6 100644
--- a/tests/codegen/fail/union/struct_same_type_ugly.stderr
+++ b/tests/codegen/fail/union/struct_same_type_ugly.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `<Character as juniper::GraphQLUnion<__S>>::mark::_::{closure#0}::MutuallyExclusive` for type `std::string::String`
- --> $DIR/struct_same_type_ugly.rs:3:10
+ --> fail/union/struct_same_type_ugly.rs:3:10
   |
 3 | #[derive(GraphQLUnion)]
   |          ^^^^^^^^^^^^
@@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `<Character as juniper::Graph
   |          first implementation here
   |          conflicting implementation for `std::string::String`
   |
-  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the derive macro `GraphQLUnion` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/union/trait_fail_infer_context.stderr b/tests/codegen/fail/union/trait_fail_infer_context.stderr
index ab1d3071..35b54f78 100644
--- a/tests/codegen/fail/union/trait_fail_infer_context.stderr
+++ b/tests/codegen/fail/union/trait_fail_infer_context.stderr
@@ -23,6 +23,6 @@ error[E0308]: mismatched types
 note: associated function defined here
    --> $WORKSPACE/juniper/src/executor/mod.rs
     |
-    |     fn into(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S>;
-    |        ^^^^
+    |     fn into_resolvable(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S>;
+    |        ^^^^^^^^^^^^^^^
     = note: this error originates in the attribute macro `graphql_union` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/codegen/fail/union/trait_method_conflicts_with_external_resolver_fn.stderr b/tests/codegen/fail/union/trait_method_conflicts_with_external_resolver_fn.stderr
index b81e5a67..c098337e 100644
--- a/tests/codegen/fail/union/trait_method_conflicts_with_external_resolver_fn.stderr
+++ b/tests/codegen/fail/union/trait_method_conflicts_with_external_resolver_fn.stderr
@@ -4,5 +4,5 @@ error: GraphQL union trait method `a` conflicts with the external resolver funct
 5 |     fn a(&self) -> Option<&Human>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
   = note: use `#[graphql(ignore)]` attribute to ignore this trait method for union variants resolution
diff --git a/tests/codegen/fail/union/trait_name_double_underscored.stderr b/tests/codegen/fail/union/trait_name_double_underscored.stderr
index baf44bc8..afb1f11e 100644
--- a/tests/codegen/fail/union/trait_name_double_underscored.stderr
+++ b/tests/codegen/fail/union/trait_name_double_underscored.stderr
@@ -4,4 +4,4 @@ error: All types and directives defined within a schema must not have a name whi
 4 | trait __Character {
   |       ^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Schema
+  = note: https://spec.graphql.org/October2021#sec-Schema
diff --git a/tests/codegen/fail/union/trait_no_fields.stderr b/tests/codegen/fail/union/trait_no_fields.stderr
index b75d5ba6..c2f032da 100644
--- a/tests/codegen/fail/union/trait_no_fields.stderr
+++ b/tests/codegen/fail/union/trait_no_fields.stderr
@@ -4,4 +4,4 @@ error: GraphQL union expects at least one union variant
 4 | trait Character {}
   | ^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/trait_same_type_pretty.stderr b/tests/codegen/fail/union/trait_same_type_pretty.stderr
index 61e642b3..116a7113 100644
--- a/tests/codegen/fail/union/trait_same_type_pretty.stderr
+++ b/tests/codegen/fail/union/trait_same_type_pretty.stderr
@@ -7,4 +7,4 @@ error: GraphQL union must have a different type for each union variant
 7 | | }
   | |_^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/trait_same_type_ugly.stderr b/tests/codegen/fail/union/trait_same_type_ugly.stderr
index 9b7eabbd..0388fef3 100644
--- a/tests/codegen/fail/union/trait_same_type_ugly.stderr
+++ b/tests/codegen/fail/union/trait_same_type_ugly.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `<(dyn Character + std::marker::Send + std::marker::Sync + '__obj) as juniper::GraphQLUnion<__S>>::mark::_::{closure#0}::MutuallyExclusive` for type `std::string::String`
- --> $DIR/trait_same_type_ugly.rs:3:1
+ --> fail/union/trait_same_type_ugly.rs:3:1
   |
 3 | #[graphql_union]
   | ^^^^^^^^^^^^^^^^
@@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `<(dyn Character + std::marke
   | first implementation here
   | conflicting implementation for `std::string::String`
   |
-  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+  = note: this error originates in the macro `::juniper::sa::assert_type_ne_all` which comes from the expansion of the attribute macro `graphql_union` (in Nightly builds, run with -Z macro-backtrace for more info)
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 2402ab17..6e406214 100644
--- a/tests/codegen/fail/union/trait_with_attr_on_method.stderr
+++ b/tests/codegen/fail/union/trait_with_attr_on_method.stderr
@@ -4,5 +4,5 @@ error: GraphQL union cannot use #[graphql(with = ...)] attribute on a trait meth
 5 |     #[graphql(with = something)]
   |               ^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
   = note: instead use #[graphql(ignore)] on the method with #[graphql_union(on ... = ...)] on the trait itself
diff --git a/tests/codegen/fail/union/trait_wrong_method_input_args.stderr b/tests/codegen/fail/union/trait_wrong_method_input_args.stderr
index 44d447c5..74c68596 100644
--- a/tests/codegen/fail/union/trait_wrong_method_input_args.stderr
+++ b/tests/codegen/fail/union/trait_wrong_method_input_args.stderr
@@ -4,4 +4,4 @@ error: GraphQL union expects trait method to accept `&self` only and, optionally
 5 |     fn a(&self, ctx: &(), rand: u8) -> Option<&Human>;
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/fail/union/trait_wrong_method_return_type.stderr b/tests/codegen/fail/union/trait_wrong_method_return_type.stderr
index 87ee8ff1..1594d53a 100644
--- a/tests/codegen/fail/union/trait_wrong_method_return_type.stderr
+++ b/tests/codegen/fail/union/trait_wrong_method_return_type.stderr
@@ -4,4 +4,4 @@ error: GraphQL union expects trait method return type to be `Option<&VariantType
 5 |     fn a(&self) -> &Human;
   |                    ^^^^^^
   |
-  = note: https://spec.graphql.org/June2018/#sec-Unions
+  = note: https://spec.graphql.org/October2021#sec-Unions
diff --git a/tests/codegen/src/lib.rs b/tests/codegen/src/lib.rs
index 656b5e7a..abdcf203 100644
--- a/tests/codegen/src/lib.rs
+++ b/tests/codegen/src/lib.rs
@@ -1,38 +1,9 @@
 // TODO: [Object] Type Validation: §4 (interfaces) for objects
 // TODO: [Non-Null] §1 A Non‐Null type must not wrap another Non‐Null type.
 
-#[cfg(test)]
-use std::{
-    fs::{read_dir, DirEntry},
-    io,
-    path::{Path, PathBuf},
-};
-
-#[cfg(test)]
-fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> io::Result<()> {
-    if dir.is_dir() {
-        for entry in read_dir(dir)? {
-            let entry = entry?;
-            let path = entry.path();
-            if path.is_dir() {
-                visit_dirs(&path, cb)?;
-            } else {
-                cb(&entry);
-            }
-        }
-    }
-    Ok(())
-}
-
+#[rustversion::nightly]
 #[test]
-fn test_failing_compiliation() {
+fn test_failing_compilation() {
     let t = trybuild::TestCases::new();
-    let dir = PathBuf::from("fail");
-
-    visit_dirs(dir.as_path(), &|entry: &DirEntry| {
-        if let Some(Some("rs")) = entry.path().extension().map(|os| os.to_str()) {
-            t.compile_fail(entry.path());
-        }
-    })
-    .unwrap();
+    t.compile_fail("fail/**/*.rs");
 }
diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml
index 2b2c3cc7..f339a718 100644
--- a/tests/integration/Cargo.toml
+++ b/tests/integration/Cargo.toml
@@ -1,19 +1,18 @@
 [package]
 name = "juniper_integration_tests"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 publish = false
 
-[dependencies]
-chrono = "0.4"
-derive_more = "0.99"
-futures = "0.3"
-juniper = { path = "../../juniper" }
-juniper_subscriptions = { path = "../../juniper_subscriptions" }
-
 [dev-dependencies]
 async-trait = "0.1.39"
+chrono = "0.4"
+derive_more = "0.99"
 fnv = "1.0"
+futures = "0.3"
+itertools = "0.10"
+juniper = { path = "../../juniper" }
+juniper_subscriptions = { path = "../../juniper_subscriptions" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 tokio = { version = "1.0", features = ["rt", "macros", "time"] }
diff --git a/tests/integration/src/codegen/derive_input_object.rs b/tests/integration/src/codegen/derive_input_object.rs
deleted file mode 100644
index f85b042e..00000000
--- a/tests/integration/src/codegen/derive_input_object.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-use fnv::FnvHashMap;
-use juniper::{
-    graphql_input_value, marker, DefaultScalarValue, FieldError, FromInputValue,
-    GraphQLInputObject, GraphQLType, GraphQLValue, InputValue, Registry, ToInputValue,
-};
-
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-#[graphql(
-    name = "MyInput",
-    description = "input descr",
-    scalar = DefaultScalarValue
-)]
-struct Input {
-    regular_field: String,
-    #[graphql(name = "haha", default = "33", description = "haha descr")]
-    c: i32,
-
-    #[graphql(default)]
-    other: Option<bool>,
-}
-
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-#[graphql(rename = "none")]
-struct NoRenameInput {
-    regular_field: String,
-}
-
-/// Object comment.
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-struct DocComment {
-    /// Field comment.
-    regular_field: bool,
-}
-
-/// Doc 1.\
-/// Doc 2.
-///
-/// Doc 4.
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-struct MultiDocComment {
-    /// Field 1.
-    /// Field 2.
-    regular_field: bool,
-}
-
-/// This is not used as the description.
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-#[graphql(description = "obj override")]
-struct OverrideDocComment {
-    /// This is not used as the description.
-    #[graphql(description = "field override")]
-    regular_field: bool,
-}
-
-#[derive(Debug, PartialEq)]
-struct Fake;
-
-impl<'a> marker::IsInputType<DefaultScalarValue> for &'a Fake {}
-
-impl<'a> FromInputValue for &'a Fake {
-    type Error = FieldError;
-
-    fn from_input_value(_v: &InputValue) -> Result<&'a Fake, Self::Error> {
-        Err("This is fake".into())
-    }
-}
-
-impl<'a> ToInputValue for &'a Fake {
-    fn to_input_value(&self) -> InputValue {
-        graphql_input_value!("this is fake")
-    }
-}
-
-impl<'a> GraphQLType<DefaultScalarValue> for &'a Fake {
-    fn name(_: &()) -> Option<&'static str> {
-        None
-    }
-    fn meta<'r>(_: &(), registry: &mut Registry<'r>) -> juniper::meta::MetaType<'r>
-    where
-        DefaultScalarValue: 'r,
-    {
-        let meta = registry.build_enum_type::<&'a Fake>(
-            &(),
-            &[juniper::meta::EnumValue {
-                name: "fake".to_string(),
-                description: None,
-                deprecation_status: juniper::meta::DeprecationStatus::Current,
-            }],
-        );
-        meta.into_meta()
-    }
-}
-
-impl<'a> GraphQLValue<DefaultScalarValue> for &'a Fake {
-    type Context = ();
-    type TypeInfo = ();
-
-    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
-        <Self as GraphQLType>::name(info)
-    }
-}
-
-#[derive(GraphQLInputObject, Debug, PartialEq)]
-#[graphql(scalar = DefaultScalarValue)]
-struct WithLifetime<'a> {
-    regular_field: &'a Fake,
-}
-
-#[test]
-fn test_derived_input_object() {
-    assert_eq!(
-        <Input as GraphQLType<DefaultScalarValue>>::name(&()),
-        Some("MyInput")
-    );
-
-    // Validate meta info.
-    let mut registry: Registry<'_> = Registry::new(FnvHashMap::default());
-    let meta = Input::meta(&(), &mut registry);
-    assert_eq!(meta.name(), Some("MyInput"));
-    assert_eq!(meta.description(), Some("input descr"));
-
-    // Test default value injection.
-
-    let input_no_defaults = graphql_input_value!({
-        "regularField": "a",
-    });
-    let output_no_defaults = Input::from_input_value(&input_no_defaults).unwrap();
-    assert_eq!(
-        output_no_defaults,
-        Input {
-            regular_field: "a".into(),
-            c: 33,
-            other: None,
-        },
-    );
-
-    // Test with all values supplied.
-
-    let input: InputValue = ::serde_json::from_value(serde_json::json!({
-        "regularField": "a",
-        "haha": 55,
-        "other": true,
-    }))
-    .unwrap();
-
-    let output: Input = FromInputValue::from_input_value(&input).unwrap();
-    assert_eq!(
-        output,
-        Input {
-            regular_field: "a".into(),
-            c: 55,
-            other: Some(true),
-        },
-    );
-
-    // Test disable renaming
-
-    let input: InputValue = ::serde_json::from_value(serde_json::json!({
-        "regular_field": "hello",
-    }))
-    .unwrap();
-
-    let output: NoRenameInput = FromInputValue::from_input_value(&input).unwrap();
-    assert_eq!(
-        output,
-        NoRenameInput {
-            regular_field: "hello".into(),
-        },
-    );
-}
-
-#[test]
-fn test_doc_comment() {
-    let mut registry: Registry<'_> = Registry::new(FnvHashMap::default());
-    let meta = DocComment::meta(&(), &mut registry);
-    assert_eq!(meta.description(), Some("Object comment."));
-}
-
-#[test]
-fn test_multi_doc_comment() {
-    let mut registry: Registry<'_> = Registry::new(FnvHashMap::default());
-    let meta = MultiDocComment::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 = OverrideDocComment::meta(&(), &mut registry);
-    assert_eq!(meta.description(), Some("obj override"));
-}
diff --git a/tests/integration/src/codegen/mod.rs b/tests/integration/src/codegen/mod.rs
deleted file mode 100644
index 830f6e1a..00000000
--- a/tests/integration/src/codegen/mod.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-mod derive_input_object;
-mod derive_object_with_raw_idents;
-mod enum_derive;
-mod interface_attr_struct;
-mod interface_attr_trait;
-mod interface_derive;
-mod object_attr;
-mod object_derive;
-mod scalar_attr_derive_input;
-mod scalar_attr_type_alias;
-mod scalar_derive;
-mod scalar_value_derive;
-mod subscription_attr;
-mod union_attr;
-mod union_derive;
diff --git a/tests/integration/src/infallible_as_field_error.rs b/tests/integration/src/infallible_as_field_error.rs
deleted file mode 100644
index 6a4539ff..00000000
--- a/tests/integration/src/infallible_as_field_error.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-struct Query;
-
-#[juniper::graphql_object]
-impl Query {
-    fn ping() -> Result<bool, std::convert::Infallible> {
-        Ok(false)
-    }
-}
diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs
deleted file mode 100644
index 98019c14..00000000
--- a/tests/integration/src/lib.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-#![deny(rust_2018_idioms)]
-
-#[cfg(test)]
-mod arc_fields;
-#[cfg(test)]
-mod array;
-#[cfg(test)]
-mod codegen;
-#[cfg(test)]
-mod custom_scalar;
-#[cfg(test)]
-mod explicit_null;
-#[cfg(test)]
-mod infallible_as_field_error;
-#[cfg(test)]
-mod inside_macro;
-#[cfg(test)]
-mod issue_371;
-#[cfg(test)]
-mod issue_372;
-#[cfg(test)]
-mod issue_398;
-#[cfg(test)]
-mod issue_407;
-#[cfg(test)]
-mod issue_500;
-#[cfg(test)]
-mod issue_798;
-#[cfg(test)]
-mod issue_914;
-#[cfg(test)]
-mod issue_922;
-#[cfg(test)]
-mod issue_925;
-#[cfg(test)]
-mod issue_945;
-#[cfg(test)]
-mod pre_parse;
-
-#[cfg(test)]
-/// Common utilities used across tests.
-pub(crate) mod util {
-    use futures::StreamExt as _;
-    use juniper::{
-        graphql_value, DefaultScalarValue, EmptyMutation, EmptySubscription, ExecutionError,
-        GraphQLError, GraphQLType, RootNode, ScalarValue, Value, ValuesStream,
-    };
-
-    pub(crate) fn schema<'q, C, Q>(
-        query_root: Q,
-    ) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
-    where
-        Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
-    {
-        RootNode::new(
-            query_root,
-            EmptyMutation::<C>::new(),
-            EmptySubscription::<C>::new(),
-        )
-    }
-
-    pub(crate) fn schema_with_scalar<'q, S, C, Q>(
-        query_root: Q,
-    ) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
-    where
-        Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
-        S: ScalarValue + 'q,
-    {
-        RootNode::new_with_scalar_value(
-            query_root,
-            EmptyMutation::<C>::new(),
-            EmptySubscription::<C>::new(),
-        )
-    }
-
-    /// Extracts a single next value from the result returned by
-    /// [`juniper::resolve_into_stream()`] and transforms it into a regular
-    /// [`Value`].
-    pub(crate) async fn extract_next<'a, S: ScalarValue>(
-        input: Result<(Value<ValuesStream<'a, S>>, Vec<ExecutionError<S>>), GraphQLError<'a>>,
-    ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>> {
-        let (stream, errs) = input?;
-        if !errs.is_empty() {
-            return Ok((Value::Null, errs));
-        }
-
-        if let Value::Object(obj) = stream {
-            for (name, mut val) in obj {
-                if let Value::Scalar(ref mut stream) = val {
-                    return match stream.next().await {
-                        Some(Ok(val)) => Ok((graphql_value!({ name: val }), vec![])),
-                        Some(Err(e)) => Ok((Value::Null, vec![e])),
-                        None => Ok((Value::Null, vec![])),
-                    };
-                }
-            }
-        }
-
-        panic!("Expected to get Value::Object containing a Stream")
-    }
-}
diff --git a/tests/integration/src/arc_fields.rs b/tests/integration/tests/arc_fields.rs
similarity index 61%
rename from tests/integration/src/arc_fields.rs
rename to tests/integration/tests/arc_fields.rs
index 5f7799f9..75e97921 100644
--- a/tests/integration/src/arc_fields.rs
+++ b/tests/integration/tests/arc_fields.rs
@@ -1,15 +1,17 @@
 use std::sync::Arc;
 
+use juniper::{graphql_object, GraphQLInputObject};
+
 struct Query;
 
-#[juniper::graphql_object]
+#[graphql_object]
 impl Query {
     fn ping() -> Arc<bool> {
         Arc::new(false)
     }
 }
 
-#[derive(juniper::GraphQLInputObject)]
+#[derive(GraphQLInputObject)]
 struct Ping {
     expect_result: Arc<bool>,
 }
diff --git a/tests/integration/src/array.rs b/tests/integration/tests/array.rs
similarity index 100%
rename from tests/integration/src/array.rs
rename to tests/integration/tests/array.rs
diff --git a/tests/integration/src/codegen/derive_object_with_raw_idents.rs b/tests/integration/tests/codegen_derive_object_with_raw_idents.rs
similarity index 98%
rename from tests/integration/src/codegen/derive_object_with_raw_idents.rs
rename to tests/integration/tests/codegen_derive_object_with_raw_idents.rs
index c1c5dea7..48d6d159 100644
--- a/tests/integration/src/codegen/derive_object_with_raw_idents.rs
+++ b/tests/integration/tests/codegen_derive_object_with_raw_idents.rs
@@ -99,6 +99,6 @@ async fn run_type_info_query(doc: &str) -> Value {
 
     assert_eq!(errs, []);
 
-    println!("Result: {:#?}", result);
+    println!("Result: {result:#?}");
     result
 }
diff --git a/tests/integration/src/codegen/enum_derive.rs b/tests/integration/tests/codegen_enum_derive.rs
similarity index 99%
rename from tests/integration/src/codegen/enum_derive.rs
rename to tests/integration/tests/codegen_enum_derive.rs
index 24aed858..295a2ead 100644
--- a/tests/integration/src/codegen/enum_derive.rs
+++ b/tests/integration/tests/codegen_enum_derive.rs
@@ -1,11 +1,13 @@
 //! Tests for `#[derive(GraphQLEnum)]` macro.
 
+pub mod common;
+
 use juniper::{
     execute, graphql_object, graphql_value, graphql_vars, parser::SourcePosition,
     DefaultScalarValue, ExecutionError, FieldError, GraphQLEnum, ScalarValue,
 };
 
-use crate::util::{schema, schema_with_scalar};
+use self::common::util::{schema, schema_with_scalar};
 
 mod trivial {
     use super::*;
@@ -785,7 +787,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -821,7 +823,6 @@ mod custom_scalar {
 }
 
 mod explicit_generic_scalar {
-
     use super::*;
 
     #[derive(GraphQLEnum)]
diff --git a/tests/integration/tests/codegen_input_object_derive.rs b/tests/integration/tests/codegen_input_object_derive.rs
new file mode 100644
index 00000000..d3113644
--- /dev/null
+++ b/tests/integration/tests/codegen_input_object_derive.rs
@@ -0,0 +1,887 @@
+//! Tests for `#[derive(GraphQLInputObject)]` macro.
+
+pub mod common;
+
+use juniper::{
+    execute, graphql_object, graphql_value, graphql_vars, parser::SourcePosition, GraphQLError,
+    GraphQLInputObject, RuleError,
+};
+
+use self::common::util::schema;
+
+mod trivial {
+    use super::*;
+
+    #[derive(GraphQLInputObject)]
+    struct Point2D {
+        x: f64,
+        y: f64,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            point.x
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"{
+            x(point: { x: 10, y: 20 })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"x": 10.0}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn uses_type_name() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                name
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"name": "Point2D"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_no_description() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                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_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                    {
+                        "name": "y",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod default_value {
+    use super::*;
+
+    #[derive(GraphQLInputObject)]
+    struct Point2D {
+        #[graphql(default = 10.0)]
+        x: f64,
+        #[graphql(default = 10.0)]
+        y: f64,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            point.x
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"query q($ve_num: Float!) {
+            literal_implicit_other_number: x(point: { y: 20 })
+            literal_explicit_number: x(point: { x: 20 })
+            literal_implicit_all: x(point: {})
+            variable_explicit_number: x(point: { x: $ve_num })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {"ve_num": 40}, &()).await,
+            Ok((
+                graphql_value!({
+                    "literal_implicit_other_number": 10.0,
+                    "literal_explicit_number": 20.0,
+                    "literal_implicit_all": 10.0,
+                    "variable_explicit_number": 40.0,
+                }),
+                vec![],
+            )),
+        );
+    }
+
+    #[tokio::test]
+    async fn errs_on_explicit_null_literal() {
+        const DOC: &str = r#"{ x(point: { x: 20, y: null }) }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Err(GraphQLError::ValidationError(vec![RuleError::new(
+                "Invalid value for argument \"point\", expected type \"Point2D!\"",
+                &[SourcePosition::new(11, 0, 11)],
+            )]))
+        );
+    }
+
+    #[tokio::test]
+    async fn errs_on_missing_variable() {
+        const DOC: &str = r#"query q($x: Float!){ x(point: { x: $x }) }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Err(GraphQLError::ValidationError(vec![RuleError::new(
+                "Variable \"$x\" of required type \"Float!\" was not provided.",
+                &[SourcePosition::new(8, 0, 8)],
+            )]))
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [{
+                    "name": "x",
+                    "description": null,
+                    "type": {"ofType": {"name": "Float"}},
+                    "defaultValue": "10",
+                }, {
+                    "name": "y",
+                    "description": null,
+                    "type": {"ofType": {"name": "Float"}},
+                    "defaultValue": "10",
+                }]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod default_nullable_value {
+    use super::*;
+
+    #[derive(GraphQLInputObject)]
+    struct Point2D {
+        #[graphql(default = 10.0)]
+        x: Option<f64>,
+        #[graphql(default = 10.0)]
+        y: Option<f64>,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> Option<f64> {
+            point.x
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"query q(
+            $ve_num: Float,
+            $ve_null: Float,
+            $vi: Float,
+            $vde_num: Float = 40,
+            $vde_null: Float = 50,
+            $vdi: Float = 60,
+        ) {
+            literal_implicit_other_number: x(point: { y: 20 })
+            literal_explicit_number: x(point: { x: 20 })
+            literal_implicit_all: x(point: {})
+            literal_explicit_null: x(point: { x: null })
+            literal_implicit_other_null: x(point: { y: null })
+            variable_explicit_number: x(point: { x: $ve_num })
+            variable_explicit_null: x(point: { x: $ve_null })
+            variable_implicit: x(point: { x: $vi })
+            variable_default_explicit_number: x(point: { x: $vde_num })
+            variable_default_explicit_null: x(point: { x: $vde_null })
+            variable_default_implicit: x(point: { x: $vdi })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(
+                DOC,
+                None,
+                &schema,
+                &graphql_vars! {
+                    "ve_num": 30.0,
+                    "ve_null": null,
+                    "vde_num": 100,
+                    "vde_null": null,
+                },
+                &(),
+            )
+            .await,
+            Ok((
+                graphql_value!({
+                    "literal_implicit_other_number": 10.0,
+                    "literal_explicit_number": 20.0,
+                    "literal_implicit_all": 10.0,
+                    "literal_explicit_null": null,
+                    "literal_implicit_other_null": 10.0,
+                    "variable_explicit_number": 30.0,
+                    "variable_explicit_null": null,
+                    "variable_implicit": 10.0,
+                    "variable_default_explicit_number": 100.0,
+                    "variable_default_explicit_null": null,
+                    "variable_default_implicit": 60.0,
+                }),
+                vec![],
+            )),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        name
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x",
+                        "description": null,
+                        "type": {"name": "Float", "ofType": null},
+                        "defaultValue": "10",
+                    },
+                    {
+                        "name": "y",
+                        "description": null,
+                        "type": {"name": "Float", "ofType": null},
+                        "defaultValue": "10",
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod ignored_field {
+    use super::*;
+
+    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+    enum System {
+        Cartesian,
+    }
+
+    #[derive(GraphQLInputObject)]
+    struct Point2D {
+        x: f64,
+        y: f64,
+        #[graphql(ignore)]
+        shift: f64,
+        #[graphql(skip, default = System::Cartesian)]
+        system: System,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            assert_eq!(point.shift, f64::default());
+            assert_eq!(point.system, System::Cartesian);
+            point.x
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"{
+            x(point: { x: 10, y: 20 })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"x": 10.0}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn uses_type_name() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                name
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"name": "Point2D"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_no_description() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                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_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                    {
+                        "name": "y",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod description_from_doc_comment {
+    use super::*;
+
+    /// Point in a Cartesian system.
+    #[derive(GraphQLInputObject)]
+    struct Point2D {
+        /// Abscissa value.
+        x: f64,
+
+        /// Ordinate value.
+        y_coord: f64,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            point.x
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"{
+            x(point: { x: 10, yCoord: 20 })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"x": 10.0}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn uses_type_name() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                name
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"name": "Point2D"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_description() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                description
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {
+                    "description": "Point in a Cartesian system.",
+                }}),
+                vec![]
+            )),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x",
+                        "description": "Abscissa value.",
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                    {
+                        "name": "yCoord",
+                        "description": "Ordinate value.",
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod description_from_graphql_attr {
+    use super::*;
+
+    /// Ignored doc.
+    #[derive(GraphQLInputObject)]
+    #[graphql(name = "Point", desc = "Point in a Cartesian system.")]
+    struct Point2D {
+        /// Ignored doc.
+        #[graphql(name = "x", description = "Abscissa value.")]
+        x_coord: f64,
+
+        /// Ordinate value.
+        y: f64,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            point.x_coord
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"{
+            x(point: { x: 10, y: 20 })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"x": 10.0}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn uses_type_name() {
+        const DOC: &str = r#"{
+            __type(name: "Point") {
+                name
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"name": "Point"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_description() {
+        const DOC: &str = r#"{
+            __type(name: "Point") {
+                description
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {
+                    "description": "Point in a Cartesian system.",
+                }}),
+                vec![]
+            )),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x",
+                        "description": "Abscissa value.",
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                    {
+                        "name": "y",
+                        "description": "Ordinate value.",
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
+
+mod renamed_all_fields {
+    use super::*;
+
+    #[derive(GraphQLInputObject)]
+    #[graphql(rename_all = "none")]
+    struct Point2D {
+        x_coord: f64,
+        y: f64,
+    }
+
+    struct QueryRoot;
+
+    #[graphql_object]
+    impl QueryRoot {
+        fn x(point: Point2D) -> f64 {
+            point.x_coord
+        }
+    }
+
+    #[tokio::test]
+    async fn resolves() {
+        const DOC: &str = r#"{
+            x(point: { x_coord: 10, y: 20 })
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"x": 10.0}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn is_graphql_input_object() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                kind
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((graphql_value!({"__type": {"kind": "INPUT_OBJECT"}}), vec![])),
+        );
+    }
+
+    #[tokio::test]
+    async fn has_input_fields() {
+        const DOC: &str = r#"{
+            __type(name: "Point2D") {
+                inputFields {
+                    name
+                    description
+                    type {
+                        ofType {
+                            name
+                        }
+                    }
+                    defaultValue
+                }
+            }
+        }"#;
+
+        let schema = schema(QueryRoot);
+
+        assert_eq!(
+            execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
+            Ok((
+                graphql_value!({"__type": {"inputFields": [
+                    {
+                        "name": "x_coord",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                    {
+                        "name": "y",
+                        "description": null,
+                        "type": {"ofType": {"name": "Float"}},
+                        "defaultValue": null,
+                    },
+                ]}}),
+                vec![],
+            )),
+        );
+    }
+}
diff --git a/tests/integration/src/codegen/interface_attr_struct.rs b/tests/integration/tests/codegen_interface_attr_struct.rs
similarity index 92%
rename from tests/integration/src/codegen/interface_attr_struct.rs
rename to tests/integration/tests/codegen_interface_attr_struct.rs
index 8d0e4f58..b7b41178 100644
--- a/tests/integration/src/codegen/interface_attr_struct.rs
+++ b/tests/integration/tests/codegen_interface_attr_struct.rs
@@ -1,5 +1,7 @@
 //! Tests for `#[graphql_interface]` macro placed on a struct.
 
+pub mod common;
+
 use std::marker::PhantomData;
 
 use juniper::{
@@ -7,7 +9,7 @@ use juniper::{
     FieldError, FieldResult, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, ID,
 };
 
-use crate::util::{schema, schema_with_scalar};
+use self::common::util::{schema, schema_with_scalar};
 
 mod no_implers {
     use super::*;
@@ -117,13 +119,13 @@ mod trivial {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -188,13 +190,12 @@ mod trivial {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -247,17 +248,16 @@ mod trivial {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -347,13 +347,13 @@ mod explicit_alias {
         fn character(&self) -> CharacterEnum {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -418,13 +418,12 @@ mod explicit_alias {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -523,13 +522,13 @@ mod trivial_async {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -591,13 +590,12 @@ mod trivial_async {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -650,17 +648,16 @@ mod trivial_async {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -758,13 +755,13 @@ mod fallible_field {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -829,13 +826,12 @@ mod fallible_field {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -928,13 +924,13 @@ mod generic {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -999,13 +995,12 @@ mod generic {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1054,8 +1049,8 @@ mod description_from_doc_comment {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1121,7 +1116,7 @@ mod deprecation_from_attr {
         }
 
         fn b() -> String {
-            "b".to_owned()
+            "b".into()
         }
     }
 
@@ -1131,8 +1126,8 @@ mod deprecation_from_attr {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1258,7 +1253,7 @@ mod explicit_name_description_and_deprecation {
         }
 
         fn a() -> String {
-            "a".to_owned()
+            "a".into()
         }
 
         fn b() -> &'static str {
@@ -1272,8 +1267,8 @@ mod explicit_name_description_and_deprecation {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1532,13 +1527,13 @@ mod explicit_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1603,13 +1598,12 @@ mod explicit_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1619,7 +1613,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -1662,13 +1656,13 @@ mod custom_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1733,13 +1727,12 @@ mod custom_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema_with_scalar::<MyScalarValue, _, _>(*root);
+            let schema = schema_with_scalar::<MyScalarValue, _, _>(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1790,13 +1783,13 @@ mod explicit_generic_scalar {
         fn character<S: ScalarValue>(&self) -> CharacterValue<S> {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1861,13 +1854,12 @@ mod explicit_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1918,13 +1910,13 @@ mod bounded_generic_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1989,13 +1981,12 @@ mod bounded_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2031,8 +2022,8 @@ mod ignored_method {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -2143,13 +2134,13 @@ mod field_return_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2214,13 +2205,12 @@ mod field_return_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2297,14 +2287,14 @@ mod field_return_union_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                     key_feature: Knowledge { value: 10 },
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                     strength: 42,
                 }
                 .into(),
@@ -2386,14 +2376,12 @@ mod field_return_union_subtyping {
             }
         }"#;
 
-        for (root, expected_id, expected_val) in &[
+        for (root, expected_id, expected_val) in [
             (QueryRoot::Human, "human-32", 10),
             (QueryRoot::Droid, "droid-99", 42),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
-            let expected_val = *expected_val;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((
@@ -2433,7 +2421,7 @@ mod nullable_argument_subtyping {
         fn id(&self, is_present: Option<bool>) -> &str {
             is_present
                 .unwrap_or_default()
-                .then(|| self.id.as_str())
+                .then_some(&*self.id)
                 .unwrap_or("missing")
         }
 
@@ -2453,13 +2441,13 @@ mod nullable_argument_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2524,13 +2512,12 @@ mod nullable_argument_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "missing"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2566,16 +2553,16 @@ mod simple_subtyping {
     impl QueryRoot {
         fn node() -> NodeValue {
             Endpoint {
-                id: ID::from("1".to_owned()),
-                url: "2".to_owned(),
+                id: ID::new("1"),
+                url: "2".into(),
             }
             .into()
         }
 
         fn resource() -> ResourceValue {
             Endpoint {
-                id: ID::from("3".to_owned()),
-                url: "4".to_owned(),
+                id: ID::new("3"),
+                url: "4".into(),
             }
             .into()
         }
@@ -2586,11 +2573,10 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -2721,14 +2707,13 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         possibleTypes {{
                             kind
                             name
                         }}
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -2765,14 +2750,13 @@ mod simple_subtyping {
         ] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{name}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                name,
             );
 
             assert_eq!(
@@ -2851,8 +2835,8 @@ mod branching_subtyping {
                 Self::Luke => HumanConnection {
                     nodes: vec![Luke {
                         id: ID::new("1"),
-                        home_planet: "earth".to_owned(),
-                        father: "SPOILER".to_owned(),
+                        home_planet: "earth".into(),
+                        father: "SPOILER".into(),
                     }
                     .into()],
                 }
@@ -2860,7 +2844,7 @@ mod branching_subtyping {
                 Self::R2D2 => DroidConnection {
                     nodes: vec![R2D2 {
                         id: ID::new("2"),
-                        primary_function: "roll".to_owned(),
+                        primary_function: "roll".into(),
                         charge: 146.0,
                     }
                     .into()],
@@ -2875,11 +2859,10 @@ mod branching_subtyping {
         for name in ["Node", "Connection", "Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot::Luke);
diff --git a/tests/integration/src/codegen/interface_attr_trait.rs b/tests/integration/tests/codegen_interface_attr_trait.rs
similarity index 92%
rename from tests/integration/src/codegen/interface_attr_trait.rs
rename to tests/integration/tests/codegen_interface_attr_trait.rs
index 150820fa..1556e6a9 100644
--- a/tests/integration/src/codegen/interface_attr_trait.rs
+++ b/tests/integration/tests/codegen_interface_attr_trait.rs
@@ -1,12 +1,14 @@
 //! Tests for `#[graphql_interface]` macro placed on a trait.
 
+pub mod common;
+
 use juniper::{
     execute, graphql_interface, graphql_object, graphql_value, graphql_vars, DefaultScalarValue,
     Executor, FieldError, FieldResult, GraphQLInputObject, GraphQLObject, GraphQLUnion,
     IntoFieldError, ScalarValue, ID,
 };
 
-use crate::util::{schema, schema_with_scalar};
+use self::common::util::{schema, schema_with_scalar};
 
 mod no_implers {
     use super::*;
@@ -116,13 +118,13 @@ mod trivial {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -187,13 +189,12 @@ mod trivial {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -246,17 +247,16 @@ mod trivial {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -346,13 +346,13 @@ mod explicit_alias {
         fn character(&self) -> CharacterEnum {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -417,13 +417,12 @@ mod explicit_alias {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -522,13 +521,13 @@ mod trivial_async {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -593,13 +592,12 @@ mod trivial_async {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -652,17 +650,16 @@ mod trivial_async {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -760,13 +757,13 @@ mod fallible_field {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -831,13 +828,12 @@ mod fallible_field {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -927,13 +923,13 @@ mod generic {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -995,13 +991,12 @@ mod generic {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1074,8 +1069,8 @@ mod argument {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1085,7 +1080,7 @@ mod argument {
     async fn resolves_id_field() {
         let schema = schema(QueryRoot);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             (
                 "{ character { idWide(isNumber: true), idWide2(isNumber: true) } }",
                 "human-32",
@@ -1095,10 +1090,8 @@ mod argument {
                 "none",
             ),
         ] {
-            let expected: &str = *expected;
-
             assert_eq!(
-                execute(*input, None, &schema, &graphql_vars! {}, &()).await,
+                execute(input, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((
                     graphql_value!({"character": {
                         "idWide": expected,
@@ -1211,7 +1204,7 @@ mod default_argument {
         fn id(
             &self,
             #[graphql(default)] first: String,
-            #[graphql(default = "second".to_string())] second: String,
+            #[graphql(default = "second")] second: String,
             #[graphql(default = "t")] third: String,
         ) -> String;
 
@@ -1227,7 +1220,7 @@ mod default_argument {
         }
 
         async fn id(&self, first: String, second: String, third: String) -> String {
-            format!("{}|{}&{}", first, second, third)
+            format!("{first}|{second}&{third}")
         }
     }
 
@@ -1244,7 +1237,7 @@ mod default_argument {
     async fn resolves_id_field() {
         let schema = schema(QueryRoot);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             ("{ character { id } }", "|second&t"),
             (r#"{ character { id(first: "first") } }"#, "first|second&t"),
             (r#"{ character { id(second: "") } }"#, "|&t"),
@@ -1257,10 +1250,8 @@ mod default_argument {
                 "first|&",
             ),
         ] {
-            let expected: &str = *expected;
-
             assert_eq!(
-                execute(*input, None, &schema, &graphql_vars! {}, &()).await,
+                execute(input, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected}}), vec![])),
             );
         }
@@ -1270,14 +1261,12 @@ mod default_argument {
     async fn resolves_info_field() {
         let schema = schema(QueryRoot);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             ("{ character { info } }", 1),
             ("{ character { info(coord: {x: 2}) } }", 2),
         ] {
-            let expected: i32 = *expected;
-
             assert_eq!(
-                execute(*input, None, &schema, &graphql_vars! {}, &()).await,
+                execute(input, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"info": expected}}), vec![])),
             );
         }
@@ -1311,21 +1300,21 @@ mod default_argument {
                     "args": [{
                         "name": "first",
                         "defaultValue": r#""""#,
-                        "type": {"name": "String", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "String"}},
                     }, {
                         "name": "second",
                         "defaultValue": r#""second""#,
-                        "type": {"name": "String", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "String"}},
                     }, {
                         "name": "third",
                         "defaultValue": r#""t""#,
-                        "type": {"name": "String", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "String"}},
                     }],
                 }, {
                     "args": [{
                         "name": "coord",
                         "defaultValue": "{x: 1}",
-                        "type": {"name": "Point", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Point"}},
                     }],
                 }]}}),
                 vec![],
@@ -1358,8 +1347,8 @@ mod description_from_doc_comment {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1425,7 +1414,7 @@ mod deprecation_from_attr {
         }
 
         fn b() -> String {
-            "b".to_owned()
+            "b".into()
         }
     }
 
@@ -1435,8 +1424,8 @@ mod deprecation_from_attr {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1562,7 +1551,7 @@ mod explicit_name_description_and_deprecation {
         }
 
         fn a() -> String {
-            "a".to_owned()
+            "a".into()
         }
 
         fn b() -> &'static str {
@@ -1576,8 +1565,8 @@ mod explicit_name_description_and_deprecation {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1854,13 +1843,13 @@ mod explicit_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1925,13 +1914,12 @@ mod explicit_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1941,7 +1929,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -1984,13 +1972,13 @@ mod custom_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2055,13 +2043,12 @@ mod custom_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema_with_scalar::<MyScalarValue, _, _>(*root);
+            let schema = schema_with_scalar::<MyScalarValue, _, _>(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2112,13 +2099,13 @@ mod explicit_generic_scalar {
         fn character<S: ScalarValue>(&self) -> CharacterValue<S> {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2183,13 +2170,12 @@ mod explicit_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2240,13 +2226,13 @@ mod bounded_generic_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2311,13 +2297,12 @@ mod bounded_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2401,13 +2386,13 @@ mod explicit_custom_context {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2474,15 +2459,12 @@ mod explicit_custom_context {
             }
         }"#;
 
-        for (root, expected_id, expected_info, expexted_more) in &[
+        for (root, expected_id, expected_info, expexted_more) in [
             (QueryRoot::Human, "human-32", "earth", "human"),
             (QueryRoot::Droid, "droid-99", "run", "droid"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
-            let expected_info: &str = *expected_info;
-            let expexted_more: &str = *expexted_more;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &CustomContext).await,
                 Ok((
@@ -2561,11 +2543,11 @@ mod inferred_custom_context_from_field {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    home_planet: "earth".to_string(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    primary_function: "run".to_string(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2633,15 +2615,13 @@ mod inferred_custom_context_from_field {
             }
         }"#;
 
-        for (root, expected_id, expected_info) in &[
+        for (root, expected_id, expected_info) in [
             (QueryRoot::Human, "human-ctx", "earth"),
             (QueryRoot::Droid, "droid-ctx", "run"),
         ] {
-            let schema = schema(*root);
-            let ctx = CustomContext(expected_id.to_string());
+            let schema = schema(root);
+            let ctx = CustomContext(expected_id.into());
 
-            let expected_id: &str = *expected_id;
-            let expected_info: &str = *expected_info;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &ctx).await,
                 Ok((
@@ -2725,11 +2705,11 @@ mod executor {
         fn character(&self) -> CharacterValue<DefaultScalarValue> {
             match self {
                 Self::Human => Human {
-                    home_planet: "earth".to_string(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    primary_function: "run".to_string(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2795,10 +2775,9 @@ mod executor {
             }
         }"#;
 
-        for (root, expected_info) in &[(QueryRoot::Human, "earth"), (QueryRoot::Droid, "run")] {
-            let schema = schema(*root);
+        for (root, expected_info) in [(QueryRoot::Human, "earth"), (QueryRoot::Droid, "run")] {
+            let schema = schema(root);
 
-            let expected_info: &str = *expected_info;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((
@@ -2869,8 +2848,8 @@ mod ignored_method {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -2981,13 +2960,13 @@ mod field_return_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -3052,13 +3031,12 @@ mod field_return_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -3136,14 +3114,14 @@ mod field_return_union_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                     key_feature: Knowledge { value: 10 },
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                     strength: 42,
                 }
                 .into(),
@@ -3225,14 +3203,12 @@ mod field_return_union_subtyping {
             }
         }"#;
 
-        for (root, expected_id, expected_val) in &[
+        for (root, expected_id, expected_val) in [
             (QueryRoot::Human, "human-32", 10),
             (QueryRoot::Droid, "droid-99", 42),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
-            let expected_val = *expected_val;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((
@@ -3272,7 +3248,7 @@ mod nullable_argument_subtyping {
         fn id(&self, is_present: Option<bool>) -> &str {
             is_present
                 .unwrap_or_default()
-                .then(|| self.id.as_str())
+                .then_some(&*self.id)
                 .unwrap_or("missing")
         }
 
@@ -3292,13 +3268,13 @@ mod nullable_argument_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -3363,13 +3339,12 @@ mod nullable_argument_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "missing"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -3405,16 +3380,16 @@ mod simple_subtyping {
     impl QueryRoot {
         fn node() -> NodeValue {
             Endpoint {
-                id: ID::from("1".to_owned()),
-                url: "2".to_owned(),
+                id: ID::new("1"),
+                url: "2".into(),
             }
             .into()
         }
 
         fn resource() -> ResourceValue {
             Endpoint {
-                id: ID::from("3".to_owned()),
-                url: "4".to_owned(),
+                id: ID::new("3"),
+                url: "4".into(),
             }
             .into()
         }
@@ -3425,11 +3400,10 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -3560,14 +3534,13 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         possibleTypes {{
                             kind
                             name
                         }}
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -3604,14 +3577,13 @@ mod simple_subtyping {
         ] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{name}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                name,
             );
 
             assert_eq!(
@@ -3690,8 +3662,8 @@ mod branching_subtyping {
                 Self::Luke => HumanConnection {
                     nodes: vec![Luke {
                         id: ID::new("1"),
-                        home_planet: "earth".to_owned(),
-                        father: "SPOILER".to_owned(),
+                        home_planet: "earth".into(),
+                        father: "SPOILER".into(),
                     }
                     .into()],
                 }
@@ -3699,7 +3671,7 @@ mod branching_subtyping {
                 Self::R2D2 => DroidConnection {
                     nodes: vec![R2D2 {
                         id: ID::new("2"),
-                        primary_function: "roll".to_owned(),
+                        primary_function: "roll".into(),
                         charge: 146.0,
                     }
                     .into()],
@@ -3714,11 +3686,10 @@ mod branching_subtyping {
         for name in ["Node", "Connection", "Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot::Luke);
diff --git a/tests/integration/src/codegen/interface_derive.rs b/tests/integration/tests/codegen_interface_derive.rs
similarity index 92%
rename from tests/integration/src/codegen/interface_derive.rs
rename to tests/integration/tests/codegen_interface_derive.rs
index bbc6a79a..6eb5f0f4 100644
--- a/tests/integration/src/codegen/interface_derive.rs
+++ b/tests/integration/tests/codegen_interface_derive.rs
@@ -1,5 +1,7 @@
 //! Tests for `#[derive(GraphQLInterface)]` macro.
 
+pub mod common;
+
 use std::marker::PhantomData;
 
 use juniper::{
@@ -7,7 +9,7 @@ use juniper::{
     FieldResult, GraphQLInterface, GraphQLObject, GraphQLUnion, IntoFieldError, ScalarValue, ID,
 };
 
-use crate::util::{schema, schema_with_scalar};
+use self::common::util::{schema, schema_with_scalar};
 
 mod no_implers {
     use super::*;
@@ -118,13 +120,13 @@ mod trivial {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -189,13 +191,12 @@ mod trivial {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -248,17 +249,16 @@ mod trivial {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -349,13 +349,13 @@ mod explicit_alias {
         fn character(&self) -> CharacterEnum {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -420,13 +420,12 @@ mod explicit_alias {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -526,13 +525,13 @@ mod trivial_async {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -597,13 +596,12 @@ mod trivial_async {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -656,17 +654,16 @@ mod trivial_async {
     async fn registers_itself_in_implementers() {
         let schema = schema(QueryRoot::Human);
 
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{object}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                object,
             );
 
             assert_eq!(
@@ -765,13 +762,13 @@ mod fallible_field {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -836,13 +833,12 @@ mod fallible_field {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -936,13 +932,13 @@ mod generic {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1007,13 +1003,12 @@ mod generic {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1063,8 +1058,8 @@ mod description_from_doc_comment {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1131,7 +1126,7 @@ mod deprecation_from_attr {
         }
 
         fn b() -> String {
-            "b".to_owned()
+            "b".into()
         }
     }
 
@@ -1141,8 +1136,8 @@ mod deprecation_from_attr {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1269,7 +1264,7 @@ mod explicit_name_description_and_deprecation {
         }
 
         fn a() -> String {
-            "a".to_owned()
+            "a".into()
         }
 
         fn b() -> &'static str {
@@ -1283,8 +1278,8 @@ mod explicit_name_description_and_deprecation {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -1545,13 +1540,13 @@ mod explicit_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1616,13 +1611,12 @@ mod explicit_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1632,7 +1626,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -1676,13 +1670,13 @@ mod custom_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1747,13 +1741,12 @@ mod custom_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema_with_scalar::<MyScalarValue, _, _>(*root);
+            let schema = schema_with_scalar::<MyScalarValue, _, _>(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1805,13 +1798,13 @@ mod explicit_generic_scalar {
         fn character<S: ScalarValue>(&self) -> CharacterValue<S> {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -1876,13 +1869,12 @@ mod explicit_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -1934,13 +1926,13 @@ mod bounded_generic_scalar {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2005,13 +1997,12 @@ mod bounded_generic_scalar {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2048,8 +2039,8 @@ mod ignored_method {
     impl QueryRoot {
         fn character(&self) -> CharacterValue {
             Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }
             .into()
         }
@@ -2161,13 +2152,13 @@ mod field_return_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2232,13 +2223,12 @@ mod field_return_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "droid-99"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2316,14 +2306,14 @@ mod field_return_union_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                     key_feature: Knowledge { value: 10 },
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                     strength: 42,
                 }
                 .into(),
@@ -2405,14 +2395,12 @@ mod field_return_union_subtyping {
             }
         }"#;
 
-        for (root, expected_id, expected_val) in &[
+        for (root, expected_id, expected_val) in [
             (QueryRoot::Human, "human-32", 10),
             (QueryRoot::Droid, "droid-99", 42),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
-            let expected_val = *expected_val;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((
@@ -2453,7 +2441,7 @@ mod nullable_argument_subtyping {
         fn id(&self, is_present: Option<bool>) -> &str {
             is_present
                 .unwrap_or_default()
-                .then(|| self.id.as_str())
+                .then_some(&*self.id)
                 .unwrap_or("missing")
         }
 
@@ -2473,13 +2461,13 @@ mod nullable_argument_subtyping {
         fn character(&self) -> CharacterValue {
             match self {
                 Self::Human => Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }
                 .into(),
                 Self::Droid => Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }
                 .into(),
             }
@@ -2544,13 +2532,12 @@ mod nullable_argument_subtyping {
             }
         }"#;
 
-        for (root, expected_id) in &[
+        for (root, expected_id) in [
             (QueryRoot::Human, "human-32"),
             (QueryRoot::Droid, "missing"),
         ] {
-            let schema = schema(*root);
+            let schema = schema(root);
 
-            let expected_id: &str = *expected_id;
             assert_eq!(
                 execute(DOC, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"character": {"id": expected_id}}), vec![])),
@@ -2588,16 +2575,16 @@ mod simple_subtyping {
     impl QueryRoot {
         fn node() -> NodeValue {
             Endpoint {
-                id: ID::from("1".to_owned()),
-                url: "2".to_owned(),
+                id: ID::new("1"),
+                url: "2".into(),
             }
             .into()
         }
 
         fn resource() -> ResourceValue {
             Endpoint {
-                id: ID::from("3".to_owned()),
-                url: "4".to_owned(),
+                id: ID::new("3"),
+                url: "4".into(),
             }
             .into()
         }
@@ -2608,11 +2595,10 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -2743,14 +2729,13 @@ mod simple_subtyping {
         for name in ["Node", "Resource"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         possibleTypes {{
                             kind
                             name
                         }}
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -2787,14 +2772,13 @@ mod simple_subtyping {
         ] {
             let doc = format!(
                 r#"{{
-                   __type(name: "{}") {{
+                   __type(name: "{name}") {{
                        interfaces {{
                            kind
                            name
                        }}
                    }}
                 }}"#,
-                name,
             );
 
             assert_eq!(
@@ -2877,8 +2861,8 @@ mod branching_subtyping {
                 Self::Luke => HumanConnection {
                     nodes: vec![Luke {
                         id: ID::new("1"),
-                        home_planet: "earth".to_owned(),
-                        father: "SPOILER".to_owned(),
+                        home_planet: "earth".into(),
+                        father: "SPOILER".into(),
                     }
                     .into()],
                 }
@@ -2886,7 +2870,7 @@ mod branching_subtyping {
                 Self::R2D2 => DroidConnection {
                     nodes: vec![R2D2 {
                         id: ID::new("2"),
-                        primary_function: "roll".to_owned(),
+                        primary_function: "roll".into(),
                         charge: 146.0,
                     }
                     .into()],
@@ -2901,11 +2885,10 @@ mod branching_subtyping {
         for name in ["Node", "Connection", "Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot::Luke);
diff --git a/tests/integration/src/codegen/object_attr.rs b/tests/integration/tests/codegen_object_attr.rs
similarity index 94%
rename from tests/integration/src/codegen/object_attr.rs
rename to tests/integration/tests/codegen_object_attr.rs
index 9161cc55..dc813e4c 100644
--- a/tests/integration/src/codegen/object_attr.rs
+++ b/tests/integration/tests/codegen_object_attr.rs
@@ -1,35 +1,13 @@
 //! Tests for `#[graphql_object]` macro.
 
+pub mod common;
+
 use juniper::{
-    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, EmptyMutation,
-    EmptySubscription, Executor, FieldError, FieldResult, GraphQLInputObject, GraphQLObject,
-    GraphQLType, IntoFieldError, RootNode, ScalarValue,
+    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, Executor, FieldError,
+    FieldResult, GraphQLInputObject, GraphQLObject, IntoFieldError, ScalarValue,
 };
 
-fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
-where
-    Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
-{
-    RootNode::new(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
-fn schema_with_scalar<'q, S, C, Q>(
-    query_root: Q,
-) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
-where
-    Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
-    S: ScalarValue + 'q,
-{
-    RootNode::new_with_scalar_value(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
+use self::common::util::{schema, schema_with_scalar};
 
 mod trivial {
     use super::*;
@@ -376,7 +354,7 @@ mod fallible_method {
     impl QueryRoot {
         fn human() -> Human {
             Human {
-                id: "human-32".to_string(),
+                id: "human-32".into(),
             }
         }
     }
@@ -885,22 +863,20 @@ mod nested_generic_lifetime_async {
 
     #[tokio::test]
     async fn uses_type_name_without_type_params() {
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{object}") {{
                         name
                     }}
                 }}"#,
-                object,
             );
 
             let schema = schema(QueryRoot("mars".into()));
 
-            let expected_name: &str = *object;
             assert_eq!(
                 execute(&doc, None, &schema, &graphql_vars! {}, &()).await,
-                Ok((graphql_value!({"__type": {"name": expected_name}}), vec![])),
+                Ok((graphql_value!({"__type": {"name": object}}), vec![])),
             );
         }
     }
@@ -918,7 +894,7 @@ mod argument {
         }
 
         async fn home_planet(&self, r#raw_arg: String, r#async: Option<i32>) -> String {
-            format!("{},{:?}", r#raw_arg, r#async)
+            format!("{raw_arg},{async:?}")
         }
     }
 
@@ -1045,10 +1021,10 @@ mod default_argument {
     impl Human {
         fn id(
             #[graphql(default)] arg1: i32,
-            #[graphql(default = "second".to_string())] arg2: String,
+            #[graphql(default = "second".to_string())] arg2: Option<String>,
             #[graphql(default = true)] r#arg3: bool,
         ) -> String {
-            format!("{}|{}&{}", arg1, arg2, r#arg3)
+            format!("{arg1}|{arg2:?}&{arg3}")
         }
 
         fn info(#[graphql(default = Point { x: 1 })] coord: Point) -> i32 {
@@ -1069,20 +1045,70 @@ mod default_argument {
     async fn resolves_id_field() {
         let schema = schema(QueryRoot);
 
-        for (input, expected) in &[
-            ("{ human { id } }", "0|second&true"),
-            ("{ human { id(arg1: 1) } }", "1|second&true"),
-            (r#"{ human { id(arg2: "") } }"#, "0|&true"),
-            (r#"{ human { id(arg1: 2, arg2: "") } }"#, "2|&true"),
+        for (input, expected, vars) in [
+            (
+                "{ human { id } }",
+                r#"0|Some("second")&true"#,
+                graphql_vars! {},
+            ),
+            (
+                "{ human { id(arg1: 1) } }",
+                r#"1|Some("second")&true"#,
+                graphql_vars! {},
+            ),
+            (
+                r#"{ human { id(arg2: "other") } }"#,
+                r#"0|Some("other")&true"#,
+                graphql_vars! {},
+            ),
+            (
+                "{ human { id(arg2: null) } }",
+                r#"0|None&true"#,
+                graphql_vars! {},
+            ),
+            (
+                "query q($arg2: String) { human { id(arg2: $arg2) } }",
+                r#"0|Some("second")&true"#,
+                graphql_vars! {},
+            ),
+            (
+                "query q($arg2: String) { human{ id(arg2: $arg2) } }",
+                r#"0|None&true"#,
+                graphql_vars! { "arg2": null },
+            ),
+            (
+                "query q($arg2: String) { human{ id(arg2: $arg2) } }",
+                r#"0|Some("other")&true"#,
+                graphql_vars! { "arg2": "other" },
+            ),
+            (
+                r#"query q($arg2: String = "other") { human { id(arg2: $arg2) } }"#,
+                r#"0|Some("other")&true"#,
+                graphql_vars! {},
+            ),
+            (
+                r#"query q($arg2: String = "other") { human { id(arg2: $arg2) } }"#,
+                r#"0|None&true"#,
+                graphql_vars! { "arg2": null },
+            ),
+            (
+                r#"query q($arg2: String = "other") { human { id(arg2: $arg2) } }"#,
+                r#"0|Some("hello")&true"#,
+                graphql_vars! { "arg2": "hello" },
+            ),
+            (
+                r#"{ human { id(arg1: 2, arg2: "") } }"#,
+                r#"2|Some("")&true"#,
+                graphql_vars! {},
+            ),
             (
                 r#"{ human { id(arg1: 1, arg2: "", arg3: false) } }"#,
-                "1|&false",
+                r#"1|Some("")&false"#,
+                graphql_vars! {},
             ),
         ] {
-            let expected: &str = *expected;
-
             assert_eq!(
-                execute(*input, None, &schema, &graphql_vars! {}, &()).await,
+                execute(input, None, &schema, &vars, &(),).await,
                 Ok((graphql_value!({"human": {"id": expected}}), vec![])),
             );
         }
@@ -1092,14 +1118,12 @@ mod default_argument {
     async fn resolves_info_field() {
         let schema = schema(QueryRoot);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             ("{ human { info } }", 1),
             ("{ human { info(coord: { x: 2 }) } }", 2),
         ] {
-            let expected: i32 = *expected;
-
             assert_eq!(
-                execute(*input, None, &schema, &graphql_vars! {}, &()).await,
+                execute(input, None, &schema, &graphql_vars! {}, &()).await,
                 Ok((graphql_value!({"human": {"info": expected}}), vec![])),
             );
         }
@@ -1133,7 +1157,7 @@ mod default_argument {
                     "args": [{
                         "name": "arg1",
                         "defaultValue": "0",
-                        "type": {"name": "Int", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Int"}},
                     }, {
                         "name": "arg2",
                         "defaultValue": r#""second""#,
@@ -1141,13 +1165,13 @@ mod default_argument {
                     }, {
                         "name": "arg3",
                         "defaultValue": "true",
-                        "type": {"name": "Boolean", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Boolean"}},
                     }],
                 }, {
                     "args": [{
                         "name": "coord",
                         "defaultValue": "{x: 1}",
-                        "type": {"name": "Point", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Point"}},
                     }],
                 }]}}),
                 vec![],
@@ -1621,7 +1645,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
diff --git a/tests/integration/src/codegen/object_derive.rs b/tests/integration/tests/codegen_object_derive.rs
similarity index 95%
rename from tests/integration/src/codegen/object_derive.rs
rename to tests/integration/tests/codegen_object_derive.rs
index 126c315a..b3ab2299 100644
--- a/tests/integration/src/codegen/object_derive.rs
+++ b/tests/integration/tests/codegen_object_derive.rs
@@ -1,34 +1,13 @@
 //! Tests for `#[derive(GraphQLObject)]` macro.
 
+pub mod common;
+
 use juniper::{
-    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, EmptyMutation,
-    EmptySubscription, GraphQLObject, GraphQLType, RootNode, ScalarValue,
+    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, GraphQLObject,
+    ScalarValue,
 };
 
-fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
-where
-    Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
-{
-    RootNode::new(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
-fn schema_with_scalar<'q, S, C, Q>(
-    query_root: Q,
-) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
-where
-    Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
-    S: ScalarValue + 'q,
-{
-    RootNode::new_with_scalar_value(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
+use self::common::util::{schema, schema_with_scalar};
 
 mod trivial {
     use super::*;
@@ -406,22 +385,20 @@ mod nested_generic_lifetime_async {
 
     #[tokio::test]
     async fn uses_type_name_without_type_params() {
-        for object in &["Human", "Droid"] {
+        for object in ["Human", "Droid"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{object}") {{
                         name
                     }}
                 }}"#,
-                object,
             );
 
             let schema = schema(QueryRoot("mars".into()));
 
-            let expected_name: &str = *object;
             assert_eq!(
                 execute(&doc, None, &schema, &graphql_vars! {}, &()).await,
-                Ok((graphql_value!({"__type": {"name": expected_name}}), vec![])),
+                Ok((graphql_value!({"__type": {"name": object}}), vec![])),
             );
         }
     }
@@ -853,7 +830,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
diff --git a/tests/integration/src/codegen/scalar_attr_derive_input.rs b/tests/integration/tests/codegen_scalar_attr_derive_input.rs
similarity index 98%
rename from tests/integration/src/codegen/scalar_attr_derive_input.rs
rename to tests/integration/tests/codegen_scalar_attr_derive_input.rs
index ccfa3575..b691aea5 100644
--- a/tests/integration/src/codegen/scalar_attr_derive_input.rs
+++ b/tests/integration/tests/codegen_scalar_attr_derive_input.rs
@@ -2,6 +2,8 @@
 //!
 //! [`DeriveInput`]: syn::DeriveInput
 
+pub mod common;
+
 use std::fmt;
 
 use chrono::{DateTime, TimeZone, Utc};
@@ -10,9 +12,9 @@ use juniper::{
     ParseScalarResult, ParseScalarValue, ScalarToken, ScalarValue, Value,
 };
 
-use crate::{
-    custom_scalar::MyScalarValue,
+use self::common::{
     util::{schema, schema_with_scalar},
+    MyScalarValue,
 };
 
 mod trivial {
@@ -29,10 +31,10 @@ mod trivial {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(t)
         }
     }
@@ -237,10 +239,10 @@ mod all_custom_resolvers {
     fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
         v.as_int_value()
             .map(Counter)
-            .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
     }
 
-    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         <i32 as ParseScalarValue<S>>::from_str(value)
     }
 
@@ -312,10 +314,10 @@ mod explicit_name {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(value)
         }
     }
@@ -388,7 +390,7 @@ mod delegated_parse_token {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -458,7 +460,7 @@ mod multiple_delegated_parse_token {
     impl StringOrInt {
         fn to_output<S: ScalarValue>(&self) -> Value<S> {
             match self {
-                Self::String(str) => Value::scalar(str.to_owned()),
+                Self::String(s) => Value::scalar(s.to_owned()),
                 Self::Int(i) => Value::scalar(*i),
             }
         }
@@ -467,7 +469,7 @@ mod multiple_delegated_parse_token {
             v.as_string_value()
                 .map(|s| Self::String(s.to_owned()))
                 .or_else(|| v.as_int_value().map(Self::Int))
-                .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
         }
     }
 
@@ -533,11 +535,11 @@ mod where_attribute {
         Tz::Offset: fmt::Display,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 DateTime::parse_from_rfc3339(s)
                     .map(|dt| CustomDateTime(dt.with_timezone(&Tz::from(Utc))))
-                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
             })
     }
 
@@ -599,10 +601,10 @@ mod with_self {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(value)
         }
     }
@@ -691,11 +693,11 @@ mod with_module {
             Tz::Offset: fmt::Display,
         {
             v.as_string_value()
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
                 .and_then(|s| {
                     DateTime::parse_from_rfc3339(s)
                         .map(|dt| CustomDateTime(dt.with_timezone(&Tz::from(Utc))))
-                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
                 })
         }
     }
@@ -759,7 +761,7 @@ mod description_from_doc_comment {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -835,7 +837,7 @@ mod description_from_attribute {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -911,7 +913,7 @@ mod custom_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -987,7 +989,7 @@ mod generic_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -1062,7 +1064,7 @@ mod bounded_generic_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
diff --git a/tests/integration/src/codegen/scalar_attr_type_alias.rs b/tests/integration/tests/codegen_scalar_attr_type_alias.rs
similarity index 98%
rename from tests/integration/src/codegen/scalar_attr_type_alias.rs
rename to tests/integration/tests/codegen_scalar_attr_type_alias.rs
index 9dfd8f6c..e6af88b3 100644
--- a/tests/integration/src/codegen/scalar_attr_type_alias.rs
+++ b/tests/integration/tests/codegen_scalar_attr_type_alias.rs
@@ -1,5 +1,7 @@
 //! Tests for `#[graphql_scalar]` macro placed on a type alias.
 
+pub mod common;
+
 use std::fmt;
 
 use chrono::{DateTime, TimeZone, Utc};
@@ -8,9 +10,9 @@ use juniper::{
     ParseScalarResult, ParseScalarValue, ScalarToken, ScalarValue, Value,
 };
 
-use crate::{
-    custom_scalar::MyScalarValue,
+use self::common::{
     util::{schema, schema_with_scalar},
+    MyScalarValue,
 };
 
 mod all_custom_resolvers {
@@ -34,10 +36,10 @@ mod all_custom_resolvers {
     fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
         v.as_int_value()
             .map(CustomCounter)
-            .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
     }
 
-    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         <i32 as ParseScalarValue<S>>::from_str(value)
     }
 
@@ -115,10 +117,10 @@ mod explicit_name {
     fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<CounterScalar, String> {
         v.as_int_value()
             .map(CustomCounter)
-            .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
     }
 
-    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         <i32 as ParseScalarValue<S>>::from_str(value)
     }
 
@@ -152,11 +154,10 @@ mod explicit_name {
         for name in ["CustomCounter", "CustomScalar"] {
             let doc = format!(
                 r#"{{
-                    __type(name: "{}") {{
+                    __type(name: "{name}") {{
                         kind
                     }}
                 }}"#,
-                name,
             );
 
             let schema = schema(QueryRoot);
@@ -216,7 +217,7 @@ mod delegated_parse_token {
     fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
         v.as_int_value()
             .map(CustomCounter)
-            .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
     }
 
     struct QueryRoot;
@@ -290,7 +291,7 @@ mod multiple_delegated_parse_token {
 
     fn to_output<S: ScalarValue>(v: &StringOrInt) -> Value<S> {
         match v {
-            StringOrInt::String(str) => Value::scalar(str.to_owned()),
+            StringOrInt::String(s) => Value::scalar(s.to_owned()),
             StringOrInt::Int(i) => Value::scalar(*i),
         }
     }
@@ -299,7 +300,7 @@ mod multiple_delegated_parse_token {
         v.as_string_value()
             .map(|s| StringOrInt::String(s.to_owned()))
             .or_else(|| v.as_int_value().map(|i| StringOrInt::Int(i)))
-            .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
     }
 
     struct QueryRoot;
@@ -366,11 +367,11 @@ mod where_attribute {
         Tz::Offset: fmt::Display,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 DateTime::parse_from_rfc3339(s)
                     .map(|dt| CustomDateTimeScalar(dt.with_timezone(&Tz::from(Utc))))
-                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
             })
     }
 
@@ -434,10 +435,10 @@ mod with_self {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(value)
         }
     }
@@ -528,11 +529,11 @@ mod with_module {
             Tz::Offset: fmt::Display,
         {
             v.as_string_value()
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
                 .and_then(|s| {
                     DateTime::parse_from_rfc3339(s)
                         .map(|dt| CustomDateTimeScalar(dt.with_timezone(&Tz::from(Utc))))
-                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
                 })
         }
     }
@@ -600,7 +601,7 @@ mod description_from_doc_comment {
         pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
             v.as_int_value()
                 .map(CustomCounter)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -684,7 +685,7 @@ mod description_from_attribute {
         pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
             v.as_int_value()
                 .map(CustomCounter)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -768,7 +769,7 @@ mod custom_scalar {
         pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
             v.as_int_value()
                 .map(CustomCounter)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -852,7 +853,7 @@ mod generic_scalar {
         pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
             v.as_int_value()
                 .map(CustomCounter)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -936,7 +937,7 @@ mod bounded_generic_scalar {
         pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
             v.as_int_value()
                 .map(CustomCounter)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
diff --git a/tests/integration/src/codegen/scalar_derive.rs b/tests/integration/tests/codegen_scalar_derive.rs
similarity index 98%
rename from tests/integration/src/codegen/scalar_derive.rs
rename to tests/integration/tests/codegen_scalar_derive.rs
index a538095f..118fb010 100644
--- a/tests/integration/src/codegen/scalar_derive.rs
+++ b/tests/integration/tests/codegen_scalar_derive.rs
@@ -1,5 +1,7 @@
 //! Tests for `#[derive(GraphQLScalar)]` macro.
 
+pub mod common;
+
 use std::fmt;
 
 use chrono::{DateTime, TimeZone, Utc};
@@ -8,9 +10,9 @@ use juniper::{
     ParseScalarResult, ParseScalarValue, ScalarToken, ScalarValue, Value,
 };
 
-use crate::{
-    custom_scalar::MyScalarValue,
+use self::common::{
     util::{schema, schema_with_scalar},
+    MyScalarValue,
 };
 
 mod trivial {
@@ -27,10 +29,10 @@ mod trivial {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(t)
         }
     }
@@ -235,10 +237,10 @@ mod all_custom_resolvers {
     fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Counter, String> {
         v.as_int_value()
             .map(Counter)
-            .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+            .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
     }
 
-    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+    fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
         <i32 as ParseScalarValue<S>>::from_str(value)
     }
 
@@ -311,10 +313,10 @@ mod explicit_name {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(value)
         }
     }
@@ -388,7 +390,7 @@ mod delegated_parse_token {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -459,7 +461,7 @@ mod multiple_delegated_parse_token {
     impl StringOrInt {
         fn to_output<S: ScalarValue>(&self) -> Value<S> {
             match self {
-                Self::String(str) => Value::scalar(str.to_owned()),
+                Self::String(s) => Value::scalar(s.to_owned()),
                 Self::Int(i) => Value::scalar(*i),
             }
         }
@@ -468,7 +470,7 @@ mod multiple_delegated_parse_token {
             v.as_string_value()
                 .map(|s| Self::String(s.to_owned()))
                 .or_else(|| v.as_int_value().map(Self::Int))
-                .ok_or_else(|| format!("Expected `String` or `Int`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
         }
     }
 
@@ -535,11 +537,11 @@ mod where_attribute {
         Tz::Offset: fmt::Display,
     {
         v.as_string_value()
-            .ok_or_else(|| format!("Expected `String`, found: {}", v))
+            .ok_or_else(|| format!("Expected `String`, found: {v}"))
             .and_then(|s| {
                 DateTime::parse_from_rfc3339(s)
                     .map(|dt| CustomDateTime(dt.with_timezone(&Tz::from(Utc))))
-                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                    .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
             })
     }
 
@@ -602,10 +604,10 @@ mod with_self {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
 
-        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<'_, S> {
+        fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
             <i32 as ParseScalarValue<S>>::from_str(value)
         }
     }
@@ -695,11 +697,11 @@ mod with_module {
             Tz::Offset: fmt::Display,
         {
             v.as_string_value()
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
                 .and_then(|s| {
                     DateTime::parse_from_rfc3339(s)
                         .map(|dt| CustomDateTime(dt.with_timezone(&Tz::from(Utc))))
-                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {}", e))
+                        .map_err(|e| format!("Failed to parse `CustomDateTime`: {e}"))
                 })
         }
     }
@@ -764,7 +766,7 @@ mod description_from_doc_comment {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -841,7 +843,7 @@ mod description_from_attribute {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -918,7 +920,7 @@ mod custom_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -995,7 +997,7 @@ mod generic_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `Counter`, found: {}", v))
+                .ok_or_else(|| format!("Expected `Counter`, found: {v}"))
         }
     }
 
@@ -1071,7 +1073,7 @@ mod bounded_generic_scalar {
         fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
             v.as_int_value()
                 .map(Self)
-                .ok_or_else(|| format!("Expected `String`, found: {}", v))
+                .ok_or_else(|| format!("Expected `String`, found: {v}"))
         }
     }
 
diff --git a/tests/integration/src/codegen/scalar_value_derive.rs b/tests/integration/tests/codegen_scalar_value_derive.rs
similarity index 100%
rename from tests/integration/src/codegen/scalar_value_derive.rs
rename to tests/integration/tests/codegen_scalar_value_derive.rs
diff --git a/tests/integration/src/codegen/subscription_attr.rs b/tests/integration/tests/codegen_subscription_attr.rs
similarity index 96%
rename from tests/integration/src/codegen/subscription_attr.rs
rename to tests/integration/tests/codegen_subscription_attr.rs
index 306b8c8e..09ffa957 100644
--- a/tests/integration/src/codegen/subscription_attr.rs
+++ b/tests/integration/tests/codegen_subscription_attr.rs
@@ -1,5 +1,7 @@
 //! Tests for `#[graphql_subscription]` macro.
 
+pub mod common;
+
 use std::pin::Pin;
 
 use futures::{future, stream, FutureExt as _};
@@ -9,7 +11,7 @@ use juniper::{
     GraphQLInputObject, GraphQLType, IntoFieldError, RootNode, ScalarValue,
 };
 
-use crate::util::extract_next;
+use self::common::util::extract_next;
 
 struct Query;
 
@@ -53,12 +55,12 @@ mod trivial {
     #[graphql_subscription]
     impl Human {
         async fn id() -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready("human-32".to_owned())))
+            Box::pin(stream::once(future::ready("human-32".into())))
         }
 
         // TODO: Make work for `Stream<'_, String>`.
         async fn home_planet(&self) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready("earth".to_owned())))
+            Box::pin(stream::once(future::ready("earth".into())))
         }
     }
 
@@ -227,7 +229,7 @@ mod ignored_method {
     #[graphql_subscription]
     impl Human {
         async fn id() -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready("human-32".to_owned())))
+            Box::pin(stream::once(future::ready("human-32".into())))
         }
 
         #[allow(dead_code)]
@@ -291,7 +293,7 @@ mod fallible_method {
     #[graphql_subscription]
     impl Human {
         async fn id(&self) -> Result<Stream<'static, String>, CustomError> {
-            Ok(Box::pin(stream::once(future::ready("human-32".to_owned()))))
+            Ok(Box::pin(stream::once(future::ready("human-32".into()))))
         }
 
         async fn home_planet<__S>() -> FieldResult<Stream<'static, &'static str>, __S> {
@@ -387,10 +389,7 @@ mod argument {
             r#raw_arg: String,
             r#async: Option<i32>,
         ) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(format!(
-                "{},{:?}",
-                r#raw_arg, r#async
-            ))))
+            Box::pin(stream::once(future::ready(format!("{raw_arg},{async:?}"))))
         }
     }
 
@@ -524,10 +523,7 @@ mod default_argument {
             #[graphql(default = "second".to_string())] arg2: String,
             #[graphql(default = true)] r#arg3: bool,
         ) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(format!(
-                "{}|{}&{}",
-                arg1, arg2, r#arg3
-            ))))
+            Box::pin(stream::once(future::ready(format!("{arg1}|{arg2}&{arg3}"))))
         }
 
         async fn info(#[graphql(default = Point { x: 1 })] coord: Point) -> Stream<'static, i32> {
@@ -539,7 +535,7 @@ mod default_argument {
     async fn resolves_id_field() {
         let schema = schema(Query, Human);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             ("subscription { id }", "0|second&true"),
             ("subscription { id(arg1: 1) }", "1|second&true"),
             (r#"subscription { id(arg2: "") }"#, "0|&true"),
@@ -549,10 +545,8 @@ mod default_argument {
                 "1|&false",
             ),
         ] {
-            let expected: &str = *expected;
-
             assert_eq!(
-                resolve_into_stream(*input, None, &schema, &graphql_vars! {}, &())
+                resolve_into_stream(input, None, &schema, &graphql_vars! {}, &())
                     .then(|s| extract_next(s))
                     .await,
                 Ok((graphql_value!({ "id": expected }), vec![])),
@@ -564,14 +558,12 @@ mod default_argument {
     async fn resolves_info_field() {
         let schema = schema(Query, Human);
 
-        for (input, expected) in &[
+        for (input, expected) in [
             ("subscription { info }", 1),
             ("subscription { info(coord: { x: 2 }) }", 2),
         ] {
-            let expected: i32 = *expected;
-
             assert_eq!(
-                resolve_into_stream(*input, None, &schema, &graphql_vars! {}, &())
+                resolve_into_stream(input, None, &schema, &graphql_vars! {}, &())
                     .then(|s| extract_next(s))
                     .await,
                 Ok((graphql_value!({ "info": expected }), vec![])),
@@ -607,21 +599,21 @@ mod default_argument {
                     "args": [{
                         "name": "arg1",
                         "defaultValue": "0",
-                        "type": {"name": "Int", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Int"}},
                     }, {
                         "name": "arg2",
                         "defaultValue": r#""second""#,
-                        "type": {"name": "String", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "String"}},
                     }, {
                         "name": "arg3",
                         "defaultValue": "true",
-                        "type": {"name": "Boolean", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Boolean"}},
                     }],
                 }, {
                     "args": [{
                         "name": "coord",
                         "defaultValue": "{x: 1}",
-                        "type": {"name": "Point", "ofType": null},
+                        "type": {"name": null, "ofType": {"name": "Point"}},
                     }],
                 }]}}),
                 vec![],
@@ -648,7 +640,7 @@ mod generic {
     #[graphql_subscription(name = "HumanString")]
     impl<B: ?Sized + Sync> Human<String, B> {
         async fn id(&self) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(self.id.to_owned())))
+            Box::pin(stream::once(future::ready(self.id.clone())))
         }
     }
 
@@ -735,7 +727,7 @@ mod generic_lifetime {
 
         // TODO: Make it work with `Stream<'_, &str>`.
         async fn planet(&self) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(self.home_planet.to_owned())))
+            Box::pin(stream::once(future::ready(self.home_planet.into())))
         }
     }
 
@@ -743,12 +735,12 @@ mod generic_lifetime {
     impl<'id, 'p> Human<'p, &'id str> {
         // TODO: Make it work with `Stream<'_, &str>`.
         async fn id(&self) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(self.id.to_owned())))
+            Box::pin(stream::once(future::ready(self.id.into())))
         }
 
         // TODO: Make it work with `Stream<'_, &str>`.
         async fn planet(&self) -> Stream<'static, String> {
-            Box::pin(stream::once(future::ready(self.home_planet.to_owned())))
+            Box::pin(stream::once(future::ready(self.home_planet.into())))
         }
     }
 
@@ -1361,7 +1353,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -1702,7 +1694,7 @@ mod executor {
             S: ScalarValue,
         {
             Box::pin(stream::once(future::ready(
-                executor.look_ahead().field_name().to_owned(),
+                executor.look_ahead().field_name().into(),
             )))
         }
 
diff --git a/tests/integration/src/codegen/union_attr.rs b/tests/integration/tests/codegen_union_attr.rs
similarity index 90%
rename from tests/integration/src/codegen/union_attr.rs
rename to tests/integration/tests/codegen_union_attr.rs
index 9f032c4c..23085ef5 100644
--- a/tests/integration/src/codegen/union_attr.rs
+++ b/tests/integration/tests/codegen_union_attr.rs
@@ -1,10 +1,14 @@
 //! Tests for `#[graphql_union]` macro.
 
+pub mod common;
+
 use juniper::{
     execute, graphql_object, graphql_union, graphql_value, graphql_vars, DefaultScalarValue,
-    EmptyMutation, EmptySubscription, GraphQLObject, GraphQLType, RootNode, ScalarValue,
+    GraphQLObject, ScalarValue,
 };
 
+use self::common::util::{schema, schema_with_scalar};
+
 #[derive(GraphQLObject)]
 struct Human {
     id: String,
@@ -51,31 +55,6 @@ struct EwokCustomContext {
     funny: bool,
 }
 
-fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
-where
-    Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
-{
-    RootNode::new(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
-fn schema_with_scalar<'q, S, C, Q>(
-    query_root: Q,
-) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
-where
-    Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
-    S: ScalarValue + 'q,
-{
-    RootNode::new_with_scalar_value(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
 mod trivial {
     use super::*;
 
@@ -113,12 +92,12 @@ mod trivial {
         fn character(&self) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -250,12 +229,12 @@ mod generic {
         fn character(&self) -> Box<DynCharacter<'_, u8, ()>> {
             let ch: Box<DynCharacter<'_, u8, ()>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -343,8 +322,8 @@ mod description_from_doc_comment {
     impl QueryRoot {
         fn character(&self) -> Box<DynCharacter<'_>> {
             Box::new(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -416,8 +395,8 @@ mod explicit_name_and_description {
     impl QueryRoot {
         fn character(&self) -> Box<DynCharacter<'_>> {
             Box::new(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -517,12 +496,12 @@ mod explicit_scalar {
         fn character(&self) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -570,7 +549,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -608,12 +587,12 @@ mod custom_scalar {
         fn character(&self) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -697,12 +676,12 @@ mod explicit_generic_scalar {
         fn character<__S: ScalarValue>(&self) -> Box<DynCharacter<'_, __S>> {
             let ch: Box<DynCharacter<'_, _>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -786,12 +765,12 @@ mod bounded_generic_scalar {
         fn character(&self) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             };
             ch
@@ -872,12 +851,12 @@ mod explicit_custom_context {
         fn character(&self, ctx: &CustomContext) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match ctx {
                 CustomContext::Human => Box::new(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Box::new(DroidCustomContext {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 _ => unimplemented!(),
             };
@@ -959,12 +938,12 @@ mod inferred_custom_context {
         fn character(&self, ctx: &CustomContext) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match ctx {
                 CustomContext::Human => Box::new(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Box::new(DroidCustomContext {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 _ => unimplemented!(),
             };
@@ -1042,8 +1021,8 @@ mod ignored_method {
     impl QueryRoot {
         fn character(&self) -> Box<DynCharacter<'_>> {
             Box::new(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -1134,12 +1113,12 @@ mod external_resolver {
         fn character(&self) -> Box<DynCharacter<'_>> {
             let ch: Box<DynCharacter<'_>> = match self {
                 Self::Human => Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Box::new(Droid {
-                    id: "?????".to_string(),
-                    primary_function: "???".to_string(),
+                    id: "?????".into(),
+                    primary_function: "???".into(),
                 }),
             };
             ch
@@ -1178,8 +1157,8 @@ mod external_resolver {
         let schema = schema(QueryRoot::Droid);
         let db = Database {
             droid: Some(Droid {
-                id: "droid-99".to_string(),
-                primary_function: "run".to_string(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         };
 
@@ -1250,15 +1229,15 @@ mod full_featured {
         fn character(&self, ctx: &CustomContext) -> Box<DynCharacter<'_, ()>> {
             let ch: Box<DynCharacter<'_, ()>> = match ctx {
                 CustomContext::Human => Box::new(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Box::new(DroidCustomContext {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 CustomContext::Ewok => Box::new(EwokCustomContext {
-                    id: "ewok-1".to_string(),
+                    id: "ewok-1".into(),
                     funny: true,
                 }),
             };
diff --git a/tests/integration/src/codegen/union_derive.rs b/tests/integration/tests/codegen_union_derive.rs
similarity index 90%
rename from tests/integration/src/codegen/union_derive.rs
rename to tests/integration/tests/codegen_union_derive.rs
index be6577e2..034e34d2 100644
--- a/tests/integration/src/codegen/union_derive.rs
+++ b/tests/integration/tests/codegen_union_derive.rs
@@ -1,12 +1,16 @@
 //! Tests for `#[derive(GraphQLUnion)]` macro.
 
+pub mod common;
+
 use std::marker::PhantomData;
 
 use juniper::{
-    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, EmptyMutation,
-    EmptySubscription, GraphQLObject, GraphQLType, GraphQLUnion, RootNode, ScalarValue,
+    execute, graphql_object, graphql_value, graphql_vars, DefaultScalarValue, GraphQLObject,
+    GraphQLUnion, ScalarValue,
 };
 
+use self::common::util::{schema, schema_with_scalar};
+
 #[derive(GraphQLObject)]
 struct Human {
     id: String,
@@ -53,31 +57,6 @@ struct EwokCustomContext {
     funny: bool,
 }
 
-fn schema<'q, C, Q>(query_root: Q) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
-where
-    Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
-{
-    RootNode::new(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
-fn schema_with_scalar<'q, S, C, Q>(
-    query_root: Q,
-) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
-where
-    Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
-    S: ScalarValue + 'q,
-{
-    RootNode::new_with_scalar_value(
-        query_root,
-        EmptyMutation::<C>::new(),
-        EmptySubscription::<C>::new(),
-    )
-}
-
 mod trivial_enum {
     use super::*;
 
@@ -97,12 +76,12 @@ mod trivial_enum {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -217,12 +196,12 @@ mod generic_enum {
         fn character(&self) -> Character<u8, ()> {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -317,7 +296,7 @@ mod generic_lifetime_enum {
             match self {
                 Self::Human => Character::A(LifetimeHuman { id: "human-32" }),
                 Self::Droid => Character::B(GenericDroid {
-                    id: "droid-99".to_string(),
+                    id: "droid-99".into(),
                     _t: PhantomData,
                 }),
             }
@@ -394,8 +373,8 @@ mod description_from_doc_comments {
     impl QueryRoot {
         fn character(&self) -> Character {
             Character::A(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -458,8 +437,8 @@ mod explicit_name_and_description {
     impl QueryRoot {
         fn character(&self) -> Character {
             Character::A(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -542,12 +521,12 @@ mod explicit_scalar {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -594,7 +573,7 @@ mod explicit_scalar {
 }
 
 mod custom_scalar {
-    use crate::custom_scalar::MyScalarValue;
+    use crate::common::MyScalarValue;
 
     use super::*;
 
@@ -615,12 +594,12 @@ mod custom_scalar {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -688,12 +667,12 @@ mod explicit_generic_scalar {
         fn character<__S: ScalarValue>(&self) -> Character<__S> {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -759,12 +738,12 @@ mod bounded_generic_scalar {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
             }
         }
@@ -827,12 +806,12 @@ mod custom_context {
         fn character(&self, ctx: &CustomContext) -> Character {
             match ctx {
                 CustomContext::Human => Character::A(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Character::B(DroidCustomContext {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 _ => unimplemented!(),
             }
@@ -896,12 +875,12 @@ mod different_context {
         fn character(&self, ctx: &CustomContext) -> Character {
             match ctx {
                 CustomContext::Human => Character::A(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Character::B(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 _ => unimplemented!(),
             }
@@ -966,8 +945,8 @@ mod ignored_enum_variants {
     impl QueryRoot {
         fn character(&self) -> Character {
             Character::A(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             })
         }
     }
@@ -1053,8 +1032,8 @@ mod external_resolver_enum {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B,
             }
@@ -1093,8 +1072,8 @@ mod external_resolver_enum {
         let schema = schema(QueryRoot::Droid);
         let db = Database {
             droid: Some(Droid {
-                id: "droid-99".to_string(),
-                primary_function: "run".to_string(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         };
 
@@ -1144,12 +1123,12 @@ mod external_resolver_enum_variant {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 Self::Droid => Character::B(Droid {
-                    id: "?????".to_string(),
-                    primary_function: "???".to_string(),
+                    id: "?????".into(),
+                    primary_function: "???".into(),
                 }),
             }
         }
@@ -1187,8 +1166,8 @@ mod external_resolver_enum_variant {
         let schema = schema(QueryRoot::Droid);
         let db = Database {
             droid: Some(Droid {
-                id: "droid-99".to_string(),
-                primary_function: "run".to_string(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         };
 
@@ -1250,15 +1229,15 @@ mod full_featured_enum {
         fn character(&self, ctx: &CustomContext) -> Character<()> {
             match ctx {
                 CustomContext::Human => Character::A(HumanCustomContext {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 }),
                 CustomContext::Droid => Character::B(DroidCustomContext {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 }),
                 CustomContext::Ewok => Character::C(EwokCustomContext {
-                    id: "ewok-1".to_string(),
+                    id: "ewok-1".into(),
                     funny: true,
                 }),
             }
@@ -1409,7 +1388,7 @@ mod trivial_struct {
                     Self::Human => "human-32",
                     Self::Droid => "droid-99",
                 }
-                .to_string(),
+                .into(),
             }
         }
     }
@@ -1432,8 +1411,8 @@ mod trivial_struct {
         let schema = schema(QueryRoot::Human);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             droid: None,
         };
@@ -1453,8 +1432,8 @@ mod trivial_struct {
         let db = Database {
             human: None,
             droid: Some(Droid {
-                id: "droid-99".to_string(),
-                primary_function: "run".to_string(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         };
 
@@ -1478,8 +1457,8 @@ mod trivial_struct {
         let schema = schema(QueryRoot::Human);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             droid: None,
         };
@@ -1501,8 +1480,8 @@ mod trivial_struct {
         let schema = schema(QueryRoot::Human);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             droid: None,
         };
@@ -1524,8 +1503,8 @@ mod trivial_struct {
         let schema = schema(QueryRoot::Human);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             droid: None,
         };
@@ -1570,7 +1549,7 @@ mod generic_struct {
     impl QueryRoot {
         fn character(&self) -> Character<u8, ()> {
             Character {
-                id: "human-32".to_string(),
+                id: "human-32".into(),
                 _s: PhantomData,
             }
         }
@@ -1590,8 +1569,8 @@ mod generic_struct {
         let schema = schema(QueryRoot);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
         };
 
@@ -1678,7 +1657,7 @@ mod full_featured_struct {
                     Self::Human => "human-32",
                     Self::Droid => "droid-99",
                 }
-                .to_string(),
+                .into(),
                 _s: PhantomData,
             }
         }
@@ -1702,8 +1681,8 @@ mod full_featured_struct {
         let schema = schema(QueryRoot::Human);
         let db = Database {
             human: Some(Human {
-                id: "human-32".to_string(),
-                home_planet: "earth".to_string(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             droid: None,
         };
@@ -1723,8 +1702,8 @@ mod full_featured_struct {
         let db = Database {
             human: None,
             droid: Some(Droid {
-                id: "droid-99".to_string(),
-                primary_function: "run".to_string(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         };
 
@@ -1804,12 +1783,12 @@ mod issue_845 {
         fn character(&self) -> Character {
             match self {
                 Self::Human => Character::A(Box::new(Human {
-                    id: "human-32".to_string(),
-                    home_planet: "earth".to_string(),
+                    id: "human-32".into(),
+                    home_planet: "earth".into(),
                 })),
                 Self::Droid => Character::B(Arc::new(Droid {
-                    id: "droid-99".to_string(),
-                    primary_function: "run".to_string(),
+                    id: "droid-99".into(),
+                    primary_function: "run".into(),
                 })),
             }
         }
diff --git a/tests/integration/tests/common/mod.rs b/tests/integration/tests/common/mod.rs
new file mode 100644
index 00000000..5dc6a277
--- /dev/null
+++ b/tests/integration/tests/common/mod.rs
@@ -0,0 +1,147 @@
+use std::fmt;
+
+use juniper::ScalarValue;
+use serde::{de, Deserialize, Deserializer, Serialize};
+
+/// Common utilities used across tests.
+pub mod util {
+    use futures::StreamExt as _;
+    use juniper::{
+        graphql_value, DefaultScalarValue, EmptyMutation, EmptySubscription, ExecutionError,
+        GraphQLError, GraphQLType, RootNode, ScalarValue, Value, ValuesStream,
+    };
+
+    pub fn schema<'q, C, Q>(
+        query_root: Q,
+    ) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>>
+    where
+        Q: GraphQLType<DefaultScalarValue, Context = C, TypeInfo = ()> + 'q,
+    {
+        RootNode::new(
+            query_root,
+            EmptyMutation::<C>::new(),
+            EmptySubscription::<C>::new(),
+        )
+    }
+
+    pub fn schema_with_scalar<'q, S, C, Q>(
+        query_root: Q,
+    ) -> RootNode<'q, Q, EmptyMutation<C>, EmptySubscription<C>, S>
+    where
+        Q: GraphQLType<S, Context = C, TypeInfo = ()> + 'q,
+        S: ScalarValue + 'q,
+    {
+        RootNode::new_with_scalar_value(
+            query_root,
+            EmptyMutation::<C>::new(),
+            EmptySubscription::<C>::new(),
+        )
+    }
+
+    /// Extracts a single next value from the result returned by
+    /// [`juniper::resolve_into_stream()`] and transforms it into a regular
+    /// [`Value`].
+    pub async fn extract_next<S: ScalarValue>(
+        input: Result<(Value<ValuesStream<'_, S>>, Vec<ExecutionError<S>>), GraphQLError>,
+    ) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError> {
+        let (stream, errs) = input?;
+        if !errs.is_empty() {
+            return Ok((Value::Null, errs));
+        }
+
+        if let Value::Object(obj) = stream {
+            for (name, mut val) in obj {
+                if let Value::Scalar(ref mut stream) = val {
+                    return match stream.next().await {
+                        Some(Ok(val)) => Ok((graphql_value!({ name: val }), vec![])),
+                        Some(Err(e)) => Ok((Value::Null, vec![e])),
+                        None => Ok((Value::Null, vec![])),
+                    };
+                }
+            }
+        }
+
+        panic!("Expected to get Value::Object containing a Stream")
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, ScalarValue, Serialize)]
+#[serde(untagged)]
+pub enum MyScalarValue {
+    #[value(as_float, as_int)]
+    Int(i32),
+    Long(i64),
+    #[value(as_float)]
+    Float(f64),
+    #[value(as_str, as_string, into_string)]
+    String(String),
+    #[value(as_bool)]
+    Boolean(bool),
+}
+
+impl<'de> Deserialize<'de> for MyScalarValue {
+    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
+        struct Visitor;
+
+        impl<'de> de::Visitor<'de> for Visitor {
+            type Value = MyScalarValue;
+
+            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.write_str("a valid input value")
+            }
+
+            fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
+                Ok(MyScalarValue::Boolean(b))
+            }
+
+            fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
+                Ok(MyScalarValue::Int(n))
+            }
+
+            fn visit_i64<E: de::Error>(self, b: i64) -> Result<Self::Value, E> {
+                if b <= i64::from(i32::MAX) {
+                    self.visit_i32(b.try_into().unwrap())
+                } else {
+                    Ok(MyScalarValue::Long(b))
+                }
+            }
+
+            fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
+                if n <= i32::MAX as u32 {
+                    self.visit_i32(n.try_into().unwrap())
+                } else {
+                    self.visit_u64(n.into())
+                }
+            }
+
+            fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
+                if n <= i64::MAX as u64 {
+                    self.visit_i64(n.try_into().unwrap())
+                } else {
+                    // Browser's `JSON.stringify()` serializes all numbers
+                    // having no fractional part as integers (no decimal point),
+                    // so we must parse large integers as floating point,
+                    // otherwise we would error on transferring large floating
+                    // point numbers.
+                    // TODO: Use `FloatToInt` conversion once stabilized:
+                    //       https://github.com/rust-lang/rust/issues/67057
+                    Ok(MyScalarValue::Float(n as f64))
+                }
+            }
+
+            fn visit_f64<E: de::Error>(self, f: f64) -> Result<Self::Value, E> {
+                Ok(MyScalarValue::Float(f))
+            }
+
+            fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
+                self.visit_string(s.into())
+            }
+
+            fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
+                Ok(MyScalarValue::String(s))
+            }
+        }
+
+        de.deserialize_any(Visitor)
+    }
+}
diff --git a/tests/integration/src/custom_scalar.rs b/tests/integration/tests/custom_scalar.rs
similarity index 50%
rename from tests/integration/src/custom_scalar.rs
rename to tests/integration/tests/custom_scalar.rs
index 7a8c6f94..ac1d31cf 100644
--- a/tests/integration/src/custom_scalar.rs
+++ b/tests/integration/tests/custom_scalar.rs
@@ -1,95 +1,16 @@
-use std::{convert::TryInto as _, fmt, pin::Pin};
+pub mod common;
+
+use std::pin::Pin;
 
 use futures::{stream, Stream};
 use juniper::{
     execute, graphql_input_value, graphql_object, graphql_scalar, graphql_subscription,
     graphql_vars,
     parser::{ParseError, ScalarToken, Token},
-    serde::{de, Deserialize, Deserializer, Serialize},
-    EmptyMutation, FieldResult, InputValue, Object, ParseScalarResult, RootNode, ScalarValue,
-    Value, Variables,
+    EmptyMutation, FieldResult, InputValue, Object, ParseScalarResult, RootNode, Value, Variables,
 };
 
-#[derive(Clone, Debug, PartialEq, ScalarValue, Serialize)]
-#[serde(untagged)]
-pub(crate) enum MyScalarValue {
-    #[value(as_float, as_int)]
-    Int(i32),
-    Long(i64),
-    #[value(as_float)]
-    Float(f64),
-    #[value(as_str, as_string, into_string)]
-    String(String),
-    #[value(as_bool)]
-    Boolean(bool),
-}
-
-impl<'de> Deserialize<'de> for MyScalarValue {
-    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
-        struct Visitor;
-
-        impl<'de> de::Visitor<'de> for Visitor {
-            type Value = MyScalarValue;
-
-            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                f.write_str("a valid input value")
-            }
-
-            fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
-                Ok(MyScalarValue::Boolean(b))
-            }
-
-            fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
-                Ok(MyScalarValue::Int(n))
-            }
-
-            fn visit_i64<E: de::Error>(self, b: i64) -> Result<Self::Value, E> {
-                if b <= i64::from(i32::MAX) {
-                    self.visit_i32(b.try_into().unwrap())
-                } else {
-                    Ok(MyScalarValue::Long(b))
-                }
-            }
-
-            fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
-                if n <= i32::MAX as u32 {
-                    self.visit_i32(n.try_into().unwrap())
-                } else {
-                    self.visit_u64(n.into())
-                }
-            }
-
-            fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
-                if n <= i64::MAX as u64 {
-                    self.visit_i64(n.try_into().unwrap())
-                } else {
-                    // Browser's `JSON.stringify()` serializes all numbers
-                    // having no fractional part as integers (no decimal point),
-                    // so we must parse large integers as floating point,
-                    // otherwise we would error on transferring large floating
-                    // point numbers.
-                    // TODO: Use `FloatToInt` conversion once stabilized:
-                    //       https://github.com/rust-lang/rust/issues/67057
-                    Ok(MyScalarValue::Float(n as f64))
-                }
-            }
-
-            fn visit_f64<E: de::Error>(self, f: f64) -> Result<Self::Value, E> {
-                Ok(MyScalarValue::Float(f))
-            }
-
-            fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
-                self.visit_string(s.into())
-            }
-
-            fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
-                Ok(MyScalarValue::String(s))
-            }
-        }
-
-        de.deserialize_any(Visitor)
-    }
-}
+use self::common::MyScalarValue;
 
 #[graphql_scalar(with = long, scalar = MyScalarValue)]
 type Long = i64;
@@ -104,16 +25,16 @@ mod long {
     pub(super) fn from_input(v: &InputValue<MyScalarValue>) -> Result<Long, String> {
         v.as_scalar_value::<i64>()
             .copied()
-            .ok_or_else(|| format!("Expected `MyScalarValue::Long`, found: {}", v))
+            .ok_or_else(|| format!("Expected `MyScalarValue::Long`, found: {v}"))
     }
 
-    pub(super) fn parse_token(value: ScalarToken<'_>) -> ParseScalarResult<'_, MyScalarValue> {
+    pub(super) fn parse_token(value: ScalarToken<'_>) -> ParseScalarResult<MyScalarValue> {
         if let ScalarToken::Int(v) = value {
             v.parse()
-                .map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
+                .map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
                 .map(|s: i64| s.into())
         } else {
-            Err(ParseError::UnexpectedToken(Token::Scalar(value)))
+            Err(ParseError::unexpected_token(Token::Scalar(value)))
         }
     }
 }
@@ -153,7 +74,7 @@ where
 
     assert_eq!(errs, []);
 
-    println!("Result: {:?}", result);
+    println!("Result: {result:?}");
 
     let obj = result.as_object_value().expect("Result is not an object");
 
diff --git a/tests/integration/tests/cve_2022_31173.rs b/tests/integration/tests/cve_2022_31173.rs
new file mode 100644
index 00000000..332306a3
--- /dev/null
+++ b/tests/integration/tests/cve_2022_31173.rs
@@ -0,0 +1,56 @@
+//! Checks that long looping chain of fragments doesn't cause a stack overflow.
+//!
+//! ```graphql
+//! # Fragment loop example
+//! query {
+//!     ...a
+//! }
+//!
+//! fragment a on Query {
+//!     ...b
+//! }
+//!
+//! fragment b on Query {
+//!     ...a
+//! }
+//! ```
+
+use std::iter;
+
+use itertools::Itertools as _;
+use juniper::{graphql_object, graphql_vars, EmptyMutation, EmptySubscription};
+
+struct Query;
+
+#[graphql_object]
+impl Query {
+    fn dummy() -> bool {
+        false
+    }
+}
+
+type Schema = juniper::RootNode<'static, Query, EmptyMutation, EmptySubscription>;
+
+#[tokio::test]
+async fn test() {
+    const PERM: &str = "abcefghijk";
+    const CIRCLE_SIZE: usize = 7500;
+
+    let query = iter::once(format!("query {{ ...{PERM} }} "))
+        .chain(
+            PERM.chars()
+                .permutations(PERM.len())
+                .map(|vec| vec.into_iter().collect::<String>())
+                .take(CIRCLE_SIZE)
+                .collect::<Vec<_>>()
+                .into_iter()
+                .circular_tuple_windows::<(_, _)>()
+                .map(|(cur, next)| format!("fragment {cur} on Query {{ ...{next} }} ")),
+        )
+        .collect::<String>();
+
+    let schema = Schema::new(Query, EmptyMutation::new(), EmptySubscription::new());
+    let _ = juniper::execute(&query, None, &schema, &graphql_vars! {}, &())
+        .await
+        .unwrap_err();
+}
diff --git a/tests/integration/src/explicit_null.rs b/tests/integration/tests/explicit_null.rs
similarity index 100%
rename from tests/integration/src/explicit_null.rs
rename to tests/integration/tests/explicit_null.rs
diff --git a/tests/integration/tests/infallible_as_field_error.rs b/tests/integration/tests/infallible_as_field_error.rs
new file mode 100644
index 00000000..43293264
--- /dev/null
+++ b/tests/integration/tests/infallible_as_field_error.rs
@@ -0,0 +1,12 @@
+use std::convert::Infallible;
+
+use juniper::graphql_object;
+
+struct Query;
+
+#[graphql_object]
+impl Query {
+    fn ping() -> Result<bool, Infallible> {
+        Ok(false)
+    }
+}
diff --git a/tests/integration/src/inside_macro.rs b/tests/integration/tests/inside_macro.rs
similarity index 100%
rename from tests/integration/src/inside_macro.rs
rename to tests/integration/tests/inside_macro.rs
diff --git a/tests/integration/src/issue_371.rs b/tests/integration/tests/issue_371.rs
similarity index 100%
rename from tests/integration/src/issue_371.rs
rename to tests/integration/tests/issue_371.rs
diff --git a/tests/integration/src/issue_372.rs b/tests/integration/tests/issue_372.rs
similarity index 100%
rename from tests/integration/src/issue_372.rs
rename to tests/integration/tests/issue_372.rs
diff --git a/tests/integration/src/issue_398.rs b/tests/integration/tests/issue_398.rs
similarity index 100%
rename from tests/integration/src/issue_398.rs
rename to tests/integration/tests/issue_398.rs
diff --git a/tests/integration/src/issue_407.rs b/tests/integration/tests/issue_407.rs
similarity index 93%
rename from tests/integration/src/issue_407.rs
rename to tests/integration/tests/issue_407.rs
index 245398c3..a8a4ef13 100644
--- a/tests/integration/src/issue_407.rs
+++ b/tests/integration/tests/issue_407.rs
@@ -31,12 +31,12 @@ struct Droid {
 impl Query {
     fn characters() -> Vec<CharacterValue> {
         let human = Human {
-            id: "1".to_string(),
-            name: "Han Solo".to_string(),
+            id: "1".into(),
+            name: "Han Solo".into(),
         };
         let droid = Droid {
-            id: "2".to_string(),
-            serial_number: "234532545235".to_string(),
+            id: "2".into(),
+            serial_number: "234532545235".into(),
         };
         vec![Into::into(human), Into::into(droid)]
     }
diff --git a/tests/integration/src/issue_500.rs b/tests/integration/tests/issue_500.rs
similarity index 100%
rename from tests/integration/src/issue_500.rs
rename to tests/integration/tests/issue_500.rs
diff --git a/tests/integration/src/issue_798.rs b/tests/integration/tests/issue_798.rs
similarity index 95%
rename from tests/integration/src/issue_798.rs
rename to tests/integration/tests/issue_798.rs
index fed322fc..40252406 100644
--- a/tests/integration/src/issue_798.rs
+++ b/tests/integration/tests/issue_798.rs
@@ -42,12 +42,12 @@ impl Query {
     fn field(&self) -> FieldResult {
         match self {
             Self::Human => FieldResult::Human(Human {
-                id: "human-32".to_owned(),
-                home_planet: "earth".to_owned(),
+                id: "human-32".into(),
+                home_planet: "earth".into(),
             }),
             Self::Droid => FieldResult::Droid(Droid {
-                id: "droid-99".to_owned(),
-                primary_function: "run".to_owned(),
+                id: "droid-99".into(),
+                primary_function: "run".into(),
             }),
         }
     }
diff --git a/tests/integration/src/issue_914.rs b/tests/integration/tests/issue_914.rs
similarity index 100%
rename from tests/integration/src/issue_914.rs
rename to tests/integration/tests/issue_914.rs
diff --git a/tests/integration/src/issue_922.rs b/tests/integration/tests/issue_922.rs
similarity index 96%
rename from tests/integration/src/issue_922.rs
rename to tests/integration/tests/issue_922.rs
index fd28b45f..1a89a68e 100644
--- a/tests/integration/src/issue_922.rs
+++ b/tests/integration/tests/issue_922.rs
@@ -14,11 +14,11 @@ impl Query {
         vec![
             Into::into(Human {
                 id: 0,
-                name: "human-32".to_owned(),
+                name: "human-32".into(),
             }),
             Into::into(Droid {
                 id: 1,
-                name: "R2-D2".to_owned(),
+                name: "R2-D2".into(),
             }),
         ]
     }
diff --git a/tests/integration/src/issue_925.rs b/tests/integration/tests/issue_925.rs
similarity index 100%
rename from tests/integration/src/issue_925.rs
rename to tests/integration/tests/issue_925.rs
diff --git a/tests/integration/src/issue_945.rs b/tests/integration/tests/issue_945.rs
similarity index 95%
rename from tests/integration/src/issue_945.rs
rename to tests/integration/tests/issue_945.rs
index 369e660b..42458313 100644
--- a/tests/integration/src/issue_945.rs
+++ b/tests/integration/tests/issue_945.rs
@@ -13,8 +13,8 @@ impl Query {
     fn artoo() -> Character {
         Character::Droid(Droid {
             id: 1,
-            name: "R2-D2".to_owned(),
-            sensor_color: "red".to_owned(),
+            name: "R2-D2".into(),
+            sensor_color: "red".into(),
         })
     }
 }
diff --git a/tests/integration/src/pre_parse.rs b/tests/integration/tests/pre_parse.rs
similarity index 92%
rename from tests/integration/src/pre_parse.rs
rename to tests/integration/tests/pre_parse.rs
index ec987eca..df2f97e3 100644
--- a/tests/integration/src/pre_parse.rs
+++ b/tests/integration/tests/pre_parse.rs
@@ -1,3 +1,5 @@
+use std::pin::Pin;
+
 use futures::{Stream, StreamExt, TryFutureExt};
 use juniper::{
     executor::{execute_validated_query_async, get_operation, resolve_validated_subscription},
@@ -6,7 +8,6 @@ use juniper::{
     validation::{validate_input_values, visit_all_rules, ValidatorContext},
     EmptyMutation, FieldError, OperationType, RootNode,
 };
-use std::pin::Pin;
 
 pub struct Context;
 
@@ -64,15 +65,10 @@ async fn query_document_can_be_pre_parsed() {
     let errors = validate_input_values(&graphql_vars! {}, operation, &root_node.schema);
     assert!(errors.is_empty());
 
-    let (_, errors) = execute_validated_query_async(
-        &document,
-        operation,
-        root_node,
-        &graphql_vars! {},
-        &Context {},
-    )
-    .await
-    .unwrap();
+    let (_, errors) =
+        execute_validated_query_async(&document, operation, root_node, &graphql_vars! {}, &Context)
+            .await
+            .unwrap();
 
     assert!(errors.len() == 0);
 }
@@ -92,7 +88,7 @@ async fn subscription_document_can_be_pre_parsed() {
         &operation,
         &root_node,
         &graphql_vars! {},
-        &Context {},
+        &Context,
     )
     .map_ok(|(stream, errors)| juniper_subscriptions::Connection::from_stream(stream, errors))
     .await