Repository: embassy-rs/embassy
Pull request #4023 (2025-03-29 07:53:31)

Fix ugly compiler error from task macro
Somehow, doing `<F, Fut> -> TaskPool<Fut>` is better than `<F> -> TaskPool<F::Fut>`. I also moved ~~all~~ some of the helper functions out of the macro and in to embassy_executor.

Before:

```
error[E0308]: mismatched types
 --> tests/ui/type_error.rs:5:5
  |
4 | async fn task() {
  |                - help: try adding a return type: `-> i32`
5 |     5
  |     ^ expected `()`, found integer

error[E0277]: the trait bound `Align<#[embassy_executor::task]>: _export::Alignment` is not satisfied
 --> tests/ui/type_error.rs:3:1
  |
3 | #[embassy_executor::task]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `_export::Alignment` is not implemented for `Align<#[embassy_executor::task]>`
  |
  = help: the following other types implement trait `_export::Alignment`:
            Align<1024>
            Align<1048576>
            Align<128>
            Align<131072>
            Align<134217728>
            Align<16384>
            Align<16777216>
            Align<16>
          and $N others
note: required by a bound in `TaskPoolHolder`
 --> src/lib.rs
  |
  |     pub struct TaskPoolHolder<const SIZE: usize, const ALIGN: usize>
  |                -------------- required by a bound in this struct
  |     where
  |         Align<ALIGN>: Alignment,
  |                       ^^^^^^^^^ required by this bound in `TaskPoolHolder`
  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0599]: the method `get` exists for struct `TaskPoolHolder<#[embassy_executor::task], #[embassy_executor::task]>`, but its trait bounds were not satisfied
 --> tests/ui/type_error.rs:3:1
  |
3 | #[embassy_executor::task]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called due to unsatisfied trait bounds
  |
 ::: src/lib.rs
  |
  |     pub struct Align<const N: usize>([<Self as Alignment>::Archetype; 0])
  |     -------------------------------- doesn't satisfy `_: Alignment`
  |
  = note: the following trait bounds were not satisfied:
          `Align<#[embassy_executor::task]>: _export::Alignment`
  = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
```

After:

```
error[E0308]: mismatched types
 --> tests/ui/type_error.rs:5:5
  |
4 | async fn task() {
  |                - help: try adding a return type: `-> i32`
5 |     5
  |     ^ expected `()`, found integer
```


Patch:
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs
index 8a2a7fdb9..91d6beee8 100644
--- a/embassy-executor-macros/src/macros/task.rs
+++ b/embassy-executor-macros/src/macros/task.rs
@@ -145,42 +145,19 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
     };
     #[cfg(not(feature = "nightly"))]
     let mut task_outer_body = quote! {
-        const fn __task_pool_size<F, Args>(_: F) -> usize
+        const fn __task_pool_get<F, Args, Fut>(_: F) -> &'static #embassy_executor::raw::TaskPool<Fut, POOL_SIZE>
         where
-            F: #embassy_executor::_export::TaskFn<Args>,
-        {
-            ::core::mem::size_of::<
-                #embassy_executor::raw::TaskPool<F::Fut, POOL_SIZE>
-            >()
-        }
-        const fn __task_pool_align<F, Args>(_: F) -> usize
-        where
-            F: #embassy_executor::_export::TaskFn<Args>,
-        {
-            ::core::mem::align_of::<
-                #embassy_executor::raw::TaskPool<F::Fut, POOL_SIZE>
-            >()
-        }
-
-        const fn __task_pool_new<F, Args>(_: F) -> #embassy_executor::raw::TaskPool<F::Fut, POOL_SIZE>
-        where
-            F: #embassy_executor::_export::TaskFn<Args>,
-        {
-            #embassy_executor::raw::TaskPool::new()
-        }
-
-        const fn __task_pool_get<F, Args>(_: F) -> &'static #embassy_executor::raw::TaskPool<F::Fut, POOL_SIZE>
-        where
-            F: #embassy_executor::_export::TaskFn<Args>
+            F: #embassy_executor::_export::TaskFn<Args, Fut = Fut>,
+            Fut: ::core::future::Future + 'static,
         {
             unsafe { &*POOL.get().cast() }
         }
 
         const POOL_SIZE: usize = #pool_size;
         static POOL: #embassy_executor::_export::TaskPoolHolder<
-            {__task_pool_size(#task_inner_ident)},
-            {__task_pool_align(#task_inner_ident)},
-        > = unsafe { ::core::mem::transmute(__task_pool_new(#task_inner_ident)) };
+            {#embassy_executor::_export::task_pool_size::<_, _, _, POOL_SIZE>(#task_inner_ident)},
+            {#embassy_executor::_export::task_pool_align::<_, _, _, POOL_SIZE>(#task_inner_ident)},
+        > = unsafe { ::core::mem::transmute(#embassy_executor::_export::task_pool_new::<_, _, _, POOL_SIZE>(#task_inner_ident)) };
         unsafe { __task_pool_get(#task_inner_ident)._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) }
     };
 
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 5485f6a6a..d6bd63665 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -59,6 +59,8 @@ pub mod _export {
     use core::future::Future;
     use core::mem::MaybeUninit;
 
+    use crate::raw::TaskPool;
+
     pub trait TaskFn<Args>: Copy {
         type Fut: Future + 'static;
     }
@@ -116,6 +118,30 @@ pub mod _export {
         }
     }
 
+    pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+    where
+        F: TaskFn<Args, Fut = Fut>,
+        Fut: Future + 'static,
+    {
+        size_of::<TaskPool<Fut, POOL_SIZE>>()
+    }
+
+    pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
+    where
+        F: TaskFn<Args, Fut = Fut>,
+        Fut: Future + 'static,
+    {
+        align_of::<TaskPool<Fut, POOL_SIZE>>()
+    }
+
+    pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
+    where
+        F: TaskFn<Args, Fut = Fut>,
+        Fut: Future + 'static,
+    {
+        TaskPool::new()
+    }
+
     #[allow(private_bounds)]
     #[repr(transparent)]
     pub struct Align<const N: usize>([<Self as Alignment>::Archetype; 0])


Test patch:
diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs
index be4679485..278a4b903 100644
--- a/embassy-executor/tests/ui.rs
+++ b/embassy-executor/tests/ui.rs
@@ -19,5 +19,6 @@ fn ui() {
     t.compile_fail("tests/ui/not_async.rs");
     t.compile_fail("tests/ui/self_ref.rs");
     t.compile_fail("tests/ui/self.rs");
+    t.compile_fail("tests/ui/type_error.rs");
     t.compile_fail("tests/ui/where_clause.rs");
 }
diff --git a/embassy-executor/tests/ui/type_error.rs b/embassy-executor/tests/ui/type_error.rs
new file mode 100644
index 000000000..1734bc6c4
--- /dev/null
+++ b/embassy-executor/tests/ui/type_error.rs
@@ -0,0 +1,8 @@
+#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
+
+#[embassy_executor::task]
+async fn task() {
+    5
+}
+
+fn main() {}
diff --git a/embassy-executor/tests/ui/type_error.stderr b/embassy-executor/tests/ui/type_error.stderr
new file mode 100644
index 000000000..bce315811
--- /dev/null
+++ b/embassy-executor/tests/ui/type_error.stderr
@@ -0,0 +1,7 @@
+error[E0308]: mismatched types
+ --> tests/ui/type_error.rs:5:5
+  |
+4 | async fn task() {
+  |                - help: try adding a return type: `-> i32`
+5 |     5
+  |     ^ expected `()`, found integer