Repository: rust
Issue: CTFE cycle error doesn't adequately point out location of cycle
Labels: A-diagnostics,T-compiler,I-cycle

Here's some inconspicuous-looking Rust code. Can you spot the error? [(playground link)](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=456b560fd1292493f37fe5178099c819)

```rust
#![feature(const_option)]

#[derive(Copy, Clone)]
pub enum Month {
    Jan,
    Feb,
    Mar,
    Apr,
    May,
    Jun,
    Jul,
    Aug,
    Sep,
    Oct,
    Nov,
    Dec,
}

pub struct MonthDay {
    month: Month,
    day: u8,
}

impl MonthDay {
    const fn new(month: Month, day: u8) -> Option<MonthDay> {
        if day <= MonthDay::last_of_leap(month).day {
            Some(MonthDay { month, day })
        } else {
            None
        }
    }

    const fn last_of_leap(month: Month) -> MonthDay {
        const FEB29: MonthDay = MonthDay::new(Month::Feb, 29).unwrap();
        if matches!(month, Month::Feb) {
            FEB29
        } else {
            MonthDay::last_of_nonleap(month)
        }
    }

    const fn last_of_nonleap(month: Month) -> MonthDay {
        let day = match month {
            Month::Feb => 28,
            Month::Apr | Month::Jun | Month::Sep | Month::Nov => 30,
            Month::Jan
            | Month::Mar
            | Month::May
            | Month::Jul
            | Month::Aug
            | Month::Oct
            | Month::Dec => 31,
        };
        MonthDay { month, day }
    }
}
```

Although the contents of the error *technically* reveal what's wrong, they do so in a very roundabout way that doesn't make it as obvious to the passive reader. At least, when I first saw this, I thought that this was just a compiler bug, not an actual error in my code.

Here's the current output:

```
Compiling playground v0.0.1 (/playground)
error[[E0391]](https://doc.rust-lang.org/nightly/error-index.html#E0391): cycle detected when elaborating drops for `<impl at src/lib.rs:24:1: 56:2>::last_of_leap`
  --> src/lib.rs:36:13
   |
36 |             FEB29
   |             ^^^^^
   |
note: ...which requires const-evaluating + checking `<impl at src/lib.rs:24:1: 56:2>::last_of_leap::FEB29`...
  --> src/lib.rs:34:9
   |
34 |         const FEB29: MonthDay = MonthDay::new(Month::Feb, 29).unwrap();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at src/lib.rs:24:1: 56:2>::last_of_leap::FEB29`...
  --> src/lib.rs:34:9
   |
34 |         const FEB29: MonthDay = MonthDay::new(Month::Feb, 29).unwrap();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires caching mir of `<impl at src/lib.rs:24:1: 56:2>::last_of_leap` for CTFE...
  --> src/lib.rs:33:5
   |
33 |     const fn last_of_leap(month: Month) -> MonthDay {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: ...which again requires elaborating drops for `<impl at src/lib.rs:24:1: 56:2>::last_of_leap`, completing the cycle
   = note: cycle used when running analysis passes on this crate

For more information about this error, try `rustc --explain E0391`.
error: could not compile `playground` due to previous error
```

However, the middle three steps are *essentially* the same, and don't reveal the full story. The way I would expect the cycle to be pointed out is:

1. Cannot evaluate `FEB29` on line 36. (span: `FEB29`)
2. Because it calls `MonthDay::new` on line 34. (span: `MonthDay::new`)
3. Because `MonthDay::new` calls `last_of_leap` on line 26. (span: `last_of_leap`)
4. Because `last_of_leap` requires evaluating `FEB29` on line 36. (same as first span)

Essentially, I think that the key changes should be:

1. The first step should always be the failure to evaluate a constant. If we were to take the existing cycle, this means that we should rotate the cycle until we reach some constant that failed; it doesn't matter which one if there are multiple in the cycle.
1. The user really doesn't need to know that normalizing, simplifying, and const-evaluating are three separate steps, unless not all three are included.
3. The full stack trace should be revealed, including exactly what methods are called where.
4. Spans should highlight the specific parts of the line being evaluated, and not the entire line.