Rust: On recursive requirements, elide repeating output

Created on 24 Jan 2018  路  4Comments  路  Source: rust-lang/rust

When encountering recursive requirements, elide some of the repeating output instead of having the following wall of text detailing every recursive step the compiler takes:

error[E0275]: overflow evaluating the requirement `Foo: std::marker::Sync`
 --> src/main.rs:5:1
  |
5 | / lazy_static! {
6 | |     static ref CHAR: Foo = unimplemented!();
7 | | }
  | |_^
  |
  = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
  = note: required because it appears within the type `std::marker::PhantomData<Foo>`
  = note: required because it appears within the type `Bar`
  = note: required because it appears within the type `std::marker::PhantomData<Bar>`
  = note: required because it appears within the type `Foo`
  = note: required because it appears within the type `std::marker::PhantomData<Foo>`
  = note: required because it appears within the type `Bar`
  = note: required because it appears within the type `std::marker::PhantomData<Bar>`
  = note: required because it appears within the type `Foo`
  = note: required because it appears within the type `std::marker::PhantomData<Foo>`
  = note: required because it appears within the type `Bar`
8<8<8<8<8<8<8<
  = note: required by `lazy_static::lazy::Lazy`
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

The following code

https://github.com/rust-lang/rust/blob/a0dcecff90c45ad5d4eb60859e22bb3f1b03842a/src/librustc/traits/error_reporting.rs#L1285-L1293

needs to be modified to pass down a vector of the Tys note_obligation_cause_code has encountered on previous runs. I feel it is reasonable to delay the notes from being produced until the bottom has been reached, and prune the list then. The output should be something along the lines of

error[E0275]: overflow evaluating the requirement `Foo: std::marker::Sync`
 --> src/main.rs:5:1
  |
5 | / lazy_static! {
6 | |     static ref CHAR: Foo = unimplemented!();
7 | | }
  | |_^
  |
  = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
  = note: required because it appears within the type `std::marker::PhantomData<Foo>`
  = note: required because it appears within the type `Bar`
  = note: required because it appears within the type `std::marker::PhantomData<Bar>`
  = note: required because it appears within the type `Foo`
  = note: required because it appears within the type `std::marker::PhantomData<Foo>`
  = note: ...and so on, these requirements repeat until reaching the recursion limit
  = note: required by `lazy_static::lazy::Lazy`
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
A-diagnostics C-enhancement D-verbose T-compiler

Most helpful comment

Minimal reproduction:

use std::marker::PhantomData;

struct AssertSync<T: Sync>(PhantomData<T>);

pub struct Foo {
    bar: *const Bar,
    phantom: PhantomData<Bar>,
}

pub struct Bar {
    foo: *const Foo,
    phantom: PhantomData<Foo>,
}

fn main() {
    let _: AssertSync<Foo> = unimplemented!();
}

All 4 comments

Hello @estebank, I would like to take this one but I could use some more clarification. Just to be clear, your solution expects to:

  1. Add new argument of type vector to note_obligation_cause_code
  2. Move err.note from line 1287 to 1292.
  3. Add errors to vector

and when end of recursion is reached:

  1. Print last 4 errors
  2. prune vector

I'm ok with any solution you come up with. The one you have mentioned should work fine. In any way you'll probably have to modify the way note_obligation_cause_code works. For instead of pruning the vector I would look for repeated sequences in the vector, and only print the repeating sequence once. It wouldn't be hard coded as the last 4, as if you add a level of indirection in the repro case it would have to be the last 6, for example.

BTW, I haven't come up with a repro that doesn't depend on lazy_static. That is something we should figure out. You can test it locally using rustc lazy_static/src/lib.rs --crate-type=lib and then using that library $DIR/rustc src/main.rs --extern lazy_static=liblib.rlib, but having a test in this repo would be appreciated to have to avoid regressions.

Minimal reproduction:

use std::marker::PhantomData;

struct AssertSync<T: Sync>(PhantomData<T>);

pub struct Foo {
    bar: *const Bar,
    phantom: PhantomData<Bar>,
}

pub struct Bar {
    foo: *const Foo,
    phantom: PhantomData<Foo>,
}

fn main() {
    let _: AssertSync<Foo> = unimplemented!();
}

I found a new instance of this. [[playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d5d720fed0c7a6295d19482e3673fcf9)]

use std::ops::Deref;

fn assert_TextSized<T: TextSized>() {}

/// Text-like structures that have a text size.
pub trait TextSized: Copy {
    /// The size of this text-alike.
    fn text_size(self) -> usize;
}

impl TextSized for &'_ str {
    fn text_size(self) -> usize {
        self.len()
    }
}

impl<D: Deref> TextSized for &'_ D
where for<'a> &'a D::Target: TextSized
{
    fn text_size(self) -> usize {
        self.deref().text_size()
    }
}

const _: fn() = || {
    assert_TextSized::<&()>();
};
error[E0275]: overflow evaluating the requirement `for<'a> &'a _: TextSized`
  --> src/lib.rs:28:5
   |
5  | fn assert_TextSized<T: TextSized>() {}
   |    ----------------    --------- required by this bound in `assert_TextSized`
...
28 |     assert_TextSized::<&()>();
   |     ^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`playground`)
   = note: required because of the requirements on the impl of `for<'a> TextSized` for `&'a _`
     [snip about 123 copies of that line]
   = note: required because of the requirements on the impl of `for<'a> TextSized` for `&'a _`
   = note: required because of the requirements on the impl of `TextSized` for `&()`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0275`.
error: could not compile `playground`.

(edited to make the example actually compile for a correct type)

Was this page helpful?
0 / 5 - 0 ratings