embassy icon indicating copy to clipboard operation
embassy copied to clipboard

Cycle detected when borrow-checking a main function relying on static_cell nightly feature

Open renkenono opened this issue 1 month ago • 0 comments

Hi,

In the process of updating my project to rely on https://github.com/esp-rs/esp-hal/releases/tag/esp-hal-v1.0.0, I came across the following error.

error[E0391]: cycle detected when borrow-checking `__main::____embassy_main_task::____embassy_main_task_inner_function`
  --> src/bin/main.rs:29:1
   |
29 | #[esp_rtos::main]
   | ^^^^^^^^^^^^^^^^^
   |
note: ...which requires computing type of opaque `__main::____embassy_main_task::____embassy_main_task_inner_function::{closure#0}::T::{opaque#0}` via HIR typeck...
  --> src/bin/main.rs:58:32
   |
58 |     let _x: &'static mut u32 = static_cell::make_static!(0u32);
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires computing the opaque types defined by `__main::__embassy_main::POOL`...
  --> src/bin/main.rs:29:1
Full compiler output
error[E0391]: cycle detected when borrow-checking `__main::____embassy_main_task::____embassy_main_task_inner_function`
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
 |
note: ...which requires computing type of opaque `__main::____embassy_main_task::____embassy_main_task_inner_function::{closure#0}::T::{opaque#0}` via HIR typeck...
--> src/bin/main.rs:58:32
 |
58 |     let _x: &'static mut u32 = static_cell::make_static!(0u32);
 |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires computing the opaque types defined by `__main::__embassy_main::POOL`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires computing type of `__main::__embassy_main::POOL`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires evaluating type-level constant...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `__main::__embassy_main::POOL::{constant#0}`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires caching mir of `__main::__embassy_main::POOL::{constant#0}` for CTFE...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires elaborating drops for `__main::__embassy_main::POOL::{constant#0}`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
 = note: ...which requires normalizing `embassy_executor::_export::task_pool_size<__main::____embassy_main_task, (embassy_executor::spawner::Spawner,), __main::____embassy_main_task::{opaque#0}, ValTree(Leaf(0x00000001): usize)>`...
note: ...which requires computing type of `__main::____embassy_main_task::____embassy_main_task_inner_function::{opaque#0}`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
note: ...which requires computing type of opaque `__main::____embassy_main_task::____embassy_main_task_inner_function::{opaque#0}`...
--> src/bin/main.rs:29:1
 |
29 | #[esp_rtos::main]
 | ^^^^^^^^^^^^^^^^^
 = note: ...which again requires borrow-checking `__main::____embassy_main_task::____embassy_main_task_inner_function`, completing the cycle
note: cycle used when computing type of opaque `__main::____embassy_main_task::____embassy_main_task_inner_function::{closure#0}::T::{opaque#0}`
--> src/bin/main.rs:58:32
 |
58 |     let _x: &'static mut u32 = static_cell::make_static!(0u32);
 |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 = 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
 = note: this error originates in the attribute macro `esp_rtos::main` which comes from the expansion of the macro `static_cell::make_static` (in Nightly builds, run with -Z macro-backtrace for more info)

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

Steps to reproduce

A standard cargo-based Rust project is provided at https://github.com/renkenono/embassy-static-cell-poc. The most important bits to note are the following dependencies and the relevant snippet of code.

Dependencies

esp-hal = { version = "1.0.0", features = ["defmt", "esp32c6", "unstable"] }

esp-rtos = { version = "0.2.0", features = [
  "defmt",
  "embassy",
  "esp-alloc",
  "esp-radio",
  "esp32c6",
] }
# $ cargo tree
# │   ├── embassy-executor v0.9.1 (*)
# │   ├── embassy-sync v0.7.2 (*)
# │   ├── embassy-time-driver v0.2.1 (*)
# │   ├── embassy-time-queue-utils v0.3.0
# │   │   ├── embassy-executor-timer-queue v0.1.0

static_cell = { version = "2.1.1", features = ["nightly"] }

Simplified example

#[esp_rtos::main]
async fn main(_: Spawner) -> ! {
    // [...]
    let _x: &'static mut u32 = static_cell::make_static!(0u32);
    // [...]
}

Potential lead

I think the problem might stem from the fact that static_cell relies on impl Trait syntax to avoid requiring the user from specifying the underlying type as part of the make_static macro as seen at https://github.com/embassy-rs/static-cell/blob/v2.1.1/src/lib.rs#L241. This however appears to break the logic used underneath by embassy to calculate the number of tasks at compile-time (I assume?).

The reason why I create the issue here and not on static-cell is because I want to understand what embassy's main macro is doing underneath which requires all types to be computed prior to its execution.

Current workaround

  1. Using the non-nightly explicit way of defining StaticCell objects.
        static SC: StaticCell<u32> = StaticCell::new();
        let _x: &'static mut u32 = SC.init(0u32);
  1. Relying on a macro requiring the type to be passed as an argument as well to avoid opaque type computation such as the one used by esp-hal in their test framework.
// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html
macro_rules! mk_static {
    ($t:ty,$val:expr) => {{
        static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
        #[deny(unused_attributes)]
        let x = STATIC_CELL.uninit().write(($val));
        x
    }};
}

What should be the next step to fix this issue for the next release of embassy/static_cell? I'd like to contribute a fix if possible.

Thank you for your work on embassy!

renkenono avatar Nov 03 '25 13:11 renkenono