feat: add #[diagnostic::on_unimplemented] to IntoResponse and IntoResponseParts (#3723)

This commit is contained in:
Dihan Nahdi
2026-05-05 14:19:09 +02:00
committed by David Pedersen
parent db96597f47
commit 7bf2f675ef
16 changed files with 115 additions and 50 deletions
+3
View File
@@ -109,6 +109,9 @@ use std::{
/// let app = Router::new().route("/", get(|| async { MyBody })); /// let app = Router::new().route("/", get(|| async { MyBody }));
/// # let _: Router = app; /// # let _: Router = app;
/// ``` /// ```
#[diagnostic::on_unimplemented(
note = "See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponse.html` for details"
)]
pub trait IntoResponse { pub trait IntoResponse {
/// Create a response. /// Create a response.
#[must_use] #[must_use]
@@ -70,6 +70,9 @@ use std::{convert::Infallible, fmt};
/// SetHeader("x-foo", "custom") /// SetHeader("x-foo", "custom")
/// } /// }
/// ``` /// ```
#[diagnostic::on_unimplemented(
note = "See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponseParts.html` for details"
)]
pub trait IntoResponseParts { pub trait IntoResponseParts {
/// The type returned in the event of an error. /// The type returned in the event of an error.
/// ///
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `bool: FromRequest<(), axum_core::extract::private
--> tests/debug_handler/fail/argument_not_extractor.rs:4:24 --> tests/debug_handler/fail/argument_not_extractor.rs:4:24
| |
4 | async fn handler(_foo: bool) {} 4 | async fn handler(_foo: bool) {}
| ^^^^ the trait `FromRequestParts<()>` is not implemented for `bool`, which is required by `bool: FromRequest<(), _>` | ^^^^ the trait `FromRequestParts<()>` is not implemented for `bool`
| |
= note: Function argument is not a valid axum extractor. = note: Function argument is not a valid axum extractor.
See `https://docs.rs/axum/0.8/axum/extract/index.html` for details See `https://docs.rs/axum/0.8/axum/extract/index.html` for details
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `NonCloneType: Clone` is not satisfied
--> tests/debug_handler/fail/extension_not_clone.rs:7:38 --> tests/debug_handler/fail/extension_not_clone.rs:7:38
| |
7 | async fn test_extension_non_clone(_: Extension<NonCloneType>) {} 7 | async fn test_extension_non_clone(_: Extension<NonCloneType>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonCloneType`, which is required by `Extension<NonCloneType>: FromRequest<(), _>` | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonCloneType`
| |
= help: the following other types implement trait `FromRequest<S, M>`: = help: the following other types implement trait `FromRequest<S, M>`:
Body Body
@@ -2,8 +2,13 @@ error[E0277]: the trait bound `Struct: serde::Deserialize<'de>` is not satisfied
--> tests/debug_handler/fail/json_not_deserialize.rs:7:24 --> tests/debug_handler/fail/json_not_deserialize.rs:7:24
| |
7 | async fn handler(_foo: Json<Struct>) {} 7 | async fn handler(_foo: Json<Struct>) {}
| ^^^^^^^^^^^^ the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `Struct`, which is required by `Json<Struct>: FromRequest<()>` | ^^^^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `Struct`
--> tests/debug_handler/fail/json_not_deserialize.rs:4:1
|
4 | struct Struct {}
| ^^^^^^^^^^^^^
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `Struct` type = note: for local types consider adding `#[derive(serde::Deserialize)]` to your `Struct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag = note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`: = help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
@@ -18,7 +23,6 @@ error[E0277]: the trait bound `Struct: serde::Deserialize<'de>` is not satisfied
and $N others and $N others
= note: required for `Struct` to implement `serde_core::de::DeserializeOwned` = note: required for `Struct` to implement `serde_core::de::DeserializeOwned`
= note: required for `Json<Struct>` to implement `FromRequest<()>` = note: required for `Json<Struct>` to implement `FromRequest<()>`
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
| |
1 + #![feature(trivial_bounds)] 1 + #![feature(trivial_bounds)]
@@ -28,8 +32,13 @@ error[E0277]: the trait bound `Struct: serde::Deserialize<'de>` is not satisfied
--> tests/debug_handler/fail/json_not_deserialize.rs:7:24 --> tests/debug_handler/fail/json_not_deserialize.rs:7:24
| |
7 | async fn handler(_foo: Json<Struct>) {} 7 | async fn handler(_foo: Json<Struct>) {}
| ^^^^^^^^^^^^ the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `Struct`, which is required by `Json<Struct>: FromRequest<()>` | ^^^^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `Struct`
--> tests/debug_handler/fail/json_not_deserialize.rs:4:1
|
4 | struct Struct {}
| ^^^^^^^^^^^^^
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `Struct` type = note: for local types consider adding `#[derive(serde::Deserialize)]` to your `Struct` type
= note: for types from other crates check whether the crate offers a `serde` feature flag = note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`: = help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
3 | #[debug_handler] 3 | #[debug_handler]
| ^^^^^^^^^^^^^^^^ future returned by `handler` is not `Send` | ^^^^^^^^^^^^^^^^ future returned by `handler` is not `Send`
| |
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send` = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await note: future is not `Send` as this value is used across an await
--> tests/debug_handler/fail/not_send.rs:6:14 --> tests/debug_handler/fail/not_send.rs:6:14
| |
@@ -1,11 +1,11 @@
error: Cannot return tuples with more than 17 elements error: Cannot return tuples with more than 17 elements
--> tests/debug_handler/fail/output_tuple_too_many.rs:4:20 --> tests/debug_handler/fail/output_tuple_too_many.rs:4:20
| |
4 | async fn handler() -> ( 4 | async fn handler() -> (
| ____________________^ | ____________________^
5 | | axum::http::StatusCode, 5 | | axum::http::StatusCode,
6 | | AppendHeaders<[(axum::http::HeaderName, &'static str); 1]>, 6 | | AppendHeaders<[(axum::http::HeaderName, &'static str); 1]>,
7 | | AppendHeaders<[(axum::http::HeaderName, &'static str); 1]>, 7 | | AppendHeaders<[(axum::http::HeaderName, &'static str); 1]>,
... | ... |
23 | | axum::http::StatusCode, 23 | | axum::http::StatusCode,
24 | | ) { 24 | | ) {
@@ -2,8 +2,14 @@ error[E0277]: the trait bound `NotIntoResponse: IntoResponse` is not satisfied
--> tests/debug_handler/fail/single_wrong_return_tuple.rs:6:23 --> tests/debug_handler/fail/single_wrong_return_tuple.rs:6:23
| |
6 | async fn handler() -> (NotIntoResponse) { 6 | async fn handler() -> (NotIntoResponse) {
| ^^^^^^^^^^^^^^^^^ the trait `IntoResponse` is not implemented for `NotIntoResponse` | ^^^^^^^^^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `IntoResponse` is not implemented for `NotIntoResponse`
--> tests/debug_handler/fail/single_wrong_return_tuple.rs:3:1
|
3 | struct NotIntoResponse;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponse.html` for details
= help: the following other types implement trait `IntoResponse`: = help: the following other types implement trait `IntoResponse`:
&'static [u8; N] &'static [u8; N]
&'static [u8] &'static [u8]
@@ -1,10 +1,10 @@
error: Handlers cannot take more than 16 arguments. Use `(a, b): (ExtractorA, ExtractorA)` to further nest extractors error: Handlers cannot take more than 16 arguments. Use `(a, b): (ExtractorA, ExtractorA)` to further nest extractors
--> tests/debug_handler/fail/too_many_extractors.rs:6:5 --> tests/debug_handler/fail/too_many_extractors.rs:6:5
| |
6 | / _e1: Uri, 6 | / _e1: Uri,
7 | | _e2: Uri, 7 | | _e2: Uri,
8 | | _e3: Uri, 8 | | _e3: Uri,
9 | | _e4: Uri, 9 | | _e4: Uri,
... | ... |
21 | | _e16: Uri, 21 | | _e16: Uri,
22 | | _e17: Uri, 22 | | _e17: Uri,
@@ -8,8 +8,14 @@ error[E0277]: the trait bound `CustomIntoResponse: IntoResponseParts` is not sat
--> tests/debug_handler/fail/wrong_return_tuple.rs:21:5 --> tests/debug_handler/fail/wrong_return_tuple.rs:21:5
| |
21 | CustomIntoResponse, 21 | CustomIntoResponse,
| ^^^^^^^^^^^^^^^^^^ the trait `IntoResponseParts` is not implemented for `CustomIntoResponse` | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `IntoResponseParts` is not implemented for `CustomIntoResponse`
--> tests/debug_handler/fail/wrong_return_tuple.rs:12:1
|
12 | struct CustomIntoResponse {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponseParts.html` for details
= help: the following other types implement trait `IntoResponseParts`: = help: the following other types implement trait `IntoResponseParts`:
() ()
(T1, T2) (T1, T2)
@@ -20,18 +26,23 @@ error[E0277]: the trait bound `CustomIntoResponse: IntoResponseParts` is not sat
(T1, T2, T3, T4, T5, T6, T7) (T1, T2, T3, T4, T5, T6, T7)
(T1, T2, T3, T4, T5, T6, T7, T8) (T1, T2, T3, T4, T5, T6, T7, T8)
and $N others and $N others
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
| |
3 + #![feature(trivial_bounds)] 3 + #![feature(trivial_bounds)]
| |
error[E0277]: the trait bound `CustomIntoResponse: IntoResponseParts` is not satisfied error[E0277]: the trait bound `CustomIntoResponse: IntoResponseParts` is not satisfied
--> tests/debug_handler/fail/wrong_return_tuple.rs:21:5 --> tests/debug_handler/fail/wrong_return_tuple.rs:21:5
| |
21 | CustomIntoResponse, 21 | CustomIntoResponse,
| ^^^^^^^^^^^^^^^^^^ the trait `IntoResponseParts` is not implemented for `CustomIntoResponse` | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `IntoResponseParts` is not implemented for `CustomIntoResponse`
--> tests/debug_handler/fail/wrong_return_tuple.rs:12:1
|
12 | struct CustomIntoResponse {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponseParts.html` for details
= help: the following other types implement trait `IntoResponseParts`: = help: the following other types implement trait `IntoResponseParts`:
() ()
(T1, T2) (T1, T2)
@@ -4,6 +4,7 @@ error[E0277]: the trait bound `bool: IntoResponse` is not satisfied
4 | async fn handler() -> bool { 4 | async fn handler() -> bool {
| ^^^^ the trait `IntoResponse` is not implemented for `bool` | ^^^^ the trait `IntoResponse` is not implemented for `bool`
| |
= note: See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponse.html` for details
= help: the following other types implement trait `IntoResponse`: = help: the following other types implement trait `IntoResponse`:
&'static [u8; N] &'static [u8; N]
&'static [u8] &'static [u8]
@@ -16,9 +16,12 @@ error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {fo
note: required by a bound in `axum::routing::get` note: required by a bound in `axum::routing::get`
--> $WORKSPACE/axum/src/routing/method_routing.rs --> $WORKSPACE/axum/src/routing/method_routing.rs
| |
| H: Handler<T, S>,
| ^^^^^^^^^^^^^ required by this bound in `get`
...
| top_level_handler_fn!(get, GET); | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^ | -------------------------------
| | | | | |
| | required by a bound in this function | | required by a bound in this function
| required by this bound in `get` | in this macro invocation
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -16,9 +16,12 @@ error[E0277]: the trait bound `fn(Extractor<()>) -> impl Future<Output = ()> {fo
note: required by a bound in `axum::routing::get` note: required by a bound in `axum::routing::get`
--> $WORKSPACE/axum/src/routing/method_routing.rs --> $WORKSPACE/axum/src/routing/method_routing.rs
| |
| H: Handler<T, S>,
| ^^^^^^^^^^^^^ required by this bound in `get`
...
| top_level_handler_fn!(get, GET); | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^ | -------------------------------
| | | | | |
| | required by a bound in this function | | required by a bound in this function
| required by this bound in `get` | in this macro invocation
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -16,28 +16,35 @@ error[E0277]: the trait bound `fn(MyExtractor) -> impl Future<Output = ()> {hand
note: required by a bound in `axum::routing::get` note: required by a bound in `axum::routing::get`
--> $WORKSPACE/axum/src/routing/method_routing.rs --> $WORKSPACE/axum/src/routing/method_routing.rs
| |
| H: Handler<T, S>,
| ^^^^^^^^^^^^^ required by this bound in `get`
...
| top_level_handler_fn!(get, GET); | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^ | -------------------------------
| | | | | |
| | required by a bound in this function | | required by a bound in this function
| required by this bound in `get` | in this macro invocation
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}: Handler<_, _>` is not satisfied error[E0277]: the trait bound `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}: Handler<_, _>` is not satisfied
--> tests/from_request/fail/override_rejection_on_enum_without_via.rs:10:64 --> tests/from_request/fail/override_rejection_on_enum_without_via.rs:10:64
| |
10 | let _: Router = Router::new().route("/", get(handler).post(handler_result)); 10 | let _: Router = Router::new().route("/", get(handler).post(handler_result));
| ---- ^^^^^^^^^^^^^^ the trait `Handler<_, _>` is not implemented for fn item `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}` | ---- ^^^^^^^^^^^^^^ unsatisfied trait bound
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: the trait `Handler<_, _>` is not implemented for fn item `fn(Result<MyExtractor, MyRejection>) -> impl Future<Output = ()> {handler_result}`
= note: Consider using `#[axum::debug_handler]` to improve the error message = note: Consider using `#[axum::debug_handler]` to improve the error message
note: required by a bound in `MethodRouter::<S>::post` note: required by a bound in `MethodRouter::<S>::post`
--> $WORKSPACE/axum/src/routing/method_routing.rs --> $WORKSPACE/axum/src/routing/method_routing.rs
| |
| H: Handler<T, S>,
| ^^^^^^^^^^^^^ required by this bound in `MethodRouter::<S>::post`
...
| chained_handler_fn!(post, POST); | chained_handler_fn!(post, POST);
| ^^^^^^^^^^^^^^^^^^^^----^^^^^^^ | -------------------------------
| | | | | |
| | required by a bound in this associated function | | required by a bound in this associated function
| required by this bound in `MethodRouter::<S>::post` | in this macro invocation
= note: this error originates in the macro `chained_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `chained_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -10,5 +10,9 @@ help: include the missing field in the pattern
| ++++++ | ++++++
help: if you don't care about this missing field, you can explicitly ignore it help: if you don't care about this missing field, you can explicitly ignore it
| |
5 | #[typed_path("/users" { id: _ })]
| +++++++++
help: or always ignore missing fields here
|
5 | #[typed_path("/users" { .. })] 5 | #[typed_path("/users" { .. })]
| ++++++ | ++++++
@@ -1,9 +1,39 @@
error[E0277]: the trait bound `MyPath: serde::de::DeserializeOwned` is not satisfied
--> tests/typed_path/fail/not_deserialize.rs:3:10
|
3 | #[derive(TypedPath)]
| ^^^^^^^^^ unsatisfied trait bound
|
help: the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`
--> tests/typed_path/fail/not_deserialize.rs:5:1
|
5 | struct MyPath {
| ^^^^^^^^^^^^^
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
&'a [u8]
&'a serde_json::raw::RawValue
&'a std::path::Path
&'a str
()
(T,)
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `MyPath` to implement `serde_core::de::DeserializeOwned`
= note: required for `axum::extract::Path<MyPath>` to implement `FromRequestParts<S>`
= note: this error originates in the derive macro `TypedPath` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MyPath: serde::Deserialize<'de>` is not satisfied error[E0277]: the trait bound `MyPath: serde::Deserialize<'de>` is not satisfied
--> tests/typed_path/fail/not_deserialize.rs:3:10 --> tests/typed_path/fail/not_deserialize.rs:3:10
| |
3 | #[derive(TypedPath)] 3 | #[derive(TypedPath)]
| ^^^^^^^^^ the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`, which is required by `axum::extract::Path<MyPath>: FromRequestParts<S>` | ^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`
--> tests/typed_path/fail/not_deserialize.rs:5:1
|
5 | struct MyPath {
| ^^^^^^^^^^^^^
= note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyPath` type = note: for local types consider adding `#[derive(serde::Deserialize)]` to your `MyPath` type
= note: for types from other crates check whether the crate offers a `serde` feature flag = note: for types from other crates check whether the crate offers a `serde` feature flag
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`: = help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
@@ -23,8 +53,13 @@ error[E0277]: the trait bound `MyPath: serde::de::DeserializeOwned` is not satis
--> tests/typed_path/fail/not_deserialize.rs:3:10 --> tests/typed_path/fail/not_deserialize.rs:3:10
| |
3 | #[derive(TypedPath)] 3 | #[derive(TypedPath)]
| ^^^^^^^^^ the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`, which is required by `axum::extract::Path<MyPath>: FromRequestParts<S>` | ^^^^^^^^^ unsatisfied trait bound
| |
help: the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`
--> tests/typed_path/fail/not_deserialize.rs:5:1
|
5 | struct MyPath {
| ^^^^^^^^^^^^^
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`: = help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
&'a [u8] &'a [u8]
&'a serde_json::raw::RawValue &'a serde_json::raw::RawValue
@@ -37,23 +72,3 @@ error[E0277]: the trait bound `MyPath: serde::de::DeserializeOwned` is not satis
and $N others and $N others
= note: required for `MyPath` to implement `serde_core::de::DeserializeOwned` = note: required for `MyPath` to implement `serde_core::de::DeserializeOwned`
= note: required for `axum::extract::Path<MyPath>` to implement `FromRequestParts<S>` = note: required for `axum::extract::Path<MyPath>` to implement `FromRequestParts<S>`
error[E0277]: the trait bound `MyPath: serde::de::DeserializeOwned` is not satisfied
--> tests/typed_path/fail/not_deserialize.rs:3:10
|
3 | #[derive(TypedPath)]
| ^^^^^^^^^ the trait `for<'de> serde_core::de::Deserialize<'de>` is not implemented for `MyPath`, which is required by `axum::extract::Path<MyPath>: FromRequestParts<S>`
|
= help: the following other types implement trait `serde_core::de::Deserialize<'de>`:
&'a [u8]
&'a serde_json::raw::RawValue
&'a std::path::Path
&'a str
()
(T,)
(T0, T1)
(T0, T1, T2)
and $N others
= note: required for `MyPath` to implement `serde_core::de::DeserializeOwned`
= note: required for `axum::extract::Path<MyPath>` to implement `FromRequestParts<S>`
= note: this error originates in the derive macro `TypedPath` (in Nightly builds, run with -Z macro-backtrace for more info)