Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error[E0425]: cannot find value rocket_param_id in this scope #635

Closed
Boscop opened this issue May 7, 2018 · 27 comments
Closed

error[E0425]: cannot find value rocket_param_id in this scope #635

Boscop opened this issue May 7, 2018 · 27 comments
Labels
deficiency Something doesn't work as well as it could triage A bug report being investigated

Comments

@Boscop
Copy link

Boscop commented May 7, 2018

After updating my nightly (from 03-06) I'm getting this error, any idea how to fix it?
error[E0425]: cannot find value rocket_param_id in this scope

image

This error happens only for my delete handler which is in a macro that's used 11 times, so I get the same error 11 times:

			#[post("/delete/<id>")]
			fn delete(me: Customer, id: i64) -> Res<()> {

The other handlers outside of macros, and even the other handlers inside macros but with only guard args and no url args don't cause any errors. E.g. this one is also inside the same macro but causes no error:

			#[post("/list")]
			fn list(me: Customer) -> Res<Vec<View>> {
@jebrosen
Copy link
Collaborator

jebrosen commented May 7, 2018

Can you make a simple reproducible test case? Since at least one and probably two different kinds of macros are involved I wouldn't want to try to guess what's happening here. For issues with the codegen, building with ROCKET_CODEGEN_DEBUG=1 can help reveal what's going on.

@Boscop
Copy link
Author

Boscop commented May 7, 2018

Thanks, with ROCKET_CODEGEN_DEBUG=1 it looks like this. Any idea why it's not working? :)

--> C:\Users\me\.cargo\git\checkouts\rocket-8bf16d9ca7e90bdc\3894e4e\codegen\src\decorators\route.rs:286
Route params: RouteParams { annotated_fn: Function(Spanned { node: (delete#0, FnDecl { inputs: [Arg { ty: type(Customer), pat: pat(4294967295: me), id: NodeId(4294967295) }, Arg { ty: type(i64), pat: pat(4294967295: id), id: NodeId(4294967295) }], output: Ty(type(Res<()>)), variadic: false }), span: Span { lo: BytePos(37053), hi: BytePos(37311), ctxt: #0 } }), method: Spanned { node: Post, span: Span { lo: BytePos(37028), hi: BytePos(37032), ctxt: #0 } }, uri: Spanned { node: Uri { uri: "/delete/<id>", path: (0, 12), query: None, fragment: None, segment_count: 2 }, span: Span { lo: BytePos(37035), hi: BytePos(37049), ctxt: #0 } }, data_param: None, query_param: None, format: None, rank: None }

--> C:\Users\me\.cargo\git\checkouts\rocket-8bf16d9ca7e90bdc\3894e4e\codegen\src\utils\mod.rs:56
Emitting item:
#[allow(unreachable_code)]
fn rocket_route_fn_delete<'_b>(__req: &'_b ::rocket::Request,
                               __data: ::rocket::Data)
 -> ::rocket::handler::Outcome<'_b> {
    #[allow(non_snake_case, unreachable_patterns)]
    let rocket_param_id: i64 =
        match match __req.get_param_str(0usize) {
                  Some(s) =>
                  <i64 as ::rocket::request::FromParam>::from_param(s),
                  None => return ::rocket::Outcome::Forward(__data),
              } {
            Ok(v) => v,
            Err(e) => {
                println!("    => Failed to parse '{}': {:?}" , stringify ! (
                         id ) , e);
                return ::rocket::Outcome::Forward(__data)
            }
        };
    #[allow(non_snake_case, unreachable_patterns)]
    let rocket_param_me: Customer =
        match ::rocket::request::FromRequest::from_request(__req) {
            ::rocket::Outcome::Success(v) => v,
            ::rocket::Outcome::Forward(_) =>
            return ::rocket::Outcome::Forward(__data),
            ::rocket::Outcome::Failure((code, _)) => {
                return ::rocket::Outcome::Failure(code)
            }
        };
    let responder = delete(rocket_param_me, rocket_param_id);
    ::rocket::handler::Outcome::from(__req, responder)
}

--> C:\Users\me\.cargo\git\checkouts\rocket-8bf16d9ca7e90bdc\3894e4e\codegen\src\utils\mod.rs:56
Emitting item:
/// Rocket code generated static route information structure.
#[allow(non_upper_case_globals)]
#[rocket_route_info]
pub static static_rocket_route_info_for_delete: ::rocket::StaticRouteInfo =
    ::rocket::StaticRouteInfo{name: "delete",
                              method: ::rocket::http::Method::Post,
                              path: "/delete/<id>",
                              handler: rocket_route_fn_delete,
                              format: None,
                              rank: None,};

--> C:\Users\me\.cargo\git\checkouts\rocket-8bf16d9ca7e90bdc\3894e4e\codegen\src\utils\mod.rs:56
Emitting item:
#[rocket_route(static_rocket_route_info_for_delete)]
fn delete(me: Customer, id: i64) -> Res<()> {
    jassert!(junwrap ! ( jtry ! ( Driver :: find ( id ) ) ) . customer_id ==
             me . user_id , "UNAUTHORIZED");
    jtry!(User :: delete ( id ));
    ok(())
}

--> C:\Users\me\.cargo\git\checkouts\rocket-8bf16d9ca7e90bdc\3894e4e\codegen\src\utils\mod.rs:56
Emitting item:
macro_rules! rocket_uri_for_delete(( $ ( $ token : tt ) * ) => {
                                   rocket_internal_uri ! (
                                   "/delete/<id>" , ( id : i64 ) , $ ( $ token
                                   ) * ) });

@SergioBenitez SergioBenitez added the triage A bug report being investigated label May 8, 2018
@Boscop
Copy link
Author

Boscop commented May 8, 2018

I really need to get this to work (for my job) asap.
Which more info would help?
I'm not sure which rev of 0.4.0-dev I was using with the nightly 03-06, but the checkout happened shortly after the "ring situation". And after I updated my nightly to the recent one, I got compile errors because of pear so I did cargo update -p pear pear_codegen and then I got compile errors for rocket so I did cargo update -p rocket (to the latest rev of 0.4.0-dev) which led me to this state.

Is there anything else I can try to get this to at least compile for now (without going back to nightly 03-06)?

@Boscop
Copy link
Author

Boscop commented May 8, 2018

Btw, for all the generated delete handlers it seems that the way rocket_param_id is used should work (it's in the same scope as the use location, so it should be found).
Btw, my macro looks like this:

macro_rules! gen_handler {
	($model:ident, $table:ident, $table_name:expr, [$($fkm:ident)*], {$($validate:meta $field:ident: $type:ty,)+}) => (
		pub mod $table {
			use rocket_contrib::Json;

			use controllers::*;
			use models::customer::Customer;
			use super::super::$table::{$model as Model, New, Update};
			use models::validation::validate;

			#[derive(Clone, Default, Deserialize)]
			#[serde(default)]
			pub struct Edit {
				pub id: Option<i64>,
				$(pub $field: $type,)+
			}

			#[post("/edit", data = "<body>")]
			pub fn edit(me: Customer, body: Json<Edit>) -> Res<()> {
				let req = body.into_inner();
				if let Some(id) = req.id {
					let model = junwrap!(jtry!(Model::find(id)));
					jassert!(model.customer_id == me.user_id, "UNAUTHORIZED"); // must be owner
					let mut update = Update::now();
					$(
						if req.$field != model.$field {
							update = update.$field(req.$field.clone());
						}
					)+
					let update = jtry_user!(validate(me.user_id, update));
					jtry!(model.update(&update));
				} else {
					let nu = New {
						customer_id: me.user_id,
						$($field: req.$field,)+
					};
					let nu = jtry_user!(validate(me.user_id, nu));
					jtry!(Model::create_from(nu));
				}
				jtry!(me.scale_data_changed());
				ok(())
			}

			#[post("/delete/<id>")]
			fn delete(me: Customer, id: i64) -> Res<()> {
				jassert!(junwrap!(jtry!(Model::find(id))).customer_id == me.user_id, "UNAUTHORIZED");
				jtry!(Model::delete(id));
				jtry!(me.scale_data_changed());
				ok(())
			}

			use $crate::models::views::$table::View;

			#[post("/list")]
			fn list(me: Customer) -> Res<Vec<View>> {
				ok(jtry!(Model::all_of_customer(me.user_id)).into_iter().map(|t| View::from(t)).collect())
			}
		}
	)
}

And it's called for a list of model structs through gen_all:

macro_rules! gen_all {
	($($model:ident, $table:ident, $table_name:expr, [$($fkm:ident)*], {$($validate:meta $field:ident: $type:ty,)+})+) => (
		pub mod handlers {
			$(gen_handler!($model, $table, $table_name, [$($fkm)*], { validate(custom = "allow") active: bool, $($validate $field: $type,)+ });)+
		}
		$(gen_orm!($model, $table, $table_name, [$($fkm)*], { validate(custom = "allow") active: bool, $($validate $field: $type,)+ });)+
		pub mod views {
			$(gen_view!($model, $table, $table_name, [$($fkm)*], { active: bool, $($field: $type,)+ });)+
		}
	)
}

And it all used to work perfectly before :)

@Boscop
Copy link
Author

Boscop commented May 8, 2018

Btw, these top-level functions (outside any macro) don't give an error:

#[post("/user-delete/<id>")]
fn delete(me: User, id: i64) -> Res<()> {
	if me.role == UserRole::Admin || me.role == UserRole::Customer && junwrap!(jtry!(Driver::find(id))).customer_id == me.id {
		jtry!(User::delete(id));
	}
	ok(())
}

// in a different module:

#[post("/delete/<id>")]
fn delete(me: Customer, id: i64) -> Res<()> {
	jassert!(junwrap!(jtry!(Driver::find(id))).customer_id == me.user_id, "UNAUTHORIZED");
	jtry!(User::delete(id));
	ok(())
}

Even though the generated code is basically the same as for the ones in the macro (with respect to rocket_param_id)..

@messense
Copy link
Sponsor Contributor

messense commented May 8, 2018

Try cargo-expand to view all generated code.

@Boscop
Copy link
Author

Boscop commented May 8, 2018

I tried it, but it shows nothing, probably because the compilation gives errors(?)

@messense
Copy link
Sponsor Contributor

messense commented May 8, 2018

Does cargo +nightly rustc -- -Z unstable-options --pretty=expanded work?

@jebrosen
Copy link
Collaborator

jebrosen commented May 8, 2018

Minimal test case, reproduced on rustc 1.27.0-nightly (428ea5f6b 2018-05-06) with rocket 0.3.10 :

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/<id>")]
fn works(id: i32) -> String {
    format!("id: {}", id)
}

macro_rules! make_handler {
    () => {
        #[get("/<id>")]
        fn fails(id: i32) -> String {
            format!("id: {}", id)
        }
    }
}

make_handler!();

fn main() {
    rocket::ignite().mount("/", routes![works, fails]).launch();
}

I thought macro hygiene could be involved in some way but have no idea how to even attempt to investigate that.

@Boscop
Copy link
Author

Boscop commented May 8, 2018

@messense No, it also doesn't output anything. (And I thought cargo expand is just a wrapper for that..)

@jebrosen Thanks! I hope we can get this to work soon again.. Btw, do you know which recent combination of a nightly and a rev on the 0.4.0-dev branch I can try to get it to work for now?

@messense
Copy link
Sponsor Contributor

messense commented May 8, 2018

The expanded code I got from @jebrosen 's code:

cargo +nightly rustc -- -Z unstable-options --pretty=expanded
#![feature(prelude_import)]
#![no_std]
#![feature(plugin)]
#![plugin(rocket_codegen)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;

extern crate rocket;

#[allow(unreachable_code)]
fn rocket_route_fn_works<'_b>(__req: &'_b ::rocket::Request,
                              __data: ::rocket::Data)
 -> ::rocket::handler::Outcome<'_b> {
    #[allow(non_snake_case, unreachable_patterns)]
    let rocket_param_id: i32 =
        match match __req.get_param_str(0usize) {
                  Some(s) =>
                  <i32 as ::rocket::request::FromParam>::from_param(s),
                  None => return ::rocket::Outcome::Forward(__data),
              } {
            Ok(v) => v,
            Err(e) => {



                ::io::_print(::std::fmt::Arguments::new_v1_formatted(&["    => Failed to parse \'",
                                                                       "\': ",
                                                                       "\n"],
                                                                     &match (&"id",
                                                                             &e)
                                                                          {
                                                                          (arg0,
                                                                           arg1)
                                                                          =>
                                                                          [::std::fmt::ArgumentV1::new(arg0,
                                                                                                       ::std::fmt::Display::fmt),
                                                                           ::std::fmt::ArgumentV1::new(arg1,
                                                                                                       ::std::fmt::Debug::fmt)],
                                                                      },
                                                                     &[::std::fmt::rt::v1::Argument{position:
                                                                                                        ::std::fmt::rt::v1::Position::At(0usize),
                                                                                                    format:
                                                                                                        ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                           ' ',
                                                                                                                                       align:
                                                                                                                                           ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                                       flags:
                                                                                                                                           0u32,
                                                                                                                                       precision:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,
                                                                                                                                       width:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,},},
                                                                       ::std::fmt::rt::v1::Argument{position:
                                                                                                        ::std::fmt::rt::v1::Position::At(1usize),
                                                                                                    format:
                                                                                                        ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                           ' ',
                                                                                                                                       align:
                                                                                                                                           ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                                       flags:
                                                                                                                                           0u32,
                                                                                                                                       precision:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,
                                                                                                                                       width:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,},}]));
                return ::rocket::Outcome::Forward(__data)
            }
        };
    let responder = works(rocket_param_id);
    ::rocket::handler::Outcome::from(__req, responder)
}
/// Rocket code generated static route information structure.
#[allow(non_upper_case_globals)]
#[rocket_route_info]
pub static static_rocket_route_info_for_works: ::rocket::StaticRouteInfo =
    ::rocket::StaticRouteInfo{method: ::rocket::http::Method::Get,
                              path: "/<id>",
                              handler: rocket_route_fn_works,
                              format: None,
                              rank: None,};
#[rocket_route(static_rocket_route_info_for_works)]
fn works(id: i32) -> String {
    ::fmt::format(::std::fmt::Arguments::new_v1_formatted(&["id: "],
                                                          &match (&id,) {
                                                               (arg0,) =>
                                                               [::std::fmt::ArgumentV1::new(arg0,
                                                                                            ::std::fmt::Display::fmt)],
                                                           },
                                                          &[::std::fmt::rt::v1::Argument{position:
                                                                                             ::std::fmt::rt::v1::Position::At(0usize),
                                                                                         format:
                                                                                             ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                ' ',
                                                                                                                            align:
                                                                                                                                ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                            flags:
                                                                                                                                0u32,
                                                                                                                            precision:
                                                                                                                                ::std::fmt::rt::v1::Count::Implied,
                                                                                                                            width:
                                                                                                                                ::std::fmt::rt::v1::Count::Implied,},}]))
}
macro_rules! make_handler((  ) => {
                          # [ get ( "/<id>" ) ] fn fails ( id : i32 ) ->
                          String { format ! ( "id: {}" , id ) } });
#[allow(unreachable_code)]
fn rocket_route_fn_fails<'_b>(__req: &'_b ::rocket::Request,
                              __data: ::rocket::Data)
 -> ::rocket::handler::Outcome<'_b> {
    #[allow(non_snake_case, unreachable_patterns)]
    let rocket_param_id: i32 =
        match match __req.get_param_str(0usize) {
                  Some(s) =>
                  <i32 as ::rocket::request::FromParam>::from_param(s),
                  None => return ::rocket::Outcome::Forward(__data),
              } {
            Ok(v) => v,
            Err(e) => {
                ::io::_print(::std::fmt::Arguments::new_v1_formatted(&["    => Failed to parse \'",
                                                                       "\': ",
                                                                       "\n"],
                                                                     &match (&"id",
                                                                             &e)
                                                                          {
                                                                          (arg0,
                                                                           arg1)
                                                                          =>
                                                                          [::std::fmt::ArgumentV1::new(arg0,
                                                                                                       ::std::fmt::Display::fmt),
                                                                           ::std::fmt::ArgumentV1::new(arg1,
                                                                                                       ::std::fmt::Debug::fmt)],
                                                                      },
                                                                     &[::std::fmt::rt::v1::Argument{position:
                                                                                                        ::std::fmt::rt::v1::Position::At(0usize),
                                                                                                    format:
                                                                                                        ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                           ' ',
                                                                                                                                       align:
                                                                                                                                           ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                                       flags:
                                                                                                                                           0u32,
                                                                                                                                       precision:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,
                                                                                                                                       width:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,},},
                                                                       ::std::fmt::rt::v1::Argument{position:
                                                                                                        ::std::fmt::rt::v1::Position::At(1usize),
                                                                                                    format:
                                                                                                        ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                           ' ',
                                                                                                                                       align:
                                                                                                                                           ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                                       flags:
                                                                                                                                           0u32,
                                                                                                                                       precision:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,
                                                                                                                                       width:
                                                                                                                                           ::std::fmt::rt::v1::Count::Implied,},}]));
                return ::rocket::Outcome::Forward(__data)
            }
        };
    let responder = fails(rocket_param_id);
    ::rocket::handler::Outcome::from(__req, responder)
}
/// Rocket code generated static route information structure.
#[allow(non_upper_case_globals)]
#[rocket_route_info]
pub static static_rocket_route_info_for_fails: ::rocket::StaticRouteInfo =
    ::rocket::StaticRouteInfo{method: ::rocket::http::Method::Get,
                              path: "/<id>",
                              handler: rocket_route_fn_fails,
                              format: None,
                              rank: None,};
#[rocket_route(static_rocket_route_info_for_fails)]
fn fails(id: i32) -> String {
    ::fmt::format(::std::fmt::Arguments::new_v1_formatted(&["id: "],
                                                          &match (&id,) {
                                                               (arg0,) =>
                                                               [::std::fmt::ArgumentV1::new(arg0,
                                                                                            ::std::fmt::Display::fmt)],
                                                           },
                                                          &[::std::fmt::rt::v1::Argument{position:
                                                                                             ::std::fmt::rt::v1::Position::At(0usize),
                                                                                         format:
                                                                                             ::std::fmt::rt::v1::FormatSpec{fill:
                                                                                                                                ' ',
                                                                                                                            align:
                                                                                                                                ::std::fmt::rt::v1::Alignment::Unknown,
                                                                                                                            flags:
                                                                                                                                0u32,
                                                                                                                            precision:
                                                                                                                                ::std::fmt::rt::v1::Count::Implied,
                                                                                                                            width:
                                                                                                                                ::std::fmt::rt::v1::Count::Implied,},}]))
}
fn main() {
    rocket::ignite().mount("/",
                           <[_]>::into_vec(box
                                               [::rocket::Route::from(&static_rocket_route_info_for_works),
                                                ::rocket::Route::from(&static_rocket_route_info_for_fails)])).launch();
}

@jebrosen
Copy link
Collaborator

jebrosen commented May 8, 2018

Compiling the expanded output of that test case works after minor tweaking, so I think there is some kind of namespace issue, macro_rules! hygiene or otherwise.

It's at https://ptpb.pw/IFyp , I added only the feature attributes and ::std prefixes necessary for it to compile.

@jebrosen
Copy link
Collaborator

jebrosen commented May 8, 2018

For this test case, rustc 1.27.0-nightly (ac3c2288f 2018-04-18) with rocket 0.3.8 works with the macro.
The next nightly that came out, after a week-long gap, is rustc 1.27.0-nightly (7f3444e1b 2018-04-26) with rocket 0.3.9, where the error message first occurs.

@messense
Copy link
Sponsor Contributor

messense commented May 8, 2018

@jebrosen Maybe we should report this issue to rust-lang/rust?

@jebrosen
Copy link
Collaborator

jebrosen commented May 8, 2018

I think reporting to the rust issue tracker would be appropriate, but I need to sleep now. I don't see anything obviously responsible in recent issues or PRs, but more eyes will help.

@Boscop
Copy link
Author

Boscop commented May 8, 2018

Thanks, I'm using nightly 04-18 with rev 3aefe4f for now..

@SergioBenitez
Copy link
Member

A PR recently landed that may have fixed this issue. Can anyone confirm? (@Boscop)

@jebrosen
Copy link
Collaborator

jebrosen commented Jul 2, 2018

New nightly builds haven't happened for a few days, but I had already built master this morning. It still apparently fails the test case I posted above, but I'd feel better testing with an official build and when I have time to check out the expansion in detail again.

@SergioBenitez
Copy link
Member

Can confirm that this is still broken on 2018-07-06.

@Boscop
Copy link
Author

Boscop commented Sep 14, 2018

I updated from nightly-2018-04-18 (and rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "3aefe4f" }) to nightly-2018-09-14 (and rocket = "0.3.16") but now I get this issue again :(

But I need to use nightly-2018-09-14 because of log4rs: estk/log4rs#75 (comment)

And I can't stay on the old nightly because sentry doesn't work with it..

So what should I do?

@jebrosen
Copy link
Collaborator

I found that "passing in" the identifier works:

macro_rules! make_handler {
    ($id:ident) => {
        #[get("/<id>")]
        fn now_works($id: i32) -> String {
            format!("id: {}", $id)
        }
    }
}

Unfortunately it has to be "passed in" from every layer of macro invocations all the way up to the original non-macro context and it's an ugly hack. In your case it looks like you would need at least the me, id, and body identifiers to be passed in this way.

I don't know how much effort we should put into solving on the Rocket side (or even rustc) given #693 -- a quick test I whipped up suggests that #[route] and #[catch] being proc_macros may even resolve this problem.

@Boscop
Copy link
Author

Boscop commented Sep 17, 2018

I don't know how much effort we should put into solving on the Rocket side (or even rustc)

@jebrosen Why shouldn't this be fixed in rustc? Generating rocket handlers is a valid use case (and very common in my projects).. This workaround makes the code even harder to read / follow, especially because it affects every macro in the call stack and the top-level invocation.


Btw, I tried your suggestion and it works, but it's weird that it was only required for the id arg of the delete() handler, not for the me or body args.
What makes id so special that it's the only arg that doesn't work normally?
Btw, this is my current code with the workaround, which compiles:

macro_rules! gen_handler {
	($id:ident, $model:ident, $table:ident, $table_name:expr, [$($fkm:ident)*], {$($validate:meta $field:ident: $type:ty,)+}) => (
		pub mod $table {
			use rocket_contrib::Json;
			use controllers::*;
			use models::customer::Customer;
			use super::super::$table::{$model as Model, New, Update};
			use models::validation::validate;

			#[derive(Clone, Default, Deserialize)]
			#[serde(default)]
			pub struct Edit {
				pub id: Option<i64>,
				$(pub $field: $type,)+
			}

			#[post("/edit", data = "<body>")]
			pub fn edit(me: Customer, body: Json<Edit>) -> Res<()> {
				let req = body.into_inner();
				if let Some(id) = req.id {
					let model = junwrap!(jtry!(Model::find(id)));
					jassert!(model.customer_id == me.user_id, "UNAUTHORIZED");
					let mut update = Update::now();
					$(
						if req.$field != model.$field {
							update = update.$field(req.$field.clone());
						}
					)+
					let update = jtry_user!(validate(me.user_id, update));
					jtry!(model.update(&update));
				} else {
					let nu = New {
						customer_id: me.user_id,
						$($field: req.$field,)+
					};
					let nu = jtry_user!(validate(me.user_id, nu));
					jtry!(Model::create_from(nu));
				}
				jtry!(me.scale_data_changed());
				ok(())
			}

			#[post("/delete/<id>")]
			fn delete(me: Customer, $id: i64) -> Res<()> {
				jassert!(junwrap!(jtry!(Model::find($id))).customer_id == me.user_id, "UNAUTHORIZED");
				jtry!(Model::delete($id));
				jtry!(me.scale_data_changed());
				ok(())
			}

			use $crate::models::views::$table::View;

			#[post("/list")]
			fn list(me: Customer) -> Res<Vec<View>> {
				ok(jtry!(Model::all_of_customer(me.user_id)).into_iter().map(|t| View::from(t)).collect())
			}
		}
	)
}


macro_rules! gen_all {
	($id:ident, $($model:ident, $table:ident, $table_name:expr, [$($fkm:ident)*], {$($validate:meta $field:ident: $type:ty,)+})+) => (
		pub mod handlers {
			$(gen_handler!($id, $model, $table, $table_name, [$($fkm)*], { validate(custom = "allow") active: bool, $($validate $field: $type,)+ });)+
		}
		$(gen_orm!($model, $table, $table_name, [$($fkm)*], { validate(custom = "allow") active: bool, $($validate $field: $type,)+ });)+
		pub mod views {
			$(gen_view!($model, $table, $table_name, [$($fkm)*], { active: bool, $($field: $type,)+ });)+
		}
	)
}

@jebrosen
Copy link
Collaborator

@jebrosen Why shouldn't this be fixed in rustc?

rustc is discouraging the use of and trying to remove some of the compiler features this issue involves (syntax extensions through compiler plugins, that is). When Rocket moves from the deprecated plugin architecture to proc_macros, this issue may go away on its own. If it's still an issue then, then it will be a bug in rustc in a supported and even (partially) stabilized feature, rather than a deprecated and discouraged feature.

Btw, I tried your suggestion and it works, but it's weird that it was only required for the id arg of the delete() handler, not for the me or body args.

I completely overlooked that detail. Is everything fine if you give it a different name like oid or obj_id?

@Boscop
Copy link
Author

Boscop commented Sep 24, 2018

@jebrosen Unfortunately, no:

error[E0425]: cannot find value rocket_param_oid in this scope

@jebrosen
Copy link
Collaborator

Btw, I tried your suggestion and it works, but it's weird that it was only required for the id arg of the delete() handler, not for the me or body args.
What makes id so special that it's the only arg that doesn't work normally?

I finally got around to taking a serious look at the codegen and have a pretty solid guess: id is implemented via FromParam; the other two are FromRequest and FromData.

This also gave me an idea of how to fix it, which appears to work pending further tests. Currently the ident rocket_param_... is derived from the route parameter string given in the route attribute. Deriving the ident from the function parameter itself seems to work.

I'm sorry I didn't look at this more closely before -- I must admit I was afraid to actually look at the syntax plugin code back then.

diff --git a/core/codegen/src/decorators/route.rs b/core/codegen/src/decorators/route.rs
index e1b4538..c86ba2b 100644
--- a/core/codegen/src/decorators/route.rs
+++ b/core/codegen/src/decorators/route.rs
@@ -8,7 +8,7 @@ use utils::*;
 
 use syntax::source_map::{Span, Spanned, dummy_spanned};
 use syntax::tokenstream::TokenTree;
-use syntax::ast::{Arg, Ident, Item, Stmt, Expr, MetaItem, Path};
+use syntax::ast::{Arg, Ident, Item, Stmt, Expr, MetaItem, Path, PatKind};
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
@@ -134,7 +134,8 @@ impl RouteParams {
         let mut declared_set = HashSet::new();
         for (i, param) in params.iter().enumerate() {
             declared_set.insert(param.ident().name);
-            let ty = match self.annotated_fn.find_input(&param.ident().name) {
+            let input = self.annotated_fn.find_input(&param.ident().name);
+            let ty = match input {
                 Some(arg) => strip_ty_lifetimes(arg.ty.clone()),
                 None => {
                     self.missing_declared_err(ecx, param.inner());
@@ -142,8 +143,12 @@ impl RouteParams {
                 }
             };
 
+            let ident = match input.unwrap().pat.node {
+                PatKind::Ident(_, i, _) => i.prepend(PARAM_PREFIX),
+                _ => param.ident().prepend(PARAM_PREFIX),
+            };
+
             // Note: the `None` case shouldn't happen if a route is matched.
-            let ident = param.ident().prepend(PARAM_PREFIX);
             let expr = match *param {
                 Param::Single(_) => quote_expr!(ecx, match __req.get_param_str($i) {
                     Some(s) => <$ty as ::rocket::request::FromParam>::from_param(s),

I haven't verified it against anything more complex than the reproduction test I posted above, but I think this approach may be viable for inclusion in a v0.3 patch release -- @SergioBenitez ?

@SergioBenitez
Copy link
Member

@jebrosen Nice work! Happy to include that in a patch release.

@jebrosen jebrosen added deficiency Something doesn't work as well as it could and removed upstream An unresolvable issue: an upstream dependency bug labels Sep 26, 2018
@SergioBenitez
Copy link
Member

@Boscop Rocket v0.3.17, containing @jebrosen's patch, has been released. Can you confirm that this resolves the issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deficiency Something doesn't work as well as it could triage A bug report being investigated
Projects
None yet
Development

No branches or pull requests

4 participants