summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-attributes/src/expand.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-attributes/src/expand.rs')
-rw-r--r--vendor/tracing-attributes/src/expand.rs118
1 files changed, 86 insertions, 32 deletions
diff --git a/vendor/tracing-attributes/src/expand.rs b/vendor/tracing-attributes/src/expand.rs
index 81ee6ed90..7005b4423 100644
--- a/vendor/tracing-attributes/src/expand.rs
+++ b/vendor/tracing-attributes/src/expand.rs
@@ -2,15 +2,16 @@ use std::iter;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
+use syn::visit_mut::VisitMut;
use syn::{
punctuated::Punctuated, spanned::Spanned, Block, Expr, ExprAsync, ExprCall, FieldPat, FnArg,
Ident, Item, ItemFn, Pat, PatIdent, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType,
- Path, Signature, Stmt, Token, TypePath,
+ Path, ReturnType, Signature, Stmt, Token, Type, TypePath,
};
use crate::{
attr::{Field, Fields, FormatMode, InstrumentArgs},
- MaybeItemFnRef,
+ MaybeItemFn, MaybeItemFnRef,
};
/// Given an existing function, generate an instrumented version of that function
@@ -18,20 +19,21 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
input: MaybeItemFnRef<'a, B>,
args: InstrumentArgs,
instrumented_function_name: &str,
- self_type: Option<&syn::TypePath>,
+ self_type: Option<&TypePath>,
) -> proc_macro2::TokenStream {
// these are needed ahead of time, as ItemFn contains the function body _and_
// isn't representable inside a quote!/quote_spanned! macro
// (Syn's ToTokens isn't implemented for ItemFn)
let MaybeItemFnRef {
- attrs,
+ outer_attrs,
+ inner_attrs,
vis,
sig,
block,
} = input;
let Signature {
- output: return_type,
+ output,
inputs: params,
unsafety,
asyncness,
@@ -49,8 +51,35 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
let warnings = args.warnings();
+ let (return_type, return_span) = if let ReturnType::Type(_, return_type) = &output {
+ (erase_impl_trait(return_type), return_type.span())
+ } else {
+ // Point at function name if we don't have an explicit return type
+ (syn::parse_quote! { () }, ident.span())
+ };
+ // Install a fake return statement as the first thing in the function
+ // body, so that we eagerly infer that the return type is what we
+ // declared in the async fn signature.
+ // The `#[allow(..)]` is given because the return statement is
+ // unreachable, but does affect inference, so it needs to be written
+ // exactly that way for it to do its magic.
+ let fake_return_edge = quote_spanned! {return_span=>
+ #[allow(unreachable_code, clippy::diverging_sub_expression, clippy::let_unit_value)]
+ if false {
+ let __tracing_attr_fake_return: #return_type =
+ unreachable!("this is just for type inference, and is unreachable code");
+ return __tracing_attr_fake_return;
+ }
+ };
+ let block = quote! {
+ {
+ #fake_return_edge
+ #block
+ }
+ };
+
let body = gen_block(
- block,
+ &block,
params,
asyncness.is_some(),
args,
@@ -59,10 +88,11 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
);
quote!(
- #(#attrs) *
- #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #return_type
+ #(#outer_attrs) *
+ #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #output
#where_clause
{
+ #(#inner_attrs) *
#warnings
#body
}
@@ -76,7 +106,7 @@ fn gen_block<B: ToTokens>(
async_context: bool,
mut args: InstrumentArgs,
instrumented_function_name: &str,
- self_type: Option<&syn::TypePath>,
+ self_type: Option<&TypePath>,
) -> proc_macro2::TokenStream {
// generate the span's name
let span_name = args
@@ -393,11 +423,11 @@ impl RecordType {
"Wrapping",
];
- /// Parse `RecordType` from [syn::Type] by looking up
+ /// Parse `RecordType` from [Type] by looking up
/// the [RecordType::TYPES_FOR_VALUE] array.
- fn parse_from_ty(ty: &syn::Type) -> Self {
+ fn parse_from_ty(ty: &Type) -> Self {
match ty {
- syn::Type::Path(syn::TypePath { path, .. })
+ Type::Path(TypePath { path, .. })
if path
.segments
.iter()
@@ -410,9 +440,7 @@ impl RecordType {
{
RecordType::Value
}
- syn::Type::Reference(syn::TypeReference { elem, .. }) => {
- RecordType::parse_from_ty(&*elem)
- }
+ Type::Reference(syn::TypeReference { elem, .. }) => RecordType::parse_from_ty(elem),
_ => RecordType::Debug,
}
}
@@ -471,7 +499,7 @@ pub(crate) struct AsyncInfo<'block> {
// statement that must be patched
source_stmt: &'block Stmt,
kind: AsyncKind<'block>,
- self_type: Option<syn::TypePath>,
+ self_type: Option<TypePath>,
input: &'block ItemFn,
}
@@ -606,11 +634,11 @@ impl<'block> AsyncInfo<'block> {
if ident == "_self" {
let mut ty = *ty.ty.clone();
// extract the inner type if the argument is "&self" or "&mut self"
- if let syn::Type::Reference(syn::TypeReference { elem, .. }) = ty {
+ if let Type::Reference(syn::TypeReference { elem, .. }) = ty {
ty = *elem;
}
- if let syn::Type::Path(tp) = ty {
+ if let Type::Path(tp) = ty {
self_type = Some(tp);
break;
}
@@ -631,7 +659,7 @@ impl<'block> AsyncInfo<'block> {
self,
args: InstrumentArgs,
instrumented_function_name: &str,
- ) -> proc_macro::TokenStream {
+ ) -> Result<proc_macro::TokenStream, syn::Error> {
// let's rewrite some statements!
let mut out_stmts: Vec<TokenStream> = self
.input
@@ -652,12 +680,15 @@ impl<'block> AsyncInfo<'block> {
// instrument the future by rewriting the corresponding statement
out_stmts[iter] = match self.kind {
// `Box::pin(immediately_invoked_async_fn())`
- AsyncKind::Function(fun) => gen_function(
- fun.into(),
- args,
- instrumented_function_name,
- self.self_type.as_ref(),
- ),
+ AsyncKind::Function(fun) => {
+ let fun = MaybeItemFn::from(fun.clone());
+ gen_function(
+ fun.as_ref(),
+ args,
+ instrumented_function_name,
+ self.self_type.as_ref(),
+ )
+ }
// `async move { ... }`, optionally pinned
AsyncKind::Async {
async_expr,
@@ -688,13 +719,13 @@ impl<'block> AsyncInfo<'block> {
let vis = &self.input.vis;
let sig = &self.input.sig;
let attrs = &self.input.attrs;
- quote!(
+ Ok(quote!(
#(#attrs) *
#vis #sig {
#(#out_stmts) *
}
)
- .into()
+ .into())
}
}
@@ -722,7 +753,7 @@ struct IdentAndTypesRenamer<'a> {
idents: Vec<(Ident, Ident)>,
}
-impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> {
+impl<'a> VisitMut for IdentAndTypesRenamer<'a> {
// we deliberately compare strings because we want to ignore the spans
// If we apply clippy's lint, the behavior changes
#[allow(clippy::cmp_owned)]
@@ -734,11 +765,11 @@ impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> {
}
}
- fn visit_type_mut(&mut self, ty: &mut syn::Type) {
+ fn visit_type_mut(&mut self, ty: &mut Type) {
for (type_name, new_type) in &self.types {
- if let syn::Type::Path(TypePath { path, .. }) = ty {
+ if let Type::Path(TypePath { path, .. }) = ty {
if path_to_string(path) == *type_name {
- *ty = syn::Type::Path(new_type.clone());
+ *ty = Type::Path(new_type.clone());
}
}
}
@@ -751,10 +782,33 @@ struct AsyncTraitBlockReplacer<'a> {
patched_block: Block,
}
-impl<'a> syn::visit_mut::VisitMut for AsyncTraitBlockReplacer<'a> {
+impl<'a> VisitMut for AsyncTraitBlockReplacer<'a> {
fn visit_block_mut(&mut self, i: &mut Block) {
if i == self.block {
*i = self.patched_block.clone();
}
}
}
+
+// Replaces any `impl Trait` with `_` so it can be used as the type in
+// a `let` statement's LHS.
+struct ImplTraitEraser;
+
+impl VisitMut for ImplTraitEraser {
+ fn visit_type_mut(&mut self, t: &mut Type) {
+ if let Type::ImplTrait(..) = t {
+ *t = syn::TypeInfer {
+ underscore_token: Token![_](t.span()),
+ }
+ .into();
+ } else {
+ syn::visit_mut::visit_type_mut(self, t);
+ }
+ }
+}
+
+fn erase_impl_trait(ty: &Type) -> Type {
+ let mut ty = ty.clone();
+ ImplTraitEraser.visit_type_mut(&mut ty);
+ ty
+}