From b14e8da9c8bebe830f1551fa8a9beb08877707d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20D=C4=85bek?= Date: Sat, 21 Aug 2021 19:46:04 +0200 Subject: [PATCH] Fix codegen issue for parameters with lifetimes This commit implements a workaround for an [issue within rustc]. The problem showed itself when using e.g. a `Vec<&str>` argument in an async route handler (but not `&str`), which resulted in a "implementation of `FromForm` is not general enough" error. The workaround itself works by gathering all invocations of `FromForm`'s methods inside a block without any `.await` points [ref]. [issue within rustc]: https://github.com/rust-lang/rust/issues/69663 [ref]: https://github.com/rust-lang/rust/issues/57478#issuecomment-501186084 --- core/codegen/src/attribute/route/mod.rs | 62 +++++++++++++------------ core/codegen/tests/async-routes.rs | 6 +++ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/core/codegen/src/attribute/route/mod.rs b/core/codegen/src/attribute/route/mod.rs index b162ff5af2..54f2cff087 100644 --- a/core/codegen/src/attribute/route/mod.rs +++ b/core/codegen/src/attribute/route/mod.rs @@ -75,37 +75,39 @@ fn query_decls(route: &Route) -> Option { #[allow(non_snake_case)] Some(quote! { - let mut __e = #_form::Errors::new(); - #(let mut #ident = #init_expr;)* - - for _f in #__req.query_fields() { - let _raw = (_f.name.source().as_str(), _f.value); - let _key = _f.name.key_lossy().as_str(); - match (_raw, _key) { - // Skip static parameters so doesn't see them. - #(((#raw_name, #raw_value), _) => { /* skip */ },)* - #((_, #matcher) => #push_expr,)* - _ => { /* in case we have no trailing, ignore all else */ }, + let (#(#ident),*) = { + let mut __e = #_form::Errors::new(); + #(let mut #ident = #init_expr;)* + + for _f in #__req.query_fields() { + let _raw = (_f.name.source().as_str(), _f.value); + let _key = _f.name.key_lossy().as_str(); + match (_raw, _key) { + // Skip static parameters so doesn't see them. + #(((#raw_name, #raw_value), _) => { /* skip */ },)* + #((_, #matcher) => #push_expr,)* + _ => { /* in case we have no trailing, ignore all else */ }, + } } - } - - #( - let #ident = match #finalize_expr { - #_Ok(_v) => #_Some(_v), - #_Err(_err) => { - __e.extend(_err.with_name(#_form::NameView::new(#name))); - #_None - }, - }; - )* - - if !__e.is_empty() { - #_log::warn_!("Query string failed to match route declaration."); - for _err in __e { #_log::warn_!("{}", _err); } - return #Outcome::Forward(#__data); - } - - #(let #ident = #ident.unwrap();)* + + #( + let #ident = match #finalize_expr { + #_Ok(_v) => #_Some(_v), + #_Err(_err) => { + __e.extend(_err.with_name(#_form::NameView::new(#name))); + #_None + }, + }; + )* + + if !__e.is_empty() { + #_log::warn_!("Query string failed to match route declaration."); + for _err in __e { #_log::warn_!("{}", _err); } + return #Outcome::Forward(#__data); + } + + (#(#ident.unwrap()),*) + }; }) } diff --git a/core/codegen/tests/async-routes.rs b/core/codegen/tests/async-routes.rs index 7354247d5d..3a9ff56416 100644 --- a/core/codegen/tests/async-routes.rs +++ b/core/codegen/tests/async-routes.rs @@ -12,6 +12,12 @@ async fn hello(_origin: &Origin<'_>) -> &'static str { "Hello, world!" } +#[get("/repeated_query?")] +async fn repeated_query(sort: Vec<&str>) -> &str { + noop().await; + sort[0] +} + #[catch(404)] async fn not_found(req: &Request<'_>) -> String { noop().await;