@@ -2,10 +2,11 @@ use std::iter;
22
33use proc_macro2:: TokenStream ;
44use quote:: { quote, quote_spanned, ToTokens } ;
5+ use syn:: visit_mut:: VisitMut ;
56use syn:: {
67 punctuated:: Punctuated , spanned:: Spanned , Block , Expr , ExprAsync , ExprCall , FieldPat , FnArg ,
78 Ident , Item , ItemFn , Pat , PatIdent , PatReference , PatStruct , PatTuple , PatTupleStruct , PatType ,
8- Path , Signature , Stmt , Token , TypePath ,
9+ Path , ReturnType , Signature , Stmt , Token , Type , TypePath ,
910} ;
1011
1112use crate :: {
@@ -18,7 +19,7 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
1819 input : MaybeItemFnRef < ' a , B > ,
1920 args : InstrumentArgs ,
2021 instrumented_function_name : & str ,
21- self_type : Option < & syn :: TypePath > ,
22+ self_type : Option < & TypePath > ,
2223) -> proc_macro2:: TokenStream {
2324 // these are needed ahead of time, as ItemFn contains the function body _and_
2425 // isn't representable inside a quote!/quote_spanned! macro
@@ -31,7 +32,7 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
3132 } = input;
3233
3334 let Signature {
34- output : return_type ,
35+ output,
3536 inputs : params,
3637 unsafety,
3738 asyncness,
@@ -49,8 +50,34 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
4950
5051 let warnings = args. warnings ( ) ;
5152
53+ let block = if let ReturnType :: Type ( _, return_type) = & output {
54+ let return_type = erase_impl_trait ( return_type) ;
55+ // Install a fake return statement as the first thing in the function
56+ // body, so that we eagerly infer that the return type is what we
57+ // declared in the async fn signature.
58+ let fake_return_edge = quote_spanned ! { return_type. span( ) =>
59+ #[ allow( unreachable_code) ]
60+ if false {
61+ let __tracing_attr_fake_return: #return_type = panic!( ) ;
62+ return __tracing_attr_fake_return;
63+ }
64+ } ;
65+ quote ! {
66+ {
67+ #fake_return_edge
68+ #block
69+ }
70+ }
71+ } else {
72+ quote ! {
73+ {
74+ let _: ( ) = #block;
75+ }
76+ }
77+ } ;
78+
5279 let body = gen_block (
53- block,
80+ & block,
5481 params,
5582 asyncness. is_some ( ) ,
5683 args,
@@ -60,7 +87,7 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
6087
6188 quote ! (
6289 #( #attrs) *
63- #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>( #params) #return_type
90+ #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>( #params) #output
6491 #where_clause
6592 {
6693 #warnings
@@ -76,7 +103,7 @@ fn gen_block<B: ToTokens>(
76103 async_context : bool ,
77104 mut args : InstrumentArgs ,
78105 instrumented_function_name : & str ,
79- self_type : Option < & syn :: TypePath > ,
106+ self_type : Option < & TypePath > ,
80107) -> proc_macro2:: TokenStream {
81108 // generate the span's name
82109 let span_name = args
@@ -393,11 +420,11 @@ impl RecordType {
393420 "Wrapping" ,
394421 ] ;
395422
396- /// Parse `RecordType` from [syn:: Type] by looking up
423+ /// Parse `RecordType` from [Type] by looking up
397424 /// the [RecordType::TYPES_FOR_VALUE] array.
398- fn parse_from_ty ( ty : & syn :: Type ) -> Self {
425+ fn parse_from_ty ( ty : & Type ) -> Self {
399426 match ty {
400- syn :: Type :: Path ( syn :: TypePath { path, .. } )
427+ Type :: Path ( TypePath { path, .. } )
401428 if path
402429 . segments
403430 . iter ( )
@@ -410,9 +437,7 @@ impl RecordType {
410437 {
411438 RecordType :: Value
412439 }
413- syn:: Type :: Reference ( syn:: TypeReference { elem, .. } ) => {
414- RecordType :: parse_from_ty ( & * elem)
415- }
440+ Type :: Reference ( syn:: TypeReference { elem, .. } ) => RecordType :: parse_from_ty ( & * elem) ,
416441 _ => RecordType :: Debug ,
417442 }
418443 }
@@ -471,7 +496,7 @@ pub(crate) struct AsyncInfo<'block> {
471496 // statement that must be patched
472497 source_stmt : & ' block Stmt ,
473498 kind : AsyncKind < ' block > ,
474- self_type : Option < syn :: TypePath > ,
499+ self_type : Option < TypePath > ,
475500 input : & ' block ItemFn ,
476501}
477502
@@ -606,11 +631,11 @@ impl<'block> AsyncInfo<'block> {
606631 if ident == "_self" {
607632 let mut ty = * ty. ty . clone ( ) ;
608633 // extract the inner type if the argument is "&self" or "&mut self"
609- if let syn :: Type :: Reference ( syn:: TypeReference { elem, .. } ) = ty {
634+ if let Type :: Reference ( syn:: TypeReference { elem, .. } ) = ty {
610635 ty = * elem;
611636 }
612637
613- if let syn :: Type :: Path ( tp) = ty {
638+ if let Type :: Path ( tp) = ty {
614639 self_type = Some ( tp) ;
615640 break ;
616641 }
@@ -722,7 +747,7 @@ struct IdentAndTypesRenamer<'a> {
722747 idents : Vec < ( Ident , Ident ) > ,
723748}
724749
725- impl < ' a > syn :: visit_mut :: VisitMut for IdentAndTypesRenamer < ' a > {
750+ impl < ' a > VisitMut for IdentAndTypesRenamer < ' a > {
726751 // we deliberately compare strings because we want to ignore the spans
727752 // If we apply clippy's lint, the behavior changes
728753 #[ allow( clippy:: cmp_owned) ]
@@ -734,11 +759,11 @@ impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> {
734759 }
735760 }
736761
737- fn visit_type_mut ( & mut self , ty : & mut syn :: Type ) {
762+ fn visit_type_mut ( & mut self , ty : & mut Type ) {
738763 for ( type_name, new_type) in & self . types {
739- if let syn :: Type :: Path ( TypePath { path, .. } ) = ty {
764+ if let Type :: Path ( TypePath { path, .. } ) = ty {
740765 if path_to_string ( path) == * type_name {
741- * ty = syn :: Type :: Path ( new_type. clone ( ) ) ;
766+ * ty = Type :: Path ( new_type. clone ( ) ) ;
742767 }
743768 }
744769 }
@@ -751,10 +776,33 @@ struct AsyncTraitBlockReplacer<'a> {
751776 patched_block : Block ,
752777}
753778
754- impl < ' a > syn :: visit_mut :: VisitMut for AsyncTraitBlockReplacer < ' a > {
779+ impl < ' a > VisitMut for AsyncTraitBlockReplacer < ' a > {
755780 fn visit_block_mut ( & mut self , i : & mut Block ) {
756781 if i == self . block {
757782 * i = self . patched_block . clone ( ) ;
758783 }
759784 }
760785}
786+
787+ // Replaces any `impl Trait` with `_` so it can be used as the type in
788+ // a `let` statement's LHS.
789+ struct ImplTraitEraser ;
790+
791+ impl VisitMut for ImplTraitEraser {
792+ fn visit_type_mut ( & mut self , t : & mut Type ) {
793+ if let Type :: ImplTrait ( ..) = t {
794+ * t = syn:: TypeInfer {
795+ underscore_token : Token ! [ _] ( t. span ( ) ) ,
796+ }
797+ . into ( ) ;
798+ } else {
799+ syn:: visit_mut:: visit_type_mut ( self , t) ;
800+ }
801+ }
802+ }
803+
804+ fn erase_impl_trait ( ty : & Type ) -> Type {
805+ let mut ty = ty. clone ( ) ;
806+ ImplTraitEraser . visit_type_mut ( & mut ty) ;
807+ ty
808+ }
0 commit comments