rust-lang / rust-lang/rust

1.90 regression: Cycle detected when type checking

Open
#146,813 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug fixed-by-next-solver I-cycle P-high regression-from-stable-to-stable S-has-bisection S-has-mcve T-compiler T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code:

use socketioxide::{SocketIo, handler::ConnectHandler};

fn main() {}

async fn fails() {
    let (_svc, io) = SocketIo::new_svc();

    #[derive(Debug)]
    struct MyError;

    impl std::fmt::Display for MyError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "MyError")
        }
    }

    let handler = || async move || Err(MyError);

    io.ns(
        "/",
        { async || {} }
            .with(handler())
            .with(handler())
            .with(handler()),
    );
}

See the following repo for the minimal reproducible example:
https://github.com/Totodore/socketioxide-rust-compiler-1.90-error

I expected to see this happen: Finished dev profile [unoptimized + debuginfo] target(s) in 6.03s

Instead, compilation failed, see the backtrace section below for the complete error.

The compiler error only happens when switching to v1.90. It comes from this CI and I can also reproduce it on my PC:
https://github.com/Totodore/socketioxide/actions/runs/17881639090/job/50850045405#step:5:267

Meta
  • The bug also happens in rust nightly 1.92
  • Here is a minimal example, the issue seems to comes from the complex traits bounds used in socketioxide, therefore I did not succeed to replicate it without the socketioxide lib.

rustc --version --verbose:

rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: x86_64-unknown-linux-gnu
release: 1.90.0
LLVM version: 20.1.8
Backtrace

error[E0391]: cycle detected when type-checking `fails`
  --> src/main.rs:5:1
   |
 5 | async fn fails() {
   | ^^^^^^^^^^^^^^^^
   |
   = note: ...which requires computing whether `<<socketioxide::handler::connect::ConnectHandler::with::{opaque#0} as socketioxide::handler::connect::ConnectHandler<socketioxide::adapter::LocalAdapter, (socketioxide::handler::connect::private::Async,)>>::with::{anon_assoc#0}<{async closure@src/main.rs:17:22: 17:35}, (socketioxide::handler::connect::private::Async,)> as socketioxide::handler::connect::ConnectHandler<socketioxide::adapter::LocalAdapter, (socketioxide::handler::connect::private::Async,)>>::with::{anon_assoc#0}<{async closure@src/main.rs:17:22: 17:35}, (socketioxide::handler::connect::private::Async,)>` is `Copy`...
   = note: ...which requires evaluating trait selection obligation `<<socketioxide::handler::connect::ConnectHandler::with::{opaque#0} as socketioxide::handler::connect::ConnectHandler<socketioxide::adapter::LocalAdapter, (socketioxide::handler::connect::private::Async,)>>::with::{anon_assoc#0}<{async closure@src/main.rs:17:22: 17:35}, (socketioxide::handler::connect::private::Async,)> as socketioxide::handler::connect::ConnectHandler<socketioxide::adapter::LocalAdapter, (socketioxide::handler::connect::private::Async,)>>::with::{anon_assoc#0}<{async closure@src/main.rs:17:22: 17:35}, (socketioxide::handler::connect::private::Async,)>: core::marker::Copy`...
note: ...which requires looking up the hidden types stored across await points in a coroutine...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires coroutine witness types for `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}`...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}`...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires checking if `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}` contains FFI-unwind calls...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires building MIR for `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}`...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires match-checking `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}`...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
note: ...which requires type-checking `fails::{closure#0}::{closure#0}::{closure#0}::{closure#0}`...
  --> src/main.rs:17:36
   |
17 |     let handler = || async move || Err(MyError);
   |                                    ^^^^^^^^^^^^
   = note: ...which again requires type-checking `fails`, completing the cycle
note: cycle used when match-checking `fails`
  --> src/main.rs:5:1
   |
 5 | async fn fails() {
   | ^^^^^^^^^^^^^^^^
   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

For more information about this error, try `rustc --explain E0391`.
error: could not compile `socketioxide-compile-test-error` (bin "socketioxide-compile-test-error") due to 1 previous error

Side note

It seems that it is related to the Display bound of MyError. Also it is really weird because this bugs happens after three .with() chaining.

Bisection results

searched nightlies: from nightly-2025-08-01 to nightly-2025-09-20
regressed nightly: nightly-2025-08-03
searched commit range: https://github.com/rust-lang/rust/compare/4b55fe199cfe9c710555a5af7f2a49491ad38254...a65b04d7c9a1eaf02b62667da1c203c8a07976d9
regressed commit: https://github.com/rust-lang/rust/commit/63f6845e570305a92eaf855897768617366164d6

bisected with cargo-bisect-rustc v0.6.10

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproducer's src/main.rs and use cargo bisect-rustc to confirm the regression around commit 63f6845e570305a92eaf855897768617366164d6. Investigate the compiler changes in that commit related to the reported type-checking cycle, then verify that the reproducer builds successfully without E0391 on the fixed compiler.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.