@@ -19,6 +19,8 @@ use syn::punctuated::Punctuated;
1919use syn:: spanned:: Spanned ;
2020use syn:: * ;
2121
22+ use crate :: visit_mut:: VisitMut ;
23+
2224/// An attribute macro designed to eliminate boilerplate code.
2325///
2426/// This macro automatically creates a span for the annotated function. The span name defaults to
@@ -124,14 +126,13 @@ pub fn trace(
124126
125127 let args = parse_macro_input ! ( args as Args ) ;
126128 let input = parse_macro_input ! ( item as ItemFn ) ;
127-
128129 let func_name = input. sig . ident . to_string ( ) ;
129- // check for async_trait-like patterns in the block, and instrument
130- // the future instead of the wrapper
130+
131+ // Check for async_trait-like patterns in the block, and instrument
132+ // the future instead of the wrapper.
131133 let func_body = if let Some ( internal_fun) =
132134 get_async_trait_info ( & input. block , input. sig . asyncness . is_some ( ) )
133135 {
134- // let's rewrite some statements!
135136 match internal_fun. kind {
136137 // async-trait <= 0.1.43
137138 AsyncTraitKind :: Function => {
@@ -141,23 +142,26 @@ pub fn trace(
141142 }
142143 // async-trait >= 0.1.44
143144 AsyncTraitKind :: Async ( async_expr) => {
144- // fallback if we couldn't find the '__async_trait' binding, might be
145- // useful for crates exhibiting the same behaviors as async-trait
146145 let instrumented_block =
147- gen_block ( & func_name, & async_expr. block , true , false , & args) ;
146+ gen_block ( & func_name, & async_expr. block , true , false , & args, None ) ;
148147 let async_attrs = & async_expr. attrs ;
149148 quote:: quote! {
150149 Box :: pin( #( #async_attrs) * #instrumented_block)
151150 }
152151 }
153152 }
154153 } else {
154+ let output_ty = match input. sig . output {
155+ ReturnType :: Type ( _, ref ty) => ( * * ty) . clone ( ) ,
156+ ReturnType :: Default => parse_quote ! { ( ) } ,
157+ } ;
155158 gen_block (
156159 & func_name,
157160 & input. block ,
158161 input. sig . asyncness . is_some ( ) ,
159162 input. sig . asyncness . is_some ( ) ,
160163 & args,
164+ Some ( output_ty) ,
161165 )
162166 } ;
163167
@@ -371,10 +375,14 @@ fn gen_block(
371375 async_context : bool ,
372376 async_keyword : bool ,
373377 args : & Args ,
378+ output_ty : Option < Type > ,
374379) -> proc_macro2:: TokenStream {
375380 let name = gen_name ( block. span ( ) , func_name, args) ;
376381 let properties = gen_properties ( block. span ( ) , args) ;
377382 let crate_path = & args. crate_path ;
383+ let output_ty_hint = output_ty
384+ . map ( erase_impl_trait)
385+ . unwrap_or_else ( || parse_quote ! { _ } ) ;
378386
379387 // Generate the instrumented function body.
380388 // If the function is an `async fn`, this will wrap it in an async block.
@@ -392,7 +400,10 @@ fn gen_block(
392400 {
393401 let __span__ = #crate_path:: Span :: enter_with_local_parent( #name ) #properties;
394402 #crate_path:: future:: FutureExt :: in_span(
395- async move { #block } ,
403+ async move {
404+ let __ret__: #output_ty_hint = #block;
405+ __ret__
406+ } ,
396407 __span__,
397408 )
398409 }
@@ -547,3 +558,25 @@ fn path_to_string(path: &Path) -> String {
547558 }
548559 res
549560}
561+
562+ /// Replaces any `impl Trait` with `_` so it can be used as the type in
563+ /// a `let` statement's LHS.
564+ struct ImplTraitEraser ;
565+
566+ impl VisitMut for ImplTraitEraser {
567+ fn visit_type_mut ( & mut self , t : & mut Type ) {
568+ if let Type :: ImplTrait ( ..) = t {
569+ * t = syn:: TypeInfer {
570+ underscore_token : Token ! [ _] ( t. span ( ) ) ,
571+ }
572+ . into ( ) ;
573+ } else {
574+ syn:: visit_mut:: visit_type_mut ( self , t) ;
575+ }
576+ }
577+ }
578+
579+ fn erase_impl_trait ( mut ty : Type ) -> Type {
580+ ImplTraitEraser . visit_type_mut ( & mut ty) ;
581+ ty
582+ }
0 commit comments