Type errors in macros have poor spans

8d750aa
Opened by Mark Rousskov at 2025-04-01 21:44:05

For example, in this code, it's hard to tell which part of the inputs to the macro has the wrong type. This is obviously a reduced example, but I've seen the same problem in real code.

I suspect this might be a duplicate issue, but couldn't find anything...

fn main() {
    assert_eq!(10u64, 10usize);
}

provides:

rustc 1.16.0-nightly (4ecc85beb 2016-12-28)
error[E0308]: mismatched types
 --> <anon>:2:5
  |
2 |     assert_eq!(10u64, 10usize);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize
  |
  = note: this error originates in a macro outside of the current crate

error: aborting due to previous error
  1. Is anyone working on it?

    Alexey at 2017-01-19 12:39:43

  2. On nightly using -Z external-macro-backtrace this looks like this:

    error[E0308]: mismatched types
     --> <assert_eq macros>:5:22
      |
    5 | if ! ( * left_val == * right_val ) {
      |                      ^^^^^^^^^^^ expected u64, found usize
    file2.rs:2:5: 2:32 note: in this expansion of assert_eq! (defined in <assert_eq macros>)
    
    error: aborting due to previous error
    

    and once #46605 lands it'll look like this:

    error[E0308]: mismatched types
     --> <assert_eq macros>:5:22
      |
    5 | if ! ( * left_val == * right_val ) {
      |                      ^^^^^^^^^^^ expected u64, found usize
     ::: file.rs
      |
    2 |     assert_eq!(10u64, 10usize);
      |     --------------------------- in this expansion of `assert_eq!`
    
    error: aborting due to previous error
    

    Esteban Kuber at 2017-12-13 01:42:26

  3. We should probably leave this ticket open for us to stabilize external-macro-backtrace.

    This reminds me, -Zteach should probably imply a simplified version of -Zexternal-macro-backtrace.

    Esteban Kuber at 2018-02-01 16:51:37

  4. I think the "only" work left to do here is to add a way to annotate macro inner spans as coming from a macro argument. This annotation has to be very viral in order to work in this case. Looking at the current output for external-macro-backtrace:

    error[E0308]: mismatched types
      --> <assert_eq macros>:5:22
       |
    1  | / ( $ left : expr , $ right : expr ) => (
    2  | | {
    3  | | match ( & $ left , & $ right ) {
    4  | | ( left_val , right_val ) => {
    5  | | if ! ( * left_val == * right_val ) {
       | |                      ^^^^^^^^^^^ expected u64, found usize
    ...  |
    20 | |  right: `{:?}`: {}"# ,
    21 | | left_val , right_val , format_args ! ( $ ( $ arg ) + ) ) } } } } ) ;
       | |____________________________________________________________________- in this expansion of `assert_eq!`
       |
      ::: test.rs:2:5
       |
    2  |       assert_eq!(10u64, 10usize);
       |       --------------------------- in this macro invocation
    

    the following spans should have the following internal_macro_backtrace:

    1  | ( $ left : expr , $ right : expr ) => (
       |     ^^^^ 1          ^^^^^ 2
    2  | {
    3  | match ( & $ left , & $ right ) {
       |         --------  ---------- 4 through 2
       |         |
       |         3 through 1
    4  | ( left_val , right_val ) => {
       |   --------  ---------- 6 through 4
       |   |
       |   5 through 3
    5  | if ! ( * left_val == * right_val ) {
       |        ^^^^^^^^^^    ^^^^^^^^^^^ 8 though 6
       |        |
       |        7 through 5
    

    Once we have a way to travel back to an individual argument, we could see that the error comes from 8, which is tied all the way to 2, which corresponds to the second match argument in the macro call and emit the following without the backtrace:

    error[E0308]: mismatched types
     --> <anon>:2:5
      |
    2 |     assert_eq!(10u64, 10usize);
      |                       ^^^^^^^ expected u64, found usize
      |
      = note: this error originates in a macro outside of the current crate
    

    or

    error[E0308]: mismatched types
     --> <anon>:2:5
      |
    2 |     assert_eq!(10u64, 10usize);
      |     ------------------^^^^^^^- in this macro call
      |                       |
      |                       expected u64, found usize
      |
      = note: this error originates in a macro outside of the current crate
    

    Esteban Kuber at 2018-08-29 18:12:11

  5. Currently (with version 1.85.1), compiling the sample code gives:

    % cargo build
       Compiling typerrmac v0.1.0 (/Users/rod/code/rust/triage/typerrmac)
    error[E0308]: mismatched types
     --> src/main.rs:2:23
      |
    2 |     assert_eq!(10u64, 10usize);
      |                       ^^^^^^^ expected `u64`, found `usize`
      |
    help: change the type of the numeric literal from `usize` to `u64`
      |
    2 |     assert_eq!(10u64, 10u64);
      |                         ~~~
    
    For more information about this error, try `rustc --explain E0308`.
    error: could not compile `typerrmac` (bin "typerrmac") due to 1 previous error
    

    Which includes which argument* is the problem and how to correct it. So I think this has been fixed and can be closed.

    • of course the first argument could be the problem and changing it to size may be what is required in a real example, but I think that fix can easily be deduced from the suggested one.

    Rod at 2025-04-01 21:44:05