1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Tells you what type things are.
//!
//! This crate provides the `what!` macro. This is functionally similar to the
//! [`todo!`] macro, except that it also tells you type information.
//!
//! ``` rust
//! # use cargo_what::what;
//! # use std::error::Error;
//! fn hello() -> Result<(), Box<dyn Error>> {
//!     what!()
//! }
//! ```
//!
//! Just like [`todo!`], `what!` passes all type-checks and makes it easy to
//! write/build/test unfinished code. If it ever ends up in a compiled program,
//! attempted to execute a `what!` will panic.
//!
//! The fun part happens when you run `cargo what`.
//!
//! ``` bash
//! $ cargo what
//! hole: expecting `std::result::Result<(), Box<dyn std::error::Error>>`
//!  --> src/hello.rs
//!   |
//! 2 |     what!()
//!   |     ^^^^^^^
//! ```
//!
//! Unfortunately, custom diagnostics aren't really available to Rust libraries,
//! requiring the extra command. `cargo what` can be installed with `cargo`:
//!
//! ``` bash
//! $ cargo install cargo-what
//! ```
//!
//! `cargo what` wraps `cargo build` to show the type-info of any `what!`s
//! you have in your code.
//!
//! `what!` also accepts arguments and shows their types, which can be useful
//! for reducing the "unused variable" noise.
//!
//! ``` rust
//! # use cargo_what::what;
//! fn hello(a: usize, b: usize) -> usize {
//!     let c = a..b;
//!     what!(a, b, c)
//! }
//! ```
//!
//! And with `cargo what`:
//!
//! ```bash
//! $ cargo what
//! hole: expecting `usize`
//!  --> src/hello.rs
//!   |
//! 3 |     what!(a, b, c)
//!   |     ^^^^^^^^^^^^^^
//!   |
//!   = note: a is `usize`
//!   = note: b is `usize`
//!   = note: c is `std::ops::Range<usize>`
//! ```
//!
//! Emacs keybindings left as an exercise to the reader.
//!
//! [`todo!`]: https://doc.rust-lang.org/std/macro.todo.html
//!

// we need this for token pasting
#[doc(hidden)]
pub use paste as __paste;


/// This is the core `what!` macro.
///
/// It behaves similarly to [`todo!`], passes all type-checks,
/// and panics if executed.
///
/// ```rust
/// # use cargo_what::what;
/// # use std::error::Error;
/// fn hello() -> Result<(), Box<dyn Error>> {
///     what!()
/// }
/// ```
///
/// One difference from [`todo!`] is that `what!` also accepts
/// arbitrary arguments, which can help reduce "unused variable"
/// noise.
///
/// ``` rust
/// # use cargo_what::what;
/// fn hello(a: usize, b: usize) -> usize {
///     let c = a..b;
///     what!(a, b, c)
/// }
/// ```
///
/// See the [crate-level documentation](/cargo_what) for more info
/// on how you can show the type-info of `what!`s in a program.
///
/// [`todo!`]: https://doc.rust-lang.org/std/macro.todo.html
///

// cargo build => todo
#[cfg(not(cargo_what_query))]
#[macro_export]
macro_rules! what {
    ($($args:expr),* $(,)*) => {
        ({
            $(
                let _ = $args;
            )*
            todo!()
        })
    };
}

// cargo what => query type info
#[cfg(cargo_what_query)]
#[macro_export]
macro_rules! what {
    (@[$($n:expr)*] $(,)*) => {};
    (@[$($n:expr)*] $arg:ident, $($args:tt)*) => {
        // we can use ident directly as a special case
        $crate::__paste::paste! {
            trait [<What_ $arg>] {};
            let _: &dyn [<What_ $arg>] = &$arg;
        }
        what!(@[$($n)* 0] $($args)*);
    };
    (@[$($n:expr)*] $arg:expr, $($args:tt)*) => {
        $crate::__paste::paste! {
            trait [<What_ $($n)*>] {};
            // yes you need these parens (tt munching?)
            let _: &dyn [<What_ $($n)*>] = &($arg);
        }
        what!(@[$($n)* 0] $($args)*);
    };
    // actual macro
    ($($args:tt)*) => {
        ({
            todo!();

            #[allow(unreachable_code)]
            {
                what!(@[0] $($args)*,);

                trait What {};
                match true {
                    true => {
                        let what;
                        let _: &dyn What = &what;
                        what
                    }
                    false => {
                        struct WhatTrait {};
                        impl What for WhatTrait {};
                        WhatTrait{}
                    }
                }
            }
        })
    };
}