Allow return type of '#[launch]' fn to be elided.

This commit is contained in:
Sergio Benitez 2020-10-12 22:32:02 -07:00
parent 092e03f720
commit 2f330d2967
2 changed files with 35 additions and 9 deletions

View File

@ -7,7 +7,7 @@ trait EntryAttr {
const REQUIRES_ASYNC: bool; const REQUIRES_ASYNC: bool;
/// Return a new or rewritten function, using block as the main execution. /// Return a new or rewritten function, using block as the main execution.
fn function(f: &syn::ItemFn, body: &syn::Block) -> Result<TokenStream>; fn function(f: &mut syn::ItemFn) -> Result<TokenStream>;
} }
struct Main; struct Main;
@ -15,8 +15,8 @@ struct Main;
impl EntryAttr for Main { impl EntryAttr for Main {
const REQUIRES_ASYNC: bool = true; const REQUIRES_ASYNC: bool = true;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> { fn function(f: &mut syn::ItemFn) -> Result<TokenStream> {
let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone()); let (attrs, vis, block, sig) = (&f.attrs, &f.vis, &f.block, &mut f.sig);
if sig.ident != "main" { if sig.ident != "main" {
// FIXME(diag): warning! // FIXME(diag): warning!
Span::call_site() Span::call_site()
@ -37,8 +37,8 @@ struct Test;
impl EntryAttr for Test { impl EntryAttr for Test {
const REQUIRES_ASYNC: bool = true; const REQUIRES_ASYNC: bool = true;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> { fn function(f: &mut syn::ItemFn) -> Result<TokenStream> {
let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone()); let (attrs, vis, block, sig) = (&f.attrs, &f.vis, &f.block, &mut f.sig);
sig.asyncness = None; sig.asyncness = None;
Ok(quote_spanned!(block.span().into() => #(#attrs)* #[test] #vis #sig { Ok(quote_spanned!(block.span().into() => #(#attrs)* #[test] #vis #sig {
::rocket::async_test(async move #block) ::rocket::async_test(async move #block)
@ -51,7 +51,7 @@ struct Launch;
impl EntryAttr for Launch { impl EntryAttr for Launch {
const REQUIRES_ASYNC: bool = false; const REQUIRES_ASYNC: bool = false;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> { fn function(f: &mut syn::ItemFn) -> Result<TokenStream> {
if f.sig.ident == "main" { if f.sig.ident == "main" {
return Err(Span::call_site() return Err(Span::call_site()
.error("attribute cannot be applied to `main` function") .error("attribute cannot be applied to `main` function")
@ -59,6 +59,14 @@ impl EntryAttr for Launch {
.span_note(f.sig.ident.span(), "this function cannot be `main`")); .span_note(f.sig.ident.span(), "this function cannot be `main`"));
} }
// Always infer the type as `::rocket::Rocket`.
if let syn::ReturnType::Type(_, ref mut ty) = &mut f.sig.output {
if let syn::Type::Infer(_) = &mut **ty {
let new = quote_spanned!(ty.span() => ::rocket::Rocket);
*ty = syn::parse2(new).expect("path is type");
}
}
let ty = match &f.sig.output { let ty = match &f.sig.output {
syn::ReturnType::Type(_, ty) => ty, syn::ReturnType::Type(_, ty) => ty,
_ => return Err(Span::call_site() _ => return Err(Span::call_site()
@ -66,13 +74,13 @@ impl EntryAttr for Launch {
.span_note(f.sig.span(), "this function must return a value")) .span_note(f.sig.span(), "this function must return a value"))
}; };
let block = &f.block;
let rocket = quote_spanned!(ty.span().into() => { let rocket = quote_spanned!(ty.span().into() => {
let ___rocket: #ty = #block; let ___rocket: #ty = #block;
let ___rocket: ::rocket::Rocket = ___rocket; let ___rocket: ::rocket::Rocket = ___rocket;
___rocket ___rocket
}); });
// FIXME: Don't duplicate the `#block` here!
let (vis, mut sig) = (&f.vis, f.sig.clone()); let (vis, mut sig) = (&f.vis, f.sig.clone());
sig.ident = syn::Ident::new("main", sig.ident.span()); sig.ident = syn::Ident::new("main", sig.ident.span());
sig.output = syn::ReturnType::Default; sig.output = syn::ReturnType::Default;
@ -112,8 +120,8 @@ fn _async_entry<A: EntryAttr>(
_args: proc_macro::TokenStream, _args: proc_macro::TokenStream,
input: proc_macro::TokenStream input: proc_macro::TokenStream
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let function = parse_input::<A>(input)?; let mut function = parse_input::<A>(input)?;
A::function(&function, &function.block).map(|t| t.into()) A::function(&mut function).map(|t| t.into())
} }
macro_rules! async_entry { macro_rules! async_entry {

View File

@ -25,6 +25,15 @@ mod b {
} }
} }
mod b_inferred {
#[rocket::launch]
async fn main2() -> _ { rocket::ignite() }
async fn use_it() {
let rocket: rocket::Rocket = main2().await;
}
}
mod c { mod c {
// non-async launch. // non-async launch.
#[rocket::launch] #[rocket::launch]
@ -37,6 +46,15 @@ mod c {
} }
} }
mod c_inferred {
#[rocket::launch]
fn rocket() -> _ { rocket::ignite() }
fn use_it() {
let rocket: rocket::Rocket = rocket();
}
}
mod d { mod d {
// main with async, is async. // main with async, is async.
#[rocket::main] #[rocket::main]