Make references to core types absolute in codegen.

Prior to this commit, codegen emitted tokens containing bare types like
'Result' and 'Box' as well as presumed imported variants such as 'None'
and 'Ok'.  However, users are free to shadow these, and if they do, the
generated code will fail to compile, or worse, be incorrect. To avoid
this, this commit makes all references to these core types and imports
absolute.
This commit is contained in:
Sergio Benitez 2020-02-06 21:04:01 -08:00
parent d0bfd8a3bb
commit 9f0e02fe27
6 changed files with 41 additions and 30 deletions

View File

@ -127,7 +127,7 @@ fn parse_route(attr: RouteAttribute, function: syn::ItemFn) -> Result<Route> {
}
fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
define_vars_and_mods!(req, data, error, log, request, Outcome);
define_vars_and_mods!(req, data, error, log, request, _None, _Some, _Ok, _Err, Outcome);
let i = seg.index.expect("dynamic parameters must be indexed");
let span = ident.span().unstable().join(ty.span()).unwrap().into();
let name = ident.to_string();
@ -149,20 +149,20 @@ fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream2
let expr = match seg.kind {
Kind::Single => quote_spanned! { span =>
match #req.raw_segment_str(#i) {
Some(__s) => match <#ty as #request::FromParam>::from_param(__s) {
Ok(__v) => __v,
Err(#error) => return #parse_error,
#_Some(__s) => match <#ty as #request::FromParam>::from_param(__s) {
#_Ok(__v) => __v,
#_Err(#error) => return #parse_error,
},
None => return #internal_error
#_None => return #internal_error
}
},
Kind::Multi => quote_spanned! { span =>
match #req.raw_segments(#i) {
Some(__s) => match <#ty as #request::FromSegments>::from_segments(__s) {
Ok(__v) => __v,
Err(#error) => return #parse_error,
#_Some(__s) => match <#ty as #request::FromSegments>::from_segments(__s) {
#_Ok(__v) => __v,
#_Err(#error) => return #parse_error,
},
None => return #internal_error
#_None => return #internal_error
}
},
Kind::Static => return quote!()
@ -204,6 +204,7 @@ fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
}
fn query_exprs(route: &Route) -> Option<TokenStream2> {
define_vars_and_mods!(_None, _Some, _Ok, _Err, _Option);
define_vars_and_mods!(data, trail, log, request, req, Outcome, SmallVec, Query);
let query_segments = route.attribute.path.query.as_ref()?;
let (mut decls, mut matchers, mut builders) = (vec![], vec![], vec![]);
@ -224,7 +225,7 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
let decl = match segment.kind {
Kind::Single => quote_spanned! { span =>
#[allow(non_snake_case)]
let mut #ident: Option<#ty> = None;
let mut #ident: #_Option<#ty> = #_None;
},
Kind::Multi => quote_spanned! { span =>
#[allow(non_snake_case)]
@ -238,14 +239,14 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
(_, #name, __v) => {
#[allow(unreachable_patterns, unreachable_code)]
let __v = match <#ty as #request::FromFormValue>::from_form_value(__v) {
Ok(__v) => __v,
Err(__e) => {
#_Ok(__v) => __v,
#_Err(__e) => {
#log::warn_(&format!("Failed to parse '{}': {:?}", #name, __e));
return #Outcome::Forward(#data);
}
};
#ident = Some(__v);
#ident = #_Some(__v);
}
},
Kind::Static => quote! {
@ -260,8 +261,8 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
Kind::Single => quote_spanned! { span =>
#[allow(non_snake_case)]
let #ident = match #ident.or_else(<#ty as #request::FromFormValue>::default) {
Some(__v) => __v,
None => {
#_Some(__v) => __v,
#_None => {
#log::warn_(&format!("Missing required query parameter '{}'.", #name));
return #Outcome::Forward(#data);
}
@ -270,8 +271,8 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
Kind::Multi => quote_spanned! { span =>
#[allow(non_snake_case)]
let #ident = match <#ty as #request::FromQuery>::from_query(#Query(&#trail)) {
Ok(__v) => __v,
Err(__e) => {
#_Ok(__v) => __v,
#_Err(__e) => {
#log::warn_(&format!("Failed to parse '{}': {:?}", #name, __e));
return #Outcome::Forward(#data);
}
@ -289,7 +290,7 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
Some(quote! {
#(#decls)*
if let Some(__items) = #req.raw_query_items() {
if let #_Some(__items) = #req.raw_query_items() {
for __i in __items {
match (__i.raw.as_str(), __i.key.as_str(), __i.value) {
#(

View File

@ -82,6 +82,7 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream {
}
})
.try_map_fields(move |_, fields| {
define_vars_and_mods!(_None, _Some, _Ok, _Err);
let (constructors, matchers, builders) = fields.iter().map(|field| {
let (ident, span) = (&field.ident, field.span().into());
let default_name = ident.as_ref().expect("named").to_string();
@ -94,10 +95,10 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream {
span => <#ty as ::rocket::request::FromFormValue>
};
let constructor = quote_spanned!(span => let mut #ident = None;);
let constructor = quote_spanned!(span => let mut #ident = #_None;);
let matcher = quote_spanned! { span =>
#name => { #ident = Some(#ty::from_form_value(__v)
#name => { #ident = #_Some(#ty::from_form_value(__v)
.map_err(|_| #form_error::BadValue(__k, __v))?); },
};
@ -116,13 +117,13 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream {
match __k.as_str() {
#(#matchers)*
_ if __strict && __k != "_method" => {
return Err(#form_error::Unknown(__k, __v));
return #_Err(#form_error::Unknown(__k, __v));
}
_ => { /* lenient or "method"; let it pass */ }
}
}
Ok(Self { #(#builders)* })
#_Ok(Self { #(#builders)* })
})
})
.to_tokens()

View File

@ -7,6 +7,7 @@ struct Form {
}
pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
define_vars_and_mods!(_Ok, _Err, _Result);
DeriveGenerator::build_for(input, quote!(impl<'__v> ::rocket::request::FromFormValue<'__v>))
.generic_support(GenericSupport::None)
.data_support(DataSupport::Enum)
@ -25,19 +26,19 @@ pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
Ok(())
})
.function(|_, inner| quote! {
.function(move |_, inner| quote! {
type Error = &'__v ::rocket::http::RawStr;
fn from_form_value(
value: &'__v ::rocket::http::RawStr
) -> ::std::result::Result<Self, Self::Error> {
) -> #_Result<Self, Self::Error> {
let uncased = value.as_uncased_str();
#inner
::std::result::Result::Err(value)
#_Err(value)
}
})
.try_map_enum(null_enum_mapper)
.try_map_variant(|_, variant| {
.try_map_variant(move |_, variant| {
let variant_str = Form::from_attrs("form", &variant.attrs)
.unwrap_or_else(|| Ok(Form { value: variant.ident.to_string() }))?
.value;
@ -45,7 +46,7 @@ pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
let builder = variant.builder(|_| unreachable!());
Ok(quote! {
if uncased == #variant_str {
return ::std::result::Result::Ok(#builder);
return #_Ok(#builder);
}
})
})

View File

@ -38,6 +38,7 @@ pub fn derive_responder(input: TokenStream) -> TokenStream {
}
})
.try_map_fields(|_, fields| {
define_vars_and_mods!(_Ok);
fn set_header_tokens<T: ToTokens + Spanned>(item: T) -> TokenStream2 {
quote_spanned!(item.span().into() => __res.set_header(#item);)
}
@ -74,7 +75,7 @@ pub fn derive_responder(input: TokenStream) -> TokenStream {
#(#headers)*
#content_type
#status
Ok(__res)
#_Ok(__res)
})
})
.to_tokens()

View File

@ -235,9 +235,10 @@ impl FromMeta for RoutePath {
impl<T: ToTokens> ToTokens for Optional<T> {
fn to_tokens(&self, tokens: &mut TokenStream2) {
define_vars_and_mods!(_Some, _None);
let opt_tokens = match self.0 {
Some(ref val) => quote!(Some(#val)),
None => quote!(None)
Some(ref val) => quote!(#_Some(#val)),
None => quote!(#_None)
};
tokens.extend(opt_tokens);

View File

@ -96,6 +96,12 @@ vars_and_mods! {
Data => rocket::Data,
StaticRouteInfo => rocket::StaticRouteInfo,
SmallVec => rocket::http::private::SmallVec,
_Option => ::std::option::Option,
_Result => ::std::result::Result,
_Some => ::std::option::Option::Some,
_None => ::std::option::Option::None,
_Ok => ::std::result::Result::Ok,
_Err => ::std::result::Result::Err,
}
macro_rules! define_vars_and_mods {