Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rustc "overflow evaluating the requirement" while it should work. #96634

Open
wdanilo opened this issue May 2, 2022 · 7 comments
Open

Rustc "overflow evaluating the requirement" while it should work. #96634

wdanilo opened this issue May 2, 2022 · 7 comments
Labels
A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@wdanilo
Copy link

wdanilo commented May 2, 2022

Consider this code:

#![recursion_limit = "256"]

pub trait Visit<T: ?Sized> {
    fn visit(&mut self, elem: &T);
}

pub enum Ast {
    Null,
    App(Box<Ast>,Box<Ast>)
}

impl<T> Visit<Ast> for T
where T: Visit<Box<Ast>> {
    fn visit(&mut self, elem: &Ast) {}
}

impl<T,S:?Sized> Visit<Box<S>> for T
where T: Visit<S> {
    fn visit(&mut self, elem: &Box<S>) {}
}

pub struct MyVisitor{}

fn test() {
    MyVisitor{}.visit(&Ast::Null);
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9014c0167fc65f14c8a2668428fc5df4

It gives the error:

error[[E0275]](https://doc.rust-lang.org/stable/error-index.html#E0275): overflow evaluating the requirement `MyVisitor: Visit<_>`
  [--> src/lib.rs:25:17
](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9014c0167fc65f14c8a2668428fc5df4#)   |
25 |     MyVisitor{}.visit(&Ast::Null);
   |                 ^^^^^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`playground`)
   = note: required because of the requirements on the impl of `Visit<Box<_>>` for `MyVisitor`
   = note: 256 redundant requirements hidden
   = note: required because of the requirements on the impl of `Visit<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<Box<_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` for `MyVisitor`

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

Which does not make sense. Let me explain:

  1. We do MyVisitor{}.visit(&Ast::Null), which requires a bound MyVisitor: Visit<Ast>.
  2. This bound is implemented (impl<T> Visit<Ast> for T), so another bound to be checked is added, which is MyVisitor: Visit<Box<Ast>>.
  3. This bound is again implemented (impl<T,S:?Sized> Visit<Box<S>> for T), which while resolving (T is MyVisitor and S is Ast) results in another bound to be resolved: MyVisitor: Visit<Ast>. However, this is our initial bound that we are currently resolving so it should compile fine.

A few things to be noted:

  1. The code compiles if the function test is commented out (only the usage throws the error (the impls are correct)).
  2. The Box<Box<Box<... situation should never happen in the Rustc type resolver - there is something wrong happening under the hood.
@wdanilo wdanilo added the C-bug Category: This is a bug. label May 2, 2022
@wdanilo
Copy link
Author

wdanilo commented May 2, 2022

This can be related: #39959, and consequently this as well: https://users.rust-lang.org/t/type-recursion-when-trait-bound-is-added-on-reference-type/74525

@b-naber
Copy link
Contributor

b-naber commented May 16, 2022

results in another bound to be resolved: MyVisitor: Visit. However, this is our initial bound that we are currently resolving so it should compile fine

Why should our initial bound be considered true? Afaict what's going on here is that you have a cycle, once you hit your initial bound you try to again prove MyVisitor: Visit<Box<Ast>>, and then infinitely recurse.

@wdanilo
Copy link
Author

wdanilo commented May 16, 2022

results in another bound to be resolved: MyVisitor: Visit. However, this is our initial bound that we are currently resolving so it should compile fine

Why should our initial bound be considered true? Afaict what's going on here is that you have a cycle, once you hit your initial bound you try to again prove MyVisitor: Visit<Box<Ast>>, and then infinitely recurse.

Such loops should be supported IMO, just as they are supported in Haskell, for example. If you have a bound A and during resolution, you've got a bound B, which requires A to exist, you can tell that it's fine, because the bound is being currently resolved. Of course, if you will bring to the resolution scope bounds that are mutually exclusive, an error should be reported. However, until then, not allowing for such a situation drastically limits the expressiveness of the Rust trait system.

jasonwhite added a commit to jasonwhite/tempfile that referenced this issue Mar 24, 2023
Due to bug rust-lang/rust#96634, these generic bounds may cause an
infinite recursion in the compiler, even in unrelated code.

This specializes the `Write for &NamedTempFile<F>` impl on `File`
instead. This keeps the API the same as before the generic parameter `F`
was added, so it shouldn't break any code.
@jasonwhite
Copy link

I ran into this issue today (Stebalien/tempfile#224) in the tempfile crate. In this issue, the impl impl<'a, F: &'a Write> Write for &'a NamedTempFile<F> broke unrelated code just for simply existing. I don't think that should ever happen, so this definitely seems like a rustc bug.

jasonwhite added a commit to jasonwhite/tempfile that referenced this issue Mar 24, 2023
Due to bug rust-lang/rust#96634, these generic bounds may cause an
infinite recursion in the compiler, even in unrelated code.

This specializes the `Write for &NamedTempFile<F>` impl on `File`
instead. This keeps the API the same as before the generic parameter `F`
was added, so it shouldn't break any code.
Stebalien pushed a commit to Stebalien/tempfile that referenced this issue Mar 29, 2023
Due to bug rust-lang/rust#96634, these generic bounds may cause an
infinite recursion in the compiler, even in unrelated code.

This specializes the `Write for &NamedTempFile<F>` impl on `File`
instead. This keeps the API the same as before the generic parameter `F`
was added, so it shouldn't break any code.
@ChrisDenton ChrisDenton added the needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. label Jul 16, 2023
@ToufeeqP
Copy link

Any update on this issue? I am also getting this issue on GAT

@fmease fmease added A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. and removed needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. labels Jan 25, 2024
@nazar-pc
Copy link

nazar-pc commented Apr 2, 2024

All cases of this error for me typically ended up being compiler failures to infer types. By removing code to localize where types can't be inferred and specifying types explicitly this error can be worked around.

@nabijaczleweli
Copy link
Contributor

trait Handler: Send + Sync + 'static {}

#[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
struct SimpleChain<H: Send + Sync + 'static>
    where &'static H: Handler
{
    pub handler: H,
}
impl<H: Send + Sync + 'static> Handler for &'static SimpleChain<H>
    where &'static H: Handler
{}

struct PruneChain;
impl Handler for &'static PruneChain {}

fn main() {
    SimpleChain {
    // SimpleChain::<PruneChain> {
        handler: PruneChain,
    };
}

yields

error[E0275]: overflow evaluating the requirement `&'static SimpleChain<_>: Handler`
  --> loop.rs:17:5
   |
17 |     SimpleChain {
   |     ^^^^^^^^^^^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`loop`)
note: required for `&'static SimpleChain<SimpleChain<_>>` to implement `Handler`
  --> loop.rs:9:32
   |
9  | impl<H: Send + Sync + 'static> Handler for &'static SimpleChain<H>
   |                                ^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^
10 |     where &'static H: Handler
   |                       ------- unsatisfied trait bound introduced here
   = note: 126 redundant requirements hidden
   = note: required for `&SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<...>>>>>>>>>>>>>>` to implement `Handler`
note: required by a bound in `SimpleChain`
  --> loop.rs:5:23
   |
4  | struct SimpleChain<H: Send + Sync + 'static>
   |        ----------- required by a bound in this struct
5  |     where &'static H: Handler
   |                       ^^^^^^^ required by this bound in `SimpleChain`
   = note: the full name for the type has been written to 'loop.long-type-17073646922255723838.txt'
   = note: consider using `--verbose` to print the full type name to the console

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0275`.

but if the constructor is instead SimpleChain::<PruneChain> { handler: PruneChain, } then this works.

Given that this type is well-known (PruneChain, as given in the constructor), it's unclear to me where SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<SimpleChain<...>>>>>>>>>>>>>> is coming from.

nabijaczleweli added a commit to thecoshman/http that referenced this issue May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants