Skip to content

fix: #[trace] compilation error when using trait objects#130

Merged
andylokandy merged 5 commits intofast:mainfrom
ArniDagur:adg/fix-trace-macro-typeerror
Aug 18, 2025
Merged

fix: #[trace] compilation error when using trait objects#130
andylokandy merged 5 commits intofast:mainfrom
ArniDagur:adg/fix-trace-macro-typeerror

Conversation

@ArniDagur
Copy link
Copy Markdown
Contributor

Before this PR, the newly added dyn-future test would fail with

test tests/ui/ok/dyn-future.rs [should pass] ... error
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error[E0308]: mismatched types
  --> tests/ui/ok/dyn-future.rs:15:50
   |
15 |   pub async fn f() -> Result<MyFuture, OuterError> {
   |  __________________________________________________^
16 | |     let inner = async { Err(InnerError) };
17 | |
18 | |     let mapped = async move { inner.await.map_err(OuterError) };
19 | |
20 | |     Ok(Box::pin(mapped))
21 | | }
   | |_^ expected `dyn Future`, found `async` block
   |
   = note: expected enum `Result<Pin<Box<(dyn Future<Output = Result<u32, OuterError>> + Send + 'static)>>, OuterError>`
              found enum `Result<Pin<Box<{async block@$DIR/tests/ui/ok/dyn-future.rs:18:18: 18:64}>>, _>`
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

By comparing the output of tracing::instrument and fastrace::trace, I figured out how to fix the issue

@ArniDagur ArniDagur changed the title Fix #[trace] compilation error when using trait objects fix: #[trace] compilation error when using trait objects Aug 11, 2025
@tisonkun tisonkun requested review from andylokandy and tisonkun and removed request for andylokandy August 13, 2025 00:49
@andylokandy
Copy link
Copy Markdown
Collaborator

andylokandy commented Aug 18, 2025

Appendix:

Test code:

use std::future::Future;
use std::pin::Pin;

use fastrace::trace;

#[derive(Debug)]
pub struct InnerError;

#[derive(Debug)]
pub struct OuterError(InnerError);

pub type MyFuture = Pin<Box<dyn Future<Output = Result<u32, OuterError>> + Send>>;

#[fastrace::trace]
pub async fn f() -> Result<MyFuture, OuterError> {
    let inner = async { Err(InnerError) };

    let mapped = async move { inner.await.map_err(OuterError) };

    Ok(Box::pin(mapped))
}

#[tokio::main]
async fn main() {
    let _ = f().await;
}

fastrace expansion:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use std::future::Future;
use std::pin::Pin;
use fastrace::trace;
pub struct InnerError;
#[automatically_derived]
impl ::core::fmt::Debug for InnerError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "InnerError")
    }
}
pub struct OuterError(InnerError);
#[automatically_derived]
impl ::core::fmt::Debug for OuterError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OuterError", &&self.0)
    }
}
pub type MyFuture = Pin<Box<dyn Future<Output = Result<u32, OuterError>> + Send>>;
pub async fn f() -> Result<MyFuture, OuterError> {
    {
        let __span__ = ::fastrace::Span::enter_with_local_parent({
            fn f() {}
            fn type_name_of<T>(_: T) -> &'static str {
                core::any::type_name::<T>()
            }
            let name = type_name_of(f);
            &name[..name.len() - 3]
        });
        ::fastrace::future::FutureExt::in_span(
            async move {
                {
                    let inner = async { Err(InnerError) };
                    let mapped = async move { inner.await.map_err(OuterError) };
                    Ok(Box::pin(mapped))
                }
            },
            __span__,
        )
    }
        .await
}
fn main() {
    let body = async {
        let _ = f().await;
    };
    #[allow(
        clippy::expect_used,
        clippy::diverging_sub_expression,
        clippy::needless_return
    )]
    {
        return tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .expect("Failed building the Runtime")
            .block_on(body);
    }
}

tracing expansion:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use std::future::Future;
use std::pin::Pin;
use fastrace::trace;
pub struct InnerError;
#[automatically_derived]
impl ::core::fmt::Debug for InnerError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "InnerError")
    }
}
pub struct OuterError(InnerError);
#[automatically_derived]
impl ::core::fmt::Debug for OuterError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OuterError", &&self.0)
    }
}
pub type MyFuture = Pin<Box<dyn Future<Output = Result<u32, OuterError>> + Send>>;
pub async fn f() -> Result<MyFuture, OuterError> {
    {}
    let __tracing_attr_span = {
        use ::tracing::__macro_support::Callsite as _;
        static __CALLSITE: ::tracing::callsite::DefaultCallsite = {
            static META: ::tracing::Metadata<'static> = {
                ::tracing_core::metadata::Metadata::new(
                    "f",
                    "a1",
                    tracing::Level::INFO,
                    ::tracing_core::__macro_support::Option::Some("examples/a1.rs"),
                    ::tracing_core::__macro_support::Option::Some(14u32),
                    ::tracing_core::__macro_support::Option::Some("a1"),
                    ::tracing_core::field::FieldSet::new(
                        &[],
                        ::tracing_core::callsite::Identifier(&__CALLSITE),
                    ),
                    ::tracing::metadata::Kind::SPAN,
                )
            };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
        let mut interest = ::tracing::subscriber::Interest::never();
        if tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
            && tracing::Level::INFO <= ::tracing::level_filters::LevelFilter::current()
            && {
                interest = __CALLSITE.interest();
                !interest.is_never()
            }
            && ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(), interest)
        {
            let meta = __CALLSITE.metadata();
            ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
        } else {
            let span = ::tracing::__macro_support::__disabled_span(
                __CALLSITE.metadata(),
            );
            {};
            span
        }
    };
    let __tracing_instrument_future = async move {
        #[allow(
            unknown_lints,
            unreachable_code,
            clippy::diverging_sub_expression,
            clippy::let_unit_value,
            clippy::unreachable,
            clippy::let_with_type_underscore,
            clippy::empty_loop
        )]
        if false {
            let __tracing_attr_fake_return: Result<MyFuture, OuterError> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let inner = async { Err(InnerError) };
            let mapped = async move { inner.await.map_err(OuterError) };
            Ok(Box::pin(mapped))
        }
    };
    if !__tracing_attr_span.is_disabled() {
        tracing::Instrument::instrument(__tracing_instrument_future, __tracing_attr_span)
            .await
    } else {
        __tracing_instrument_future.await
    }
}
fn main() {
    let body = async {
        let _ = f().await;
    };
    #[allow(
        clippy::expect_used,
        clippy::diverging_sub_expression,
        clippy::needless_return
    )]
    {
        return tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .expect("Failed building the Runtime")
            .block_on(body);
    }
}

PR expansion:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use std::future::Future;
use std::pin::Pin;
use fastrace::trace;
pub struct InnerError;
#[automatically_derived]
impl ::core::fmt::Debug for InnerError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "InnerError")
    }
}
pub struct OuterError(InnerError);
#[automatically_derived]
impl ::core::fmt::Debug for OuterError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OuterError", &&self.0)
    }
}
pub type MyFuture = Pin<Box<dyn Future<Output = Result<u32, OuterError>> + Send>>;
pub async fn f() -> Result<MyFuture, OuterError> {
    {
        let __span__ = ::fastrace::Span::enter_with_local_parent({
            fn f() {}
            fn type_name_of<T>(_: T) -> &'static str {
                core::any::type_name::<T>()
            }
            let name = type_name_of(f);
            &name[..name.len() - 3]
        });
        ::fastrace::future::FutureExt::in_span(
            async move {
                #[allow(
                    unknown_lints,
                    unreachable_code,
                    clippy::diverging_sub_expression,
                    clippy::empty_loop,
                    clippy::let_unit_value,
                    clippy::let_with_type_underscore,
                    clippy::needless_return,
                    clippy::unreachable
                )]
                if false {
                    let __fake_return__: Result<MyFuture, OuterError> = loop {};
                    return __fake_return__;
                }
                {
                    let inner = async { Err(InnerError) };
                    let mapped = async move { inner.await.map_err(OuterError) };
                    Ok(Box::pin(mapped))
                }
            },
            __span__,
        )
    }
        .await
}
fn main() {
    let body = async {
        let _ = f().await;
    };
    #[allow(
        clippy::expect_used,
        clippy::diverging_sub_expression,
        clippy::needless_return
    )]
    {
        return tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .expect("Failed building the Runtime")
            .block_on(body);
    }
}

@andylokandy
Copy link
Copy Markdown
Collaborator

@ArniDagur Thank you very much! This is valuable improvement!

I've changed the dummy loop with a straightforward type hint, and it seemed to work. This is the expansion after patch:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use std::future::Future;
use std::pin::Pin;
use fastrace::trace;
pub struct InnerError;
#[automatically_derived]
impl ::core::fmt::Debug for InnerError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "InnerError")
    }
}
pub struct OuterError(InnerError);
#[automatically_derived]
impl ::core::fmt::Debug for OuterError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "OuterError", &&self.0)
    }
}
pub type MyFuture = Pin<Box<dyn Future<Output = Result<u32, OuterError>> + Send>>;
pub async fn f() -> Result<MyFuture, OuterError> {
    {
        let __span__ = ::fastrace::Span::enter_with_local_parent({
            fn f() {}
            fn type_name_of<T>(_: T) -> &'static str {
                core::any::type_name::<T>()
            }
            let name = type_name_of(f);
            &name[..name.len() - 3]
        });
        ::fastrace::future::FutureExt::in_span(
            async move {
                let __ret__: Result<MyFuture, OuterError> = {
                    let inner = async { Err(InnerError) };
                    let mapped = async move { inner.await.map_err(OuterError) };
                    Ok(Box::pin(mapped))
                };
                __ret__
            },
            __span__,
        )
    }
        .await
}
fn main() {
    let body = async {
        let _ = f().await;
    };
    #[allow(
        clippy::expect_used,
        clippy::diverging_sub_expression,
        clippy::needless_return
    )]
    {
        return tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .expect("Failed building the Runtime")
            .block_on(body);
    }
}

@andylokandy andylokandy merged commit 4621ec7 into fast:main Aug 18, 2025
11 checks passed
goffrie pushed a commit to get-convex/fastrace that referenced this pull request Oct 23, 2025
Co-authored-by: Andy Lok <andylokandy@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants