How to inspect hir or mir?

For async/await codes, is there some tool to show their hir or mir (as well as normal rust source codes)? So that I could get the understanding of async/await deeper.

You can select MIR as an output mode on play.rust-lang.org, although I'm not quite sure how you convince the compiler to do it locally.

In the following post, I'll be using

async fn foo () {}

async fn bar ()
{
    for _ in 0 .. 10 {
        let x = &42;
        foo().await;
        drop(x);
    }
}

as the Rust code being examined.


The rustc flag to do it is -Zunpretty=${EXPANSION_KIND}, where ${EXPANSION_KIND} can be:

  • expanded
    get the Rust code after macro expansion;

    #![feature(prelude_import)]
    #![no_std]
    #[prelude_import]
    use ::std::prelude::v1::*;
    #[macro_use]
    extern crate std as std;
    
    async fn foo() { }
    
    async fn bar() { for _ in 0..10 { let x = &42; foo().await; drop(x); } }
    
  • hir
    get the high-level representation of the Rust code (after macro expansion).
    This, for instance, unsugars for ... loop constructs and .await statements (although the latter rely on generators, which are their own form of sugar);

    Click to show example
    #[prelude_import]
    use ::std::prelude::v1::*;
    #[macro_use]
    extern crate std as std;
    
    async fn foo() ->  ::std::future::from_generator(move || { })
    
    async fn bar()
     ->
          ::std::future::from_generator(move ||
                                            {
                                                {
                                                    let _t =
                                                        match ::std::iter::IntoIterator::into_iter(::std::ops::Range{start:
                                                                                                                         0,
                                                                                                                     end:
                                                                                                                         10,})
                                                            {
                                                            mut iter =>
                                                            loop  {
                                                                let mut __next;
                                                                match ::std::iter::Iterator::next(&mut iter)
                                                                    {
                                                                    ::std::option::Option::Some(val)
                                                                    =>
                                                                    __next = val,
                                                                    ::std::option::Option::None
                                                                    => break ,
                                                                }
                                                                let _ = __next;
                                                                {
                                                                    let x = &42;
                                                                    {
                                                                        let mut pinned =
                                                                            foo();
                                                                        loop  {
                                                                            match ::std::future::poll_with_tls_context(unsafe
                                                                                                                       {
                                                                                                                           <::std::pin::Pin>::new_unchecked(&mut pinned)
                                                                                                                       })
                                                                                {
                                                                                ::std::task::Poll::Ready(result)
                                                                                =>
                                                                                break
                                                                                    result
                                                                                    ,
                                                                                ::std::task::Poll::Pending
                                                                                =>
                                                                                {
                                                                                }
                                                                            }
                                                                            yield
                                                                                ();
                                                                        }
                                                                    };
                                                                    drop(x);
                                                                }
                                                            },
                                                        };
                                                    _t
                                                }
                                            })
    
    • hir,typed
      This will add redundant as ... casts everywhere to "annotate" each expression with their corresponding type (in the case of generators, for instance, you get to see what they are capturing).
  • mir

    To show the medium-level representation of the code, with all the local allocations, drops, and unwind paths made explicit: (Example, click on MIR on the top left)

    • mir-cfg
      Generates the above code in the DOT language (graphviz), which allows rendering it in a graphical form

So in practice to run it on a cargo project you do:

cargo rustc -- -Z unpretty=...
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.