From 592e441de5062a3e3a122a578c2896ff720b6caa Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 9 Sep 2019 21:06:55 -0700 Subject: [PATCH] Use proper span in responder codegen output. --- core/codegen/src/attribute/route.rs | 24 +++++++- core/codegen/src/lib.rs | 56 ++++++++++++------- core/codegen/tests/ui-fail/responder-types.rs | 6 ++ .../tests/ui-fail/responder-types.stderr | 38 ++++++++----- 4 files changed, 85 insertions(+), 39 deletions(-) diff --git a/core/codegen/src/attribute/route.rs b/core/codegen/src/attribute/route.rs index f846a678..6f7763f6 100644 --- a/core/codegen/src/attribute/route.rs +++ b/core/codegen/src/attribute/route.rs @@ -356,6 +356,24 @@ fn generate_internal_uri_macro(route: &Route) -> TokenStream2 { } } +fn generate_respond_expr(route: &Route) -> TokenStream2 { + let ret_span = match route.function.sig.output { + syn::ReturnType::Default => route.function.sig.ident.span(), + syn::ReturnType::Type(_, ref ty) => ty.span().into() + }; + + define_vars_and_mods!(req); + define_vars_and_mods!(ret_span => handler); + let user_handler_fn_name = &route.function.sig.ident; + let parameter_names = route.inputs.iter() + .map(|(_, rocket_ident, _)| rocket_ident); + + quote_spanned! { ret_span => + let ___responder = #user_handler_fn_name(#(#parameter_names),*); + #handler::Outcome::from(#req, ___responder) + } +} + fn codegen_route(route: Route) -> Result { // Generate the declarations for path, data, and request guard parameters. let mut data_stmt = None; @@ -389,8 +407,9 @@ fn codegen_route(route: Route) -> Result { let user_handler_fn_name = &user_handler_fn.sig.ident; let generated_fn_name = user_handler_fn_name.prepend(ROUTE_FN_PREFIX); let generated_struct_name = user_handler_fn_name.prepend(ROUTE_STRUCT_PREFIX); - let parameter_names = route.inputs.iter().map(|(_, rocket_ident, _)| rocket_ident); let generated_internal_uri_macro = generate_internal_uri_macro(&route); + let generated_respond_expr = generate_respond_expr(&route); + let method = route.attribute.method; let path = route.attribute.path.origin.0.to_string(); let rank = Optional(route.attribute.rank); @@ -408,8 +427,7 @@ fn codegen_route(route: Route) -> Result { #(#parameter_definitions)* #data_stmt - let ___responder = #user_handler_fn_name(#(#parameter_names),*); - #handler::Outcome::from(#req, ___responder) + #generated_respond_expr } /// Rocket code generated wrapping URI macro. diff --git a/core/codegen/src/lib.rs b/core/codegen/src/lib.rs index 87a8f859..0e6d18b6 100644 --- a/core/codegen/src/lib.rs +++ b/core/codegen/src/lib.rs @@ -64,30 +64,44 @@ extern crate proc_macro; use rocket_http as http; -macro_rules! define { - ($val:path as $v:ident) => (#[allow(non_snake_case)] let $v = quote!($val);); +macro_rules! vars_and_mods { + ($($name:ident => $path:path,)*) => { + macro_rules! define { + // Note: the `o` is to capture the input's span + $(($i:ident $name) => { + #[allow(non_snake_case)] let $i = quote!($path); + };)* + $(($span:expr => $i:ident $name) => { + #[allow(non_snake_case)] let $i = quote_spanned!($span => $path); + };)* + } + } +} + +vars_and_mods! { + req => __req, + catcher => __catcher, + data => __data, + error => __error, + trail => __trail, + request => rocket::request, + response => rocket::response, + handler => rocket::handler, + log => rocket::logger, + Outcome => rocket::Outcome, + FromData => rocket::data::FromData, + Transform => rocket::data::Transform, + Query => rocket::request::Query, + Request => rocket::Request, + Response => rocket::response::Response, + Data => rocket::Data, + StaticRouteInfo => rocket::StaticRouteInfo, + SmallVec => rocket::http::private::SmallVec, } macro_rules! define_vars_and_mods { - (@req as $v:ident) => (define!(__req as $v)); - (@catcher as $v:ident) => (define!(__catcher as $v)); - (@data as $v:ident) => (define!(__data as $v)); - (@error as $v:ident) => (define!(__error as $v)); - (@trail as $v:ident) => (define!(__trail as $v)); - (@request as $v:ident) => (define!(::rocket::request as $v)); - (@response as $v:ident) => (define!(::rocket::response as $v)); - (@handler as $v:ident) => (define!(::rocket::handler as $v)); - (@log as $v:ident) => (define!(::rocket::logger as $v)); - (@Outcome as $v:ident) => (define!(::rocket::Outcome as $v)); - (@FromData as $v:ident) => (define!(::rocket::data::FromData as $v)); - (@Transform as $v:ident) => (define!(::rocket::data::Transform as $v)); - (@Query as $v:ident) => (define!(::rocket::request::Query as $v)); - (@Request as $v:ident) => (define!(::rocket::Request as $v)); - (@Response as $v:ident) => (define!(::rocket::response::Response as $v)); - (@Data as $v:ident) => (define!(::rocket::Data as $v)); - (@StaticRouteInfo as $v:ident) => (define!(::rocket::StaticRouteInfo as $v)); - (@SmallVec as $v:ident) => (define!(::rocket::http::private::SmallVec as $v)); - ($($name:ident),*) => ($(define_vars_and_mods!(@$name as $name);)*) + ($($name:ident),*) => ($(define!($name $name);)*); + ($span:expr => $($name:ident),*) => ($(define!($span => $name $name);)*) } #[macro_use] diff --git a/core/codegen/tests/ui-fail/responder-types.rs b/core/codegen/tests/ui-fail/responder-types.rs index 14e73fda..a08dcb97 100644 --- a/core/codegen/tests/ui-fail/responder-types.rs +++ b/core/codegen/tests/ui-fail/responder-types.rs @@ -1,6 +1,8 @@ // normalize-stderr-test: "<(.*) as (.*)>" -> "$1 as $$TRAIT" // normalize-stderr-test: "and \d+ others" -> "and $$N others" +#![feature(proc_macro_hygiene)] + #[macro_use] extern crate rocket; #[derive(Responder)] @@ -32,4 +34,8 @@ struct Thing4 { //~^ ERROR Header } +#[get("/")] +fn foo() -> usize { 0 } +//~^ ERROR Responder + fn main() { } diff --git a/core/codegen/tests/ui-fail/responder-types.stderr b/core/codegen/tests/ui-fail/responder-types.stderr index 884153e5..dd778c1c 100644 --- a/core/codegen/tests/ui-fail/responder-types.stderr +++ b/core/codegen/tests/ui-fail/responder-types.stderr @@ -1,15 +1,15 @@ error[E0277]: the trait bound `u8: rocket::response::Responder<'_>` is not satisfied - --> $DIR/responder-types.rs:8:5 - | -8 | thing: u8, - | ^^^^^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `u8` - | - = note: required by `rocket::response::Responder::respond_to` + --> $DIR/responder-types.rs:10:5 + | +10 | thing: u8, + | ^^^^^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `u8` + | + = note: required by `rocket::response::Responder::respond_to` error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From` is not satisfied - --> $DIR/responder-types.rs:15:5 + --> $DIR/responder-types.rs:17:5 | -15 | other: u8, +17 | other: u8, | ^^^^^^^^^ the trait `std::convert::From` is not implemented for `rocket::http::Header<'_>` | = help: the following implementations were found: @@ -21,17 +21,17 @@ error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From` = note: required because of the requirements on the impl of `std::convert::Into>` for `u8` error[E0277]: the trait bound `u8: rocket::response::Responder<'_>` is not satisfied - --> $DIR/responder-types.rs:21:5 + --> $DIR/responder-types.rs:23:5 | -21 | thing: u8, +23 | thing: u8, | ^^^^^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `u8` | = note: required by `rocket::response::Responder::respond_to` error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From` is not satisfied - --> $DIR/responder-types.rs:23:5 + --> $DIR/responder-types.rs:25:5 | -23 | other: u8, +25 | other: u8, | ^^^^^^^^^ the trait `std::convert::From` is not implemented for `rocket::http::Header<'_>` | = help: the following implementations were found: @@ -43,9 +43,9 @@ error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From` = note: required because of the requirements on the impl of `std::convert::Into>` for `u8` error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From` is not satisfied - --> $DIR/responder-types.rs:31:5 + --> $DIR/responder-types.rs:33:5 | -31 | then: String, +33 | then: String, | ^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `rocket::http::Header<'_>` | = help: the following implementations were found: @@ -56,6 +56,14 @@ error[E0277]: the trait bound `rocket::http::Header<'_>: std::convert::From>` for `std::string::String` -error: aborting due to 5 previous errors +error[E0277]: the trait bound `usize: rocket::response::Responder<'_>` is not satisfied + --> $DIR/responder-types.rs:38:13 + | +38 | fn foo() -> usize { 0 } + | ^^^^^ the trait `rocket::response::Responder<'_>` is not implemented for `usize` + | + = note: required by `rocket::handler::, rocket::http::Status, rocket::Data>>::from` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`.